diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index e4695b64a0705..be72216c6bf6e 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -1199,6 +1199,12 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D for (int i = mTmpOrderedDisplayIds.size() - 1; i >= 0; --i) { final int displayId = mTmpOrderedDisplayIds.get(i); final ActivityDisplay display = mActivityDisplays.get(displayId); + + // If WindowManagerService has encountered the display before we have, ignore as there + // will be no stacks present and therefore no activities. + 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()) { diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java index 8721d9c28e0e4..b452ea506095f 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java @@ -22,6 +22,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -33,18 +34,27 @@ import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.ArgumentMatchers.any; + import android.app.ActivityManager; import android.app.WaitResult; import android.content.ComponentName; +import android.content.res.Configuration; import android.graphics.Rect; +import android.hardware.display.DisplayManager; import android.platform.test.annotations.Presubmit; import android.support.test.filters.MediumTest; import android.support.test.runner.AndroidJUnit4; +import android.util.SparseIntArray; import org.junit.runner.RunWith; import org.junit.Before; import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -238,4 +248,21 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { verify(stack, times(expectResumeTopActivity ? 1 : 0)).resumeTopActivityUncheckedLocked( null /* target */, null /* targetOptions */); } + + @Test + public void testTopRunningActivityLockedWithNonExistentDisplay() throws Exception { + // Create display that ActivityManagerService does not know about + final int unknownDisplayId = 100; + + doAnswer((InvocationOnMock invocationOnMock) -> { + final SparseIntArray displayIds = invocationOnMock.getArgument(0); + displayIds.put(0, unknownDisplayId); + return null; + }).when(mSupervisor.mWindowManager).getDisplaysInFocusOrder(any()); + + mSupervisor.mFocusedStack = mock(ActivityStack.class); + + // Supervisor should skip over the non-existent display. + assertEquals(null, mSupervisor.topRunningActivityLocked()); + } }