From 943ebe705cece8f643d9d7ace005322ddf114d86 Mon Sep 17 00:00:00 2001 From: Bryce Lee Date: Thu, 4 May 2017 10:19:07 -0700 Subject: [PATCH] Prevent NPE in ActivityStack#shouldbeVisible. 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 --- .../com/android/server/am/ActivityStack.java | 4 ++-- .../android/server/am/ActivityStackTests.java | 22 +++++++++++++++++++ .../android/server/am/ActivityTestsBase.java | 6 +++-- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index d348224df3772..c5d5867633a95 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -232,7 +232,7 @@ class ActivityStack 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 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; 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 c87eaed5c9542..711c36b8b1d49 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java @@ -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*/)); + } } 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 28051f9b2f8c8..9cfa542da9d12 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java @@ -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 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(); }