diff --git a/core/java/android/window/TransitionFilter.java b/core/java/android/window/TransitionFilter.java index 141f47b130d16..6351b03950205 100644 --- a/core/java/android/window/TransitionFilter.java +++ b/core/java/android/window/TransitionFilter.java @@ -18,6 +18,7 @@ package android.window; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.WindowConfiguration; @@ -33,6 +34,18 @@ import android.os.Parcelable; */ public final class TransitionFilter implements Parcelable { + /** The associated requirement doesn't care about the z-order. */ + public static final int CONTAINER_ORDER_ANY = 0; + /** The associated requirement only matches the top-most (z-order) container. */ + public static final int CONTAINER_ORDER_TOP = 1; + + /** @hide */ + @IntDef(prefix = { "CONTAINER_ORDER_" }, value = { + CONTAINER_ORDER_ANY, + CONTAINER_ORDER_TOP, + }) + public @interface ContainerOrder {} + /** * When non-null: this is a list of transition types that this filter applies to. This filter * will fail for transitions that aren't one of these types. @@ -126,6 +139,7 @@ public final class TransitionFilter implements Parcelable { public static final class Requirement implements Parcelable { public int mActivityType = ACTIVITY_TYPE_UNDEFINED; public int[] mModes = null; + public @ContainerOrder int mOrder = CONTAINER_ORDER_ANY; public Requirement() { } @@ -133,6 +147,7 @@ public final class TransitionFilter implements Parcelable { private Requirement(Parcel in) { mActivityType = in.readInt(); mModes = in.createIntArray(); + mOrder = in.readInt(); } /** Go through changes and find if at-least one change matches this filter */ @@ -143,6 +158,9 @@ public final class TransitionFilter implements Parcelable { // Only look at independent animating windows. continue; } + if (mOrder == CONTAINER_ORDER_TOP && i > 0) { + continue; + } if (mActivityType != ACTIVITY_TYPE_UNDEFINED) { if (change.getTaskInfo() == null || change.getTaskInfo().getActivityType() != mActivityType) { @@ -166,7 +184,7 @@ public final class TransitionFilter implements Parcelable { /** Check if the request matches this filter. It may generate false positives */ boolean matches(@NonNull TransitionRequestInfo request) { - // Can't check modes since the transition hasn't been built at this point. + // Can't check modes/order since the transition hasn't been built at this point. if (mActivityType == ACTIVITY_TYPE_UNDEFINED) return true; return request.getTriggerTask() != null && request.getTriggerTask().getActivityType() == mActivityType; @@ -177,6 +195,7 @@ public final class TransitionFilter implements Parcelable { public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mActivityType); dest.writeIntArray(mModes); + dest.writeInt(mOrder); } @NonNull @@ -209,7 +228,17 @@ public final class TransitionFilter implements Parcelable { out.append((i == 0 ? "" : ",") + TransitionInfo.modeToString(mModes[i])); } } - return out.append("]}").toString(); + out.append("]").toString(); + out.append(" order=" + containerOrderToString(mOrder)); + return out.toString(); } } + + private static String containerOrderToString(int order) { + switch (order) { + case CONTAINER_ORDER_ANY: return "ANY"; + case CONTAINER_ORDER_TOP: return "TOP"; + } + return "UNKNOWN(" + order + ")"; + } } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java index f8160d6d1982d..a77cc87a4e2ca 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java @@ -17,10 +17,12 @@ package com.android.systemui.shared.system; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_TO_FRONT; +import static android.window.TransitionFilter.CONTAINER_ORDER_TOP; import android.annotation.NonNull; import android.annotation.Nullable; @@ -163,9 +165,13 @@ public class RemoteTransitionCompat implements Parcelable { mFilter = new TransitionFilter(); } mFilter.mRequirements = - new TransitionFilter.Requirement[]{new TransitionFilter.Requirement()}; + new TransitionFilter.Requirement[]{new TransitionFilter.Requirement(), + new TransitionFilter.Requirement()}; mFilter.mRequirements[0].mActivityType = ACTIVITY_TYPE_HOME; mFilter.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT}; + mFilter.mRequirements[0].mOrder = CONTAINER_ORDER_TOP; + mFilter.mRequirements[1].mActivityType = ACTIVITY_TYPE_STANDARD; + mFilter.mRequirements[1].mModes = new int[]{TRANSIT_CLOSE, TRANSIT_TO_BACK}; } /** diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 37e4fc16cb753..7bd3565421467 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -4817,9 +4817,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A * this has become invisible. */ private void postApplyAnimation(boolean visible) { + final boolean usingShellTransitions = + mAtmService.getTransitionController().getTransitionPlayer() != null; final boolean delayed = isAnimating(PARENTS | CHILDREN, ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_WINDOW_ANIMATION); - if (!delayed) { + if (!delayed && !usingShellTransitions) { // We aren't delayed anything, but exiting windows rely on the animation finished // callback being called in case the ActivityRecord was pretending to be delayed, // which we might have done because we were in closing/opening apps list. @@ -4838,7 +4840,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // updated. // If we're becoming invisible, update the client visibility if we are not running an // animation. Otherwise, we'll update client visibility in onAnimationFinished. - if (visible || !isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION)) { + if (visible || !isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION) + || usingShellTransitions) { setClientVisible(visible); } diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 8a4c788385909..8b09ba96a9c63 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -1586,7 +1586,8 @@ class ActivityStarter { statusBar.collapsePanels(); } } - if (result == START_SUCCESS || result == START_TASK_TO_FRONT) { + final boolean started = result == START_SUCCESS || result == START_TASK_TO_FRONT; + if (started) { // The activity is started new rather than just brought forward, so record // it as an existence change. mService.getTransitionController().collectExistenceChange(r); @@ -1594,7 +1595,7 @@ class ActivityStarter { if (newTransition != null) { mService.getTransitionController().requestStartTransition(newTransition, mTargetTask, remoteTransition); - } else { + } else if (started) { // Make the collecting transition wait until this request is ready. mService.getTransitionController().setReady(false); } diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 7169988f10f68..8e18da14d3b31 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -297,21 +297,27 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe } // Commit all going-invisible containers + boolean activitiesWentInvisible = false; for (int i = 0; i < mParticipants.size(); ++i) { final ActivityRecord ar = mParticipants.valueAt(i).asActivityRecord(); - if (ar != null && !ar.isVisibleRequested()) { - // If activity is capable of entering PiP, give it a chance to enter it now. - if (ar.getDeferHidingClient() && ar.getTask() != null) { - mController.mAtm.mTaskSupervisor.mUserLeaving = true; - ar.getTaskFragment().startPausing(false /* uiSleeping */, null /* resuming */, - "finishTransition"); - mController.mAtm.mTaskSupervisor.mUserLeaving = false; - } - ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, - " Commit activity becoming invisible: %s", ar); - ar.commitVisibility(false /* visible */, false /* performLayout */); - } if (ar != null) { + if (!ar.isVisibleRequested()) { + // If activity is capable of entering PiP, give it a chance to enter it now. + if (ar.getDeferHidingClient() && ar.getTask() != null) { + mController.mAtm.mTaskSupervisor.mUserLeaving = true; + ar.getTaskFragment().startPausing(false /* uiSleeping */, + null /* resuming */, "finishTransition"); + mController.mAtm.mTaskSupervisor.mUserLeaving = false; + } + ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, + " Commit activity becoming invisible: %s", ar); + ar.commitVisibility(false /* visible */, false /* performLayout */); + activitiesWentInvisible = true; + } + if (mChanges.get(ar).mVisible != ar.isVisibleRequested()) { + // Legacy dispatch relies on this (for now). + ar.mEnteringAnimation = ar.isVisibleRequested(); + } mController.dispatchLegacyAppTransitionFinished(ar); } final WallpaperWindowToken wt = mParticipants.valueAt(i).asWallpaperToken(); @@ -321,6 +327,12 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe wt.commitVisibility(false /* visible */); } } + if (activitiesWentInvisible) { + // Always schedule stop processing when transition finishes because activities don't + // stop while they are in a transition thus their stop could still be pending. + mController.mAtm.mTaskSupervisor + .scheduleProcessStoppingAndFinishingActivitiesIfNeeded(); + } legacyRestoreNavigationBarFromApp(); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index a748b45ab07c1..d436bace3c46a 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1806,7 +1806,8 @@ public class WindowManagerService extends IWindowManager.Stub winAnimator.mEnterAnimationPending = true; winAnimator.mEnteringAnimation = true; // Check if we need to prepare a transition for replacing window first. - if (activity != null && activity.isVisible() + if (mAtmService.getTransitionController().getTransitionPlayer() == null + && activity != null && activity.isVisible() && !prepareWindowReplacementTransition(activity)) { // If not, check if need to set up a dummy transition during display freeze // so that the unfreeze wait for the apps to draw. This might be needed if