diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 3e8bc5d31af0f..859115e1dd35a 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -114,8 +114,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; @@ -324,7 +322,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; @@ -2384,7 +2381,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; } @@ -2822,7 +2820,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 */); @@ -2879,7 +2876,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; @@ -2897,11 +2894,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 { @@ -2914,28 +2909,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 @@ -2947,13 +2947,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() diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 721432e66e888..a11772dbc1e19 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -5828,8 +5828,13 @@ class Task extends 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, diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index bd143f8a5c35a..eccc78ba2d28a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -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; @@ -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); } /** diff --git a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java index 748622b810d58..e280a363d7d4b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java @@ -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; @@ -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());