Loading core/java/android/app/IActivityTaskManager.aidl +8 −0 Original line number Diff line number Diff line Loading @@ -336,4 +336,12 @@ interface IActivityTaskManager { * TODO(188595497): Remove this once navbar attachment is in shell. */ void detachNavigationBarFromApp(in IBinder transition); /** * Marks a process as a delegate for the currently playing remote transition animation. This * must be called from a process that is already a remote transition player or delegate. Any * marked delegates are cleaned-up automatically at the end of the transition. * @param caller is the IApplicationThread representing the calling process. */ void setRunningRemoteTransitionDelegate(in IApplicationThread caller); } core/java/android/view/RemoteAnimationAdapter.java +22 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.view; import android.app.ActivityOptions; import android.app.IApplicationThread; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; Loading Loading @@ -58,6 +59,9 @@ public class RemoteAnimationAdapter implements Parcelable { private int mCallingPid; private int mCallingUid; /** @see #getCallingApplication */ private IApplicationThread mCallingApplication; /** * @param runner The interface that gets notified when we actually need to start the animation. * @param duration The duration of the animation. Loading @@ -81,11 +85,19 @@ public class RemoteAnimationAdapter implements Parcelable { this(runner, duration, statusBarTransitionDelay, false /* changeNeedsSnapshot */); } @UnsupportedAppUsage public RemoteAnimationAdapter(IRemoteAnimationRunner runner, long duration, long statusBarTransitionDelay, IApplicationThread callingApplication) { this(runner, duration, statusBarTransitionDelay, false /* changeNeedsSnapshot */); mCallingApplication = callingApplication; } public RemoteAnimationAdapter(Parcel in) { mRunner = IRemoteAnimationRunner.Stub.asInterface(in.readStrongBinder()); mDuration = in.readLong(); mStatusBarTransitionDelay = in.readLong(); mChangeNeedsSnapshot = in.readBoolean(); mCallingApplication = IApplicationThread.Stub.asInterface(in.readStrongBinder()); } public IRemoteAnimationRunner getRunner() { Loading Loading @@ -126,6 +138,15 @@ public class RemoteAnimationAdapter implements Parcelable { return mCallingUid; } /** * Gets the ApplicationThread that will run the animation. Instead it is intended to pass the * calling information among client processes (eg. shell + launcher) through one-way binder * calls (where binder itself doesn't track calling information). */ public IApplicationThread getCallingApplication() { return mCallingApplication; } @Override public int describeContents() { return 0; Loading @@ -137,6 +158,7 @@ public class RemoteAnimationAdapter implements Parcelable { dest.writeLong(mDuration); dest.writeLong(mStatusBarTransitionDelay); dest.writeBoolean(mChangeNeedsSnapshot); dest.writeStrongInterface(mCallingApplication); } public static final @android.annotation.NonNull Creator<RemoteAnimationAdapter> CREATOR Loading libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl +10 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ import android.app.PendingIntent; import android.content.Intent; import android.os.Bundle; import android.os.UserHandle; import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationTarget; import android.window.IRemoteTransition; import com.android.wm.shell.splitscreen.ISplitScreenListener; Loading Loading @@ -77,9 +79,15 @@ interface ISplitScreen { int position, in Bundle options) = 9; /** * Starts tasks simultaneously in one transition. The first task in the list will be in the * main-stage and on the left/top. * Starts tasks simultaneously in one transition. */ oneway void startTasks(int mainTaskId, in Bundle mainOptions, int sideTaskId, in Bundle sideOptions, int sidePosition, in IRemoteTransition remoteTransition) = 10; /** * Version of startTasks using legacy transition system. */ oneway void startTasksWithLegacyTransition(int mainTaskId, in Bundle mainOptions, int sideTaskId, in Bundle sideOptions, int sidePosition, in RemoteAnimationAdapter adapter) = 11; } libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +11 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import android.os.IBinder; import android.os.RemoteException; import android.os.UserHandle; import android.util.Slog; import android.view.RemoteAnimationAdapter; import android.window.IRemoteTransition; import androidx.annotation.BinderThread; Loading Loading @@ -427,6 +428,16 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, }); } @Override public void startTasksWithLegacyTransition(int mainTaskId, @Nullable Bundle mainOptions, int sideTaskId, @Nullable Bundle sideOptions, @SplitPosition int sidePosition, RemoteAnimationAdapter adapter) { executeRemoteCallWithTaskPermission(mController, "startTasks", (controller) -> controller.mStageCoordinator.startTasksWithLegacyTransition( mainTaskId, mainOptions, sideTaskId, sideOptions, sidePosition, adapter)); } @Override public void startTasks(int mainTaskId, @Nullable Bundle mainOptions, int sideTaskId, @Nullable Bundle sideOptions, Loading libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +89 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static android.app.ActivityOptions.KEY_LAUNCH_ROOT_TASK_TOKEN; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_TO_FRONT; Loading @@ -42,12 +43,21 @@ import static com.android.wm.shell.transition.Transitions.isOpeningType; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.ActivityTaskManager; import android.app.WindowConfiguration; import android.content.Context; import android.graphics.Rect; import android.hardware.devicestate.DeviceStateManager; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import android.util.Slog; import android.view.IRemoteAnimationFinishedCallback; import android.view.IRemoteAnimationRunner; import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.SurfaceSession; import android.view.WindowManager; Loading Loading @@ -248,6 +258,75 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, TRANSIT_SPLIT_SCREEN_PAIR_OPEN, wct, remoteTransition, this); } /** Starts 2 tasks in one legacy transition. */ void startTasksWithLegacyTransition(int mainTaskId, @Nullable Bundle mainOptions, int sideTaskId, @Nullable Bundle sideOptions, @SplitPosition int sidePosition, RemoteAnimationAdapter adapter) { final WindowContainerTransaction wct = new WindowContainerTransaction(); // Need to add another wrapper here in shell so that we can inject the divider bar // and also manage the process elevation via setRunningRemote IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() { @Override public void onAnimationStart(@WindowManager.TransitionOldType int transit, RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, final IRemoteAnimationFinishedCallback finishedCallback) { RemoteAnimationTarget[] augmentedNonApps = new RemoteAnimationTarget[nonApps.length + 1]; for (int i = 0; i < nonApps.length; ++i) { augmentedNonApps[i] = nonApps[i]; } augmentedNonApps[augmentedNonApps.length - 1] = getDividerBarLegacyTarget(); try { ActivityTaskManager.getService().setRunningRemoteTransitionDelegate( adapter.getCallingApplication()); adapter.getRunner().onAnimationStart(transit, apps, wallpapers, nonApps, finishedCallback); } catch (RemoteException e) { Slog.e(TAG, "Error starting remote animation", e); } } @Override public void onAnimationCancelled() { try { adapter.getRunner().onAnimationCancelled(); } catch (RemoteException e) { Slog.e(TAG, "Error starting remote animation", e); } } }; RemoteAnimationAdapter wrappedAdapter = new RemoteAnimationAdapter( wrapper, adapter.getDuration(), adapter.getStatusBarTransitionDelay()); if (mainOptions == null) { mainOptions = ActivityOptions.makeRemoteAnimation(wrappedAdapter).toBundle(); } else { ActivityOptions mainActivityOptions = ActivityOptions.fromBundle(mainOptions); mainActivityOptions.update(ActivityOptions.makeRemoteAnimation(wrappedAdapter)); } sideOptions = sideOptions != null ? sideOptions : new Bundle(); setSideStagePosition(sidePosition); // Build a request WCT that will launch both apps such that task 0 is on the main stage // while task 1 is on the side stage. mMainStage.activate(getMainStageBounds(), wct); mSideStage.setBounds(getSideStageBounds(), wct); // Make sure the launch options will put tasks in the corresponding split roots addActivityOptions(mainOptions, mMainStage); addActivityOptions(sideOptions, mSideStage); // Add task launch requests wct.startTask(mainTaskId, mainOptions); wct.startTask(sideTaskId, sideOptions); // Using legacy transitions, so we can't use blast sync since it conflicts. mTaskOrganizer.applyTransaction(wct); } @SplitLayout.SplitPosition int getSideStagePosition() { return mSideStagePosition; Loading Loading @@ -891,6 +970,16 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, } } private RemoteAnimationTarget getDividerBarLegacyTarget() { final Rect bounds = mSplitLayout.getDividerBounds(); return new RemoteAnimationTarget(-1 /* taskId */, -1 /* mode */, mSplitLayout.getDividerLeash(), false /* isTranslucent */, null /* clipRect */, null /* contentInsets */, Integer.MAX_VALUE /* prefixOrderIndex */, new android.graphics.Point(0, 0) /* position */, bounds, bounds, new WindowConfiguration(), true, null /* startLeash */, null /* startBounds */, null /* taskInfo */, TYPE_DOCK_DIVIDER); } @Override public void dump(@NonNull PrintWriter pw, String prefix) { final String innerPrefix = prefix + " "; Loading Loading
core/java/android/app/IActivityTaskManager.aidl +8 −0 Original line number Diff line number Diff line Loading @@ -336,4 +336,12 @@ interface IActivityTaskManager { * TODO(188595497): Remove this once navbar attachment is in shell. */ void detachNavigationBarFromApp(in IBinder transition); /** * Marks a process as a delegate for the currently playing remote transition animation. This * must be called from a process that is already a remote transition player or delegate. Any * marked delegates are cleaned-up automatically at the end of the transition. * @param caller is the IApplicationThread representing the calling process. */ void setRunningRemoteTransitionDelegate(in IApplicationThread caller); }
core/java/android/view/RemoteAnimationAdapter.java +22 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.view; import android.app.ActivityOptions; import android.app.IApplicationThread; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; Loading Loading @@ -58,6 +59,9 @@ public class RemoteAnimationAdapter implements Parcelable { private int mCallingPid; private int mCallingUid; /** @see #getCallingApplication */ private IApplicationThread mCallingApplication; /** * @param runner The interface that gets notified when we actually need to start the animation. * @param duration The duration of the animation. Loading @@ -81,11 +85,19 @@ public class RemoteAnimationAdapter implements Parcelable { this(runner, duration, statusBarTransitionDelay, false /* changeNeedsSnapshot */); } @UnsupportedAppUsage public RemoteAnimationAdapter(IRemoteAnimationRunner runner, long duration, long statusBarTransitionDelay, IApplicationThread callingApplication) { this(runner, duration, statusBarTransitionDelay, false /* changeNeedsSnapshot */); mCallingApplication = callingApplication; } public RemoteAnimationAdapter(Parcel in) { mRunner = IRemoteAnimationRunner.Stub.asInterface(in.readStrongBinder()); mDuration = in.readLong(); mStatusBarTransitionDelay = in.readLong(); mChangeNeedsSnapshot = in.readBoolean(); mCallingApplication = IApplicationThread.Stub.asInterface(in.readStrongBinder()); } public IRemoteAnimationRunner getRunner() { Loading Loading @@ -126,6 +138,15 @@ public class RemoteAnimationAdapter implements Parcelable { return mCallingUid; } /** * Gets the ApplicationThread that will run the animation. Instead it is intended to pass the * calling information among client processes (eg. shell + launcher) through one-way binder * calls (where binder itself doesn't track calling information). */ public IApplicationThread getCallingApplication() { return mCallingApplication; } @Override public int describeContents() { return 0; Loading @@ -137,6 +158,7 @@ public class RemoteAnimationAdapter implements Parcelable { dest.writeLong(mDuration); dest.writeLong(mStatusBarTransitionDelay); dest.writeBoolean(mChangeNeedsSnapshot); dest.writeStrongInterface(mCallingApplication); } public static final @android.annotation.NonNull Creator<RemoteAnimationAdapter> CREATOR Loading
libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl +10 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ import android.app.PendingIntent; import android.content.Intent; import android.os.Bundle; import android.os.UserHandle; import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationTarget; import android.window.IRemoteTransition; import com.android.wm.shell.splitscreen.ISplitScreenListener; Loading Loading @@ -77,9 +79,15 @@ interface ISplitScreen { int position, in Bundle options) = 9; /** * Starts tasks simultaneously in one transition. The first task in the list will be in the * main-stage and on the left/top. * Starts tasks simultaneously in one transition. */ oneway void startTasks(int mainTaskId, in Bundle mainOptions, int sideTaskId, in Bundle sideOptions, int sidePosition, in IRemoteTransition remoteTransition) = 10; /** * Version of startTasks using legacy transition system. */ oneway void startTasksWithLegacyTransition(int mainTaskId, in Bundle mainOptions, int sideTaskId, in Bundle sideOptions, int sidePosition, in RemoteAnimationAdapter adapter) = 11; }
libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +11 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import android.os.IBinder; import android.os.RemoteException; import android.os.UserHandle; import android.util.Slog; import android.view.RemoteAnimationAdapter; import android.window.IRemoteTransition; import androidx.annotation.BinderThread; Loading Loading @@ -427,6 +428,16 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, }); } @Override public void startTasksWithLegacyTransition(int mainTaskId, @Nullable Bundle mainOptions, int sideTaskId, @Nullable Bundle sideOptions, @SplitPosition int sidePosition, RemoteAnimationAdapter adapter) { executeRemoteCallWithTaskPermission(mController, "startTasks", (controller) -> controller.mStageCoordinator.startTasksWithLegacyTransition( mainTaskId, mainOptions, sideTaskId, sideOptions, sidePosition, adapter)); } @Override public void startTasks(int mainTaskId, @Nullable Bundle mainOptions, int sideTaskId, @Nullable Bundle sideOptions, Loading
libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +89 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static android.app.ActivityOptions.KEY_LAUNCH_ROOT_TASK_TOKEN; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_TO_FRONT; Loading @@ -42,12 +43,21 @@ import static com.android.wm.shell.transition.Transitions.isOpeningType; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.ActivityTaskManager; import android.app.WindowConfiguration; import android.content.Context; import android.graphics.Rect; import android.hardware.devicestate.DeviceStateManager; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import android.util.Slog; import android.view.IRemoteAnimationFinishedCallback; import android.view.IRemoteAnimationRunner; import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.SurfaceSession; import android.view.WindowManager; Loading Loading @@ -248,6 +258,75 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, TRANSIT_SPLIT_SCREEN_PAIR_OPEN, wct, remoteTransition, this); } /** Starts 2 tasks in one legacy transition. */ void startTasksWithLegacyTransition(int mainTaskId, @Nullable Bundle mainOptions, int sideTaskId, @Nullable Bundle sideOptions, @SplitPosition int sidePosition, RemoteAnimationAdapter adapter) { final WindowContainerTransaction wct = new WindowContainerTransaction(); // Need to add another wrapper here in shell so that we can inject the divider bar // and also manage the process elevation via setRunningRemote IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() { @Override public void onAnimationStart(@WindowManager.TransitionOldType int transit, RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, final IRemoteAnimationFinishedCallback finishedCallback) { RemoteAnimationTarget[] augmentedNonApps = new RemoteAnimationTarget[nonApps.length + 1]; for (int i = 0; i < nonApps.length; ++i) { augmentedNonApps[i] = nonApps[i]; } augmentedNonApps[augmentedNonApps.length - 1] = getDividerBarLegacyTarget(); try { ActivityTaskManager.getService().setRunningRemoteTransitionDelegate( adapter.getCallingApplication()); adapter.getRunner().onAnimationStart(transit, apps, wallpapers, nonApps, finishedCallback); } catch (RemoteException e) { Slog.e(TAG, "Error starting remote animation", e); } } @Override public void onAnimationCancelled() { try { adapter.getRunner().onAnimationCancelled(); } catch (RemoteException e) { Slog.e(TAG, "Error starting remote animation", e); } } }; RemoteAnimationAdapter wrappedAdapter = new RemoteAnimationAdapter( wrapper, adapter.getDuration(), adapter.getStatusBarTransitionDelay()); if (mainOptions == null) { mainOptions = ActivityOptions.makeRemoteAnimation(wrappedAdapter).toBundle(); } else { ActivityOptions mainActivityOptions = ActivityOptions.fromBundle(mainOptions); mainActivityOptions.update(ActivityOptions.makeRemoteAnimation(wrappedAdapter)); } sideOptions = sideOptions != null ? sideOptions : new Bundle(); setSideStagePosition(sidePosition); // Build a request WCT that will launch both apps such that task 0 is on the main stage // while task 1 is on the side stage. mMainStage.activate(getMainStageBounds(), wct); mSideStage.setBounds(getSideStageBounds(), wct); // Make sure the launch options will put tasks in the corresponding split roots addActivityOptions(mainOptions, mMainStage); addActivityOptions(sideOptions, mSideStage); // Add task launch requests wct.startTask(mainTaskId, mainOptions); wct.startTask(sideTaskId, sideOptions); // Using legacy transitions, so we can't use blast sync since it conflicts. mTaskOrganizer.applyTransaction(wct); } @SplitLayout.SplitPosition int getSideStagePosition() { return mSideStagePosition; Loading Loading @@ -891,6 +970,16 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, } } private RemoteAnimationTarget getDividerBarLegacyTarget() { final Rect bounds = mSplitLayout.getDividerBounds(); return new RemoteAnimationTarget(-1 /* taskId */, -1 /* mode */, mSplitLayout.getDividerLeash(), false /* isTranslucent */, null /* clipRect */, null /* contentInsets */, Integer.MAX_VALUE /* prefixOrderIndex */, new android.graphics.Point(0, 0) /* position */, bounds, bounds, new WindowConfiguration(), true, null /* startLeash */, null /* startBounds */, null /* taskInfo */, TYPE_DOCK_DIVIDER); } @Override public void dump(@NonNull PrintWriter pw, String prefix) { final String innerPrefix = prefix + " "; Loading