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 ef93bc3110721..e9ac26182c7e7 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 @@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY; +import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_TO_FRONT; @@ -168,7 +169,8 @@ public class RemoteTransitionCompat implements Parcelable { } t.apply(); mRecentsSession.setup(controller, info, finishedCallback, pausingTasks, pipTask, - recentsTask, leashMap, mToken); + recentsTask, leashMap, mToken, + (info.getFlags() & TRANSIT_FLAG_KEYGUARD_LOCKED) != 0); recents.onAnimationStart(mRecentsSession, apps, wallpapers, new Rect(0, 0, 0, 0), new Rect()); } @@ -223,12 +225,13 @@ public class RemoteTransitionCompat implements Parcelable { private ArrayMap mLeashMap = null; private PictureInPictureSurfaceTransaction mPipTransaction = null; private IBinder mTransition = null; + private boolean mKeyguardLocked = false; void setup(RecentsAnimationControllerCompat wrapped, TransitionInfo info, IRemoteTransitionFinishedCallback finishCB, ArrayList pausingTasks, WindowContainerToken pipTask, WindowContainerToken recentsTask, ArrayMap leashMap, - IBinder transition) { + IBinder transition, boolean keyguardLocked) { if (mInfo != null) { throw new IllegalStateException("Trying to run a new recents animation while" + " recents is already active."); @@ -241,6 +244,7 @@ public class RemoteTransitionCompat implements Parcelable { mRecentsTask = recentsTask; mLeashMap = leashMap; mTransition = transition; + mKeyguardLocked = keyguardLocked; } @SuppressLint("NewApi") @@ -375,6 +379,10 @@ public class RemoteTransitionCompat implements Parcelable { final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); final WindowContainerTransaction wct = new WindowContainerTransaction(); + if (mKeyguardLocked && mRecentsTask != null) { + if (toHome) wct.reorder(mRecentsTask, true /* toTop */); + else wct.restoreTransientOrder(mRecentsTask); + } if (!toHome && mPausingTasks != null && mOpeningLeashes == null) { // The gesture went back to opening the app rather than continuing with // recents, so end the transition by moving the app back to the top (and also @@ -384,7 +392,7 @@ public class RemoteTransitionCompat implements Parcelable { wct.reorder(mPausingTasks.get(i), true /* onTop */); t.show(mInfo.getChange(mPausingTasks.get(i)).getLeash()); } - if (mRecentsTask != null) { + if (!mKeyguardLocked && mRecentsTask != null) { wct.restoreTransientOrder(mRecentsTask); } } else { diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 0fcd68317c59f..83812b8fb74f7 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -211,6 +211,7 @@ class ActivityStarter { // The task which was above the targetTask before starting this activity. null if the targetTask // was already on top or if the activity is in a new task. private Task mPriorAboveTask; + private boolean mDisplayLockAndOccluded; // We must track when we deliver the new intent since multiple code paths invoke // {@link #deliverNewIntent}. This is due to early returns in the code path. This flag is used @@ -1734,19 +1735,38 @@ class ActivityStarter { // Transition housekeeping. final TransitionController transitionController = started.mTransitionController; final boolean isStarted = result == START_SUCCESS || result == START_TASK_TO_FRONT; + final boolean isTransientLaunch = options != null && options.getTransientLaunch(); + // Start transient launch while keyguard locked and occluded by other app, for this + // condition we would like to play the remote transition without modify any visible state + // for the hierarchy in core, so here will force execute this transition. + final boolean forceTransientTransition = isTransientLaunch && mPriorAboveTask != null + && mDisplayLockAndOccluded; if (isStarted) { // The activity is started new rather than just brought forward, so record it as an // existence change. transitionController.collectExistenceChange(started); } else if (result == START_DELIVERED_TO_TOP && newTransition != null) { // We just delivered to top, so there isn't an actual transition here. - newTransition.abort(); - newTransition = null; + if (!forceTransientTransition) { + newTransition.abort(); + newTransition = null; + } } - if (options != null && options.getTransientLaunch()) { + if (isTransientLaunch) { + if (forceTransientTransition && newTransition != null) { + newTransition.collect(mLastStartActivityRecord); + newTransition.collect(mPriorAboveTask); + } // `started` isn't guaranteed to be the actual relevant activity, so we must wait // until after we launched to identify the relevant activity. transitionController.setTransientLaunch(mLastStartActivityRecord, mPriorAboveTask); + if (forceTransientTransition && newTransition != null) { + final DisplayContent dc = mLastStartActivityRecord.getDisplayContent(); + // update wallpaper target to TransientHide + dc.mWallpaperController.adjustWallpaperWindows(); + // execute transition because there is no change + newTransition.setReady(dc, true /* ready */); + } } if (!userLeaving) { // no-user-leaving implies not entering PiP. @@ -2384,6 +2404,7 @@ class ActivityStarter { mAvoidMoveToFront = false; mFrozeTaskList = false; mTransientLaunch = false; + mDisplayLockAndOccluded = false; mVoiceSession = null; mVoiceInteractor = null; @@ -2492,6 +2513,16 @@ class ActivityStarter { mAvoidMoveToFront = true; } mTransientLaunch = mOptions.getTransientLaunch(); + final KeyguardController kc = mSupervisor.getKeyguardController(); + final int displayId = mPreferredTaskDisplayArea.getDisplayId(); + mDisplayLockAndOccluded = kc.isKeyguardLocked(displayId) + && kc.isDisplayOccluded(displayId); + // Recents animation on lock screen, do not resume & move launcher to top. + if (mTransientLaunch && mDisplayLockAndOccluded + && mService.getTransitionController().isShellTransitionsEnabled()) { + mDoResume = false; + mAvoidMoveToFront = true; + } mTargetRootTask = Task.fromWindowContainerToken(mOptions.getLaunchRootTask()); if (inTaskFragment == null) { diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 470e835ddfc57..b95c25b69444a 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -1559,8 +1559,11 @@ class TaskFragment extends WindowContainer { } else { prev.schedulePauseTimeout(); - // Unset readiness since we now need to wait until this pause is complete. - mTransitionController.setReady(this, false /* ready */); + // All activities will be stopped when sleeping, don't need to wait for pause. + if (!uiSleeping) { + // Unset readiness since we now need to wait until this pause is complete. + mTransitionController.setReady(this, false /* ready */); + } return true; } diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 4e8b9db75dda9..47eb715684119 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -214,10 +214,26 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe mTransientLaunches = new ArrayMap<>(); } mTransientLaunches.put(activity, restoreBelow); + setTransientLaunchToChanges(activity); + + if (restoreBelow != null) { + final ChangeInfo info = mChanges.get(restoreBelow); + info.mFlags |= ChangeInfo.FLAG_ABOVE_TRANSIENT_LAUNCH; + } ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Transition %d: Set %s as " + "transient-launch", mSyncId, activity); } + boolean isTransientHide(@NonNull Task task) { + if (mTransientLaunches == null) return false; + for (int i = 0; i < mTransientLaunches.size(); ++i) { + if (mTransientLaunches.valueAt(i) == task) { + return true; + } + } + return false; + } + boolean isTransientLaunch(@NonNull ActivityRecord activity) { return mTransientLaunches != null && mTransientLaunches.containsKey(activity); } @@ -242,6 +258,20 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe info.mFlags = info.mFlags | ChangeInfo.FLAG_SEAMLESS_ROTATION; } + /** + * Only set flag to the parent tasks and activity itself. + */ + private void setTransientLaunchToChanges(@NonNull WindowContainer wc) { + for (WindowContainer curr = wc; curr != null && mChanges.containsKey(curr); + curr = curr.getParent()) { + if (curr.asTask() == null && curr.asActivityRecord() == null) { + return; + } + final ChangeInfo info = mChanges.get(curr); + info.mFlags = info.mFlags | ChangeInfo.FLAG_TRANSIENT_LAUNCH; + } + } + @VisibleForTesting int getSyncId() { return mSyncId; @@ -1546,10 +1576,14 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe * seamless rotation. This is currently only used by DisplayContent during fixed-rotation. */ private static final int FLAG_SEAMLESS_ROTATION = 1; + private static final int FLAG_TRANSIENT_LAUNCH = 2; + private static final int FLAG_ABOVE_TRANSIENT_LAUNCH = 4; @IntDef(prefix = { "FLAG_" }, value = { FLAG_NONE, - FLAG_SEAMLESS_ROTATION + FLAG_SEAMLESS_ROTATION, + FLAG_TRANSIENT_LAUNCH, + FLAG_ABOVE_TRANSIENT_LAUNCH }) @Retention(RetentionPolicy.SOURCE) @interface Flag {} @@ -1586,6 +1620,11 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe } boolean hasChanged(@NonNull WindowContainer newState) { + // the task including transient launch must promote to root task + if ((mFlags & ChangeInfo.FLAG_TRANSIENT_LAUNCH) != 0 + || (mFlags & ChangeInfo.FLAG_ABOVE_TRANSIENT_LAUNCH) != 0) { + return true; + } // If it's invisible and hasn't changed visibility, always return false since even if // something changed, it wouldn't be a visible change. final boolean currVisible = newState.isVisibleRequested(); @@ -1601,6 +1640,9 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe @TransitionInfo.TransitionMode int getTransitMode(@NonNull WindowContainer wc) { + if ((mFlags & ChangeInfo.FLAG_ABOVE_TRANSIENT_LAUNCH) != 0) { + return TRANSIT_CLOSE; + } final boolean nowVisible = wc.isVisibleRequested(); if (nowVisible == mVisible) { return TRANSIT_CHANGE; diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java index 85101660b0510..15ab3a2803acb 100644 --- a/services/core/java/com/android/server/wm/TransitionController.java +++ b/services/core/java/com/android/server/wm/TransitionController.java @@ -282,6 +282,16 @@ class TransitionController { return false; } + boolean isTransientHide(@NonNull Task task) { + if (mCollectingTransition != null && mCollectingTransition.isTransientHide(task)) { + return true; + } + for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) { + if (mPlayingTransitions.get(i).isTransientHide(task)) return true; + } + return false; + } + /** * @return {@code true} if {@param ar} is part of a transient-launch activity in an active * transition. diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java index a32a6087a04d0..483f51a1c0f5b 100644 --- a/services/core/java/com/android/server/wm/WallpaperController.java +++ b/services/core/java/com/android/server/wm/WallpaperController.java @@ -188,7 +188,8 @@ class WallpaperController { && animatingContainer.getAnimation().getShowWallpaper(); final boolean hasWallpaper = w.hasWallpaper() || animationWallpaper; final boolean isRecentsTransitionTarget = (recentsAnimationController != null - && recentsAnimationController.isWallpaperVisible(w)); + && recentsAnimationController.isWallpaperVisible(w)) + || w.mTransitionController.isTransientHide(w.getTask()); if (isRecentsTransitionTarget) { if (DEBUG_WALLPAPER) Slog.v(TAG, "Found recents animation wallpaper target: " + w); mFindResults.setWallpaperTarget(w);