OSDN Git Service

Consider lock state when determining next activity to become visible.
authorBryce Lee <brycelee@google.com>
Sat, 14 Apr 2018 00:58:02 +0000 (17:58 -0700)
committerBryce Lee <brycelee@google.com>
Fri, 20 Apr 2018 15:32:11 +0000 (08:32 -0700)
When an activity shown on top of the lock screen finishes, the next
activity to become visible is considered. This activity is determined
by the supervisor's top running activity. When the focused stack does
not have a top running activity, the top most non-focused stack's
top running activity is considered. In the case the device is locked,
this value may be an activity that does not show on lock screen. As
a result, the finishing activity will wait indefinitely for an
activity that will never appear.

This changelist introduces the ability to ask for the top running
activity taking the current locked state into consideration. When
locked, only activities that can show on top of the lock screen will
be returned if we consider non-focused stacks.

Change-Id: I235e345c0b1d255b44d147bc71069c164389db4f
Fixes: 76424176
Test: atest FrameworksServicesTests:com.android.server.am.ActivityStackSupervisorTests#testNonFocusedTopRunningActivity

services/core/java/com/android/server/am/ActivityStack.java
services/core/java/com/android/server/am/ActivityStackSupervisor.java
services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java

index e20356f..511391a 100644 (file)
@@ -3797,7 +3797,11 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
         // and the resumed activity is not yet visible, then hold off on
         // finishing until the resumed one becomes visible.
 
-        final ActivityRecord next = mStackSupervisor.topRunningActivityLocked();
+        // The activity that we are finishing may be over the lock screen. In this case, we do not
+        // want to consider activities that cannot be shown on the lock screen as running and should
+        // proceed with finishing the activity if there is no valid next top running activity.
+        final ActivityRecord next = mStackSupervisor.topRunningActivityLocked(
+                true /* considerKeyguardState */);
 
         if (mode == FINISH_AFTER_VISIBLE && (r.visible || r.nowVisible)
                 && next != null && !next.nowVisible) {
index 6a3587c..d7e9cda 100644 (file)
@@ -1195,6 +1195,18 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
     }
 
     ActivityRecord topRunningActivityLocked() {
+        return topRunningActivityLocked(false /* considerKeyguardState */);
+    }
+
+    /**
+     * Returns the top running activity in the focused stack. In the case the focused stack has no
+     * such activity, the next focusable stack on top of a display is returned.
+     * @param considerKeyguardState Indicates whether the locked state should be considered. if
+     *                            {@code true} and the keyguard is locked, only activities that
+     *                            can be shown on top of the keyguard will be considered.
+     * @return The top running activity. {@code null} if none is available.
+     */
+    ActivityRecord topRunningActivityLocked(boolean considerKeyguardState) {
         final ActivityStack focusedStack = mFocusedStack;
         ActivityRecord r = focusedStack.topRunningActivityLocked();
         if (r != null) {
@@ -1213,16 +1225,33 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
             if (display == null) {
                 continue;
             }
-            for (int j = display.getChildCount() - 1; j >= 0; --j) {
-                final ActivityStack stack = display.getChildAt(j);
-                if (stack != focusedStack && stack.isTopStackOnDisplay() && stack.isFocusable()) {
-                    r = stack.topRunningActivityLocked();
-                    if (r != null) {
-                        return r;
-                    }
-                }
+
+            // TODO: We probably want to consider the top fullscreen stack as we could have a pinned
+            // stack on top.
+            final ActivityStack topStack = display.getTopStack();
+
+            // Only consider focusable top stacks other than the current focused one.
+            if (topStack == null || !topStack.isFocusable() || topStack == focusedStack) {
+                continue;
+            }
+
+            final ActivityRecord topActivity = topStack.topRunningActivityLocked();
+
+            // Skip if no top activity.
+            if (topActivity == null) {
+                continue;
+            }
+
+            final boolean keyguardLocked = getKeyguardController().isKeyguardLocked();
+
+            // This activity can be considered the top running activity if we are not
+            // considering the locked state, the keyguard isn't locked, or we can show when
+            // locked.
+            if (!considerKeyguardState || !keyguardLocked || topActivity.canShowWhenLocked()) {
+                return topActivity;
             }
         }
+
         return null;
     }
 
index 08b8af2..9daea1a 100644 (file)
@@ -25,6 +25,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
+import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
 import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
@@ -329,4 +330,52 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase {
                 REMOVE_TASK_MODE_DESTROYING);
         assertFalse(pinnedStack.isFocusable());
     }
+
+    /**
+     * Verifies the correct activity is returned when querying the top running activity with an
+     * empty focused stack.
+     */
+    @Test
+    public void testNonFocusedTopRunningActivity() throws Exception {
+        // Create stack to hold focus
+        final ActivityStack focusedStack = mService.mStackSupervisor.getDefaultDisplay()
+                .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+
+        final KeyguardController keyguard = mSupervisor.getKeyguardController();
+        final ActivityStack stack = mService.mStackSupervisor.getDefaultDisplay().createStack(
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+        final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true)
+                .setStack(stack).build();
+
+        mSupervisor.mFocusedStack = focusedStack;
+
+        doAnswer((InvocationOnMock invocationOnMock) -> {
+            final SparseIntArray displayIds = invocationOnMock.<SparseIntArray>getArgument(0);
+            displayIds.put(0, mSupervisor.getDefaultDisplay().mDisplayId);
+            return null;
+        }).when(mSupervisor.mWindowManager).getDisplaysInFocusOrder(any());
+
+        // Make sure the top running activity is not affected when keyguard is not locked
+        assertEquals(activity, mService.mStackSupervisor.topRunningActivityLocked());
+        assertEquals(activity, mService.mStackSupervisor.topRunningActivityLocked(
+                true /* considerKeyguardState */));
+
+        // Check to make sure activity not reported when it cannot show on lock and lock is on.
+        doReturn(true).when(keyguard).isKeyguardLocked();
+        assertEquals(activity, mService.mStackSupervisor.topRunningActivityLocked());
+        assertEquals(null, mService.mStackSupervisor.topRunningActivityLocked(
+                true /* considerKeyguardState */));
+
+        // Add activity that should be shown on the keyguard.
+        final ActivityRecord showWhenLockedActivity = new ActivityBuilder(mService)
+                .setCreateTask(true)
+                .setStack(stack)
+                .setActivityFlags(FLAG_SHOW_WHEN_LOCKED)
+                .build();
+
+        // Ensure the show when locked activity is returned.
+        assertEquals(showWhenLockedActivity, mService.mStackSupervisor.topRunningActivityLocked());
+        assertEquals(showWhenLockedActivity, mService.mStackSupervisor.topRunningActivityLocked(
+                true /* considerKeyguardState */));
+    }
 }
index f5e61a1..1cd111f 100644 (file)
@@ -132,6 +132,7 @@ public class ActivityTestsBase {
         private int mUid;
         private boolean mCreateTask;
         private ActivityStack mStack;
+        private int mActivityFlags;
 
         ActivityBuilder(ActivityManagerService service) {
             mService = service;
@@ -152,6 +153,11 @@ public class ActivityTestsBase {
             return this;
         }
 
+        ActivityBuilder setActivityFlags(int flags) {
+            mActivityFlags = flags;
+            return this;
+        }
+
         ActivityBuilder setStack(ActivityStack stack) {
             mStack = stack;
             return this;
@@ -186,6 +192,8 @@ public class ActivityTestsBase {
             aInfo.applicationInfo = new ApplicationInfo();
             aInfo.applicationInfo.packageName = mComponent.getPackageName();
             aInfo.applicationInfo.uid = mUid;
+            aInfo.flags |= mActivityFlags;
+
             final ActivityRecord activity = new ActivityRecord(mService, null /* caller */,
                     0 /* launchedFromPid */, 0, null, intent, null,
                     aInfo /*aInfo*/, new Configuration(), null /* resultTo */, null /* resultWho */,