@onekeyfe/react-native-native-overlay 3.0.162-alpha.270 → 6.7.0-11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/build.gradle +6 -0
- package/android/src/main/java/com/onekey/nativeoverlay/NativeOverlayAccessibilityIsolation.kt +37 -0
- package/android/src/main/java/com/onekey/nativeoverlay/NativeOverlayAnimation.kt +5 -10
- package/android/src/main/java/com/onekey/nativeoverlay/NativeOverlayEntryRootView.kt +23 -2
- package/android/src/main/java/com/onekey/nativeoverlay/NativeOverlayHost.kt +31 -32
- package/android/src/main/java/com/onekey/nativeoverlay/NativeOverlayPageHostView.kt +21 -0
- package/android/src/main/java/com/onekey/nativeoverlay/NativeOverlayView.kt +10 -3
- package/android/src/test/java/com/onekey/nativeoverlay/NativeOverlayAccessibilityIsolationTest.kt +112 -0
- package/android/src/test/java/com/onekey/nativeoverlay/NativeOverlayBackTest.kt +295 -0
- package/android/src/test/java/com/onekey/nativeoverlay/NativeOverlayMotionTest.kt +101 -0
- package/docs/SPEC.md +198 -30
- package/ios/NativeOverlayContainerView.swift +20 -7
- package/ios/NativeOverlaySheetController.swift +37 -1
- package/lib/module/OverlayPageHost.web.js +19 -6
- package/lib/module/OverlayPageHost.web.js.map +1 -1
- package/lib/module/OverlayStore.js +13 -1
- package/lib/module/OverlayStore.js.map +1 -1
- package/lib/module/OverlayView.web.js +107 -25
- package/lib/module/OverlayView.web.js.map +1 -1
- package/lib/module/useOverlayController.js +11 -3
- package/lib/module/useOverlayController.js.map +1 -1
- package/lib/module/web/animateTransition.js +20 -12
- package/lib/module/web/animateTransition.js.map +1 -1
- package/lib/module/web/overlayLayers.js +27 -9
- package/lib/module/web/overlayLayers.js.map +1 -1
- package/lib/module/web/useKeyboardShift.js +1 -1
- package/lib/module/web/useKeyboardShift.js.map +1 -1
- package/lib/module/web/useSheetDrag.js +22 -2
- package/lib/module/web/useSheetDrag.js.map +1 -1
- package/lib/typescript/src/OverlayPageHost.web.d.ts.map +1 -1
- package/lib/typescript/src/OverlayStore.d.ts +2 -0
- package/lib/typescript/src/OverlayStore.d.ts.map +1 -1
- package/lib/typescript/src/OverlayView.web.d.ts.map +1 -1
- package/lib/typescript/src/useOverlayController.d.ts.map +1 -1
- package/lib/typescript/src/web/animateTransition.d.ts +2 -2
- package/lib/typescript/src/web/animateTransition.d.ts.map +1 -1
- package/lib/typescript/src/web/overlayLayers.d.ts +3 -0
- package/lib/typescript/src/web/overlayLayers.d.ts.map +1 -1
- package/lib/typescript/src/web/useSheetDrag.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/OverlayPageHost.web.tsx +24 -9
- package/src/OverlayStore.ts +13 -1
- package/src/OverlayView.web.tsx +197 -56
- package/src/useOverlayController.ts +11 -4
- package/src/web/animateTransition.ts +30 -11
- package/src/web/overlayLayers.ts +48 -10
- package/src/web/useKeyboardShift.ts +1 -1
- package/src/web/useSheetDrag.ts +23 -2
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
package com.onekey.nativeoverlay
|
|
2
|
+
|
|
3
|
+
import android.view.KeyEvent
|
|
4
|
+
import android.view.MotionEvent
|
|
5
|
+
import android.view.View
|
|
6
|
+
import android.widget.FrameLayout
|
|
7
|
+
import androidx.activity.ComponentActivity
|
|
8
|
+
import com.facebook.react.bridge.BridgeReactContext
|
|
9
|
+
import com.facebook.react.uimanager.PointerEvents
|
|
10
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
11
|
+
import com.facebook.react.uimanager.TouchTargetHelper
|
|
12
|
+
import com.facebook.react.views.view.ReactViewGroup
|
|
13
|
+
import java.lang.ref.WeakReference
|
|
14
|
+
import java.util.WeakHashMap
|
|
15
|
+
import org.junit.Assert.assertEquals
|
|
16
|
+
import org.junit.Assert.assertFalse
|
|
17
|
+
import org.junit.Assert.assertNotSame
|
|
18
|
+
import org.junit.Assert.assertSame
|
|
19
|
+
import org.junit.Assert.assertTrue
|
|
20
|
+
import org.junit.Before
|
|
21
|
+
import org.junit.Test
|
|
22
|
+
import org.junit.runner.RunWith
|
|
23
|
+
import org.robolectric.Robolectric
|
|
24
|
+
import org.robolectric.RobolectricTestRunner
|
|
25
|
+
import org.robolectric.annotation.Config
|
|
26
|
+
|
|
27
|
+
@RunWith(RobolectricTestRunner::class)
|
|
28
|
+
@Config(sdk = [34])
|
|
29
|
+
class NativeOverlayBackTest {
|
|
30
|
+
private lateinit var activity: ComponentActivity
|
|
31
|
+
private lateinit var context: ThemedReactContext
|
|
32
|
+
private lateinit var host: NativeOverlayHost
|
|
33
|
+
private val dismissals = mutableListOf<String>()
|
|
34
|
+
|
|
35
|
+
@Before
|
|
36
|
+
fun setUp() {
|
|
37
|
+
activity = Robolectric.buildActivity(ComponentActivity::class.java).setup().visible().get()
|
|
38
|
+
val reactContext = BridgeReactContext(activity)
|
|
39
|
+
reactContext.onHostResume(activity)
|
|
40
|
+
context = ThemedReactContext(reactContext, activity, "OverlayBackTest", 1)
|
|
41
|
+
host = NativeOverlayHost.of(activity)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private fun entry(name: String, blocking: Boolean, dismissible: Boolean, order: Int = 0) =
|
|
45
|
+
NativeOverlayEntryRootView(context).apply {
|
|
46
|
+
this.blocking = blocking
|
|
47
|
+
dismissOnBackPress = dismissible
|
|
48
|
+
stackOrder = order
|
|
49
|
+
isShownForInput = true
|
|
50
|
+
onRequestDismiss = { dismissals.add("$name:$it") }
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private fun back(action: Int = KeyEvent.ACTION_UP, flags: Int = 0) =
|
|
54
|
+
host.handleBackKey(KeyEvent(0L, 0L, action, KeyEvent.KEYCODE_BACK, 0, 0, 0, 0, flags))
|
|
55
|
+
|
|
56
|
+
@Test
|
|
57
|
+
fun dismissibleNonBlockingGlobalEntryWinsOverLowerBlocker() {
|
|
58
|
+
host.attach(entry("lower", true, true), NativeOverlayLevel.MODAL)
|
|
59
|
+
host.attach(entry("top", false, true), NativeOverlayLevel.TOAST)
|
|
60
|
+
assertTrue(back(KeyEvent.ACTION_DOWN))
|
|
61
|
+
assertEquals(emptyList<String>(), dismissals)
|
|
62
|
+
assertTrue(back())
|
|
63
|
+
assertEquals(listOf("top:back"), dismissals)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@Test
|
|
67
|
+
fun dispatcherHandlesNonBlockingEntryAndKeepsPageAccessible() {
|
|
68
|
+
val page = View(activity).apply { importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_YES }
|
|
69
|
+
activity.setContentView(page)
|
|
70
|
+
val top = entry("top", false, true)
|
|
71
|
+
host.attach(top, NativeOverlayLevel.MODAL)
|
|
72
|
+
activity.onBackPressedDispatcher.onBackPressed()
|
|
73
|
+
assertEquals(listOf("top:back"), dismissals)
|
|
74
|
+
assertEquals(View.IMPORTANT_FOR_ACCESSIBILITY_YES, page.importantForAccessibility)
|
|
75
|
+
host.detach(top)
|
|
76
|
+
assertFalse(back())
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
@Test
|
|
80
|
+
fun nonDismissibleBlockerConsumesBackWithoutClosingLowerEntry() {
|
|
81
|
+
host.attach(entry("lower", false, true), NativeOverlayLevel.MODAL)
|
|
82
|
+
host.attach(entry("lock", true, false), NativeOverlayLevel.LOCK)
|
|
83
|
+
assertTrue(back())
|
|
84
|
+
assertEquals(emptyList<String>(), dismissals)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@Test
|
|
88
|
+
fun passiveOrNotInputReadyEntriesDoNotTakeBack() {
|
|
89
|
+
host.attach(entry("passive", false, false), NativeOverlayLevel.TOAST)
|
|
90
|
+
host.attach(entry("hidden", true, true).apply { isShownForInput = false }, NativeOverlayLevel.LOCK)
|
|
91
|
+
assertFalse(back())
|
|
92
|
+
assertEquals(emptyList<String>(), dismissals)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
@Test
|
|
96
|
+
fun canceledKeyUpDoesNotDismiss() {
|
|
97
|
+
host.attach(entry("top", false, true), NativeOverlayLevel.MODAL)
|
|
98
|
+
assertTrue(back(flags = KeyEvent.FLAG_CANCELED))
|
|
99
|
+
assertEquals(emptyList<String>(), dismissals)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
@Test
|
|
103
|
+
fun dismissiblePageEntryWinsOverLowerPageBlockerAndSuspensionSkipsIt() {
|
|
104
|
+
val pageHost = NativeOverlayPageHostView(context).apply { hostKey = "page-back-test" }
|
|
105
|
+
activity.setContentView(pageHost)
|
|
106
|
+
val lower = entry("lower", true, true).apply { ownerKey = "owner" }
|
|
107
|
+
val top = entry("top", false, true, 1).apply { ownerKey = "owner" }
|
|
108
|
+
pageHost.attach(lower)
|
|
109
|
+
pageHost.attach(top)
|
|
110
|
+
assertTrue(back())
|
|
111
|
+
assertEquals(listOf("top:back"), dismissals)
|
|
112
|
+
pageHost.setSuspendedOwners("owner")
|
|
113
|
+
assertFalse(back())
|
|
114
|
+
pageHost.invalidateHost()
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@Test
|
|
118
|
+
fun globalEntryTakesBackBeforePageEntryAndDismissalRestoresPageTarget() {
|
|
119
|
+
val pageHost = NativeOverlayPageHostView(context).apply { hostKey = "page-global-test" }
|
|
120
|
+
activity.setContentView(FrameLayout(activity).apply { addView(pageHost) })
|
|
121
|
+
pageHost.attach(entry("page", false, true))
|
|
122
|
+
val global = entry("global", false, true)
|
|
123
|
+
host.attach(global, NativeOverlayLevel.MODAL)
|
|
124
|
+
assertTrue(back())
|
|
125
|
+
host.detach(global)
|
|
126
|
+
assertTrue(back())
|
|
127
|
+
assertEquals(listOf("global:back", "page:back"), dismissals)
|
|
128
|
+
pageHost.invalidateHost()
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
@Test
|
|
132
|
+
fun closingGlobalBlockerKeepsTouchBackAndAccessibilityOwnership() {
|
|
133
|
+
var pageTouches = 0
|
|
134
|
+
val page = View(activity).apply {
|
|
135
|
+
setOnTouchListener { _, _ ->
|
|
136
|
+
pageTouches += 1
|
|
137
|
+
true
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
activity.setContentView(page)
|
|
141
|
+
val lower = entry("lower", true, true)
|
|
142
|
+
val top = entry("top", true, true, 1)
|
|
143
|
+
host.attach(lower, NativeOverlayLevel.MODAL)
|
|
144
|
+
host.attach(top, NativeOverlayLevel.MODAL)
|
|
145
|
+
top.isClosing = true
|
|
146
|
+
host.onEntriesChanged()
|
|
147
|
+
|
|
148
|
+
assertEquals(PointerEvents.BOX_ONLY, top.pointerEvents)
|
|
149
|
+
assertEquals(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, top.contentView.importantForAccessibility)
|
|
150
|
+
assertEquals(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, page.importantForAccessibility)
|
|
151
|
+
assertEquals(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, lower.importantForAccessibility)
|
|
152
|
+
assertTrue(back())
|
|
153
|
+
assertEquals(emptyList<String>(), dismissals)
|
|
154
|
+
|
|
155
|
+
val content = activity.findViewById<FrameLayout>(android.R.id.content)
|
|
156
|
+
val size = View.MeasureSpec.makeMeasureSpec(300, View.MeasureSpec.EXACTLY)
|
|
157
|
+
content.measure(size, size)
|
|
158
|
+
content.layout(0, 0, 300, 300)
|
|
159
|
+
val down = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 150f, 150f, 0)
|
|
160
|
+
try {
|
|
161
|
+
assertTrue(content.dispatchTouchEvent(down))
|
|
162
|
+
assertEquals(0, pageTouches)
|
|
163
|
+
} finally {
|
|
164
|
+
down.recycle()
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
top.isClosing = false
|
|
168
|
+
host.onEntriesChanged()
|
|
169
|
+
assertEquals(PointerEvents.AUTO, top.pointerEvents)
|
|
170
|
+
assertEquals(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO, top.contentView.importantForAccessibility)
|
|
171
|
+
assertTrue(back())
|
|
172
|
+
assertEquals(listOf("top:back"), dismissals)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
@Test
|
|
176
|
+
fun closingPageBlockerStillTakesBack() {
|
|
177
|
+
val pageHost = NativeOverlayPageHostView(context).apply { hostKey = "closing-page" }
|
|
178
|
+
activity.setContentView(pageHost)
|
|
179
|
+
val top = entry("page", true, true)
|
|
180
|
+
pageHost.attach(top)
|
|
181
|
+
top.isClosing = true
|
|
182
|
+
host.onEntriesChanged()
|
|
183
|
+
|
|
184
|
+
assertEquals(PointerEvents.BOX_ONLY, top.pointerEvents)
|
|
185
|
+
assertTrue(back())
|
|
186
|
+
assertEquals(emptyList<String>(), dismissals)
|
|
187
|
+
top.isClosing = false
|
|
188
|
+
host.onEntriesChanged()
|
|
189
|
+
assertEquals(PointerEvents.AUTO, top.pointerEvents)
|
|
190
|
+
assertTrue(back())
|
|
191
|
+
assertEquals(listOf("page:back"), dismissals)
|
|
192
|
+
pageHost.invalidateHost()
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
@Test
|
|
196
|
+
fun pageEntryHitTestingKeepsClosingContentAndLowerPageSeparate() {
|
|
197
|
+
val root = ReactViewGroup(context).apply { id = 101 }
|
|
198
|
+
val below = ReactViewGroup(context).apply { id = 102 }
|
|
199
|
+
val child = ReactViewGroup(context).apply { id = 103 }
|
|
200
|
+
val pageHost = NativeOverlayPageHostView(context).apply { hostKey = "page-hit-test" }
|
|
201
|
+
root.addView(below)
|
|
202
|
+
root.addView(pageHost)
|
|
203
|
+
activity.setContentView(root)
|
|
204
|
+
val overlay = entry("page", true, true)
|
|
205
|
+
overlay.contentView.addView(child)
|
|
206
|
+
pageHost.attach(overlay)
|
|
207
|
+
|
|
208
|
+
val size = View.MeasureSpec.makeMeasureSpec(300, View.MeasureSpec.EXACTLY)
|
|
209
|
+
root.measure(size, size)
|
|
210
|
+
root.layout(0, 0, 300, 300)
|
|
211
|
+
below.layout(0, 0, 300, 300)
|
|
212
|
+
pageHost.layout(0, 0, 300, 300)
|
|
213
|
+
child.layout(0, 0, 300, 300)
|
|
214
|
+
|
|
215
|
+
fun target() = TouchTargetHelper.findTargetTagForTouch(150f, 150f, root)
|
|
216
|
+
assertEquals(child.id, target())
|
|
217
|
+
overlay.isClosing = true
|
|
218
|
+
assertEquals(root.id, target())
|
|
219
|
+
overlay.updateBlocking(false)
|
|
220
|
+
assertEquals(below.id, target())
|
|
221
|
+
overlay.updateBlocking(true)
|
|
222
|
+
overlay.isClosing = false
|
|
223
|
+
assertEquals(child.id, target())
|
|
224
|
+
pageHost.invalidateHost()
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
@Test
|
|
228
|
+
fun reopeningCoveredClosingEntryRestoresItsContentAccessibility() {
|
|
229
|
+
activity.setContentView(View(activity))
|
|
230
|
+
val first = entry("first", true, true)
|
|
231
|
+
val second = entry("second", true, true)
|
|
232
|
+
host.attach(first, NativeOverlayLevel.MODAL)
|
|
233
|
+
first.isClosing = true
|
|
234
|
+
host.onEntriesChanged()
|
|
235
|
+
host.attach(second, NativeOverlayLevel.SECURE)
|
|
236
|
+
|
|
237
|
+
first.isClosing = false
|
|
238
|
+
host.onEntriesChanged()
|
|
239
|
+
assertEquals(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, first.importantForAccessibility)
|
|
240
|
+
host.detach(second)
|
|
241
|
+
assertEquals(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO, first.importantForAccessibility)
|
|
242
|
+
assertEquals(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO, first.contentView.importantForAccessibility)
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
@Test
|
|
246
|
+
fun closingNonBlockingEntryPassesTouchAndBackToLowerBlocker() {
|
|
247
|
+
val lower = entry("lower", true, true)
|
|
248
|
+
val toast = entry("toast", false, true)
|
|
249
|
+
host.attach(lower, NativeOverlayLevel.MODAL)
|
|
250
|
+
host.attach(toast, NativeOverlayLevel.TOAST)
|
|
251
|
+
toast.isClosing = true
|
|
252
|
+
host.onEntriesChanged()
|
|
253
|
+
|
|
254
|
+
assertEquals(PointerEvents.NONE, toast.pointerEvents)
|
|
255
|
+
val down = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 150f, 150f, 0)
|
|
256
|
+
try {
|
|
257
|
+
assertFalse(toast.dispatchTouchEvent(down))
|
|
258
|
+
} finally {
|
|
259
|
+
down.recycle()
|
|
260
|
+
}
|
|
261
|
+
assertTrue(back())
|
|
262
|
+
assertEquals(listOf("lower:back"), dismissals)
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
@Test
|
|
266
|
+
fun hostCacheReusesLiveHostAndSeparatesActivities() {
|
|
267
|
+
assertSame(host, NativeOverlayHost.of(activity))
|
|
268
|
+
val otherActivity = Robolectric.buildActivity(ComponentActivity::class.java).setup().get()
|
|
269
|
+
assertNotSame(host, NativeOverlayHost.of(otherActivity))
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
@Test
|
|
273
|
+
fun hostCacheRebuildsAfterWeakValueIsCleared() {
|
|
274
|
+
val field = NativeOverlayHost::class.java.getDeclaredField("hosts").apply {
|
|
275
|
+
isAccessible = true
|
|
276
|
+
}
|
|
277
|
+
val cache = field.get(null) as WeakHashMap<*, *>
|
|
278
|
+
(cache[activity] as WeakReference<*>).clear()
|
|
279
|
+
val replacement = NativeOverlayHost.of(activity)
|
|
280
|
+
assertNotSame(host, replacement)
|
|
281
|
+
assertSame(replacement, NativeOverlayHost.of(activity))
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
@Test
|
|
285
|
+
fun pageOnlyBackInterceptorRetainsItsHost() {
|
|
286
|
+
val pageHost = NativeOverlayPageHostView(context).apply { hostKey = "page-only" }
|
|
287
|
+
activity.setContentView(pageHost)
|
|
288
|
+
pageHost.attach(entry("page", false, true))
|
|
289
|
+
host.installBackInterceptor()
|
|
290
|
+
assertTrue(activity.window.callback.dispatchKeyEvent(KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK)))
|
|
291
|
+
assertEquals(listOf("page:back"), dismissals)
|
|
292
|
+
assertSame(host, NativeOverlayHost.of(activity))
|
|
293
|
+
pageHost.invalidateHost()
|
|
294
|
+
}
|
|
295
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
package com.onekey.nativeoverlay
|
|
2
|
+
|
|
3
|
+
import android.graphics.Color
|
|
4
|
+
import android.os.Looper
|
|
5
|
+
import android.view.View
|
|
6
|
+
import androidx.activity.ComponentActivity
|
|
7
|
+
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
|
8
|
+
import com.facebook.react.bridge.BridgeReactContext
|
|
9
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
10
|
+
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
|
11
|
+
import org.junit.Assert.assertEquals
|
|
12
|
+
import org.junit.Assert.assertFalse
|
|
13
|
+
import org.junit.Assert.assertNotSame
|
|
14
|
+
import org.junit.Assert.assertSame
|
|
15
|
+
import org.junit.Assert.assertTrue
|
|
16
|
+
import org.junit.Test
|
|
17
|
+
import org.junit.runner.RunWith
|
|
18
|
+
import org.robolectric.Robolectric
|
|
19
|
+
import org.robolectric.RobolectricTestRunner
|
|
20
|
+
import org.robolectric.Shadows
|
|
21
|
+
import org.robolectric.annotation.Config
|
|
22
|
+
import java.time.Duration
|
|
23
|
+
|
|
24
|
+
@RunWith(RobolectricTestRunner::class)
|
|
25
|
+
@Config(sdk = [34])
|
|
26
|
+
class NativeOverlayMotionTest {
|
|
27
|
+
@Test
|
|
28
|
+
fun sheetAnimationMovesCoordinatorWithoutTakingMaterialsSheetTranslation() {
|
|
29
|
+
val activity = Robolectric.buildActivity(ComponentActivity::class.java).setup().get()
|
|
30
|
+
val reactContext = BridgeReactContext(activity)
|
|
31
|
+
reactContext.onHostResume(activity)
|
|
32
|
+
val context = ThemedReactContext(reactContext, activity, "OverlayMotionTest", 1)
|
|
33
|
+
val entry = NativeOverlayEntryRootView(context)
|
|
34
|
+
assertSame(entry.contentView, entry.animatedView)
|
|
35
|
+
|
|
36
|
+
entry.configureSheet(500, 16f, Color.WHITE, showHandle = true, draggable = true)
|
|
37
|
+
val sheet = entry.sheetView!!
|
|
38
|
+
val animated = entry.animatedView
|
|
39
|
+
assertTrue(animated is CoordinatorLayout)
|
|
40
|
+
assertSame(animated, sheet.parent)
|
|
41
|
+
assertNotSame(sheet, animated)
|
|
42
|
+
assertTrue((sheet.layoutParams as CoordinatorLayout.LayoutParams).behavior is BottomSheetBehavior<*>)
|
|
43
|
+
|
|
44
|
+
animated.translationY = 42f
|
|
45
|
+
assertEquals(0f, sheet.translationY)
|
|
46
|
+
sheet.translationY = 7f
|
|
47
|
+
assertEquals(42f, animated.translationY)
|
|
48
|
+
assertEquals(7f, sheet.translationY)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@Test
|
|
52
|
+
fun quickMatchesMeasuredCriticalResponseWithoutChangingUnderdampedResponse() {
|
|
53
|
+
val quick = OverlayMotion.QUICK
|
|
54
|
+
assertEquals(292L, quick.durationMs())
|
|
55
|
+
assertEquals(0.8238140348, SpringInterpolator.progressAt(quick, 0.1), 0.000001)
|
|
56
|
+
assertEquals(0.9990003945, SpringInterpolator.progressAt(quick, 0.292), 0.000001)
|
|
57
|
+
|
|
58
|
+
val underdamped = OverlayMotion.Spring(1.0, 100.0, 5.0)
|
|
59
|
+
assertEquals(0.3929451508, SpringInterpolator.progressAt(underdamped, 0.1), 0.000001)
|
|
60
|
+
val timing = OverlayMotion.Timing(250L, 0.25f, 0.1f, 0.25f, 1f)
|
|
61
|
+
assertEquals(250L, timing.durationMs())
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@Test
|
|
65
|
+
fun reopeningTheSameEntryDuringExitRetargetsItsAnimation() {
|
|
66
|
+
val activity = Robolectric.buildActivity(ComponentActivity::class.java).setup().visible().get()
|
|
67
|
+
val reactContext = BridgeReactContext(activity)
|
|
68
|
+
reactContext.onHostResume(activity)
|
|
69
|
+
val context = ThemedReactContext(reactContext, activity, "OverlayMotionTest", 1)
|
|
70
|
+
val overlay = NativeOverlayView(context).apply {
|
|
71
|
+
presentation = "sheet"
|
|
72
|
+
sheetHeight = 200.0
|
|
73
|
+
addReactChild(View(context))
|
|
74
|
+
}
|
|
75
|
+
activity.setContentView(overlay)
|
|
76
|
+
var dismissals = 0
|
|
77
|
+
overlay.onDismissed = { dismissals++ }
|
|
78
|
+
overlay.visible = true
|
|
79
|
+
overlay.commitConfiguration()
|
|
80
|
+
|
|
81
|
+
val entryField = NativeOverlayView::class.java.getDeclaredField("entry").apply { isAccessible = true }
|
|
82
|
+
val original = entryField.get(overlay) as NativeOverlayEntryRootView
|
|
83
|
+
overlay.visible = false
|
|
84
|
+
overlay.commitConfiguration()
|
|
85
|
+
assertTrue(original.isClosing)
|
|
86
|
+
|
|
87
|
+
overlay.visible = true
|
|
88
|
+
overlay.commitConfiguration()
|
|
89
|
+
assertSame(original, entryField.get(overlay))
|
|
90
|
+
assertTrue(original.isShownForInput)
|
|
91
|
+
assertFalse(original.isClosing)
|
|
92
|
+
assertEquals(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO, original.contentView.importantForAccessibility)
|
|
93
|
+
Shadows.shadowOf(Looper.getMainLooper()).idleFor(Duration.ofMillis(350))
|
|
94
|
+
assertEquals(0, dismissals)
|
|
95
|
+
|
|
96
|
+
overlay.visible = false
|
|
97
|
+
overlay.commitConfiguration()
|
|
98
|
+
Shadows.shadowOf(Looper.getMainLooper()).idleFor(Duration.ofMillis(350))
|
|
99
|
+
assertEquals(1, dismissals)
|
|
100
|
+
}
|
|
101
|
+
}
|