Loading services/core/java/com/android/server/am/ActivityDisplay.java +36 −3 Original line number Diff line number Diff line Loading @@ -113,6 +113,13 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> */ private boolean mRemoved; /** * A focusable stack that is purposely to be positioned at the top. Although the stack may not * have the topmost index, it is used as a preferred candidate to prevent being unable to resume * target stack properly when there are other focusable always-on-top stacks. */ private ActivityStack mPreferredTopFocusableStack; // Cached reference to some special stacks we tend to get a lot so we don't need to loop // through the list to find them. private ActivityStack mHomeStack = null; Loading Loading @@ -165,6 +172,9 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> if (DEBUG_STACK) Slog.v(TAG_STACK, "removeChild: detaching " + stack + " from displayId=" + mDisplayId); mStacks.remove(stack); if (mPreferredTopFocusableStack == stack) { mPreferredTopFocusableStack = null; } removeStackReferenceIfNeeded(stack); releaseSelfIfNeeded(); mSupervisor.mService.updateSleepIfNeededLocked(); Loading @@ -186,9 +196,21 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> private void positionChildAt(ActivityStack stack, int position, boolean includingParents) { // TODO: Keep in sync with WindowContainer.positionChildAt(), once we change that to adjust // the position internally, also update the logic here mStacks.remove(stack); final boolean wasContained = mStacks.remove(stack); final int insertPosition = getTopInsertPosition(stack, position); mStacks.add(insertPosition, stack); // The insert position may be adjusted to non-top when there is always-on-top stack. Since // the original position is preferred to be top, the stack should have higher priority when // we are looking for top focusable stack. The condition {@code wasContained} restricts the // preferred stack is set only when moving an existing stack to top instead of adding a new // stack that may be too early (e.g. in the middle of launching or reparenting). if (wasContained && position >= mStacks.size() - 1 && stack.isFocusableAndVisible()) { mPreferredTopFocusableStack = stack; } else if (mPreferredTopFocusableStack == stack) { mPreferredTopFocusableStack = null; } // Since positionChildAt() is called during the creation process of pinned stacks, // ActivityStack#getWindowContainerController() can be null. In this special case, // since DisplayContest#positionStackAt() is called in TaskStack#onConfigurationChanged(), Loading Loading @@ -357,10 +379,18 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> this, stackId, mSupervisor, windowingMode, activityType, onTop); } /** * Get the preferred focusable stack in priority. If the preferred stack does not exist, find a * focusable and visible stack from the top of stacks in this display. */ ActivityStack getFocusedStack() { if (mPreferredTopFocusableStack != null) { return mPreferredTopFocusableStack; } for (int i = mStacks.size() - 1; i >= 0; --i) { final ActivityStack stack = mStacks.get(i); if (stack.isFocusable() && stack.shouldBeVisible(null /* starting */)) { if (stack.isFocusableAndVisible()) { return stack; } } Loading @@ -382,7 +412,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> if (ignoreCurrent && stack == currentFocus) { continue; } if (!stack.isFocusable() || !stack.shouldBeVisible(null)) { if (!stack.isFocusableAndVisible()) { continue; } Loading Loading @@ -1105,6 +1135,9 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> if (mSplitScreenPrimaryStack != null) { pw.println(myPrefix + "mSplitScreenPrimaryStack=" + mSplitScreenPrimaryStack); } if (mPreferredTopFocusableStack != null) { pw.println(myPrefix + "mPreferredTopFocusableStack=" + mPreferredTopFocusableStack); } } public void dumpStacks(PrintWriter pw) { Loading services/core/java/com/android/server/am/ActivityStack.java +4 −0 Original line number Diff line number Diff line Loading @@ -1146,6 +1146,10 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai return mStackSupervisor.isFocusable(this, r != null && r.isFocusable()); } boolean isFocusableAndVisible() { return isFocusable() && shouldBeVisible(null /* starting */); } final boolean isAttached() { return getParent() != null; } Loading services/core/java/com/android/server/am/ActivityStackSupervisor.java +8 −7 Original line number Diff line number Diff line Loading @@ -733,10 +733,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } ActivityRecord getTopResumedActivity() { if (mWindowManager == null) { return null; } final ActivityStack focusedStack = getTopDisplayFocusedStack(); if (focusedStack == null) { return null; Loading Loading @@ -2284,7 +2280,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return false; } if (targetStack != null && targetStack.isTopStackOnDisplay()) { if (targetStack != null && (targetStack.isTopStackOnDisplay() || getTopDisplayFocusedStack() == targetStack)) { return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions); } Loading Loading @@ -3982,8 +3979,12 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } public void dump(PrintWriter pw, String prefix) { pw.print(prefix); pw.print("mFocusedStack=" + getTopDisplayFocusedStack()); pw.print(" mLastFocusedStack="); pw.println(mLastFocusedStack); pw.println(); pw.println("ActivityStackSupervisor state:"); pw.print(prefix); pw.println("topDisplayFocusedStack=" + getTopDisplayFocusedStack()); pw.print(prefix); pw.println("mLastFocusedStack=" + mLastFocusedStack); pw.print(prefix); pw.println("mCurTaskIdForUser=" + mCurTaskIdForUser); pw.print(prefix); pw.println("mUserStackInFront=" + mUserStackInFront); Loading services/tests/servicestests/src/com/android/server/am/ActivityDisplayTests.java 0 → 100644 +115 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.am; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; import static com.android.server.am.ActivityStackSupervisor.ON_TOP; import static org.junit.Assert.assertTrue; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; /** * Tests for the {@link ActivityDisplay} class. * * Build/Install/Run: * atest WmTests:ActivityDisplayTests */ @SmallTest @Presubmit @RunWith(AndroidJUnit4.class) public class ActivityDisplayTests extends ActivityTestsBase { @Before @Override public void setUp() throws Exception { super.setUp(); setupActivityTaskManagerService(); } /** * This test simulates the picture-in-picture menu activity launches an activity to fullscreen * stack. The fullscreen stack should be the top focused for resuming correctly. */ @Test public void testFullscreenStackCanBeFocusedWhenFocusablePinnedStackExists() { // Create a pinned stack and move to front. final ActivityStack pinnedStack = mSupervisor.getDefaultDisplay().createStack( WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, ON_TOP); final TaskRecord pinnedTask = new TaskBuilder(mService.mStackSupervisor) .setStack(pinnedStack).build(); new ActivityBuilder(mService).setActivityFlags(FLAG_ALWAYS_FOCUSABLE) .setTask(pinnedTask).build(); pinnedStack.moveToFront("movePinnedStackToFront"); // The focused stack should be the pinned stack. assertTrue(pinnedStack.isFocusedStackOnDisplay()); // Create a fullscreen stack and move to front. final ActivityStack fullscreenStack = createFullscreenStackWithSimpleActivityAt( mSupervisor.getDefaultDisplay()); fullscreenStack.moveToFront("moveFullscreenStackToFront"); // The focused stack should be the fullscreen stack. assertTrue(fullscreenStack.isFocusedStackOnDisplay()); } /** * Test {@link ActivityDisplay#mPreferredTopFocusableStack} will be cleared when the stack is * removed or moved to back, and the focused stack will be according to z-order. */ @Test public void testStackShouldNotBeFocusedAfterMovingToBackOrRemoving() { // Create a display which only contains 2 stacks. final ActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP); final ActivityStack stack1 = createFullscreenStackWithSimpleActivityAt(display); final ActivityStack stack2 = createFullscreenStackWithSimpleActivityAt(display); // Put stack1 and stack2 on top. stack1.moveToFront("moveStack1ToFront"); stack2.moveToFront("moveStack2ToFront"); assertTrue(stack2.isFocusedStackOnDisplay()); // Stack1 should be focused after moving stack2 to back. stack2.moveToBack("moveStack2ToBack", null /* task */); assertTrue(stack1.isFocusedStackOnDisplay()); // Stack2 should be focused after removing stack1. display.removeChild(stack1); assertTrue(stack2.isFocusedStackOnDisplay()); } private ActivityStack createFullscreenStackWithSimpleActivityAt(ActivityDisplay display) { final ActivityStack fullscreenStack = display.createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP); final TaskRecord fullscreenTask = new TaskBuilder(mService.mStackSupervisor) .setStack(fullscreenStack).build(); new ActivityBuilder(mService).setTask(fullscreenTask).build(); return fullscreenStack; } } services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java +31 −1 Original line number Diff line number Diff line Loading @@ -33,10 +33,12 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; Loading Loading @@ -403,4 +405,32 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { assertEquals(primaryStack.getBounds(), STACK_SIZE); assertEquals(task.getBounds(), TASK_SIZE); } /** * Verify if a stack is not at the topmost position, it should be able to resume its activity if * the stack is the top focused. */ @Test public void testResumeActivityWhenNonTopmostStackIsTopFocused() throws Exception { // Create a stack at bottom. final ActivityDisplay display = mSupervisor.getDefaultDisplay(); final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */)); final TaskRecord task = new TaskBuilder(mSupervisor).setStack(targetStack).build(); final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build(); display.positionChildAtBottom(targetStack); // Assume the stack is not at the topmost position (e.g. behind always-on-top stacks) but it // is the current top focused stack. assertFalse(targetStack.isTopStackOnDisplay()); doReturn(targetStack).when(mSupervisor).getTopDisplayFocusedStack(); // Use the stack as target to resume. mSupervisor.resumeFocusedStacksTopActivitiesLocked( targetStack, activity, null /* targetOptions */); // Verify the target stack should resume its activity. verify(targetStack, times(1)).resumeTopActivityUncheckedLocked( eq(activity), eq(null /* targetOptions */)); } } Loading
services/core/java/com/android/server/am/ActivityDisplay.java +36 −3 Original line number Diff line number Diff line Loading @@ -113,6 +113,13 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> */ private boolean mRemoved; /** * A focusable stack that is purposely to be positioned at the top. Although the stack may not * have the topmost index, it is used as a preferred candidate to prevent being unable to resume * target stack properly when there are other focusable always-on-top stacks. */ private ActivityStack mPreferredTopFocusableStack; // Cached reference to some special stacks we tend to get a lot so we don't need to loop // through the list to find them. private ActivityStack mHomeStack = null; Loading Loading @@ -165,6 +172,9 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> if (DEBUG_STACK) Slog.v(TAG_STACK, "removeChild: detaching " + stack + " from displayId=" + mDisplayId); mStacks.remove(stack); if (mPreferredTopFocusableStack == stack) { mPreferredTopFocusableStack = null; } removeStackReferenceIfNeeded(stack); releaseSelfIfNeeded(); mSupervisor.mService.updateSleepIfNeededLocked(); Loading @@ -186,9 +196,21 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> private void positionChildAt(ActivityStack stack, int position, boolean includingParents) { // TODO: Keep in sync with WindowContainer.positionChildAt(), once we change that to adjust // the position internally, also update the logic here mStacks.remove(stack); final boolean wasContained = mStacks.remove(stack); final int insertPosition = getTopInsertPosition(stack, position); mStacks.add(insertPosition, stack); // The insert position may be adjusted to non-top when there is always-on-top stack. Since // the original position is preferred to be top, the stack should have higher priority when // we are looking for top focusable stack. The condition {@code wasContained} restricts the // preferred stack is set only when moving an existing stack to top instead of adding a new // stack that may be too early (e.g. in the middle of launching or reparenting). if (wasContained && position >= mStacks.size() - 1 && stack.isFocusableAndVisible()) { mPreferredTopFocusableStack = stack; } else if (mPreferredTopFocusableStack == stack) { mPreferredTopFocusableStack = null; } // Since positionChildAt() is called during the creation process of pinned stacks, // ActivityStack#getWindowContainerController() can be null. In this special case, // since DisplayContest#positionStackAt() is called in TaskStack#onConfigurationChanged(), Loading Loading @@ -357,10 +379,18 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> this, stackId, mSupervisor, windowingMode, activityType, onTop); } /** * Get the preferred focusable stack in priority. If the preferred stack does not exist, find a * focusable and visible stack from the top of stacks in this display. */ ActivityStack getFocusedStack() { if (mPreferredTopFocusableStack != null) { return mPreferredTopFocusableStack; } for (int i = mStacks.size() - 1; i >= 0; --i) { final ActivityStack stack = mStacks.get(i); if (stack.isFocusable() && stack.shouldBeVisible(null /* starting */)) { if (stack.isFocusableAndVisible()) { return stack; } } Loading @@ -382,7 +412,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> if (ignoreCurrent && stack == currentFocus) { continue; } if (!stack.isFocusable() || !stack.shouldBeVisible(null)) { if (!stack.isFocusableAndVisible()) { continue; } Loading Loading @@ -1105,6 +1135,9 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> if (mSplitScreenPrimaryStack != null) { pw.println(myPrefix + "mSplitScreenPrimaryStack=" + mSplitScreenPrimaryStack); } if (mPreferredTopFocusableStack != null) { pw.println(myPrefix + "mPreferredTopFocusableStack=" + mPreferredTopFocusableStack); } } public void dumpStacks(PrintWriter pw) { Loading
services/core/java/com/android/server/am/ActivityStack.java +4 −0 Original line number Diff line number Diff line Loading @@ -1146,6 +1146,10 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai return mStackSupervisor.isFocusable(this, r != null && r.isFocusable()); } boolean isFocusableAndVisible() { return isFocusable() && shouldBeVisible(null /* starting */); } final boolean isAttached() { return getParent() != null; } Loading
services/core/java/com/android/server/am/ActivityStackSupervisor.java +8 −7 Original line number Diff line number Diff line Loading @@ -733,10 +733,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } ActivityRecord getTopResumedActivity() { if (mWindowManager == null) { return null; } final ActivityStack focusedStack = getTopDisplayFocusedStack(); if (focusedStack == null) { return null; Loading Loading @@ -2284,7 +2280,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return false; } if (targetStack != null && targetStack.isTopStackOnDisplay()) { if (targetStack != null && (targetStack.isTopStackOnDisplay() || getTopDisplayFocusedStack() == targetStack)) { return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions); } Loading Loading @@ -3982,8 +3979,12 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } public void dump(PrintWriter pw, String prefix) { pw.print(prefix); pw.print("mFocusedStack=" + getTopDisplayFocusedStack()); pw.print(" mLastFocusedStack="); pw.println(mLastFocusedStack); pw.println(); pw.println("ActivityStackSupervisor state:"); pw.print(prefix); pw.println("topDisplayFocusedStack=" + getTopDisplayFocusedStack()); pw.print(prefix); pw.println("mLastFocusedStack=" + mLastFocusedStack); pw.print(prefix); pw.println("mCurTaskIdForUser=" + mCurTaskIdForUser); pw.print(prefix); pw.println("mUserStackInFront=" + mUserStackInFront); Loading
services/tests/servicestests/src/com/android/server/am/ActivityDisplayTests.java 0 → 100644 +115 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.am; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; import static com.android.server.am.ActivityStackSupervisor.ON_TOP; import static org.junit.Assert.assertTrue; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; /** * Tests for the {@link ActivityDisplay} class. * * Build/Install/Run: * atest WmTests:ActivityDisplayTests */ @SmallTest @Presubmit @RunWith(AndroidJUnit4.class) public class ActivityDisplayTests extends ActivityTestsBase { @Before @Override public void setUp() throws Exception { super.setUp(); setupActivityTaskManagerService(); } /** * This test simulates the picture-in-picture menu activity launches an activity to fullscreen * stack. The fullscreen stack should be the top focused for resuming correctly. */ @Test public void testFullscreenStackCanBeFocusedWhenFocusablePinnedStackExists() { // Create a pinned stack and move to front. final ActivityStack pinnedStack = mSupervisor.getDefaultDisplay().createStack( WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, ON_TOP); final TaskRecord pinnedTask = new TaskBuilder(mService.mStackSupervisor) .setStack(pinnedStack).build(); new ActivityBuilder(mService).setActivityFlags(FLAG_ALWAYS_FOCUSABLE) .setTask(pinnedTask).build(); pinnedStack.moveToFront("movePinnedStackToFront"); // The focused stack should be the pinned stack. assertTrue(pinnedStack.isFocusedStackOnDisplay()); // Create a fullscreen stack and move to front. final ActivityStack fullscreenStack = createFullscreenStackWithSimpleActivityAt( mSupervisor.getDefaultDisplay()); fullscreenStack.moveToFront("moveFullscreenStackToFront"); // The focused stack should be the fullscreen stack. assertTrue(fullscreenStack.isFocusedStackOnDisplay()); } /** * Test {@link ActivityDisplay#mPreferredTopFocusableStack} will be cleared when the stack is * removed or moved to back, and the focused stack will be according to z-order. */ @Test public void testStackShouldNotBeFocusedAfterMovingToBackOrRemoving() { // Create a display which only contains 2 stacks. final ActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP); final ActivityStack stack1 = createFullscreenStackWithSimpleActivityAt(display); final ActivityStack stack2 = createFullscreenStackWithSimpleActivityAt(display); // Put stack1 and stack2 on top. stack1.moveToFront("moveStack1ToFront"); stack2.moveToFront("moveStack2ToFront"); assertTrue(stack2.isFocusedStackOnDisplay()); // Stack1 should be focused after moving stack2 to back. stack2.moveToBack("moveStack2ToBack", null /* task */); assertTrue(stack1.isFocusedStackOnDisplay()); // Stack2 should be focused after removing stack1. display.removeChild(stack1); assertTrue(stack2.isFocusedStackOnDisplay()); } private ActivityStack createFullscreenStackWithSimpleActivityAt(ActivityDisplay display) { final ActivityStack fullscreenStack = display.createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP); final TaskRecord fullscreenTask = new TaskBuilder(mService.mStackSupervisor) .setStack(fullscreenStack).build(); new ActivityBuilder(mService).setTask(fullscreenTask).build(); return fullscreenStack; } }
services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java +31 −1 Original line number Diff line number Diff line Loading @@ -33,10 +33,12 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; Loading Loading @@ -403,4 +405,32 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { assertEquals(primaryStack.getBounds(), STACK_SIZE); assertEquals(task.getBounds(), TASK_SIZE); } /** * Verify if a stack is not at the topmost position, it should be able to resume its activity if * the stack is the top focused. */ @Test public void testResumeActivityWhenNonTopmostStackIsTopFocused() throws Exception { // Create a stack at bottom. final ActivityDisplay display = mSupervisor.getDefaultDisplay(); final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */)); final TaskRecord task = new TaskBuilder(mSupervisor).setStack(targetStack).build(); final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build(); display.positionChildAtBottom(targetStack); // Assume the stack is not at the topmost position (e.g. behind always-on-top stacks) but it // is the current top focused stack. assertFalse(targetStack.isTopStackOnDisplay()); doReturn(targetStack).when(mSupervisor).getTopDisplayFocusedStack(); // Use the stack as target to resume. mSupervisor.resumeFocusedStacksTopActivitiesLocked( targetStack, activity, null /* targetOptions */); // Verify the target stack should resume its activity. verify(targetStack, times(1)).resumeTopActivityUncheckedLocked( eq(activity), eq(null /* targetOptions */)); } }