OSDN Git Service

Prevent NPE in ActivityStack#shouldbeVisible.
authorBryce Lee <brycelee@google.com>
Thu, 4 May 2017 17:19:07 +0000 (10:19 -0700)
committerBryce Lee <brycelee@google.com>
Fri, 5 May 2017 14:09:43 +0000 (07:09 -0700)
If there is a visibleBehind activity, we check to see if the top
activity in the top stack is not fullscreen. However, it is possible
for the top stack to be empty. This can happen if the previously top
activity is being re-installed.

This changelist addresses the issue by checking if the top activity is
null before referencing it.

Change-Id: I6de904bed1c7035ed1e112c9cacc1b6c2bac4e8f
Fixes: 32180256
Test: bit FrameworksServicesTests:com.android.server.am.ActivityStackTests#testShouldBeVisibleWithVisibleBehindActivity

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

index d348224..c5d5867 100644 (file)
@@ -232,7 +232,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
     static final int STACK_VISIBLE = 1;
     // Stack is considered visible, but only becuase it has activity that is visible behind other
     // activities and there is a specific combination of stacks.
-    private static final int STACK_VISIBLE_ACTIVITY_BEHIND = 2;
+    static final int STACK_VISIBLE_ACTIVITY_BEHIND = 2;
 
     @VisibleForTesting
     /* The various modes for the method {@link #removeTask}. */
@@ -1652,7 +1652,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
 
         if (StackId.isBackdropToTranslucentActivity(mStackId)
                 && hasVisibleBehindActivity() && StackId.isHomeOrRecentsStack(topStackId)
-                && !topStack.topActivity().fullscreen) {
+                && (topStack.topActivity() == null || !topStack.topActivity().fullscreen)) {
             // The fullscreen or assistant stack should be visible if it has a visible behind
             // activity behind the home or recents stack that is translucent.
             return STACK_VISIBLE_ACTIVITY_BEHIND;
index c87eaed..711c36b 100644 (file)
@@ -21,6 +21,7 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
+import android.app.ActivityManager;
 import android.content.ComponentName;
 import android.content.pm.ActivityInfo;
 import android.platform.test.annotations.Presubmit;
@@ -97,4 +98,25 @@ public class ActivityStackTests extends ActivityTestsBase {
 
         testStack.stopActivityLocked(activityRecord);
     }
+
+    /**
+     * This test verifies that {@link ActivityStack#STACK_VISIBLE_ACTIVITY_BEHIND} is returned from
+     * {@link ActivityStack#shouldBeVisible(ActivityRecord)} from a fullscreen workspace stack with
+     * a visible behind activity when top focused stack is the home stack.
+     */
+    @Test
+    public void testShouldBeVisibleWithVisibleBehindActivity() throws Exception {
+        final ActivityManagerService service = createActivityManagerService();
+        final TaskRecord task = createTask(service, testActivityComponent,
+                ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID);
+        final ActivityStack fullscreenWorkspaceStackId = task.getStack();
+        final ActivityStack homeStack = service.mStackSupervisor.getStack(
+                ActivityManager.StackId.HOME_STACK_ID, true /*createStaticStackIfNeeded*/,
+                true /*onTop*/);
+        final ActivityRecord activityRecord = createActivity(service, testActivityComponent, task);
+        service.mStackSupervisor.setFocusStackUnchecked("testEmptyStackShouldBeVisible", homeStack);
+        service.mStackSupervisor.requestVisibleBehindLocked(activityRecord, true);
+        assertEquals(ActivityStack.STACK_VISIBLE_ACTIVITY_BEHIND,
+                fullscreenWorkspaceStackId.shouldBeVisible(null /*starting*/));
+    }
 }
index 28051f9..9cfa542 100644 (file)
@@ -151,9 +151,12 @@ public class ActivityTestsBase {
      * setup not available in the test environment. Also specifies an injector for
      */
     protected static class TestActivityStackSupervisor extends ActivityStackSupervisor {
+        private final ActivityDisplay mDisplay;
+
         public TestActivityStackSupervisor(ActivityManagerService service, Looper looper) {
             super(service, looper);
             mWindowManager = prepareMockWindowManager();
+            mDisplay = new ActivityDisplay();
         }
 
         // No home stack is set.
@@ -185,9 +188,8 @@ public class ActivityTestsBase {
 
         public <T extends ActivityStack> T createTestStack(ActivityManagerService service,
                 int stackId, boolean onTop) {
-            final ActivityDisplay display = new ActivityDisplay();
             final TestActivityContainer container =
-                    new TestActivityContainer(service, stackId, display, onTop);
+                    new TestActivityContainer(service, stackId, mDisplay, onTop);
             mActivityContainers.put(stackId, container);
             return (T) container.getStack();
         }