Loading services/core/java/com/android/server/wm/ActivityRecord.java +19 −21 Original line number Diff line number Diff line Loading @@ -115,8 +115,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND; import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE; import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE; import static android.view.WindowManager.TRANSIT_OLD_UNSET; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; Loading Loading @@ -325,7 +323,6 @@ import com.android.internal.policy.AttributeCache; import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.ToBooleanFunction; import com.android.internal.util.XmlUtils; import com.android.internal.util.function.pooled.PooledConsumer; import com.android.internal.util.function.pooled.PooledFunction; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.LocalServices; Loading Loading @@ -2385,7 +2382,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return occludesParent(false /* includingFinishing */); } private boolean occludesParent(boolean includingFinishing) { @VisibleForTesting boolean occludesParent(boolean includingFinishing) { if (!includingFinishing && finishing) { return false; } Loading Loading @@ -2843,7 +2841,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final boolean endTask = task.getTopNonFinishingActivity() == null && !task.isClearingToReuseTask(); final int transit = endTask ? TRANSIT_OLD_TASK_CLOSE : TRANSIT_OLD_ACTIVITY_CLOSE; if (newTransition != null) { mAtmService.getTransitionController().requestStartTransition(newTransition, endTask ? task : null, null /* remote */); Loading Loading @@ -2900,7 +2897,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } else if (!isState(PAUSING)) { if (mVisibleRequested) { // Prepare and execute close transition. prepareActivityHideTransitionAnimation(transit); prepareActivityHideTransitionAnimation(); } final boolean removedActivity = completeFinishing("finishIfPossible") == null; Loading @@ -2918,11 +2915,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // In this case, we can set the visibility of all the task overlay activities when // we detect the last one is finishing to keep them in sync. if (task.onlyHasTaskOverlayActivities(false /* includeFinishing */)) { final PooledConsumer c = PooledLambda.obtainConsumer( ActivityRecord::prepareActivityHideTransitionAnimationIfOvarlay, PooledLambda.__(ActivityRecord.class), transit); task.forAllActivities(c); c.recycle(); task.forAllActivities((r) -> { r.prepareActivityHideTransitionAnimationIfOvarlay(); }); } return removedActivity ? FINISH_RESULT_REMOVED : FINISH_RESULT_REQUESTED; } else { Loading @@ -2935,28 +2930,33 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } private void prepareActivityHideTransitionAnimationIfOvarlay(@TransitionOldType int transit) { private void prepareActivityHideTransitionAnimationIfOvarlay() { if (mTaskOverlay) { prepareActivityHideTransitionAnimation(transit); prepareActivityHideTransitionAnimation(); } } private void prepareActivityHideTransitionAnimation(@TransitionOldType int transit) { private void prepareActivityHideTransitionAnimation() { final DisplayContent dc = mDisplayContent; dc.prepareAppTransition(TRANSIT_CLOSE); setVisibility(false); dc.executeAppTransition(); } ActivityRecord completeFinishing(String reason) { return completeFinishing(true /* updateVisibility */, reason); } /** * Complete activity finish request that was initiated earlier. If the activity is still * pausing we will wait for it to complete its transition. If the activity that should appear in * place of this one is not visible yet - we'll wait for it first. Otherwise - activity can be * destroyed right away. * @param updateVisibility Indicate if need to update activity visibility. * @param reason Reason for finishing the activity. * @return Flag indicating whether the activity was removed from history. */ ActivityRecord completeFinishing(String reason) { ActivityRecord completeFinishing(boolean updateVisibility, String reason) { if (!finishing || isState(RESUMED)) { throw new IllegalArgumentException( "Activity must be finishing and not resumed to complete, r=" + this Loading @@ -2968,13 +2968,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return this; } final boolean isCurrentVisible = mVisibleRequested || isState(PAUSED); if (isCurrentVisible) { final Task rootTask = getRootTask(); final ActivityRecord activity = rootTask.getResumedActivity(); final boolean isCurrentVisible = mVisibleRequested || isState(PAUSED, STARTED); if (updateVisibility && isCurrentVisible) { boolean ensureVisibility = false; if (activity != null && !activity.occludesParent()) { // If the resume activity is not opaque, we need to make sure the visibilities of if (occludesParent(true /* includingFinishing */)) { // If the current activity is not opaque, we need to make sure the visibilities of // activities be updated, they may be seen by users. ensureVisibility = true; } else if (mTaskSupervisor.getKeyguardController().isKeyguardLocked() Loading services/core/java/com/android/server/wm/Task.java +6 −1 Original line number Diff line number Diff line Loading @@ -5842,8 +5842,13 @@ class Task extends WindowContainer<WindowContainer> { final boolean wasStopping = prev.isState(STOPPING); prev.setState(PAUSED, "completePausedLocked"); if (prev.finishing) { // We will update the activity visibility later, no need to do in // completeFinishing(). Updating visibility here might also making the next // activities to be resumed, and could result in wrong app transition due to // lack of previous activity information. ProtoLog.v(WM_DEBUG_STATES, "Executing finish of activity: %s", prev); prev = prev.completeFinishing("completePausedLocked"); prev = prev.completeFinishing(false /* updateVisibility */, "completePausedLocked"); } else if (prev.hasProcess()) { ProtoLog.v(WM_DEBUG_STATES, "Enqueue pending stop if needed: %s " + "wasStopping=%b visibleRequested=%b", prev, wasStopping, Loading services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +24 −6 Original line number Diff line number Diff line Loading @@ -1351,25 +1351,39 @@ public class ActivityRecordTests extends WindowTestsBase { * must ensure the visibilities of activities being updated. */ @Test public void testCompleteFinishing_ensureActivitiesVisible() { public void testCompleteFinishing_ensureActivitiesVisible_withConditions() { testCompleteFinishing_ensureActivitiesVisible(false, PAUSED); testCompleteFinishing_ensureActivitiesVisible(false, STARTED); testCompleteFinishing_ensureActivitiesVisible(true, PAUSED); testCompleteFinishing_ensureActivitiesVisible(true, STARTED); } private void testCompleteFinishing_ensureActivitiesVisible(boolean diffTask, ActivityState secondActivityState) { final ActivityRecord activity = createActivityWithTask(); final Task task = activity.getTask(); final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(task).build(); firstActivity.mVisibleRequested = false; firstActivity.nowVisible = false; firstActivity.setState(STOPPED, "true"); firstActivity.setState(STOPPED, "test"); final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setTask(task).build(); secondActivity.mVisibleRequested = true; secondActivity.nowVisible = true; secondActivity.setState(PAUSED, "true"); secondActivity.setState(secondActivityState, "test"); final ActivityRecord translucentActivity = new ActivityBuilder(mAtm).setTask(task).build(); ActivityRecord translucentActivity; if (diffTask) { translucentActivity = new ActivityBuilder(mAtm).setCreateTask(true).build(); } else { translucentActivity = new ActivityBuilder(mAtm).setTask(task).build(); } translucentActivity.mVisibleRequested = true; translucentActivity.nowVisible = true; translucentActivity.setState(RESUMED, "true"); translucentActivity.setState(RESUMED, "test"); doReturn(false).when(translucentActivity).occludesParent(); doReturn(true).when(firstActivity).occludesParent(true); doReturn(true).when(secondActivity).occludesParent(true); // Finish the second activity secondActivity.finishing = true; Loading @@ -1385,6 +1399,10 @@ public class ActivityRecordTests extends WindowTestsBase { verify(firstActivity.mDisplayContent, times(2)).ensureActivitiesVisible(null /* starting */, 0 /* configChanges */ , false /* preserveWindows */, true /* notifyClients */); // Remove the translucent activity and clear invocations for next test translucentActivity.getTask().removeImmediately("test"); clearInvocations(mDefaultDisplay); } /** Loading services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java +4 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE; import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; import static com.android.server.wm.Task.ActivityState.DESTROYED; import static com.android.server.wm.Task.ActivityState.DESTROYING; import static com.android.server.wm.Task.ActivityState.FINISHING; import static com.android.server.wm.Task.ActivityState.PAUSING; Loading Loading @@ -1204,6 +1205,9 @@ public class RootTaskTests extends WindowTestsBase { // See {@link ActivityStack#destroyActivityLocked}. activity.app = null; overlayActivity.app = null; // Simulate the process is dead activity.mVisibleRequested = false; activity.setState(DESTROYED, "Test"); assertEquals(2, task.getChildCount()); Loading Loading
services/core/java/com/android/server/wm/ActivityRecord.java +19 −21 Original line number Diff line number Diff line Loading @@ -115,8 +115,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND; import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE; import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE; import static android.view.WindowManager.TRANSIT_OLD_UNSET; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; Loading Loading @@ -325,7 +323,6 @@ import com.android.internal.policy.AttributeCache; import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.ToBooleanFunction; import com.android.internal.util.XmlUtils; import com.android.internal.util.function.pooled.PooledConsumer; import com.android.internal.util.function.pooled.PooledFunction; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.LocalServices; Loading Loading @@ -2385,7 +2382,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return occludesParent(false /* includingFinishing */); } private boolean occludesParent(boolean includingFinishing) { @VisibleForTesting boolean occludesParent(boolean includingFinishing) { if (!includingFinishing && finishing) { return false; } Loading Loading @@ -2843,7 +2841,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final boolean endTask = task.getTopNonFinishingActivity() == null && !task.isClearingToReuseTask(); final int transit = endTask ? TRANSIT_OLD_TASK_CLOSE : TRANSIT_OLD_ACTIVITY_CLOSE; if (newTransition != null) { mAtmService.getTransitionController().requestStartTransition(newTransition, endTask ? task : null, null /* remote */); Loading Loading @@ -2900,7 +2897,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } else if (!isState(PAUSING)) { if (mVisibleRequested) { // Prepare and execute close transition. prepareActivityHideTransitionAnimation(transit); prepareActivityHideTransitionAnimation(); } final boolean removedActivity = completeFinishing("finishIfPossible") == null; Loading @@ -2918,11 +2915,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // In this case, we can set the visibility of all the task overlay activities when // we detect the last one is finishing to keep them in sync. if (task.onlyHasTaskOverlayActivities(false /* includeFinishing */)) { final PooledConsumer c = PooledLambda.obtainConsumer( ActivityRecord::prepareActivityHideTransitionAnimationIfOvarlay, PooledLambda.__(ActivityRecord.class), transit); task.forAllActivities(c); c.recycle(); task.forAllActivities((r) -> { r.prepareActivityHideTransitionAnimationIfOvarlay(); }); } return removedActivity ? FINISH_RESULT_REMOVED : FINISH_RESULT_REQUESTED; } else { Loading @@ -2935,28 +2930,33 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } private void prepareActivityHideTransitionAnimationIfOvarlay(@TransitionOldType int transit) { private void prepareActivityHideTransitionAnimationIfOvarlay() { if (mTaskOverlay) { prepareActivityHideTransitionAnimation(transit); prepareActivityHideTransitionAnimation(); } } private void prepareActivityHideTransitionAnimation(@TransitionOldType int transit) { private void prepareActivityHideTransitionAnimation() { final DisplayContent dc = mDisplayContent; dc.prepareAppTransition(TRANSIT_CLOSE); setVisibility(false); dc.executeAppTransition(); } ActivityRecord completeFinishing(String reason) { return completeFinishing(true /* updateVisibility */, reason); } /** * Complete activity finish request that was initiated earlier. If the activity is still * pausing we will wait for it to complete its transition. If the activity that should appear in * place of this one is not visible yet - we'll wait for it first. Otherwise - activity can be * destroyed right away. * @param updateVisibility Indicate if need to update activity visibility. * @param reason Reason for finishing the activity. * @return Flag indicating whether the activity was removed from history. */ ActivityRecord completeFinishing(String reason) { ActivityRecord completeFinishing(boolean updateVisibility, String reason) { if (!finishing || isState(RESUMED)) { throw new IllegalArgumentException( "Activity must be finishing and not resumed to complete, r=" + this Loading @@ -2968,13 +2968,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return this; } final boolean isCurrentVisible = mVisibleRequested || isState(PAUSED); if (isCurrentVisible) { final Task rootTask = getRootTask(); final ActivityRecord activity = rootTask.getResumedActivity(); final boolean isCurrentVisible = mVisibleRequested || isState(PAUSED, STARTED); if (updateVisibility && isCurrentVisible) { boolean ensureVisibility = false; if (activity != null && !activity.occludesParent()) { // If the resume activity is not opaque, we need to make sure the visibilities of if (occludesParent(true /* includingFinishing */)) { // If the current activity is not opaque, we need to make sure the visibilities of // activities be updated, they may be seen by users. ensureVisibility = true; } else if (mTaskSupervisor.getKeyguardController().isKeyguardLocked() Loading
services/core/java/com/android/server/wm/Task.java +6 −1 Original line number Diff line number Diff line Loading @@ -5842,8 +5842,13 @@ class Task extends WindowContainer<WindowContainer> { final boolean wasStopping = prev.isState(STOPPING); prev.setState(PAUSED, "completePausedLocked"); if (prev.finishing) { // We will update the activity visibility later, no need to do in // completeFinishing(). Updating visibility here might also making the next // activities to be resumed, and could result in wrong app transition due to // lack of previous activity information. ProtoLog.v(WM_DEBUG_STATES, "Executing finish of activity: %s", prev); prev = prev.completeFinishing("completePausedLocked"); prev = prev.completeFinishing(false /* updateVisibility */, "completePausedLocked"); } else if (prev.hasProcess()) { ProtoLog.v(WM_DEBUG_STATES, "Enqueue pending stop if needed: %s " + "wasStopping=%b visibleRequested=%b", prev, wasStopping, Loading
services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +24 −6 Original line number Diff line number Diff line Loading @@ -1351,25 +1351,39 @@ public class ActivityRecordTests extends WindowTestsBase { * must ensure the visibilities of activities being updated. */ @Test public void testCompleteFinishing_ensureActivitiesVisible() { public void testCompleteFinishing_ensureActivitiesVisible_withConditions() { testCompleteFinishing_ensureActivitiesVisible(false, PAUSED); testCompleteFinishing_ensureActivitiesVisible(false, STARTED); testCompleteFinishing_ensureActivitiesVisible(true, PAUSED); testCompleteFinishing_ensureActivitiesVisible(true, STARTED); } private void testCompleteFinishing_ensureActivitiesVisible(boolean diffTask, ActivityState secondActivityState) { final ActivityRecord activity = createActivityWithTask(); final Task task = activity.getTask(); final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(task).build(); firstActivity.mVisibleRequested = false; firstActivity.nowVisible = false; firstActivity.setState(STOPPED, "true"); firstActivity.setState(STOPPED, "test"); final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setTask(task).build(); secondActivity.mVisibleRequested = true; secondActivity.nowVisible = true; secondActivity.setState(PAUSED, "true"); secondActivity.setState(secondActivityState, "test"); final ActivityRecord translucentActivity = new ActivityBuilder(mAtm).setTask(task).build(); ActivityRecord translucentActivity; if (diffTask) { translucentActivity = new ActivityBuilder(mAtm).setCreateTask(true).build(); } else { translucentActivity = new ActivityBuilder(mAtm).setTask(task).build(); } translucentActivity.mVisibleRequested = true; translucentActivity.nowVisible = true; translucentActivity.setState(RESUMED, "true"); translucentActivity.setState(RESUMED, "test"); doReturn(false).when(translucentActivity).occludesParent(); doReturn(true).when(firstActivity).occludesParent(true); doReturn(true).when(secondActivity).occludesParent(true); // Finish the second activity secondActivity.finishing = true; Loading @@ -1385,6 +1399,10 @@ public class ActivityRecordTests extends WindowTestsBase { verify(firstActivity.mDisplayContent, times(2)).ensureActivitiesVisible(null /* starting */, 0 /* configChanges */ , false /* preserveWindows */, true /* notifyClients */); // Remove the translucent activity and clear invocations for next test translucentActivity.getTask().removeImmediately("test"); clearInvocations(mDefaultDisplay); } /** Loading
services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java +4 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE; import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; import static com.android.server.wm.Task.ActivityState.DESTROYED; import static com.android.server.wm.Task.ActivityState.DESTROYING; import static com.android.server.wm.Task.ActivityState.FINISHING; import static com.android.server.wm.Task.ActivityState.PAUSING; Loading Loading @@ -1204,6 +1205,9 @@ public class RootTaskTests extends WindowTestsBase { // See {@link ActivityStack#destroyActivityLocked}. activity.app = null; overlayActivity.app = null; // Simulate the process is dead activity.mVisibleRequested = false; activity.setState(DESTROYED, "Test"); assertEquals(2, task.getChildCount()); Loading