Loading packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt +81 −42 Original line number Diff line number Diff line Loading @@ -20,9 +20,11 @@ import android.content.Context import android.graphics.Insets import android.graphics.Rect import android.testing.TestableLooper import android.testing.ViewUtils import android.view.Gravity import android.view.View import android.widget.FrameLayout import androidx.compose.ui.platform.ComposeView import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase Loading Loading @@ -55,6 +57,7 @@ class SystemEventChipAnimationControllerTest : SysuiTestCase() { @Mock private lateinit var sbWindowController: StatusBarWindowController @Mock private lateinit var insetsProvider: StatusBarContentInsetsProvider private val statusbarFake = FrameLayout(mContext) private var testView = TestView(mContext) private var viewCreator: ViewCreator = { testView } Loading @@ -64,7 +67,6 @@ class SystemEventChipAnimationControllerTest : SysuiTestCase() { // StatusBarWindowController is mocked. The addViewToWindow function needs to be mocked to // ensure that the chip view is added to a parent view whenever(sbWindowController.addViewToWindow(any(), any())).then { val statusbarFake = FrameLayout(mContext) statusbarFake.layout( portraitArea.left, portraitArea.top, Loading Loading @@ -108,18 +110,25 @@ class SystemEventChipAnimationControllerTest : SysuiTestCase() { @Test fun prepareChipAnimation_positionsChip() { try { ViewUtils.attachView(statusbarFake) TestableLooper.get(this).processAllMessages() controller.prepareChipAnimation(viewCreator) val chipRect = controller.chipBounds // SB area = 10, 10, 990, 100 // chip size = 0, 0, 100, 50 val chipRect = controller.chipBounds assertThat(chipRect).isEqualTo(Rect(890, 30, 990, 80)) } finally { ViewUtils.detachView(statusbarFake) } } @Test fun prepareChipAnimation_rotation_repositionsChip() { controller.prepareChipAnimation(viewCreator) try { ViewUtils.attachView(statusbarFake) TestableLooper.get(this).processAllMessages() controller.prepareChipAnimation(viewCreator) // Chip has been prepared, and is located at (890, 30, 990, 75) // Rotation should put it into its landscape location: // SB area = 10, 10, 1990, 80 Loading @@ -131,18 +140,45 @@ class SystemEventChipAnimationControllerTest : SysuiTestCase() { val chipRect = controller.chipBounds assertThat(chipRect).isEqualTo(Rect(1890, 20, 1990, 70)) } finally { ViewUtils.detachView(statusbarFake) } } /** regression test for b/294462223. */ @Test fun prepareChipAnimation_withComposeView_doesNotCrash() { val composeViewCreator: ViewCreator = { object : BackgroundAnimatableView { override val view = ComposeView(mContext) override fun setBoundsForAnimation(l: Int, t: Int, r: Int, b: Int) {} } } try { ViewUtils.attachView(statusbarFake) // Make sure prepareChipAnimation does not crash when it adds the chip to a ComposeView. controller.prepareChipAnimation(composeViewCreator) } finally { ViewUtils.detachView(statusbarFake) } } /** regression test for (b/289378932) */ @Test fun fullScreenStatusBar_positionsChipAtTop_withTopGravity() { // In the case of a fullscreen status bar window, the content insets area is still correct try { ViewUtils.attachView(statusbarFake) TestableLooper.get(this).processAllMessages() // In the case of a fullscreen status bar window, the content insets area is still // correct // (because it uses the dimens), but the window can be full screen. This seems to happen // when launching an app from the ongoing call chip. // GIVEN layout the status bar window fullscreen portrait whenever(sbWindowController.addViewToWindow(any(), any())).then { val statusbarFake = FrameLayout(mContext) statusbarFake.layout( fullScreenSb.left, fullScreenSb.top, Loading @@ -166,6 +202,9 @@ class SystemEventChipAnimationControllerTest : SysuiTestCase() { // THEN it still aligns the chip to the content area provided by the insets provider val chipRect = controller.chipBounds assertThat(chipRect).isEqualTo(Rect(890, 30, 990, 80)) } finally { ViewUtils.detachView(statusbarFake) } } private class TestView(context: Context) : View(context), BackgroundAnimatableView { Loading packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt +34 −16 Original line number Diff line number Diff line Loading @@ -124,23 +124,32 @@ constructor( ), ) it.view.alpha = 0f // For some reason, the window view's measured width is always 0 here, so use the // parent (status bar) it.view.measure( View.MeasureSpec.makeMeasureSpec( (animationWindowView.parent as View).width, AT_MOST, ), View.MeasureSpec.makeMeasureSpec( (animationWindowView.parent as View).height, AT_MOST, ), ) // b/294462223: We are not guaranteed to be attached to a window at this point so we // need this check to prevent a crash. if (it.view.isAttachedToWindow) { measure(it.view) updateChipBounds( it, contentInsetsProvider.getStatusBarContentAreaForCurrentRotation(), ) } else { it.view.addOnAttachStateChangeListener( object : View.OnAttachStateChangeListener { override fun onViewAttachedToWindow(v: View) { measure(v) updateChipBounds( it, contentInsetsProvider .getStatusBarContentAreaForCurrentRotation(), ) v.removeOnAttachStateChangeListener(this) } override fun onViewDetachedFromWindow(v: View) {} } ) } } } Loading Loading @@ -376,6 +385,15 @@ constructor( animRect.set(chipBounds) } private fun measure(v: View) { // For some reason, the window view's measured width is always 0 here, so use the parent // (status bar) v.measure( View.MeasureSpec.makeMeasureSpec((animationWindowView.parent as View).width, AT_MOST), View.MeasureSpec.makeMeasureSpec((animationWindowView.parent as View).height, AT_MOST), ) } private fun layoutParamsDefault(marginEnd: Int): FrameLayout.LayoutParams = FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).also { it.gravity = Gravity.END or Gravity.CENTER_VERTICAL Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt +81 −42 Original line number Diff line number Diff line Loading @@ -20,9 +20,11 @@ import android.content.Context import android.graphics.Insets import android.graphics.Rect import android.testing.TestableLooper import android.testing.ViewUtils import android.view.Gravity import android.view.View import android.widget.FrameLayout import androidx.compose.ui.platform.ComposeView import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase Loading Loading @@ -55,6 +57,7 @@ class SystemEventChipAnimationControllerTest : SysuiTestCase() { @Mock private lateinit var sbWindowController: StatusBarWindowController @Mock private lateinit var insetsProvider: StatusBarContentInsetsProvider private val statusbarFake = FrameLayout(mContext) private var testView = TestView(mContext) private var viewCreator: ViewCreator = { testView } Loading @@ -64,7 +67,6 @@ class SystemEventChipAnimationControllerTest : SysuiTestCase() { // StatusBarWindowController is mocked. The addViewToWindow function needs to be mocked to // ensure that the chip view is added to a parent view whenever(sbWindowController.addViewToWindow(any(), any())).then { val statusbarFake = FrameLayout(mContext) statusbarFake.layout( portraitArea.left, portraitArea.top, Loading Loading @@ -108,18 +110,25 @@ class SystemEventChipAnimationControllerTest : SysuiTestCase() { @Test fun prepareChipAnimation_positionsChip() { try { ViewUtils.attachView(statusbarFake) TestableLooper.get(this).processAllMessages() controller.prepareChipAnimation(viewCreator) val chipRect = controller.chipBounds // SB area = 10, 10, 990, 100 // chip size = 0, 0, 100, 50 val chipRect = controller.chipBounds assertThat(chipRect).isEqualTo(Rect(890, 30, 990, 80)) } finally { ViewUtils.detachView(statusbarFake) } } @Test fun prepareChipAnimation_rotation_repositionsChip() { controller.prepareChipAnimation(viewCreator) try { ViewUtils.attachView(statusbarFake) TestableLooper.get(this).processAllMessages() controller.prepareChipAnimation(viewCreator) // Chip has been prepared, and is located at (890, 30, 990, 75) // Rotation should put it into its landscape location: // SB area = 10, 10, 1990, 80 Loading @@ -131,18 +140,45 @@ class SystemEventChipAnimationControllerTest : SysuiTestCase() { val chipRect = controller.chipBounds assertThat(chipRect).isEqualTo(Rect(1890, 20, 1990, 70)) } finally { ViewUtils.detachView(statusbarFake) } } /** regression test for b/294462223. */ @Test fun prepareChipAnimation_withComposeView_doesNotCrash() { val composeViewCreator: ViewCreator = { object : BackgroundAnimatableView { override val view = ComposeView(mContext) override fun setBoundsForAnimation(l: Int, t: Int, r: Int, b: Int) {} } } try { ViewUtils.attachView(statusbarFake) // Make sure prepareChipAnimation does not crash when it adds the chip to a ComposeView. controller.prepareChipAnimation(composeViewCreator) } finally { ViewUtils.detachView(statusbarFake) } } /** regression test for (b/289378932) */ @Test fun fullScreenStatusBar_positionsChipAtTop_withTopGravity() { // In the case of a fullscreen status bar window, the content insets area is still correct try { ViewUtils.attachView(statusbarFake) TestableLooper.get(this).processAllMessages() // In the case of a fullscreen status bar window, the content insets area is still // correct // (because it uses the dimens), but the window can be full screen. This seems to happen // when launching an app from the ongoing call chip. // GIVEN layout the status bar window fullscreen portrait whenever(sbWindowController.addViewToWindow(any(), any())).then { val statusbarFake = FrameLayout(mContext) statusbarFake.layout( fullScreenSb.left, fullScreenSb.top, Loading @@ -166,6 +202,9 @@ class SystemEventChipAnimationControllerTest : SysuiTestCase() { // THEN it still aligns the chip to the content area provided by the insets provider val chipRect = controller.chipBounds assertThat(chipRect).isEqualTo(Rect(890, 30, 990, 80)) } finally { ViewUtils.detachView(statusbarFake) } } private class TestView(context: Context) : View(context), BackgroundAnimatableView { Loading
packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt +34 −16 Original line number Diff line number Diff line Loading @@ -124,23 +124,32 @@ constructor( ), ) it.view.alpha = 0f // For some reason, the window view's measured width is always 0 here, so use the // parent (status bar) it.view.measure( View.MeasureSpec.makeMeasureSpec( (animationWindowView.parent as View).width, AT_MOST, ), View.MeasureSpec.makeMeasureSpec( (animationWindowView.parent as View).height, AT_MOST, ), ) // b/294462223: We are not guaranteed to be attached to a window at this point so we // need this check to prevent a crash. if (it.view.isAttachedToWindow) { measure(it.view) updateChipBounds( it, contentInsetsProvider.getStatusBarContentAreaForCurrentRotation(), ) } else { it.view.addOnAttachStateChangeListener( object : View.OnAttachStateChangeListener { override fun onViewAttachedToWindow(v: View) { measure(v) updateChipBounds( it, contentInsetsProvider .getStatusBarContentAreaForCurrentRotation(), ) v.removeOnAttachStateChangeListener(this) } override fun onViewDetachedFromWindow(v: View) {} } ) } } } Loading Loading @@ -376,6 +385,15 @@ constructor( animRect.set(chipBounds) } private fun measure(v: View) { // For some reason, the window view's measured width is always 0 here, so use the parent // (status bar) v.measure( View.MeasureSpec.makeMeasureSpec((animationWindowView.parent as View).width, AT_MOST), View.MeasureSpec.makeMeasureSpec((animationWindowView.parent as View).height, AT_MOST), ) } private fun layoutParamsDefault(marginEnd: Int): FrameLayout.LayoutParams = FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).also { it.gravity = Gravity.END or Gravity.CENTER_VERTICAL Loading