Merge changes I61bfb975,I2cb907c5,I13c60b3b into tm-qpr-dev
* changes:
[Media TTT] Animate the sender chip out.
[Chipbar] Define #shouldIgnoreViewRemoval as a specific API on the TemporaryViewDisplayController, instead of having subclasses just override #removeView.
[Media TTT] Add the background back to the receiver chip.
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
index dc2c6356..1b7e26b 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
@@ -361,13 +361,17 @@
*
* The end state of the animation is controlled by [destination]. This value can be any of
* the four corners, any of the four edges, or the center of the view.
+ *
+ * @param onAnimationEnd an optional runnable that will be run once the animation finishes
+ * successfully. Will not be run if the animation is cancelled.
*/
@JvmOverloads
fun animateRemoval(
rootView: View,
destination: Hotspot = Hotspot.CENTER,
interpolator: Interpolator = DEFAULT_REMOVAL_INTERPOLATOR,
- duration: Long = DEFAULT_DURATION
+ duration: Long = DEFAULT_DURATION,
+ onAnimationEnd: Runnable? = null,
): Boolean {
if (
!occupiesSpace(
@@ -391,13 +395,28 @@
addListener(child, listener, recursive = false)
}
- // Remove the view so that a layout update is triggered for the siblings and they
- // animate to their next position while the view's removal is also animating.
- parent.removeView(rootView)
- // By adding the view to the overlay, we can animate it while it isn't part of the view
- // hierarchy. It is correctly positioned because we have its previous bounds, and we set
- // them manually during the animation.
- parent.overlay.add(rootView)
+ val viewHasSiblings = parent.childCount > 1
+ if (viewHasSiblings) {
+ // Remove the view so that a layout update is triggered for the siblings and they
+ // animate to their next position while the view's removal is also animating.
+ parent.removeView(rootView)
+ // By adding the view to the overlay, we can animate it while it isn't part of the
+ // view hierarchy. It is correctly positioned because we have its previous bounds,
+ // and we set them manually during the animation.
+ parent.overlay.add(rootView)
+ }
+ // If this view has no siblings, the parent view may shrink to (0,0) size and mess
+ // up the animation if we immediately remove the view. So instead, we just leave the
+ // view in the real hierarchy until the animation finishes.
+
+ val endRunnable = Runnable {
+ if (viewHasSiblings) {
+ parent.overlay.remove(rootView)
+ } else {
+ parent.removeView(rootView)
+ }
+ onAnimationEnd?.run()
+ }
val startValues =
mapOf(
@@ -430,7 +449,8 @@
endValues,
interpolator,
duration,
- ephemeral = true
+ ephemeral = true,
+ endRunnable,
)
if (rootView is ViewGroup) {
@@ -463,7 +483,6 @@
.alpha(0f)
.setInterpolator(Interpolators.ALPHA_OUT)
.setDuration(duration / 2)
- .withEndAction { parent.overlay.remove(rootView) }
.start()
}
}
@@ -477,7 +496,6 @@
.setInterpolator(Interpolators.ALPHA_OUT)
.setDuration(duration / 2)
.setStartDelay(duration / 2)
- .withEndAction { parent.overlay.remove(rootView) }
.start()
}
diff --git a/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml b/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml
index e079fd3..21d12c2 100644
--- a/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml
+++ b/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml
@@ -29,6 +29,7 @@
<com.android.internal.widget.CachingIconView
android:id="@+id/app_icon"
+ android:background="@drawable/media_ttt_chip_background_receiver"
android:layout_width="@dimen/media_ttt_icon_size_receiver"
android:layout_height="@dimen/media_ttt_icon_size_receiver"
android:layout_gravity="center|bottom"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index f7019dc..8fdfc89 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1056,9 +1056,8 @@
<!-- Media tap-to-transfer chip for receiver device -->
<dimen name="media_ttt_chip_size_receiver">100dp</dimen>
<dimen name="media_ttt_icon_size_receiver">95dp</dimen>
- <!-- Since the generic icon isn't circular, we need to scale it down so it still fits within
- the circular chip. -->
- <dimen name="media_ttt_generic_icon_size_receiver">70dp</dimen>
+ <!-- Add some padding for the generic icon so it doesn't go all the way to the border. -->
+ <dimen name="media_ttt_generic_icon_padding">12dp</dimen>
<dimen name="media_ttt_receiver_vert_translation">20dp</dimen>
<!-- Window magnification -->
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt
index 792ae7c..c3de94f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt
@@ -19,7 +19,6 @@
import android.content.Context
import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
-import com.android.internal.widget.CachingIconView
import com.android.settingslib.Utils
import com.android.systemui.R
@@ -76,29 +75,6 @@
isAppIcon = false
)
}
-
- /**
- * Sets an icon to be displayed by the given view.
- *
- * @param iconSize the size in pixels that the icon should be. If null, the size of
- * [appIconView] will not be adjusted.
- */
- fun setIcon(
- appIconView: CachingIconView,
- icon: Drawable,
- iconContentDescription: CharSequence,
- iconSize: Int? = null,
- ) {
- iconSize?.let { size ->
- val lp = appIconView.layoutParams
- lp.width = size
- lp.height = size
- appIconView.layoutParams = lp
- }
-
- appIconView.contentDescription = iconContentDescription
- appIconView.setImageDrawable(icon)
- }
}
}
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 dfd9e22..8fc5519 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
@@ -30,6 +30,7 @@
import android.view.ViewGroup
import android.view.WindowManager
import android.view.accessibility.AccessibilityManager
+import com.android.internal.widget.CachingIconView
import com.android.settingslib.Utils
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
@@ -146,20 +147,17 @@
)
val iconDrawable = newInfo.appIconDrawableOverride ?: iconInfo.drawable
val iconContentDescription = newInfo.appNameOverride ?: iconInfo.contentDescription
- val iconSize = context.resources.getDimensionPixelSize(
+ val iconPadding =
if (iconInfo.isAppIcon) {
- R.dimen.media_ttt_icon_size_receiver
+ 0
} else {
- R.dimen.media_ttt_generic_icon_size_receiver
+ context.resources.getDimensionPixelSize(R.dimen.media_ttt_generic_icon_padding)
}
- )
- MediaTttUtils.setIcon(
- currentView.requireViewById(R.id.app_icon),
- iconDrawable,
- iconContentDescription,
- iconSize,
- )
+ val iconView = currentView.requireViewById<CachingIconView>(R.id.app_icon)
+ iconView.setPadding(iconPadding, iconPadding, iconPadding, iconPadding)
+ iconView.setImageDrawable(iconDrawable)
+ iconView.contentDescription = iconContentDescription
}
override fun animateViewIn(view: ViewGroup) {
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 007eb8f..11c5528 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
@@ -29,6 +29,7 @@
import android.view.accessibility.AccessibilityManager
import android.widget.TextView
import com.android.internal.statusbar.IUndoMediaTransferCallback
+import com.android.internal.widget.CachingIconView
import com.android.systemui.Gefingerpoken
import com.android.systemui.R
import com.android.systemui.animation.Interpolators
@@ -53,7 +54,7 @@
* chip is shown when a user is transferring media to/from this device and a receiver device.
*/
@SysUISingleton
-class MediaTttChipControllerSender @Inject constructor(
+open class MediaTttChipControllerSender @Inject constructor(
commandQueue: CommandQueue,
context: Context,
@MediaTttSenderLogger logger: MediaTttLogger,
@@ -145,11 +146,9 @@
val iconInfo = MediaTttUtils.getIconInfoFromPackageName(
context, newInfo.routeInfo.clientPackageName, logger
)
- MediaTttUtils.setIcon(
- currentView.requireViewById(R.id.app_icon),
- iconInfo.drawable,
- iconInfo.contentDescription
- )
+ val iconView = currentView.requireViewById<CachingIconView>(R.id.app_icon)
+ iconView.setImageDrawable(iconInfo.drawable)
+ iconView.contentDescription = iconInfo.contentDescription
// Text
val otherDeviceName = newInfo.routeInfo.name.toString()
@@ -196,7 +195,19 @@
)
}
- override fun removeView(removalReason: String) {
+ override fun animateViewOut(view: ViewGroup, onAnimationEnd: Runnable) {
+ ViewHierarchyAnimator.animateRemoval(
+ view.requireViewById<ViewGroup>(R.id.media_ttt_sender_chip_inner),
+ ViewHierarchyAnimator.Hotspot.TOP,
+ Interpolators.EMPHASIZED_ACCELERATE,
+ ANIMATION_DURATION,
+ onAnimationEnd,
+ )
+ // TODO(b/203800644): Add includeMargins as an option to ViewHierarchyAnimator so that the
+ // animateChipOut matches the animateChipIn.
+ }
+
+ override fun shouldIgnoreViewRemoval(removalReason: String): Boolean {
// Don't remove the chip if we're in progress or succeeded, since the user should still be
// able to see the status of the transfer. (But do remove it if it's finally timed out.)
val transferStatus = info?.state?.transferStatus
@@ -208,9 +219,9 @@
logger.logRemovalBypass(
removalReason, bypassReason = "transferStatus=${transferStatus.name}"
)
- return
+ return true
}
- super.removeView(removalReason)
+ return false
}
private fun Boolean.visibleIfTrue(): Int {
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
index a52e2af..91e20ee 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
@@ -167,11 +167,19 @@
* @param removalReason a short string describing why the view was removed (timeout, state
* change, etc.)
*/
- open fun removeView(removalReason: String) {
- if (view == null) { return }
+ fun removeView(removalReason: String) {
+ if (shouldIgnoreViewRemoval(removalReason)) {
+ return
+ }
+ val currentView = view ?: return
+
+ animateViewOut(currentView) { windowManager.removeView(currentView) }
+
logger.logChipRemoval(removalReason)
configurationController.removeCallback(displayScaleListener)
- windowManager.removeView(view)
+ // Re-set the view to null immediately (instead as part of the animation end runnable) so
+ // that if a new view event comes in while this view is animating out, we still display the
+ // new view appropriately.
view = null
info = null
// No need to time the view out since it's already gone
@@ -179,6 +187,13 @@
}
/**
+ * Returns true if a view removal request should be ignored and false otherwise.
+ *
+ * Allows subclasses to keep the view visible for longer in certain circumstances.
+ */
+ open fun shouldIgnoreViewRemoval(removalReason: String): Boolean = false
+
+ /**
* A method implemented by subclasses to update [currentView] based on [newInfo].
*/
@CallSuper
@@ -190,7 +205,17 @@
* A method that can be implemented by subclasses to do custom animations for when the view
* appears.
*/
- open fun animateViewIn(view: ViewGroup) {}
+ internal open fun animateViewIn(view: ViewGroup) {}
+
+ /**
+ * A method that can be implemented by subclasses to do custom animations for when the view
+ * disappears.
+ *
+ * @param onAnimationEnd an action that *must* be run once the animation finishes successfully.
+ */
+ internal open fun animateViewOut(view: ViewGroup, onAnimationEnd: Runnable) {
+ onAnimationEnd.run()
+ }
}
object TemporaryDisplayRemovalReason {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
index 8fc0489..986e7cd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
@@ -718,7 +718,7 @@
}
@Test
- fun animatesViewRemovalFromStartToEnd() {
+ fun animatesViewRemovalFromStartToEnd_viewHasSiblings() {
setUpRootWithChildren()
val child = rootView.getChildAt(0)
@@ -742,6 +742,35 @@
}
@Test
+ fun animatesViewRemovalFromStartToEnd_viewHasNoSiblings() {
+ rootView = LinearLayout(mContext)
+ (rootView as LinearLayout).orientation = LinearLayout.HORIZONTAL
+ (rootView as LinearLayout).weightSum = 1f
+
+ val onlyChild = View(mContext)
+ rootView.addView(onlyChild)
+ forceLayout()
+
+ val success = ViewHierarchyAnimator.animateRemoval(
+ onlyChild,
+ destination = ViewHierarchyAnimator.Hotspot.LEFT,
+ interpolator = Interpolators.LINEAR
+ )
+
+ assertTrue(success)
+ assertNotNull(onlyChild.getTag(R.id.tag_animator))
+ checkBounds(onlyChild, l = 0, t = 0, r = 200, b = 100)
+ advanceAnimation(onlyChild, 0.5f)
+ checkBounds(onlyChild, l = 0, t = 0, r = 100, b = 100)
+ advanceAnimation(onlyChild, 1.0f)
+ checkBounds(onlyChild, l = 0, t = 0, r = 0, b = 100)
+ endAnimation(rootView)
+ endAnimation(onlyChild)
+ assertEquals(0, rootView.childCount)
+ assertFalse(onlyChild in rootView.children)
+ }
+
+ @Test
fun animatesViewRemovalRespectingDestination() {
// CENTER
setUpRootWithChildren()
@@ -964,6 +993,60 @@
}
@Test
+ fun animateRemoval_runnableRunsWhenAnimationEnds() {
+ var runnableRun = false
+ val onAnimationEndRunnable = { runnableRun = true }
+
+ setUpRootWithChildren()
+ forceLayout()
+ val removedView = rootView.getChildAt(0)
+
+ ViewHierarchyAnimator.animateRemoval(
+ removedView,
+ onAnimationEnd = onAnimationEndRunnable
+ )
+ endAnimation(removedView)
+
+ assertEquals(true, runnableRun)
+ }
+
+ @Test
+ fun animateRemoval_runnableDoesNotRunWhenAnimationCancelled() {
+ var runnableRun = false
+ val onAnimationEndRunnable = { runnableRun = true }
+
+ setUpRootWithChildren()
+ forceLayout()
+ val removedView = rootView.getChildAt(0)
+
+ ViewHierarchyAnimator.animateRemoval(
+ removedView,
+ onAnimationEnd = onAnimationEndRunnable
+ )
+ cancelAnimation(removedView)
+
+ assertEquals(false, runnableRun)
+ }
+
+ @Test
+ fun animationRemoval_runnableDoesNotRunWhenOnlyPartwayThroughAnimation() {
+ var runnableRun = false
+ val onAnimationEndRunnable = { runnableRun = true }
+
+ setUpRootWithChildren()
+ forceLayout()
+ val removedView = rootView.getChildAt(0)
+
+ ViewHierarchyAnimator.animateRemoval(
+ removedView,
+ onAnimationEnd = onAnimationEndRunnable
+ )
+ advanceAnimation(removedView, 0.5f)
+
+ assertEquals(false, runnableRun)
+ }
+
+ @Test
fun cleansUpListenersCorrectly() {
val firstChild = View(mContext)
firstChild.layoutParams = LinearLayout.LayoutParams(50 /* width */, 100 /* height */)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt
index 37f6434..7c83cb7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt
@@ -19,9 +19,7 @@
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
-import android.widget.FrameLayout
import androidx.test.filters.SmallTest
-import com.android.internal.widget.CachingIconView
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.any
@@ -90,48 +88,6 @@
assertThat(iconInfo.drawable).isEqualTo(appIconFromPackageName)
assertThat(iconInfo.contentDescription).isEqualTo(APP_NAME)
}
-
- @Test
- fun setIcon_viewHasIconAndContentDescription() {
- val view = CachingIconView(context)
- val icon = context.getDrawable(R.drawable.ic_celebration)!!
- val contentDescription = "Happy birthday!"
-
- MediaTttUtils.setIcon(view, icon, contentDescription)
-
- assertThat(view.drawable).isEqualTo(icon)
- assertThat(view.contentDescription).isEqualTo(contentDescription)
- }
-
- @Test
- fun setIcon_iconSizeNull_viewSizeDoesNotChange() {
- val view = CachingIconView(context)
- val size = 456
- view.layoutParams = FrameLayout.LayoutParams(size, size)
-
- MediaTttUtils.setIcon(view, context.getDrawable(R.drawable.ic_cake)!!, "desc")
-
- assertThat(view.layoutParams.width).isEqualTo(size)
- assertThat(view.layoutParams.height).isEqualTo(size)
- }
-
- @Test
- fun setIcon_iconSizeProvided_viewSizeUpdates() {
- val view = CachingIconView(context)
- val size = 456
- view.layoutParams = FrameLayout.LayoutParams(size, size)
-
- val newSize = 40
- MediaTttUtils.setIcon(
- view,
- context.getDrawable(R.drawable.ic_cake)!!,
- "desc",
- iconSize = newSize
- )
-
- assertThat(view.layoutParams.width).isEqualTo(newSize)
- assertThat(view.layoutParams.height).isEqualTo(newSize)
- }
}
private const val PACKAGE_NAME = "com.android.systemui"
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 d41ad48..775dc11 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
@@ -212,35 +212,27 @@
}
@Test
- fun updateView_isAppIcon_usesAppIconSize() {
+ fun updateView_isAppIcon_usesAppIconPadding() {
controllerReceiver.displayView(getChipReceiverInfo(packageName = PACKAGE_NAME))
+
val chipView = getChipView()
-
- chipView.measure(
- View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
- View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
- )
-
- val expectedSize =
- context.resources.getDimensionPixelSize(R.dimen.media_ttt_icon_size_receiver)
- assertThat(chipView.getAppIconView().measuredWidth).isEqualTo(expectedSize)
- assertThat(chipView.getAppIconView().measuredHeight).isEqualTo(expectedSize)
+ assertThat(chipView.getAppIconView().paddingLeft).isEqualTo(0)
+ assertThat(chipView.getAppIconView().paddingRight).isEqualTo(0)
+ assertThat(chipView.getAppIconView().paddingTop).isEqualTo(0)
+ assertThat(chipView.getAppIconView().paddingBottom).isEqualTo(0)
}
@Test
- fun updateView_notAppIcon_usesGenericIconSize() {
+ fun updateView_notAppIcon_usesGenericIconPadding() {
controllerReceiver.displayView(getChipReceiverInfo(packageName = null))
+
val chipView = getChipView()
-
- chipView.measure(
- View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
- View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
- )
-
- val expectedSize =
- context.resources.getDimensionPixelSize(R.dimen.media_ttt_generic_icon_size_receiver)
- assertThat(chipView.getAppIconView().measuredWidth).isEqualTo(expectedSize)
- assertThat(chipView.getAppIconView().measuredHeight).isEqualTo(expectedSize)
+ val expectedPadding =
+ context.resources.getDimensionPixelSize(R.dimen.media_ttt_generic_icon_padding)
+ assertThat(chipView.getAppIconView().paddingLeft).isEqualTo(expectedPadding)
+ assertThat(chipView.getAppIconView().paddingRight).isEqualTo(expectedPadding)
+ assertThat(chipView.getAppIconView().paddingTop).isEqualTo(expectedPadding)
+ assertThat(chipView.getAppIconView().paddingBottom).isEqualTo(expectedPadding)
}
@Test
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 098086a..eca3bed 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
@@ -17,6 +17,7 @@
package com.android.systemui.media.taptotransfer.sender
import android.app.StatusBarManager
+import android.content.Context
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
@@ -37,9 +38,11 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.media.taptotransfer.common.MediaTttLogger
+import com.android.systemui.media.taptotransfer.receiver.MediaTttReceiverLogger
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
@@ -61,7 +64,7 @@
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
class MediaTttChipControllerSenderTest : SysuiTestCase() {
- private lateinit var controllerSender: MediaTttChipControllerSender
+ private lateinit var controllerSender: TestMediaTttChipControllerSender
@Mock
private lateinit var packageManager: PackageManager
@@ -116,7 +119,7 @@
whenever(lazyFalsingManager.get()).thenReturn(falsingManager)
whenever(lazyFalsingCollector.get()).thenReturn(falsingCollector)
- controllerSender = MediaTttChipControllerSender(
+ controllerSender = TestMediaTttChipControllerSender(
commandQueue,
context,
logger,
@@ -821,6 +824,37 @@
/** Helper method providing default parameters to not clutter up the tests. */
private fun transferToThisDeviceFailed() =
ChipSenderInfo(ChipStateSender.TRANSFER_TO_RECEIVER_FAILED, routeInfo)
+
+ private class TestMediaTttChipControllerSender(
+ commandQueue: CommandQueue,
+ context: Context,
+ @MediaTttReceiverLogger logger: MediaTttLogger,
+ windowManager: WindowManager,
+ mainExecutor: DelayableExecutor,
+ accessibilityManager: AccessibilityManager,
+ configurationController: ConfigurationController,
+ powerManager: PowerManager,
+ uiEventLogger: MediaTttSenderUiEventLogger,
+ falsingManager: Lazy<FalsingManager>,
+ falsingCollector: Lazy<FalsingCollector>,
+ ) : MediaTttChipControllerSender(
+ commandQueue,
+ context,
+ logger,
+ windowManager,
+ mainExecutor,
+ accessibilityManager,
+ configurationController,
+ powerManager,
+ uiEventLogger,
+ falsingManager,
+ falsingCollector,
+ ) {
+ override fun animateViewOut(view: ViewGroup, onAnimationEnd: Runnable) {
+ // Just bypass the animation in tests
+ onAnimationEnd.run()
+ }
+ }
}
private const val APP_NAME = "Fake app name"
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 921b7ef..7cb2806 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
@@ -61,6 +61,8 @@
@Mock
private lateinit var powerManager: PowerManager
+ private var shouldIgnoreViewRemoval: Boolean = false
+
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
@@ -205,6 +207,26 @@
verify(windowManager, never()).removeView(any())
}
+ @Test
+ fun removeView_shouldIgnoreRemovalFalse_viewRemoved() {
+ shouldIgnoreViewRemoval = false
+ underTest.displayView(getState())
+
+ underTest.removeView("reason")
+
+ verify(windowManager).removeView(any())
+ }
+
+ @Test
+ fun removeView_shouldIgnoreRemovalTrue_viewNotRemoved() {
+ shouldIgnoreViewRemoval = true
+ underTest.displayView(getState())
+
+ underTest.removeView("reason")
+
+ verify(windowManager, never()).removeView(any())
+ }
+
private fun getState(name: String = "name") = ViewInfo(name)
private fun getConfigurationListener(): ConfigurationListener {
@@ -240,6 +262,10 @@
super.updateView(newInfo, currentView)
mostRecentViewInfo = newInfo
}
+
+ override fun shouldIgnoreViewRemoval(removalReason: String): Boolean {
+ return shouldIgnoreViewRemoval
+ }
}
inner class ViewInfo(val name: String) : TemporaryViewInfo {