From 5ca3820ae66f37c9a278cb9621afaa7d9bdc10a5 Mon Sep 17 00:00:00 2001 From: Evan Rosky Date: Tue, 29 Jun 2021 18:16:51 -0700 Subject: [PATCH] Hook up split-launch to legacy transition system Part 1 of hooking up stage-split to legacy stuff. This actually routes the legacy remoteAnimation through shell in order to gather the dividerbar and interract with the WindowProcessController Bug: 192279476 Test: atest WindowOrganizerTests. use SPLIT_SELECT to launch 2 apps in split and observe. Change-Id: I4f8802e6eb33f068fae0e4b3c12942bea76e332b --- .../android/app/IActivityTaskManager.aidl | 8 ++ .../android/view/RemoteAnimationAdapter.java | 22 +++++ .../wm/shell/splitscreen/ISplitScreen.aidl | 12 ++- .../splitscreen/SplitScreenController.java | 11 +++ .../shell/splitscreen/StageCoordinator.java | 89 +++++++++++++++++++ .../system/RemoteAnimationAdapterCompat.java | 3 +- .../server/wm/ActivityTaskManagerService.java | 28 ++++++ .../server/wm/SafeActivityOptions.java | 23 +++++ .../server/wm/WindowOrganizerController.java | 41 +++++++-- .../server/wm/WindowProcessController.java | 34 ++++++- .../server/wm/WindowOrganizerTests.java | 25 +++--- 11 files changed, 272 insertions(+), 24 deletions(-) diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl index 9f97fade6e986..2be78033ddf70 100644 --- a/core/java/android/app/IActivityTaskManager.aidl +++ b/core/java/android/app/IActivityTaskManager.aidl @@ -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); } diff --git a/core/java/android/view/RemoteAnimationAdapter.java b/core/java/android/view/RemoteAnimationAdapter.java index a78036fba0940..e1cc60491f72d 100644 --- a/core/java/android/view/RemoteAnimationAdapter.java +++ b/core/java/android/view/RemoteAnimationAdapter.java @@ -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; @@ -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. @@ -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() { @@ -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; @@ -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 CREATOR diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl index 8f0892fdcbba8..2427d53f48422 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl @@ -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; @@ -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; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index 89e6ca86487fc..197409d6d07f1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -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; @@ -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, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index 9f8b79932dede..bc4827315f824 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -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; @@ -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; @@ -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; @@ -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 + " "; diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java index fdd1abebe0eac..025d7ef480963 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java @@ -69,7 +69,8 @@ public class RemoteAnimationAdapterCompat { return mRemoteTransition; } - private static IRemoteAnimationRunner.Stub wrapRemoteAnimationRunner( + /** Wraps a RemoteAnimationRunnerCompat in an IRemoteAnimationRunner. */ + public static IRemoteAnimationRunner.Stub wrapRemoteAnimationRunner( final RemoteAnimationRunnerCompat remoteAnimationAdapter) { return new IRemoteAnimationRunner.Stub() { @Override diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 2aaf6f7f40ad9..737800123415b 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -5069,6 +5069,34 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { process.registerDisplayAreaConfigurationListener(imeContainer); } + @Override + public void setRunningRemoteTransitionDelegate(IApplicationThread caller) { + mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS, + "setRunningRemoteTransition"); + final int callingPid = Binder.getCallingPid(); + final int callingUid = Binder.getCallingUid(); + synchronized (mGlobalLock) { + // Also only allow a process which is already runningRemoteAnimation to mark another + // process. + final WindowProcessController callingProc = getProcessController(callingPid, + callingUid); + if (callingProc == null || !callingProc.isRunningRemoteTransition()) { + final String msg = "Can't call setRunningRemoteTransition from a process (pid=" + + callingPid + " uid=" + callingUid + ") which isn't itself running a " + + "remote transition."; + Slog.e(TAG, msg); + throw new SecurityException(msg); + } + final WindowProcessController wpc = getProcessController(caller); + if (wpc == null) { + Slog.w(TAG, "Unable to find process for application " + caller); + return; + } + wpc.setRunningRemoteAnimation(true /* running */); + callingProc.addRemoteAnimationDelegate(wpc); + } + } + final class H extends Handler { static final int REPORT_TIME_TRACKER_MSG = 1; static final int UPDATE_PROCESS_ANIMATING_STATE = 2; diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java index 4892005631ba4..2d4aef682d623 100644 --- a/services/core/java/com/android/server/wm/SafeActivityOptions.java +++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java @@ -77,6 +77,18 @@ public class SafeActivityOptions { : null; } + /** + * Constructs a new instance from a bundle and provided pid/uid. + * + * @param bOptions The {@link ActivityOptions} as {@link Bundle}. + */ + static SafeActivityOptions fromBundle(Bundle bOptions, int callingPid, int callingUid) { + return bOptions != null + ? new SafeActivityOptions(ActivityOptions.fromBundle(bOptions), + callingPid, callingUid) + : null; + } + /** * Constructs a new instance and records {@link Binder#getCallingPid}/ * {@link Binder#getCallingUid}. Thus, calling identity MUST NOT be cleared when constructing @@ -90,6 +102,17 @@ public class SafeActivityOptions { mOriginalOptions = options; } + /** + * Constructs a new instance. + * + * @param options The options to wrap. + */ + private SafeActivityOptions(@Nullable ActivityOptions options, int callingPid, int callingUid) { + mOriginalCallingPid = callingPid; + mOriginalCallingUid = callingUid; + mOriginalOptions = options; + } + /** * Overrides options with options from a caller and records {@link Binder#getCallingPid}/ * {@link Binder#getCallingUid}. Thus, calling identity MUST NOT be cleared when calling this diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index a7bf887e98c9e..b82819c8396eb 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.Manifest.permission.START_TASKS_FROM_RECENTS; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT; @@ -142,10 +143,11 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub if (t == null) { throw new IllegalArgumentException("Null transaction passed to applySyncTransaction"); } + final CallerInfo caller = new CallerInfo(); final long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { - applyTransaction(t, -1 /*syncId*/, null /*transition*/); + applyTransaction(t, -1 /*syncId*/, null /*transition*/, caller); } } finally { Binder.restoreCallingIdentity(ident); @@ -159,6 +161,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub if (t == null) { throw new IllegalArgumentException("Null transaction passed to applySyncTransaction"); } + final CallerInfo caller = new CallerInfo(); final long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -178,7 +181,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub if (callback != null) { syncId = startSyncWithOrganizer(callback); } - applyTransaction(t, syncId, null /*transition*/); + applyTransaction(t, syncId, null /*transition*/, caller); if (syncId >= 0) { setSyncReady(syncId); } @@ -193,6 +196,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub public IBinder startTransition(int type, @Nullable IBinder transitionToken, @Nullable WindowContainerTransaction t) { enforceTaskPermission("startTransition()"); + final CallerInfo caller = new CallerInfo(); final long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -212,7 +216,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub throw new IllegalArgumentException("Can't use legacy transitions in" + " compatibility mode with no WCT."); } - applyTransaction(t, -1 /* syncId */, null); + applyTransaction(t, -1 /* syncId */, null, caller); return null; } transition = mTransitionController.createTransition(type); @@ -221,7 +225,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub if (t == null) { t = new WindowContainerTransaction(); } - applyTransaction(t, -1 /*syncId*/, transition); + applyTransaction(t, -1 /*syncId*/, transition, caller); if (needsSetReady) { transition.setReady(); } @@ -237,6 +241,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub @Nullable WindowContainerTransaction t, @Nullable IWindowContainerTransactionCallback callback) { enforceTaskPermission("finishTransition()"); + final CallerInfo caller = new CallerInfo(); final long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { @@ -247,7 +252,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub // apply the incoming transaction before finish in case it alters the visibility // of the participants. if (t != null) { - applyTransaction(t, syncId, null /*transition*/); + applyTransaction(t, syncId, null /*transition*/, caller); } getTransitionController().finishTransition(transitionToken); if (syncId >= 0) { @@ -263,9 +268,10 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub /** * @param syncId If non-null, this will be a sync-transaction. * @param transition A transition to collect changes into. + * @param caller Info about the calling process. */ private void applyTransaction(@NonNull WindowContainerTransaction t, int syncId, - @Nullable Transition transition) { + @Nullable Transition transition, @Nullable CallerInfo caller) { int effects = 0; ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d", syncId); mService.deferWindowLayout(); @@ -319,7 +325,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub final boolean isInLockTaskMode = mService.isInLockTaskMode(); for (int i = 0; i < hopSize; ++i) { effects |= applyHierarchyOp(hops.get(i), effects, syncId, transition, - isInLockTaskMode); + isInLockTaskMode, caller); } } // Queue-up bounds-change transactions for tasks which are now organized. Do @@ -474,7 +480,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } private int applyHierarchyOp(WindowContainerTransaction.HierarchyOp hop, int effects, - int syncId, @Nullable Transition transition, boolean isInLockTaskMode) { + int syncId, @Nullable Transition transition, boolean isInLockTaskMode, + @Nullable CallerInfo caller) { final int type = hop.getType(); switch (type) { case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: { @@ -555,11 +562,17 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub effects |= sanitizeAndApplyHierarchyOp(wc, hop); break; case HIERARCHY_OP_TYPE_LAUNCH_TASK: + mService.mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS, + "launchTask HierarchyOp"); final Bundle launchOpts = hop.getLaunchOptions(); final int taskId = launchOpts.getInt( WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID); launchOpts.remove(WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID); - mService.startActivityFromRecents(taskId, launchOpts); + final SafeActivityOptions safeOptions = caller != null + ? SafeActivityOptions.fromBundle(launchOpts, caller.mPid, caller.mUid) + : SafeActivityOptions.fromBundle(launchOpts); + mService.mTaskSupervisor.startActivityFromRecents(caller.mPid, caller.mUid, + taskId, safeOptions); break; case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT: final TaskFragmentCreationParams taskFragmentCreationOptions = @@ -936,4 +949,14 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub mLaunchTaskFragments.removeAt(index); taskFragment.removeImmediately(); } + + static class CallerInfo { + final int mPid; + final int mUid; + + CallerInfo() { + mPid = Binder.getCallingPid(); + mUid = Binder.getCallingUid(); + } + } } diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index bb5d545c93622..65b065ab8eab3 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -75,6 +75,7 @@ import com.android.server.wm.ActivityTaskManagerService.HotPath; import java.io.IOException; import java.io.PrintWriter; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; @@ -219,6 +220,10 @@ public class WindowProcessController extends ConfigurationContainer> mRemoteAnimationDelegates = + new ArrayList<>(); + // The bits used for mActivityStateFlags. private static final int ACTIVITY_STATE_FLAG_IS_VISIBLE = 1 << 16; private static final int ACTIVITY_STATE_FLAG_IS_PAUSING_OR_PAUSED = 1 << 17; @@ -1596,11 +1601,38 @@ public class WindowProcessController extends ConfigurationContainer(delegate)); + } + void updateRunningRemoteOrRecentsAnimation() { + if (!isRunningRemoteTransition()) { + // Clean-up any delegates + for (int i = 0; i < mRemoteAnimationDelegates.size(); ++i) { + final WindowProcessController delegate = mRemoteAnimationDelegates.get(i).get(); + if (delegate == null) continue; + delegate.setRunningRemoteAnimation(false); + delegate.setRunningRecentsAnimation(false); + } + mRemoteAnimationDelegates.clear(); + } + // Posting on handler so WM lock isn't held when we call into AM. mAtm.mH.sendMessage(PooledLambda.obtainMessage( WindowProcessListener::setRunningRemoteAnimation, mListener, - mRunningRecentsAnimation || mRunningRemoteAnimation)); + isRunningRemoteTransition())); + } + + boolean isRunningRemoteTransition() { + return mRunningRecentsAnimation || mRunningRemoteAnimation; } /** Adjusts scheduling group for animation. This method MUST NOT be called inside WM lock. */ diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java index d7f2cec2c233b..39fe952cc1998 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java @@ -61,6 +61,7 @@ import static org.mockito.Mockito.clearInvocations; import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; +import android.app.ActivityOptions; import android.app.ActivityTaskManager.RootTaskInfo; import android.app.IRequestFinishCallback; import android.app.PictureInPictureParams; @@ -69,7 +70,6 @@ import android.content.pm.ParceledListSlice; import android.content.res.Configuration; import android.graphics.Rect; import android.os.Binder; -import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; @@ -1255,21 +1255,24 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testStartTasksInTransaction() { WindowContainerTransaction wct = new WindowContainerTransaction(); - Bundle testOptions = new Bundle(); - testOptions.putInt("test", 20); + ActivityOptions testOptions = ActivityOptions.makeBasic(); + testOptions.setTransientLaunch(); wct.startTask(1, null /* options */); - wct.startTask(2, testOptions); - spyOn(mWm.mAtmService); - doReturn(START_CANCELED).when(mWm.mAtmService).startActivityFromRecents(anyInt(), any()); + wct.startTask(2, testOptions.toBundle()); + spyOn(mWm.mAtmService.mTaskSupervisor); + doReturn(START_CANCELED).when(mWm.mAtmService.mTaskSupervisor).startActivityFromRecents( + anyInt(), anyInt(), anyInt(), any()); clearInvocations(mWm.mAtmService); mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); - final ArgumentCaptor bundleCaptor = ArgumentCaptor.forClass(Bundle.class); - verify(mWm.mAtmService, times(1)).startActivityFromRecents(eq(1), bundleCaptor.capture()); - assertTrue(bundleCaptor.getValue().isEmpty()); + verify(mWm.mAtmService.mTaskSupervisor, times(1)).startActivityFromRecents( + anyInt(), anyInt(), eq(1), any()); - verify(mWm.mAtmService, times(1)).startActivityFromRecents(eq(2), bundleCaptor.capture()); - assertEquals(20, bundleCaptor.getValue().getInt("test")); + final ArgumentCaptor optionsCaptor = + ArgumentCaptor.forClass(SafeActivityOptions.class); + verify(mWm.mAtmService.mTaskSupervisor, times(1)).startActivityFromRecents( + anyInt(), anyInt(), eq(2), optionsCaptor.capture()); + assertTrue(optionsCaptor.getValue().getOriginalOptions().getTransientLaunch()); } /**