summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Caitlin Shkuratov <caitlinshk@google.com> 2022-10-04 21:01:29 +0000
committer Caitlin Shkuratov <caitlinshk@google.com> 2022-10-07 16:53:04 +0000
commitcd5a7d1a326172407dc74880f2e5226a057310fc (patch)
tree9ada81638940973db2e466094bed22673264fa8c
parent7d9b0e622e2f9574e5bcafd15dddef6a465f5c8b (diff)
[Media TTT] Set specific touchable regions for the media chips so that
other touches will get correctly passed through to the window below. Fixes: 249639836 Fixes: 249632655 Test: manual: On lockscreen, display media sender chip then verify you can swipe down to open QS Test: manual: On homescreen, display media receiver chip then verify you can swipe up to see recent apps Test: manual: verify you can still click the Undo button on the "Transfer succeeded" chip Test: atest SystemUITests Change-Id: Idce510fc5b4e0c5ccd74d2b56e1d23db183ebe69
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/temporarydisplay/TouchableRegionViewController.kt57
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/view/ViewUtil.kt35
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TouchableRegionViewControllerTest.kt81
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/view/ViewUtilTest.kt37
10 files changed, 272 insertions, 6 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
index 8fc5519cc73e..04d66af038b4 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
@@ -19,6 +19,7 @@ package com.android.systemui.media.taptotransfer.receiver
import android.annotation.SuppressLint
import android.app.StatusBarManager
import android.content.Context
+import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.graphics.drawable.Icon
import android.media.MediaRoute2Info
@@ -44,6 +45,7 @@ import com.android.systemui.temporarydisplay.TemporaryViewDisplayController
import com.android.systemui.temporarydisplay.TemporaryViewInfo
import com.android.systemui.util.animation.AnimationUtil.Companion.frames
import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.view.ViewUtil
import javax.inject.Inject
/**
@@ -63,6 +65,7 @@ class MediaTttChipControllerReceiver @Inject constructor(
powerManager: PowerManager,
@Main private val mainHandler: Handler,
private val uiEventLogger: MediaTttReceiverUiEventLogger,
+ private val viewUtil: ViewUtil,
) : TemporaryViewDisplayController<ChipReceiverInfo, MediaTttLogger>(
context,
logger,
@@ -83,7 +86,6 @@ class MediaTttChipControllerReceiver @Inject constructor(
height = WindowManager.LayoutParams.MATCH_PARENT
layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
fitInsetsTypes = 0 // Ignore insets from all system bars
- flags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
}
private val commandQueueCallbacks = object : CommandQueue.Callbacks {
@@ -154,14 +156,14 @@ class MediaTttChipControllerReceiver @Inject constructor(
context.resources.getDimensionPixelSize(R.dimen.media_ttt_generic_icon_padding)
}
- val iconView = currentView.requireViewById<CachingIconView>(R.id.app_icon)
+ val iconView = currentView.getAppIconView()
iconView.setPadding(iconPadding, iconPadding, iconPadding, iconPadding)
iconView.setImageDrawable(iconDrawable)
iconView.contentDescription = iconContentDescription
}
override fun animateViewIn(view: ViewGroup) {
- val appIconView = view.requireViewById<View>(R.id.app_icon)
+ val appIconView = view.getAppIconView()
appIconView.animate()
.translationYBy(-1 * getTranslationAmount().toFloat())
.setDuration(30.frames)
@@ -175,6 +177,12 @@ class MediaTttChipControllerReceiver @Inject constructor(
startRipple(view.requireViewById(R.id.ripple))
}
+ override fun getTouchableRegion(view: View, outRect: Rect) {
+ // Even though the app icon view isn't touchable, users might think it is. So, use it as the
+ // touchable region to ensure that touches don't get passed to the window below.
+ viewUtil.setRectToViewWindowLocation(view.getAppIconView(), outRect)
+ }
+
/** Returns the amount that the chip will be translated by in its intro animation. */
private fun getTranslationAmount(): Int {
return context.resources.getDimensionPixelSize(R.dimen.media_ttt_receiver_vert_translation)
@@ -212,6 +220,10 @@ class MediaTttChipControllerReceiver @Inject constructor(
val color = Utils.getColorAttrDefaultColor(context, R.attr.wallpaperTextColorAccent)
rippleView.setColor(color, 70)
}
+
+ private fun View.getAppIconView(): CachingIconView {
+ return this.requireViewById(R.id.app_icon)
+ }
}
data class ChipReceiverInfo(
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
index 11c55285c00b..56e3333f8c9b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
@@ -18,6 +18,7 @@ package com.android.systemui.media.taptotransfer.sender
import android.app.StatusBarManager
import android.content.Context
+import android.graphics.Rect
import android.media.MediaRoute2Info
import android.os.PowerManager
import android.util.Log
@@ -46,6 +47,7 @@ import com.android.systemui.temporarydisplay.TemporaryDisplayRemovalReason
import com.android.systemui.temporarydisplay.TemporaryViewDisplayController
import com.android.systemui.temporarydisplay.TemporaryViewInfo
import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.view.ViewUtil
import dagger.Lazy
import javax.inject.Inject
@@ -68,6 +70,7 @@ open class MediaTttChipControllerSender @Inject constructor(
// And overcome performance issue, check [b/247817628] for details.
private val falsingManager: Lazy<FalsingManager>,
private val falsingCollector: Lazy<FalsingCollector>,
+ private val viewUtil: ViewUtil,
) : TemporaryViewDisplayController<ChipSenderInfo, MediaTttLogger>(
context,
logger,
@@ -224,6 +227,10 @@ open class MediaTttChipControllerSender @Inject constructor(
return false
}
+ override fun getTouchableRegion(view: View, outRect: Rect) {
+ viewUtil.setRectToViewWindowLocation(view, outRect)
+ }
+
private fun Boolean.visibleIfTrue(): Int {
return if (this) {
View.VISIBLE
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
index 91e20ee30976..132d45d0fb18 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
@@ -20,10 +20,12 @@ import android.annotation.LayoutRes
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.PixelFormat
+import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.os.PowerManager
import android.os.SystemClock
import android.view.LayoutInflater
+import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.view.accessibility.AccessibilityManager
@@ -70,7 +72,8 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
width = WindowManager.LayoutParams.WRAP_CONTENT
height = WindowManager.LayoutParams.WRAP_CONTENT
type = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY
- flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
+ WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
title = windowTitle
format = PixelFormat.TRANSLUCENT
setTrustedOverlay()
@@ -87,9 +90,15 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
/** The view currently being displayed. Null if the view is not being displayed. */
private var view: ViewGroup? = null
+ /** The view controller for [view]. Null if the view is not being displayed. */
+ private var viewController: TouchableRegionViewController? = null
+
/** The info currently being displayed. Null if the view is not being displayed. */
internal var info: T? = null
+ // TODO(b/245610654): We should probably group [view], [viewController], and [info] together
+ // into one object since they're either all null or all non-null.
+
/** A [Runnable] that, when run, will cancel the pending timeout of the view. */
private var cancelViewTimeout: Runnable? = null
@@ -141,6 +150,11 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
.from(context)
.inflate(viewLayoutRes, null) as ViewGroup
view = newView
+
+ val newViewController = TouchableRegionViewController(newView, this::getTouchableRegion)
+ newViewController.init()
+ viewController = newViewController
+
updateView(newInfo, newView)
windowManager.addView(newView, windowLayoutParams)
animateViewIn(newView)
@@ -181,6 +195,7 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
// that if a new view event comes in while this view is animating out, we still display the
// new view appropriately.
view = null
+ viewController = null
info = null
// No need to time the view out since it's already gone
cancelViewTimeout?.run()
@@ -202,6 +217,12 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
}
/**
+ * Fills [outRect] with the touchable region of this view. This will be used by WindowManager
+ * to decide which touch events go to the view.
+ */
+ abstract fun getTouchableRegion(view: View, outRect: Rect)
+
+ /**
* A method that can be implemented by subclasses to do custom animations for when the view
* appears.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TouchableRegionViewController.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TouchableRegionViewController.kt
new file mode 100644
index 000000000000..60241a9684d9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TouchableRegionViewController.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.temporarydisplay
+
+import android.graphics.Rect
+import android.view.View
+import android.view.ViewTreeObserver
+import com.android.systemui.util.ViewController
+
+/**
+ * A view controller that will notify the [ViewTreeObserver] about the touchable region for this
+ * view. This will be used by WindowManager to decide which touch events go to the view and which
+ * pass through to the window below.
+ *
+ * @param touchableRegionSetter a function that, given the view and an out rect, fills the rect with
+ * the touchable region of this view.
+ */
+class TouchableRegionViewController(
+ view: View,
+ touchableRegionSetter: (View, Rect) -> Unit,
+) : ViewController<View>(view) {
+
+ private val tempRect = Rect()
+
+ private val internalInsetsListener =
+ ViewTreeObserver.OnComputeInternalInsetsListener { inoutInfo ->
+ inoutInfo.setTouchableInsets(
+ ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION
+ )
+
+ tempRect.setEmpty()
+ touchableRegionSetter.invoke(mView, tempRect)
+ inoutInfo.touchableRegion.set(tempRect)
+ }
+
+ public override fun onViewAttached() {
+ mView.viewTreeObserver.addOnComputeInternalInsetsListener(internalInsetsListener)
+ }
+
+ public override fun onViewDetached() {
+ mView.viewTreeObserver.removeOnComputeInternalInsetsListener(internalInsetsListener)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/view/ViewUtil.kt b/packages/SystemUI/src/com/android/systemui/util/view/ViewUtil.kt
index 613a797f020c..6160b00379ef 100644
--- a/packages/SystemUI/src/com/android/systemui/util/view/ViewUtil.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/view/ViewUtil.kt
@@ -1,5 +1,22 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.systemui.util.view
+import android.graphics.Rect
import android.view.View
import com.android.systemui.dagger.SysUISingleton
import javax.inject.Inject
@@ -23,4 +40,22 @@ class ViewUtil @Inject constructor() {
top <= y &&
y <= top + view.height
}
+
+ /**
+ * Sets [outRect] to be the view's location within its window.
+ */
+ fun setRectToViewWindowLocation(view: View, outRect: Rect) {
+ val locInWindow = IntArray(2)
+ view.getLocationInWindow(locInWindow)
+
+ val x = locInWindow[0]
+ val y = locInWindow[1]
+
+ outRect.set(
+ x,
+ y,
+ x + view.width,
+ y + view.height,
+ )
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
index 775dc11f6edd..f7b30919738c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
@@ -41,6 +41,7 @@ import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
+import com.android.systemui.util.view.ViewUtil
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
@@ -71,6 +72,8 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
@Mock
private lateinit var powerManager: PowerManager
@Mock
+ private lateinit var viewUtil: ViewUtil
+ @Mock
private lateinit var windowManager: WindowManager
@Mock
private lateinit var commandQueue: CommandQueue
@@ -104,7 +107,8 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
configurationController,
powerManager,
Handler.getMain(),
- receiverUiEventLogger
+ receiverUiEventLogger,
+ viewUtil,
)
val callbackCaptor = ArgumentCaptor.forClass(CommandQueue.Callbacks::class.java)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
index eca3bedee108..213b74a6e8a3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
@@ -47,6 +47,7 @@ import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
+import com.android.systemui.util.view.ViewUtil
import com.google.common.truth.Truth.assertThat
import dagger.Lazy
import org.junit.Before
@@ -90,6 +91,8 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
private lateinit var lazyFalsingCollector: Lazy<FalsingCollector>
@Mock
private lateinit var falsingCollector: FalsingCollector
+ @Mock
+ private lateinit var viewUtil: ViewUtil
private lateinit var commandQueueCallback: CommandQueue.Callbacks
private lateinit var fakeAppIconDrawable: Drawable
private lateinit var fakeClock: FakeSystemClock
@@ -130,7 +133,8 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
powerManager,
senderUiEventLogger,
lazyFalsingManager,
- lazyFalsingCollector
+ lazyFalsingCollector,
+ viewUtil,
)
val callbackCaptor = ArgumentCaptor.forClass(CommandQueue.Callbacks::class.java)
@@ -837,6 +841,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
uiEventLogger: MediaTttSenderUiEventLogger,
falsingManager: Lazy<FalsingManager>,
falsingCollector: Lazy<FalsingCollector>,
+ viewUtil: ViewUtil,
) : MediaTttChipControllerSender(
commandQueue,
context,
@@ -849,6 +854,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
uiEventLogger,
falsingManager,
falsingCollector,
+ viewUtil,
) {
override fun animateViewOut(view: ViewGroup, onAnimationEnd: Runnable) {
// Just bypass the animation in tests
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
index 7cb28068fe6c..245ab63b3051 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
@@ -17,7 +17,9 @@
package com.android.systemui.temporarydisplay
import android.content.Context
+import android.graphics.Rect
import android.os.PowerManager
+import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.view.accessibility.AccessibilityManager
@@ -266,6 +268,10 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
override fun shouldIgnoreViewRemoval(removalReason: String): Boolean {
return shouldIgnoreViewRemoval
}
+
+ override fun getTouchableRegion(view: View, outRect: Rect) {
+ outRect.setEmpty()
+ }
}
inner class ViewInfo(val name: String) : TemporaryViewInfo {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TouchableRegionViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TouchableRegionViewControllerTest.kt
new file mode 100644
index 000000000000..7586fe48b308
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TouchableRegionViewControllerTest.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.temporarydisplay
+
+import android.graphics.Rect
+import android.view.View
+import android.view.ViewTreeObserver
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.any
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+class TouchableRegionViewControllerTest : SysuiTestCase() {
+
+ @Mock private lateinit var view: View
+ @Mock private lateinit var viewTreeObserver: ViewTreeObserver
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ whenever(view.viewTreeObserver).thenReturn(viewTreeObserver)
+ }
+
+ @Test
+ fun viewAttached_listenerAdded() {
+ val controller = TouchableRegionViewController(view) { _, _ -> }
+
+ controller.onViewAttached()
+
+ verify(viewTreeObserver).addOnComputeInternalInsetsListener(any())
+ }
+
+ @Test
+ fun viewDetached_listenerRemoved() {
+ val controller = TouchableRegionViewController(view) { _, _ -> }
+
+ controller.onViewDetached()
+
+ verify(viewTreeObserver).removeOnComputeInternalInsetsListener(any())
+ }
+
+ @Test
+ fun listener_usesPassedInFunction() {
+ val controller =
+ TouchableRegionViewController(view) { _, outRect -> outRect.set(1, 2, 3, 4) }
+
+ controller.onViewAttached()
+
+ val captor =
+ ArgumentCaptor.forClass(ViewTreeObserver.OnComputeInternalInsetsListener::class.java)
+ verify(viewTreeObserver).addOnComputeInternalInsetsListener(captor.capture())
+ val listener = captor.value!!
+
+ val inoutInfo = ViewTreeObserver.InternalInsetsInfo()
+ listener.onComputeInternalInsets(inoutInfo)
+
+ assertThat(inoutInfo.touchableRegion.bounds).isEqualTo(Rect(1, 2, 3, 4))
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/view/ViewUtilTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/view/ViewUtilTest.kt
index dead1592992d..e3cd9b2d6eaf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/view/ViewUtilTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/view/ViewUtilTest.kt
@@ -1,12 +1,31 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.systemui.util.view
+import android.graphics.Rect
import android.view.View
import android.widget.TextView
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.any
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
+import org.mockito.Mockito.doAnswer
import org.mockito.Mockito.spy
import org.mockito.Mockito.`when`
@@ -25,6 +44,12 @@ class ViewUtilTest : SysuiTestCase() {
location[0] = VIEW_LEFT
location[1] = VIEW_TOP
`when`(view.locationOnScreen).thenReturn(location)
+ doAnswer { invocation ->
+ val pos = invocation.arguments[0] as IntArray
+ pos[0] = VIEW_LEFT
+ pos[1] = VIEW_TOP
+ null
+ }.`when`(view).getLocationInWindow(any())
}
@Test
@@ -64,6 +89,18 @@ class ViewUtilTest : SysuiTestCase() {
fun touchIsWithinView_yTooLarge_returnsFalse() {
assertThat(viewUtil.touchIsWithinView(view, VIEW_LEFT + 1f, VIEW_BOTTOM + 1f)).isFalse()
}
+
+ @Test
+ fun setRectToViewWindowLocation_rectHasLocation() {
+ val outRect = Rect()
+
+ viewUtil.setRectToViewWindowLocation(view, outRect)
+
+ assertThat(outRect.left).isEqualTo(VIEW_LEFT)
+ assertThat(outRect.right).isEqualTo(VIEW_RIGHT)
+ assertThat(outRect.top).isEqualTo(VIEW_TOP)
+ assertThat(outRect.bottom).isEqualTo(VIEW_BOTTOM)
+ }
}
private const val VIEW_LEFT = 30