Loading libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TransitionUtil.java +47 −0 Original line number Original line Diff line number Diff line Loading @@ -40,6 +40,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.annotation.SuppressLint; import android.app.ActivityManager; import android.app.ActivityManager; import android.app.TaskInfo; import android.app.WindowConfiguration; import android.app.WindowConfiguration; import android.graphics.Rect; import android.graphics.Rect; import android.util.ArrayMap; import android.util.ArrayMap; Loading Loading @@ -339,6 +340,52 @@ public class TransitionUtil { return target; return target; } } /** * Creates a new RemoteAnimationTarget from the provided change and leash */ public static RemoteAnimationTarget newSyntheticTarget(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash, @TransitionInfo.TransitionMode int mode, int order, boolean isTranslucent) { int taskId; boolean isNotInRecents; WindowConfiguration windowConfiguration; if (taskInfo != null) { taskId = taskInfo.taskId; isNotInRecents = !taskInfo.isRunning; windowConfiguration = taskInfo.configuration.windowConfiguration; } else { taskId = INVALID_TASK_ID; isNotInRecents = true; windowConfiguration = new WindowConfiguration(); } Rect localBounds = new Rect(); RemoteAnimationTarget target = new RemoteAnimationTarget( taskId, newModeToLegacyMode(mode), // TODO: once we can properly sync transactions across process, // then get rid of this leash. leash, isTranslucent, null, // TODO(shell-transitions): we need to send content insets? evaluate how its used. new Rect(0, 0, 0, 0), order, null, localBounds, new Rect(), windowConfiguration, isNotInRecents, null, new Rect(), taskInfo, false, INVALID_WINDOW_TYPE ); return target; } private static RemoteAnimationTarget getDividerTarget(TransitionInfo.Change change, private static RemoteAnimationTarget getDividerTarget(TransitionInfo.Change change, SurfaceControl leash) { SurfaceControl leash) { return new RemoteAnimationTarget(-1 /* taskId */, newModeToLegacyMode(change.getMode()), return new RemoteAnimationTarget(-1 /* taskId */, newModeToLegacyMode(change.getMode()), Loading libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java +0 −16 Original line number Original line Diff line number Diff line Loading @@ -46,7 +46,6 @@ import android.util.Log; import android.util.SparseArray; import android.util.SparseArray; import android.view.SurfaceControl; import android.view.SurfaceControl; import android.window.ITaskOrganizerController; import android.window.ITaskOrganizerController; import android.window.ScreenCapture; import android.window.StartingWindowInfo; import android.window.StartingWindowInfo; import android.window.StartingWindowRemovalInfo; import android.window.StartingWindowRemovalInfo; import android.window.TaskAppearedInfo; import android.window.TaskAppearedInfo; Loading @@ -55,7 +54,6 @@ import android.window.TaskOrganizer; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.ProtoLog; import com.android.internal.protolog.ProtoLog; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.FrameworkStatsLog; import com.android.wm.shell.common.ScreenshotUtils; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.compatui.CompatUIController; import com.android.wm.shell.compatui.CompatUIController; import com.android.wm.shell.compatui.api.CompatUIHandler; import com.android.wm.shell.compatui.api.CompatUIHandler; Loading @@ -74,7 +72,6 @@ import java.util.Arrays; import java.util.List; import java.util.List; import java.util.Objects; import java.util.Objects; import java.util.Optional; import java.util.Optional; import java.util.function.Consumer; /** /** * Unified task organizer for all components in the shell. * Unified task organizer for all components in the shell. Loading Loading @@ -561,19 +558,6 @@ public class ShellTaskOrganizer extends TaskOrganizer { mRecentTasks.ifPresent(recentTasks -> recentTasks.onTaskAdded(info.getTaskInfo())); mRecentTasks.ifPresent(recentTasks -> recentTasks.onTaskAdded(info.getTaskInfo())); } } /** * Take a screenshot of a task. */ public void screenshotTask(RunningTaskInfo taskInfo, Rect crop, Consumer<ScreenCapture.ScreenshotHardwareBuffer> consumer) { final TaskAppearedInfo info = mTasks.get(taskInfo.taskId); if (info == null) { return; } ScreenshotUtils.captureLayer(info.getLeash(), crop, consumer); } @Override @Override public void onTaskInfoChanged(RunningTaskInfo taskInfo) { public void onTaskInfoChanged(RunningTaskInfo taskInfo) { synchronized (mLock) { synchronized (mLock) { Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +2 −1 Original line number Original line Diff line number Diff line Loading @@ -487,10 +487,11 @@ public abstract class WMShellModule { @Provides @Provides static RecentsTransitionHandler provideRecentsTransitionHandler( static RecentsTransitionHandler provideRecentsTransitionHandler( ShellInit shellInit, ShellInit shellInit, ShellTaskOrganizer shellTaskOrganizer, Transitions transitions, Transitions transitions, Optional<RecentTasksController> recentTasksController, Optional<RecentTasksController> recentTasksController, HomeTransitionObserver homeTransitionObserver) { HomeTransitionObserver homeTransitionObserver) { return new RecentsTransitionHandler(shellInit, transitions, return new RecentsTransitionHandler(shellInit, shellTaskOrganizer, transitions, recentTasksController.orElse(null), homeTransitionObserver); recentTasksController.orElse(null), homeTransitionObserver); } } Loading libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java +215 −31 Original line number Original line Diff line number Diff line Loading @@ -20,9 +20,12 @@ import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.KEYGUARD_VISIBILITY_TRANSIT_FLAGS; import static android.view.WindowManager.KEYGUARD_VISIBILITY_TRANSIT_FLAGS; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_PIP; import static android.view.WindowManager.TRANSIT_PIP; import static android.view.WindowManager.TRANSIT_SLEEP; import static android.view.WindowManager.TRANSIT_SLEEP; import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.view.WindowManager.TRANSIT_TO_FRONT; Loading @@ -41,6 +44,7 @@ import android.app.PendingIntent; import android.content.Intent; import android.content.Intent; import android.graphics.Color; import android.graphics.Color; import android.graphics.Rect; import android.graphics.Rect; import android.os.Binder; import android.os.Bundle; import android.os.Bundle; import android.os.IBinder; import android.os.IBinder; import android.os.RemoteException; import android.os.RemoteException; Loading @@ -64,6 +68,7 @@ import androidx.annotation.NonNull; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.IResultReceiver; import com.android.internal.os.IResultReceiver; import com.android.internal.protolog.ProtoLog; import com.android.internal.protolog.ProtoLog; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.pip.PipUtils; import com.android.wm.shell.common.pip.PipUtils; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.protolog.ShellProtoLogGroup; Loading @@ -79,10 +84,15 @@ import java.util.function.Consumer; * Handles the Recents (overview) animation. Only one of these can run at a time. A recents * Handles the Recents (overview) animation. Only one of these can run at a time. A recents * transition must be created via {@link #startRecentsTransition}. Anything else will be ignored. * transition must be created via {@link #startRecentsTransition}. Anything else will be ignored. */ */ public class RecentsTransitionHandler implements Transitions.TransitionHandler { public class RecentsTransitionHandler implements Transitions.TransitionHandler, Transitions.TransitionObserver { private static final String TAG = "RecentsTransitionHandler"; private static final String TAG = "RecentsTransitionHandler"; // A placeholder for a synthetic transition that isn't backed by a true system transition public static final IBinder SYNTHETIC_TRANSITION = new Binder(); private final Transitions mTransitions; private final Transitions mTransitions; private final ShellTaskOrganizer mShellTaskOrganizer; private final ShellExecutor mExecutor; private final ShellExecutor mExecutor; @Nullable @Nullable private final RecentTasksController mRecentTasksController; private final RecentTasksController mRecentTasksController; Loading @@ -99,19 +109,26 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { private final HomeTransitionObserver mHomeTransitionObserver; private final HomeTransitionObserver mHomeTransitionObserver; private @Nullable Color mBackgroundColor; private @Nullable Color mBackgroundColor; public RecentsTransitionHandler(ShellInit shellInit, Transitions transitions, public RecentsTransitionHandler( @NonNull ShellInit shellInit, @NonNull ShellTaskOrganizer shellTaskOrganizer, @NonNull Transitions transitions, @Nullable RecentTasksController recentTasksController, @Nullable RecentTasksController recentTasksController, HomeTransitionObserver homeTransitionObserver) { @NonNull HomeTransitionObserver homeTransitionObserver) { mShellTaskOrganizer = shellTaskOrganizer; mTransitions = transitions; mTransitions = transitions; mExecutor = transitions.getMainExecutor(); mExecutor = transitions.getMainExecutor(); mRecentTasksController = recentTasksController; mRecentTasksController = recentTasksController; mHomeTransitionObserver = homeTransitionObserver; mHomeTransitionObserver = homeTransitionObserver; if (!Transitions.ENABLE_SHELL_TRANSITIONS) return; if (!Transitions.ENABLE_SHELL_TRANSITIONS) return; if (recentTasksController == null) return; if (recentTasksController == null) return; shellInit.addInitCallback(() -> { shellInit.addInitCallback(this::onInit, this); recentTasksController.setTransitionHandler(this); } transitions.addHandler(this); }, this); private void onInit() { mRecentTasksController.setTransitionHandler(this); mTransitions.addHandler(this); mTransitions.registerObserver(this); } } /** Register a mixer handler. {@see RecentsMixedHandler}*/ /** Register a mixer handler. {@see RecentsMixedHandler}*/ Loading @@ -138,17 +155,59 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { mBackgroundColor = color; mBackgroundColor = color; } } /** * Starts a new real/synthetic recents transition. */ @VisibleForTesting @VisibleForTesting public IBinder startRecentsTransition(PendingIntent intent, Intent fillIn, Bundle options, public IBinder startRecentsTransition(PendingIntent intent, Intent fillIn, Bundle options, IApplicationThread appThread, IRecentsAnimationRunner listener) { IApplicationThread appThread, IRecentsAnimationRunner listener) { // only care about latest one. mAnimApp = appThread; // TODO(b/366021931): Formalize this later final boolean isSyntheticRequest = options.containsKey("is_synthetic_recents_transition"); if (isSyntheticRequest) { return startSyntheticRecentsTransition(listener); } else { return startRealRecentsTransition(intent, fillIn, options, listener); } } /** * Starts a synthetic recents transition that is not backed by a real WM transition. */ private IBinder startSyntheticRecentsTransition(@NonNull IRecentsAnimationRunner listener) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "RecentsTransitionHandler.startRecentsTransition(synthetic)"); final RecentsController lastController = getLastController(); if (lastController != null) { lastController.cancel(lastController.isSyntheticTransition() ? "existing_running_synthetic_transition" : "existing_running_transition"); return null; } // Create a new synthetic transition and start it immediately final RecentsController controller = new RecentsController(listener); controller.startSyntheticTransition(); mControllers.add(controller); return SYNTHETIC_TRANSITION; } /** * Starts a real WM-backed recents transition. */ private IBinder startRealRecentsTransition(PendingIntent intent, Intent fillIn, Bundle options, IRecentsAnimationRunner listener) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "RecentsTransitionHandler.startRecentsTransition"); "RecentsTransitionHandler.startRecentsTransition"); // only care about latest one. final WindowContainerTransaction wct = new WindowContainerTransaction(); mAnimApp = appThread; WindowContainerTransaction wct = new WindowContainerTransaction(); wct.sendPendingIntent(intent, fillIn, options); wct.sendPendingIntent(intent, fillIn, options); final RecentsController controller = new RecentsController(listener); // Find the mixed handler which should handle this request (if we are in a state where a // mixed handler is needed). This is slightly convoluted because starting the transition // requires the handler, but the mixed handler also needs a reference to the transition. RecentsMixedHandler mixer = null; RecentsMixedHandler mixer = null; Consumer<IBinder> setTransitionForMixer = null; Consumer<IBinder> setTransitionForMixer = null; for (int i = 0; i < mMixers.size(); ++i) { for (int i = 0; i < mMixers.size(); ++i) { Loading @@ -160,12 +219,11 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { } } final IBinder transition = mTransitions.startTransition(TRANSIT_TO_FRONT, wct, final IBinder transition = mTransitions.startTransition(TRANSIT_TO_FRONT, wct, mixer == null ? this : mixer); mixer == null ? this : mixer); for (int i = 0; i < mStateListeners.size(); i++) { mStateListeners.get(i).onTransitionStarted(transition); } if (mixer != null) { if (mixer != null) { setTransitionForMixer.accept(transition); setTransitionForMixer.accept(transition); } } final RecentsController controller = new RecentsController(listener); if (transition != null) { if (transition != null) { controller.setTransition(transition); controller.setTransition(transition); mControllers.add(controller); mControllers.add(controller); Loading @@ -187,11 +245,28 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { return null; return null; } } private int findController(IBinder transition) { /** * Returns if there is currently a pending or active recents transition. */ @Nullable private RecentsController getLastController() { return !mControllers.isEmpty() ? mControllers.getLast() : null; } /** * Finds an existing controller for the provided {@param transition}, or {@code null} if none * exists. */ @Nullable @VisibleForTesting RecentsController findController(@NonNull IBinder transition) { for (int i = mControllers.size() - 1; i >= 0; --i) { for (int i = mControllers.size() - 1; i >= 0; --i) { if (mControllers.get(i).mTransition == transition) return i; final RecentsController controller = mControllers.get(i); if (controller.mTransition == transition) { return controller; } } return -1; } return null; } } @Override @Override Loading @@ -199,13 +274,12 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { SurfaceControl.Transaction startTransaction, SurfaceControl.Transaction startTransaction, SurfaceControl.Transaction finishTransaction, SurfaceControl.Transaction finishTransaction, Transitions.TransitionFinishCallback finishCallback) { Transitions.TransitionFinishCallback finishCallback) { final int controllerIdx = findController(transition); final RecentsController controller = findController(transition); if (controllerIdx < 0) { if (controller == null) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "RecentsTransitionHandler.startAnimation: no controller found"); "RecentsTransitionHandler.startAnimation: no controller found"); return false; return false; } } final RecentsController controller = mControllers.get(controllerIdx); final IApplicationThread animApp = mAnimApp; final IApplicationThread animApp = mAnimApp; mAnimApp = null; mAnimApp = null; if (!controller.start(info, startTransaction, finishTransaction, finishCallback)) { if (!controller.start(info, startTransaction, finishTransaction, finishCallback)) { Loading @@ -221,13 +295,12 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { public void mergeAnimation(IBinder transition, TransitionInfo info, public void mergeAnimation(IBinder transition, TransitionInfo info, SurfaceControl.Transaction t, IBinder mergeTarget, SurfaceControl.Transaction t, IBinder mergeTarget, Transitions.TransitionFinishCallback finishCallback) { Transitions.TransitionFinishCallback finishCallback) { final int targetIdx = findController(mergeTarget); final RecentsController controller = findController(mergeTarget); if (targetIdx < 0) { if (controller == null) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "RecentsTransitionHandler.mergeAnimation: no controller found"); "RecentsTransitionHandler.mergeAnimation: no controller found"); return; return; } } final RecentsController controller = mControllers.get(targetIdx); controller.merge(info, t, finishCallback); controller.merge(info, t, finishCallback); } } Loading @@ -244,8 +317,21 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { } } } } @Override public void onTransitionReady(@NonNull IBinder transition, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction) { RecentsController controller = findController(SYNTHETIC_TRANSITION); if (controller != null) { // Cancel the existing synthetic transition if there is one controller.cancel("incoming_transition"); } } /** There is only one of these and it gets reset on finish. */ /** There is only one of these and it gets reset on finish. */ private class RecentsController extends IRecentsAnimationController.Stub { @VisibleForTesting class RecentsController extends IRecentsAnimationController.Stub { private final int mInstanceId; private final int mInstanceId; private IRecentsAnimationRunner mListener; private IRecentsAnimationRunner mListener; Loading Loading @@ -307,7 +393,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { mDeathHandler = () -> { mDeathHandler = () -> { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "[%d] RecentsController.DeathRecipient: binder died", mInstanceId); "[%d] RecentsController.DeathRecipient: binder died", mInstanceId); finish(mWillFinishToHome, false /* leaveHint */, null /* finishCb */); finishInner(mWillFinishToHome, false /* leaveHint */, null /* finishCb */, "deathRecipient"); }; }; try { try { mListener.asBinder().linkToDeath(mDeathHandler, 0 /* flags */); mListener.asBinder().linkToDeath(mDeathHandler, 0 /* flags */); Loading @@ -317,6 +404,9 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { } } } } /** * Sets the started transition for this instance of the recents transition. */ void setTransition(IBinder transition) { void setTransition(IBinder transition) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "[%d] RecentsController.setTransition: id=%s", mInstanceId, transition); "[%d] RecentsController.setTransition: id=%s", mInstanceId, transition); Loading @@ -330,6 +420,10 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { } } void cancel(boolean toHome, boolean withScreenshots, String reason) { void cancel(boolean toHome, boolean withScreenshots, String reason) { if (cancelSyntheticTransition(reason)) { return; } ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "[%d] RecentsController.cancel: toHome=%b reason=%s", "[%d] RecentsController.cancel: toHome=%b reason=%s", mInstanceId, toHome, reason); mInstanceId, toHome, reason); Loading @@ -341,7 +435,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { } } } } if (mFinishCB != null) { if (mFinishCB != null) { finishInner(toHome, false /* userLeave */, null /* finishCb */); finishInner(toHome, false /* userLeave */, null /* finishCb */, "cancel"); } else { } else { cleanUp(); cleanUp(); } } Loading Loading @@ -436,6 +530,91 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { } } } } /** * Starts a new transition that is not backed by a system transition. */ void startSyntheticTransition() { mTransition = SYNTHETIC_TRANSITION; // TODO(b/366021931): Update mechanism for pulling the home task, for now add home as // both opening and closing since there's some pre-existing // dependencies on having a closing task final ActivityManager.RunningTaskInfo homeTask = mShellTaskOrganizer.getRunningTasks(DEFAULT_DISPLAY).stream() .filter(task -> task.getActivityType() == ACTIVITY_TYPE_HOME) .findFirst() .get(); final RemoteAnimationTarget openingTarget = TransitionUtil.newSyntheticTarget( homeTask, mShellTaskOrganizer.getHomeTaskOverlayContainer(), TRANSIT_OPEN, 0, true /* isTranslucent */); final RemoteAnimationTarget closingTarget = TransitionUtil.newSyntheticTarget( homeTask, mShellTaskOrganizer.getHomeTaskOverlayContainer(), TRANSIT_CLOSE, 0, true /* isTranslucent */); final ArrayList<RemoteAnimationTarget> apps = new ArrayList<>(); apps.add(openingTarget); apps.add(closingTarget); try { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "[%d] RecentsController.start: calling onAnimationStart with %d apps", mInstanceId, apps.size()); mListener.onAnimationStart(this, apps.toArray(new RemoteAnimationTarget[apps.size()]), new RemoteAnimationTarget[0], new Rect(0, 0, 0, 0), new Rect(), new Bundle()); for (int i = 0; i < mStateListeners.size(); i++) { mStateListeners.get(i).onAnimationStateChanged(true); } } catch (RemoteException e) { Slog.e(TAG, "Error starting recents animation", e); cancel("startSynthetricTransition() failed"); } } /** * Returns whether this transition is backed by a real system transition or not. */ boolean isSyntheticTransition() { return mTransition == SYNTHETIC_TRANSITION; } /** * Called when a synthetic transition is canceled. */ boolean cancelSyntheticTransition(String reason) { if (!isSyntheticTransition()) { return false; } ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "[%d] RecentsController.cancelSyntheticTransition reason=%s", mInstanceId, reason); try { // TODO(b/366021931): Notify the correct tasks once we build actual targets, and // clean up leashes accordingly mListener.onAnimationCanceled(new int[0], new TaskSnapshot[0]); } catch (RemoteException e) { Slog.e(TAG, "Error canceling previous recents animation", e); } cleanUp(); return true; } /** * Called when a synthetic transition is finished. * @return */ boolean finishSyntheticTransition() { if (!isSyntheticTransition()) { return false; } ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "[%d] RecentsController.finishSyntheticTransition", mInstanceId); // TODO(b/366021931): Clean up leashes accordingly cleanUp(); return true; } boolean start(TransitionInfo info, SurfaceControl.Transaction t, boolean start(TransitionInfo info, SurfaceControl.Transaction t, SurfaceControl.Transaction finishT, Transitions.TransitionFinishCallback finishCB) { SurfaceControl.Transaction finishT, Transitions.TransitionFinishCallback finishCB) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, Loading Loading @@ -662,7 +841,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { // Set the callback once again so we can finish correctly. // Set the callback once again so we can finish correctly. mFinishCB = finishCB; mFinishCB = finishCB; finishInner(true /* toHome */, false /* userLeave */, finishInner(true /* toHome */, false /* userLeave */, null /* finishCb */); null /* finishCb */, "takeOverAnimation"); }, updatedStates); }, updatedStates); }); }); } } Loading Loading @@ -810,7 +989,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { sendCancelWithSnapshots(); sendCancelWithSnapshots(); mExecutor.executeDelayed( mExecutor.executeDelayed( () -> finishInner(true /* toHome */, false /* userLeaveHint */, () -> finishInner(true /* toHome */, false /* userLeaveHint */, null /* finishCb */), 0); null /* finishCb */, "merge"), 0); return; return; } } if (recentsOpening != null) { if (recentsOpening != null) { Loading Loading @@ -1005,7 +1184,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { return; return; } } final int displayId = mInfo.getRootCount() > 0 ? mInfo.getRoot(0).getDisplayId() final int displayId = mInfo.getRootCount() > 0 ? mInfo.getRoot(0).getDisplayId() : Display.DEFAULT_DISPLAY; : DEFAULT_DISPLAY; // transient launches don't receive focus automatically. Since we are taking over // transient launches don't receive focus automatically. Since we are taking over // the gesture now, take focus explicitly. // the gesture now, take focus explicitly. // This also moves recents back to top if the user gestured before a switch // This also moves recents back to top if the user gestured before a switch Loading Loading @@ -1038,11 +1217,16 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { @Override @Override @SuppressLint("NewApi") @SuppressLint("NewApi") public void finish(boolean toHome, boolean sendUserLeaveHint, IResultReceiver finishCb) { public void finish(boolean toHome, boolean sendUserLeaveHint, IResultReceiver finishCb) { mExecutor.execute(() -> finishInner(toHome, sendUserLeaveHint, finishCb)); mExecutor.execute(() -> finishInner(toHome, sendUserLeaveHint, finishCb, "requested")); } } private void finishInner(boolean toHome, boolean sendUserLeaveHint, private void finishInner(boolean toHome, boolean sendUserLeaveHint, IResultReceiver runnerFinishCb) { IResultReceiver runnerFinishCb, String reason) { if (finishSyntheticTransition()) { return; } if (mFinishCB == null) { if (mFinishCB == null) { Slog.e(TAG, "Duplicate call to finish"); Slog.e(TAG, "Duplicate call to finish"); return; return; Loading libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionStateListener.java +0 −3 Original line number Original line Diff line number Diff line Loading @@ -24,7 +24,4 @@ public interface RecentsTransitionStateListener { /** Notifies whether the recents animation is running. */ /** Notifies whether the recents animation is running. */ default void onAnimationStateChanged(boolean running) { default void onAnimationStateChanged(boolean running) { } } /** Notifies that a recents shell transition has started. */ default void onTransitionStarted(IBinder transition) {} } } Loading
libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/TransitionUtil.java +47 −0 Original line number Original line Diff line number Diff line Loading @@ -40,6 +40,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.annotation.SuppressLint; import android.app.ActivityManager; import android.app.ActivityManager; import android.app.TaskInfo; import android.app.WindowConfiguration; import android.app.WindowConfiguration; import android.graphics.Rect; import android.graphics.Rect; import android.util.ArrayMap; import android.util.ArrayMap; Loading Loading @@ -339,6 +340,52 @@ public class TransitionUtil { return target; return target; } } /** * Creates a new RemoteAnimationTarget from the provided change and leash */ public static RemoteAnimationTarget newSyntheticTarget(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash, @TransitionInfo.TransitionMode int mode, int order, boolean isTranslucent) { int taskId; boolean isNotInRecents; WindowConfiguration windowConfiguration; if (taskInfo != null) { taskId = taskInfo.taskId; isNotInRecents = !taskInfo.isRunning; windowConfiguration = taskInfo.configuration.windowConfiguration; } else { taskId = INVALID_TASK_ID; isNotInRecents = true; windowConfiguration = new WindowConfiguration(); } Rect localBounds = new Rect(); RemoteAnimationTarget target = new RemoteAnimationTarget( taskId, newModeToLegacyMode(mode), // TODO: once we can properly sync transactions across process, // then get rid of this leash. leash, isTranslucent, null, // TODO(shell-transitions): we need to send content insets? evaluate how its used. new Rect(0, 0, 0, 0), order, null, localBounds, new Rect(), windowConfiguration, isNotInRecents, null, new Rect(), taskInfo, false, INVALID_WINDOW_TYPE ); return target; } private static RemoteAnimationTarget getDividerTarget(TransitionInfo.Change change, private static RemoteAnimationTarget getDividerTarget(TransitionInfo.Change change, SurfaceControl leash) { SurfaceControl leash) { return new RemoteAnimationTarget(-1 /* taskId */, newModeToLegacyMode(change.getMode()), return new RemoteAnimationTarget(-1 /* taskId */, newModeToLegacyMode(change.getMode()), Loading
libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java +0 −16 Original line number Original line Diff line number Diff line Loading @@ -46,7 +46,6 @@ import android.util.Log; import android.util.SparseArray; import android.util.SparseArray; import android.view.SurfaceControl; import android.view.SurfaceControl; import android.window.ITaskOrganizerController; import android.window.ITaskOrganizerController; import android.window.ScreenCapture; import android.window.StartingWindowInfo; import android.window.StartingWindowInfo; import android.window.StartingWindowRemovalInfo; import android.window.StartingWindowRemovalInfo; import android.window.TaskAppearedInfo; import android.window.TaskAppearedInfo; Loading @@ -55,7 +54,6 @@ import android.window.TaskOrganizer; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.ProtoLog; import com.android.internal.protolog.ProtoLog; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.FrameworkStatsLog; import com.android.wm.shell.common.ScreenshotUtils; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.compatui.CompatUIController; import com.android.wm.shell.compatui.CompatUIController; import com.android.wm.shell.compatui.api.CompatUIHandler; import com.android.wm.shell.compatui.api.CompatUIHandler; Loading @@ -74,7 +72,6 @@ import java.util.Arrays; import java.util.List; import java.util.List; import java.util.Objects; import java.util.Objects; import java.util.Optional; import java.util.Optional; import java.util.function.Consumer; /** /** * Unified task organizer for all components in the shell. * Unified task organizer for all components in the shell. Loading Loading @@ -561,19 +558,6 @@ public class ShellTaskOrganizer extends TaskOrganizer { mRecentTasks.ifPresent(recentTasks -> recentTasks.onTaskAdded(info.getTaskInfo())); mRecentTasks.ifPresent(recentTasks -> recentTasks.onTaskAdded(info.getTaskInfo())); } } /** * Take a screenshot of a task. */ public void screenshotTask(RunningTaskInfo taskInfo, Rect crop, Consumer<ScreenCapture.ScreenshotHardwareBuffer> consumer) { final TaskAppearedInfo info = mTasks.get(taskInfo.taskId); if (info == null) { return; } ScreenshotUtils.captureLayer(info.getLeash(), crop, consumer); } @Override @Override public void onTaskInfoChanged(RunningTaskInfo taskInfo) { public void onTaskInfoChanged(RunningTaskInfo taskInfo) { synchronized (mLock) { synchronized (mLock) { Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +2 −1 Original line number Original line Diff line number Diff line Loading @@ -487,10 +487,11 @@ public abstract class WMShellModule { @Provides @Provides static RecentsTransitionHandler provideRecentsTransitionHandler( static RecentsTransitionHandler provideRecentsTransitionHandler( ShellInit shellInit, ShellInit shellInit, ShellTaskOrganizer shellTaskOrganizer, Transitions transitions, Transitions transitions, Optional<RecentTasksController> recentTasksController, Optional<RecentTasksController> recentTasksController, HomeTransitionObserver homeTransitionObserver) { HomeTransitionObserver homeTransitionObserver) { return new RecentsTransitionHandler(shellInit, transitions, return new RecentsTransitionHandler(shellInit, shellTaskOrganizer, transitions, recentTasksController.orElse(null), homeTransitionObserver); recentTasksController.orElse(null), homeTransitionObserver); } } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java +215 −31 Original line number Original line Diff line number Diff line Loading @@ -20,9 +20,12 @@ import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.KEYGUARD_VISIBILITY_TRANSIT_FLAGS; import static android.view.WindowManager.KEYGUARD_VISIBILITY_TRANSIT_FLAGS; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_PIP; import static android.view.WindowManager.TRANSIT_PIP; import static android.view.WindowManager.TRANSIT_SLEEP; import static android.view.WindowManager.TRANSIT_SLEEP; import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.view.WindowManager.TRANSIT_TO_FRONT; Loading @@ -41,6 +44,7 @@ import android.app.PendingIntent; import android.content.Intent; import android.content.Intent; import android.graphics.Color; import android.graphics.Color; import android.graphics.Rect; import android.graphics.Rect; import android.os.Binder; import android.os.Bundle; import android.os.Bundle; import android.os.IBinder; import android.os.IBinder; import android.os.RemoteException; import android.os.RemoteException; Loading @@ -64,6 +68,7 @@ import androidx.annotation.NonNull; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.IResultReceiver; import com.android.internal.os.IResultReceiver; import com.android.internal.protolog.ProtoLog; import com.android.internal.protolog.ProtoLog; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.pip.PipUtils; import com.android.wm.shell.common.pip.PipUtils; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.protolog.ShellProtoLogGroup; Loading @@ -79,10 +84,15 @@ import java.util.function.Consumer; * Handles the Recents (overview) animation. Only one of these can run at a time. A recents * Handles the Recents (overview) animation. Only one of these can run at a time. A recents * transition must be created via {@link #startRecentsTransition}. Anything else will be ignored. * transition must be created via {@link #startRecentsTransition}. Anything else will be ignored. */ */ public class RecentsTransitionHandler implements Transitions.TransitionHandler { public class RecentsTransitionHandler implements Transitions.TransitionHandler, Transitions.TransitionObserver { private static final String TAG = "RecentsTransitionHandler"; private static final String TAG = "RecentsTransitionHandler"; // A placeholder for a synthetic transition that isn't backed by a true system transition public static final IBinder SYNTHETIC_TRANSITION = new Binder(); private final Transitions mTransitions; private final Transitions mTransitions; private final ShellTaskOrganizer mShellTaskOrganizer; private final ShellExecutor mExecutor; private final ShellExecutor mExecutor; @Nullable @Nullable private final RecentTasksController mRecentTasksController; private final RecentTasksController mRecentTasksController; Loading @@ -99,19 +109,26 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { private final HomeTransitionObserver mHomeTransitionObserver; private final HomeTransitionObserver mHomeTransitionObserver; private @Nullable Color mBackgroundColor; private @Nullable Color mBackgroundColor; public RecentsTransitionHandler(ShellInit shellInit, Transitions transitions, public RecentsTransitionHandler( @NonNull ShellInit shellInit, @NonNull ShellTaskOrganizer shellTaskOrganizer, @NonNull Transitions transitions, @Nullable RecentTasksController recentTasksController, @Nullable RecentTasksController recentTasksController, HomeTransitionObserver homeTransitionObserver) { @NonNull HomeTransitionObserver homeTransitionObserver) { mShellTaskOrganizer = shellTaskOrganizer; mTransitions = transitions; mTransitions = transitions; mExecutor = transitions.getMainExecutor(); mExecutor = transitions.getMainExecutor(); mRecentTasksController = recentTasksController; mRecentTasksController = recentTasksController; mHomeTransitionObserver = homeTransitionObserver; mHomeTransitionObserver = homeTransitionObserver; if (!Transitions.ENABLE_SHELL_TRANSITIONS) return; if (!Transitions.ENABLE_SHELL_TRANSITIONS) return; if (recentTasksController == null) return; if (recentTasksController == null) return; shellInit.addInitCallback(() -> { shellInit.addInitCallback(this::onInit, this); recentTasksController.setTransitionHandler(this); } transitions.addHandler(this); }, this); private void onInit() { mRecentTasksController.setTransitionHandler(this); mTransitions.addHandler(this); mTransitions.registerObserver(this); } } /** Register a mixer handler. {@see RecentsMixedHandler}*/ /** Register a mixer handler. {@see RecentsMixedHandler}*/ Loading @@ -138,17 +155,59 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { mBackgroundColor = color; mBackgroundColor = color; } } /** * Starts a new real/synthetic recents transition. */ @VisibleForTesting @VisibleForTesting public IBinder startRecentsTransition(PendingIntent intent, Intent fillIn, Bundle options, public IBinder startRecentsTransition(PendingIntent intent, Intent fillIn, Bundle options, IApplicationThread appThread, IRecentsAnimationRunner listener) { IApplicationThread appThread, IRecentsAnimationRunner listener) { // only care about latest one. mAnimApp = appThread; // TODO(b/366021931): Formalize this later final boolean isSyntheticRequest = options.containsKey("is_synthetic_recents_transition"); if (isSyntheticRequest) { return startSyntheticRecentsTransition(listener); } else { return startRealRecentsTransition(intent, fillIn, options, listener); } } /** * Starts a synthetic recents transition that is not backed by a real WM transition. */ private IBinder startSyntheticRecentsTransition(@NonNull IRecentsAnimationRunner listener) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "RecentsTransitionHandler.startRecentsTransition(synthetic)"); final RecentsController lastController = getLastController(); if (lastController != null) { lastController.cancel(lastController.isSyntheticTransition() ? "existing_running_synthetic_transition" : "existing_running_transition"); return null; } // Create a new synthetic transition and start it immediately final RecentsController controller = new RecentsController(listener); controller.startSyntheticTransition(); mControllers.add(controller); return SYNTHETIC_TRANSITION; } /** * Starts a real WM-backed recents transition. */ private IBinder startRealRecentsTransition(PendingIntent intent, Intent fillIn, Bundle options, IRecentsAnimationRunner listener) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "RecentsTransitionHandler.startRecentsTransition"); "RecentsTransitionHandler.startRecentsTransition"); // only care about latest one. final WindowContainerTransaction wct = new WindowContainerTransaction(); mAnimApp = appThread; WindowContainerTransaction wct = new WindowContainerTransaction(); wct.sendPendingIntent(intent, fillIn, options); wct.sendPendingIntent(intent, fillIn, options); final RecentsController controller = new RecentsController(listener); // Find the mixed handler which should handle this request (if we are in a state where a // mixed handler is needed). This is slightly convoluted because starting the transition // requires the handler, but the mixed handler also needs a reference to the transition. RecentsMixedHandler mixer = null; RecentsMixedHandler mixer = null; Consumer<IBinder> setTransitionForMixer = null; Consumer<IBinder> setTransitionForMixer = null; for (int i = 0; i < mMixers.size(); ++i) { for (int i = 0; i < mMixers.size(); ++i) { Loading @@ -160,12 +219,11 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { } } final IBinder transition = mTransitions.startTransition(TRANSIT_TO_FRONT, wct, final IBinder transition = mTransitions.startTransition(TRANSIT_TO_FRONT, wct, mixer == null ? this : mixer); mixer == null ? this : mixer); for (int i = 0; i < mStateListeners.size(); i++) { mStateListeners.get(i).onTransitionStarted(transition); } if (mixer != null) { if (mixer != null) { setTransitionForMixer.accept(transition); setTransitionForMixer.accept(transition); } } final RecentsController controller = new RecentsController(listener); if (transition != null) { if (transition != null) { controller.setTransition(transition); controller.setTransition(transition); mControllers.add(controller); mControllers.add(controller); Loading @@ -187,11 +245,28 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { return null; return null; } } private int findController(IBinder transition) { /** * Returns if there is currently a pending or active recents transition. */ @Nullable private RecentsController getLastController() { return !mControllers.isEmpty() ? mControllers.getLast() : null; } /** * Finds an existing controller for the provided {@param transition}, or {@code null} if none * exists. */ @Nullable @VisibleForTesting RecentsController findController(@NonNull IBinder transition) { for (int i = mControllers.size() - 1; i >= 0; --i) { for (int i = mControllers.size() - 1; i >= 0; --i) { if (mControllers.get(i).mTransition == transition) return i; final RecentsController controller = mControllers.get(i); if (controller.mTransition == transition) { return controller; } } return -1; } return null; } } @Override @Override Loading @@ -199,13 +274,12 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { SurfaceControl.Transaction startTransaction, SurfaceControl.Transaction startTransaction, SurfaceControl.Transaction finishTransaction, SurfaceControl.Transaction finishTransaction, Transitions.TransitionFinishCallback finishCallback) { Transitions.TransitionFinishCallback finishCallback) { final int controllerIdx = findController(transition); final RecentsController controller = findController(transition); if (controllerIdx < 0) { if (controller == null) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "RecentsTransitionHandler.startAnimation: no controller found"); "RecentsTransitionHandler.startAnimation: no controller found"); return false; return false; } } final RecentsController controller = mControllers.get(controllerIdx); final IApplicationThread animApp = mAnimApp; final IApplicationThread animApp = mAnimApp; mAnimApp = null; mAnimApp = null; if (!controller.start(info, startTransaction, finishTransaction, finishCallback)) { if (!controller.start(info, startTransaction, finishTransaction, finishCallback)) { Loading @@ -221,13 +295,12 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { public void mergeAnimation(IBinder transition, TransitionInfo info, public void mergeAnimation(IBinder transition, TransitionInfo info, SurfaceControl.Transaction t, IBinder mergeTarget, SurfaceControl.Transaction t, IBinder mergeTarget, Transitions.TransitionFinishCallback finishCallback) { Transitions.TransitionFinishCallback finishCallback) { final int targetIdx = findController(mergeTarget); final RecentsController controller = findController(mergeTarget); if (targetIdx < 0) { if (controller == null) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "RecentsTransitionHandler.mergeAnimation: no controller found"); "RecentsTransitionHandler.mergeAnimation: no controller found"); return; return; } } final RecentsController controller = mControllers.get(targetIdx); controller.merge(info, t, finishCallback); controller.merge(info, t, finishCallback); } } Loading @@ -244,8 +317,21 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { } } } } @Override public void onTransitionReady(@NonNull IBinder transition, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction) { RecentsController controller = findController(SYNTHETIC_TRANSITION); if (controller != null) { // Cancel the existing synthetic transition if there is one controller.cancel("incoming_transition"); } } /** There is only one of these and it gets reset on finish. */ /** There is only one of these and it gets reset on finish. */ private class RecentsController extends IRecentsAnimationController.Stub { @VisibleForTesting class RecentsController extends IRecentsAnimationController.Stub { private final int mInstanceId; private final int mInstanceId; private IRecentsAnimationRunner mListener; private IRecentsAnimationRunner mListener; Loading Loading @@ -307,7 +393,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { mDeathHandler = () -> { mDeathHandler = () -> { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "[%d] RecentsController.DeathRecipient: binder died", mInstanceId); "[%d] RecentsController.DeathRecipient: binder died", mInstanceId); finish(mWillFinishToHome, false /* leaveHint */, null /* finishCb */); finishInner(mWillFinishToHome, false /* leaveHint */, null /* finishCb */, "deathRecipient"); }; }; try { try { mListener.asBinder().linkToDeath(mDeathHandler, 0 /* flags */); mListener.asBinder().linkToDeath(mDeathHandler, 0 /* flags */); Loading @@ -317,6 +404,9 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { } } } } /** * Sets the started transition for this instance of the recents transition. */ void setTransition(IBinder transition) { void setTransition(IBinder transition) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "[%d] RecentsController.setTransition: id=%s", mInstanceId, transition); "[%d] RecentsController.setTransition: id=%s", mInstanceId, transition); Loading @@ -330,6 +420,10 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { } } void cancel(boolean toHome, boolean withScreenshots, String reason) { void cancel(boolean toHome, boolean withScreenshots, String reason) { if (cancelSyntheticTransition(reason)) { return; } ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "[%d] RecentsController.cancel: toHome=%b reason=%s", "[%d] RecentsController.cancel: toHome=%b reason=%s", mInstanceId, toHome, reason); mInstanceId, toHome, reason); Loading @@ -341,7 +435,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { } } } } if (mFinishCB != null) { if (mFinishCB != null) { finishInner(toHome, false /* userLeave */, null /* finishCb */); finishInner(toHome, false /* userLeave */, null /* finishCb */, "cancel"); } else { } else { cleanUp(); cleanUp(); } } Loading Loading @@ -436,6 +530,91 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { } } } } /** * Starts a new transition that is not backed by a system transition. */ void startSyntheticTransition() { mTransition = SYNTHETIC_TRANSITION; // TODO(b/366021931): Update mechanism for pulling the home task, for now add home as // both opening and closing since there's some pre-existing // dependencies on having a closing task final ActivityManager.RunningTaskInfo homeTask = mShellTaskOrganizer.getRunningTasks(DEFAULT_DISPLAY).stream() .filter(task -> task.getActivityType() == ACTIVITY_TYPE_HOME) .findFirst() .get(); final RemoteAnimationTarget openingTarget = TransitionUtil.newSyntheticTarget( homeTask, mShellTaskOrganizer.getHomeTaskOverlayContainer(), TRANSIT_OPEN, 0, true /* isTranslucent */); final RemoteAnimationTarget closingTarget = TransitionUtil.newSyntheticTarget( homeTask, mShellTaskOrganizer.getHomeTaskOverlayContainer(), TRANSIT_CLOSE, 0, true /* isTranslucent */); final ArrayList<RemoteAnimationTarget> apps = new ArrayList<>(); apps.add(openingTarget); apps.add(closingTarget); try { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "[%d] RecentsController.start: calling onAnimationStart with %d apps", mInstanceId, apps.size()); mListener.onAnimationStart(this, apps.toArray(new RemoteAnimationTarget[apps.size()]), new RemoteAnimationTarget[0], new Rect(0, 0, 0, 0), new Rect(), new Bundle()); for (int i = 0; i < mStateListeners.size(); i++) { mStateListeners.get(i).onAnimationStateChanged(true); } } catch (RemoteException e) { Slog.e(TAG, "Error starting recents animation", e); cancel("startSynthetricTransition() failed"); } } /** * Returns whether this transition is backed by a real system transition or not. */ boolean isSyntheticTransition() { return mTransition == SYNTHETIC_TRANSITION; } /** * Called when a synthetic transition is canceled. */ boolean cancelSyntheticTransition(String reason) { if (!isSyntheticTransition()) { return false; } ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "[%d] RecentsController.cancelSyntheticTransition reason=%s", mInstanceId, reason); try { // TODO(b/366021931): Notify the correct tasks once we build actual targets, and // clean up leashes accordingly mListener.onAnimationCanceled(new int[0], new TaskSnapshot[0]); } catch (RemoteException e) { Slog.e(TAG, "Error canceling previous recents animation", e); } cleanUp(); return true; } /** * Called when a synthetic transition is finished. * @return */ boolean finishSyntheticTransition() { if (!isSyntheticTransition()) { return false; } ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "[%d] RecentsController.finishSyntheticTransition", mInstanceId); // TODO(b/366021931): Clean up leashes accordingly cleanUp(); return true; } boolean start(TransitionInfo info, SurfaceControl.Transaction t, boolean start(TransitionInfo info, SurfaceControl.Transaction t, SurfaceControl.Transaction finishT, Transitions.TransitionFinishCallback finishCB) { SurfaceControl.Transaction finishT, Transitions.TransitionFinishCallback finishCB) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, Loading Loading @@ -662,7 +841,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { // Set the callback once again so we can finish correctly. // Set the callback once again so we can finish correctly. mFinishCB = finishCB; mFinishCB = finishCB; finishInner(true /* toHome */, false /* userLeave */, finishInner(true /* toHome */, false /* userLeave */, null /* finishCb */); null /* finishCb */, "takeOverAnimation"); }, updatedStates); }, updatedStates); }); }); } } Loading Loading @@ -810,7 +989,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { sendCancelWithSnapshots(); sendCancelWithSnapshots(); mExecutor.executeDelayed( mExecutor.executeDelayed( () -> finishInner(true /* toHome */, false /* userLeaveHint */, () -> finishInner(true /* toHome */, false /* userLeaveHint */, null /* finishCb */), 0); null /* finishCb */, "merge"), 0); return; return; } } if (recentsOpening != null) { if (recentsOpening != null) { Loading Loading @@ -1005,7 +1184,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { return; return; } } final int displayId = mInfo.getRootCount() > 0 ? mInfo.getRoot(0).getDisplayId() final int displayId = mInfo.getRootCount() > 0 ? mInfo.getRoot(0).getDisplayId() : Display.DEFAULT_DISPLAY; : DEFAULT_DISPLAY; // transient launches don't receive focus automatically. Since we are taking over // transient launches don't receive focus automatically. Since we are taking over // the gesture now, take focus explicitly. // the gesture now, take focus explicitly. // This also moves recents back to top if the user gestured before a switch // This also moves recents back to top if the user gestured before a switch Loading Loading @@ -1038,11 +1217,16 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { @Override @Override @SuppressLint("NewApi") @SuppressLint("NewApi") public void finish(boolean toHome, boolean sendUserLeaveHint, IResultReceiver finishCb) { public void finish(boolean toHome, boolean sendUserLeaveHint, IResultReceiver finishCb) { mExecutor.execute(() -> finishInner(toHome, sendUserLeaveHint, finishCb)); mExecutor.execute(() -> finishInner(toHome, sendUserLeaveHint, finishCb, "requested")); } } private void finishInner(boolean toHome, boolean sendUserLeaveHint, private void finishInner(boolean toHome, boolean sendUserLeaveHint, IResultReceiver runnerFinishCb) { IResultReceiver runnerFinishCb, String reason) { if (finishSyntheticTransition()) { return; } if (mFinishCB == null) { if (mFinishCB == null) { Slog.e(TAG, "Duplicate call to finish"); Slog.e(TAG, "Duplicate call to finish"); return; return; Loading
libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionStateListener.java +0 −3 Original line number Original line Diff line number Diff line Loading @@ -24,7 +24,4 @@ public interface RecentsTransitionStateListener { /** Notifies whether the recents animation is running. */ /** Notifies whether the recents animation is running. */ default void onAnimationStateChanged(boolean running) { default void onAnimationStateChanged(boolean running) { } } /** Notifies that a recents shell transition has started. */ default void onTransitionStarted(IBinder transition) {} } }