Add a 5 second timeout to launch animation touch blocking

This is a workaround for b/288507023, which is caused by launch
animations hanging. It does not address the cause of the animation
not completing, but it will allow users to resume interacting with
their device after 5 seconds.

Test: added unit test
Test: simulated the bug with a temporary change and verified manually
Bug: 288507023
Change-Id: I5c240a9ee852bf57e8ec251b733708086e825b45
This commit is contained in:
Justin Weir
2023-08-18 09:33:00 -04:00
parent a39feffeb3
commit a8bd8a8ba0
2 changed files with 49 additions and 3 deletions

View File

@@ -107,7 +107,14 @@ public class NotificationShadeWindowViewController {
private boolean mTouchActive; private boolean mTouchActive;
private boolean mTouchCancelled; private boolean mTouchCancelled;
private MotionEvent mDownEvent; private MotionEvent mDownEvent;
// TODO rename to mLaunchAnimationRunning
private boolean mExpandAnimationRunning; private boolean mExpandAnimationRunning;
/**
* When mExpandAnimationRunning is true and the touch dispatcher receives a down even after
* uptime exceeds this, the dispatcher will stop blocking touches for the launch animation,
* which has presumabely not completed due to an error.
*/
private long mLaunchAnimationTimeout;
private NotificationStackScrollLayout mStackScrollLayout; private NotificationStackScrollLayout mStackScrollLayout;
private PhoneStatusBarViewController mStatusBarViewController; private PhoneStatusBarViewController mStatusBarViewController;
private final CentralSurfaces mService; private final CentralSurfaces mService;
@@ -280,8 +287,13 @@ public class NotificationShadeWindowViewController {
return logDownDispatch(ev, "touch cancelled", false); return logDownDispatch(ev, "touch cancelled", false);
} }
if (mExpandAnimationRunning) { if (mExpandAnimationRunning) {
if (isDown && mClock.uptimeMillis() > mLaunchAnimationTimeout) {
mShadeLogger.d("NSWVC: launch animation timed out");
setExpandAnimationRunning(false);
} else {
return logDownDispatch(ev, "expand animation running", false); return logDownDispatch(ev, "expand animation running", false);
} }
}
if (mKeyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()) { if (mKeyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()) {
// If the user was sliding their finger across the lock screen, // If the user was sliding their finger across the lock screen,
@@ -530,8 +542,12 @@ public class NotificationShadeWindowViewController {
pw.println(mTouchActive); pw.println(mTouchActive);
} }
private void setExpandAnimationRunning(boolean running) { @VisibleForTesting
void setExpandAnimationRunning(boolean running) {
if (mExpandAnimationRunning != running) { if (mExpandAnimationRunning != running) {
if (running) {
mLaunchAnimationTimeout = mClock.uptimeMillis() + 5000;
}
mExpandAnimationRunning = running; mExpandAnimationRunning = running;
mNotificationShadeWindowController.setLaunchingActivity(mExpandAnimationRunning); mNotificationShadeWindowController.setLaunchingActivity(mExpandAnimationRunning);
} }

View File

@@ -123,6 +123,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
@Mock lateinit var keyEventInteractor: KeyEventInteractor @Mock lateinit var keyEventInteractor: KeyEventInteractor
private val notificationExpansionRepository = NotificationExpansionRepository() private val notificationExpansionRepository = NotificationExpansionRepository()
private lateinit var fakeClock: FakeSystemClock
private lateinit var interactionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler> private lateinit var interactionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler>
private lateinit var interactionEventHandler: InteractionEventHandler private lateinit var interactionEventHandler: InteractionEventHandler
@@ -151,6 +152,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
featureFlags.set(Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false) featureFlags.set(Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false)
testScope = TestScope() testScope = TestScope()
fakeClock = FakeSystemClock()
underTest = underTest =
NotificationShadeWindowViewController( NotificationShadeWindowViewController(
lockscreenShadeTransitionController, lockscreenShadeTransitionController,
@@ -183,7 +185,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
primaryBouncerToGoneTransitionViewModel, primaryBouncerToGoneTransitionViewModel,
notificationExpansionRepository, notificationExpansionRepository,
featureFlags, featureFlags,
FakeSystemClock(), fakeClock,
BouncerMessageInteractor( BouncerMessageInteractor(
FakeBouncerMessageRepository(), FakeBouncerMessageRepository(),
mock(BouncerMessageFactory::class.java), mock(BouncerMessageFactory::class.java),
@@ -331,6 +333,33 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
assertThat(returnVal).isTrue() assertThat(returnVal).isTrue()
} }
@Test
fun handleDispatchTouchEvent_launchAnimationRunningTimesOut() =
testScope.runTest {
// GIVEN touch dispatcher in a state that returns true
underTest.setStatusBarViewController(phoneStatusBarViewController)
whenever(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()).thenReturn(
true
)
assertThat(interactionEventHandler.handleDispatchTouchEvent(DOWN_EVENT)).isTrue()
// WHEN launch animation is running for 2 seconds
fakeClock.setUptimeMillis(10000)
underTest.setExpandAnimationRunning(true)
fakeClock.advanceTime(2000)
// THEN touch is ignored
assertThat(interactionEventHandler.handleDispatchTouchEvent(DOWN_EVENT)).isFalse()
// WHEN Launch animation is running for 6 seconds
fakeClock.advanceTime(4000)
// THEN move is ignored, down is handled, and window is notified
assertThat(interactionEventHandler.handleDispatchTouchEvent(MOVE_EVENT)).isFalse()
assertThat(interactionEventHandler.handleDispatchTouchEvent(DOWN_EVENT)).isTrue()
verify(notificationShadeWindowController).setLaunchingActivity(false)
}
@Test @Test
fun shouldInterceptTouchEvent_statusBarKeyguardViewManagerShouldIntercept() { fun shouldInterceptTouchEvent_statusBarKeyguardViewManagerShouldIntercept() {
// down event should be intercepted by keyguardViewManager // down event should be intercepted by keyguardViewManager
@@ -372,6 +401,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
companion object { companion object {
private val DOWN_EVENT = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0) private val DOWN_EVENT = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
private val MOVE_EVENT = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, 0f, 0)
private const val VIEW_BOTTOM = 100 private const val VIEW_BOTTOM = 100
} }
} }