Do not sleep activities in focused stack when keyguard is going away

ActivityStack#shouldSleepActivities reports back whether we should
put activities in stack to sleep based on the display state. We
should also consider the keyguard state, as it's possible for a stack
to become visible as the keyguard is disappearing, but before the
display has reported on, such as when we're unlocking by fingerprint.
In this case, sleeping will lead to an extraneous and incorrect
lifecycle shift to stop.

Change-Id: I0f0c8bc90093bf636e5ba9ddce7046da631248b0
Fixes: 74603384
Test: atest FrameworksServicesTests:com.android.server.am.ActivityStackTests#testShouldSleepActivities
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 2c4eac0..377d574 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -5283,6 +5283,14 @@
 
     boolean shouldSleepActivities() {
         final ActivityDisplay display = getDisplay();
+
+        // Do not sleep activities in this stack if we're marked as focused and the keyguard
+        // is in the process of going away.
+        if (mStackSupervisor.getFocusedStack() == this
+                && mStackSupervisor.getKeyguardController().isKeyguardGoingAway()) {
+            return false;
+        }
+
         return display != null ? display.isSleeping() : mService.isSleepingLocked();
     }
 
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index 72882de..0d7eab6 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -98,6 +98,14 @@
     }
 
     /**
+     * @return {@code true} if the keyguard is going away, {@code false} otherwise.
+     */
+    boolean isKeyguardGoingAway() {
+        // Also check keyguard showing in case value is stale.
+        return mKeyguardGoingAway && mKeyguardShowing;
+    }
+
+    /**
      * Update the Keyguard showing state.
      */
     void setKeyguardShown(boolean showing, int secondaryDisplayShowing) {
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
index f17bfa4..1a95fdd 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
@@ -37,12 +37,15 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import android.app.servertransaction.DestroyActivityItem;
 import android.content.pm.ActivityInfo;
+import android.os.Debug;
 import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
@@ -518,4 +521,37 @@
         assertTrue(mTask.mActivities.isEmpty());
         assertTrue(mStack.getAllTasks().isEmpty());
     }
+
+    @Test
+    public void testShouldSleepActivities() throws Exception {
+        // When focused activity and keyguard is going away, we should not sleep regardless
+        // of the display state
+        verifyShouldSleepActivities(true /* focusedStack */, true /*keyguardGoingAway*/,
+                true /* displaySleeping */, false /* expected*/);
+
+        // When not the focused stack, defer to display sleeping state.
+        verifyShouldSleepActivities(false /* focusedStack */, true /*keyguardGoingAway*/,
+                true /* displaySleeping */, true /* expected*/);
+
+        // If keyguard is going away, defer to the display sleeping state.
+        verifyShouldSleepActivities(true /* focusedStack */, false /*keyguardGoingAway*/,
+                true /* displaySleeping */, true /* expected*/);
+        verifyShouldSleepActivities(true /* focusedStack */, false /*keyguardGoingAway*/,
+                false /* displaySleeping */, false /* expected*/);
+    }
+
+    private void verifyShouldSleepActivities(boolean focusedStack,
+            boolean keyguardGoingAway, boolean displaySleeping, boolean expected) {
+        mSupervisor.mFocusedStack = focusedStack ? mStack : null;
+
+        final ActivityDisplay display = mock(ActivityDisplay.class);
+        final KeyguardController keyguardController = mSupervisor.getKeyguardController();
+
+        doReturn(display).when(mSupervisor).getActivityDisplay(anyInt());
+        doReturn(keyguardGoingAway).when(keyguardController).isKeyguardGoingAway();
+        doReturn(displaySleeping).when(display).isSleeping();
+
+        assertEquals(expected, mStack.shouldSleepActivities());
+    }
+
 }
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index 3041a5f..c130592 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -316,6 +316,7 @@
         @Override
         final protected ActivityStackSupervisor createStackSupervisor() {
             final ActivityStackSupervisor supervisor = spy(createTestSupervisor());
+            final KeyguardController keyguardController = mock(KeyguardController.class);
 
             // No home stack is set.
             doNothing().when(supervisor).moveHomeStackToFront(any());
@@ -330,6 +331,7 @@
             doNothing().when(supervisor).scheduleIdleTimeoutLocked(any());
             // unit test version does not handle launch wake lock
             doNothing().when(supervisor).acquireLaunchWakelock();
+            doReturn(keyguardController).when(supervisor).getKeyguardController();
 
             supervisor.initialize();