Merge "Hook up split-launch to legacy transition system" into sc-v2-dev
This commit is contained in:
@@ -336,4 +336,12 @@ interface IActivityTaskManager {
|
|||||||
* TODO(188595497): Remove this once navbar attachment is in shell.
|
* TODO(188595497): Remove this once navbar attachment is in shell.
|
||||||
*/
|
*/
|
||||||
void detachNavigationBarFromApp(in IBinder transition);
|
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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package android.view;
|
package android.view;
|
||||||
|
|
||||||
import android.app.ActivityOptions;
|
import android.app.ActivityOptions;
|
||||||
|
import android.app.IApplicationThread;
|
||||||
import android.compat.annotation.UnsupportedAppUsage;
|
import android.compat.annotation.UnsupportedAppUsage;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
@@ -58,6 +59,9 @@ public class RemoteAnimationAdapter implements Parcelable {
|
|||||||
private int mCallingPid;
|
private int mCallingPid;
|
||||||
private int mCallingUid;
|
private int mCallingUid;
|
||||||
|
|
||||||
|
/** @see #getCallingApplication */
|
||||||
|
private IApplicationThread mCallingApplication;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param runner The interface that gets notified when we actually need to start the animation.
|
* @param runner The interface that gets notified when we actually need to start the animation.
|
||||||
* @param duration The duration of the animation.
|
* @param duration The duration of the animation.
|
||||||
@@ -81,11 +85,19 @@ public class RemoteAnimationAdapter implements Parcelable {
|
|||||||
this(runner, duration, statusBarTransitionDelay, false /* changeNeedsSnapshot */);
|
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) {
|
public RemoteAnimationAdapter(Parcel in) {
|
||||||
mRunner = IRemoteAnimationRunner.Stub.asInterface(in.readStrongBinder());
|
mRunner = IRemoteAnimationRunner.Stub.asInterface(in.readStrongBinder());
|
||||||
mDuration = in.readLong();
|
mDuration = in.readLong();
|
||||||
mStatusBarTransitionDelay = in.readLong();
|
mStatusBarTransitionDelay = in.readLong();
|
||||||
mChangeNeedsSnapshot = in.readBoolean();
|
mChangeNeedsSnapshot = in.readBoolean();
|
||||||
|
mCallingApplication = IApplicationThread.Stub.asInterface(in.readStrongBinder());
|
||||||
}
|
}
|
||||||
|
|
||||||
public IRemoteAnimationRunner getRunner() {
|
public IRemoteAnimationRunner getRunner() {
|
||||||
@@ -126,6 +138,15 @@ public class RemoteAnimationAdapter implements Parcelable {
|
|||||||
return mCallingUid;
|
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
|
@Override
|
||||||
public int describeContents() {
|
public int describeContents() {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -137,6 +158,7 @@ public class RemoteAnimationAdapter implements Parcelable {
|
|||||||
dest.writeLong(mDuration);
|
dest.writeLong(mDuration);
|
||||||
dest.writeLong(mStatusBarTransitionDelay);
|
dest.writeLong(mStatusBarTransitionDelay);
|
||||||
dest.writeBoolean(mChangeNeedsSnapshot);
|
dest.writeBoolean(mChangeNeedsSnapshot);
|
||||||
|
dest.writeStrongInterface(mCallingApplication);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final @android.annotation.NonNull Creator<RemoteAnimationAdapter> CREATOR
|
public static final @android.annotation.NonNull Creator<RemoteAnimationAdapter> CREATOR
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ import android.app.PendingIntent;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
|
import android.view.RemoteAnimationAdapter;
|
||||||
|
import android.view.RemoteAnimationTarget;
|
||||||
import android.window.IRemoteTransition;
|
import android.window.IRemoteTransition;
|
||||||
|
|
||||||
import com.android.wm.shell.splitscreen.ISplitScreenListener;
|
import com.android.wm.shell.splitscreen.ISplitScreenListener;
|
||||||
@@ -77,9 +79,15 @@ interface ISplitScreen {
|
|||||||
int position, in Bundle options) = 9;
|
int position, in Bundle options) = 9;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts tasks simultaneously in one transition. The first task in the list will be in the
|
* Starts tasks simultaneously in one transition.
|
||||||
* main-stage and on the left/top.
|
|
||||||
*/
|
*/
|
||||||
oneway void startTasks(int mainTaskId, in Bundle mainOptions, int sideTaskId,
|
oneway void startTasks(int mainTaskId, in Bundle mainOptions, int sideTaskId,
|
||||||
in Bundle sideOptions, int sidePosition, in IRemoteTransition remoteTransition) = 10;
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import android.os.IBinder;
|
|||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
|
import android.view.RemoteAnimationAdapter;
|
||||||
import android.window.IRemoteTransition;
|
import android.window.IRemoteTransition;
|
||||||
|
|
||||||
import androidx.annotation.BinderThread;
|
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
|
@Override
|
||||||
public void startTasks(int mainTaskId, @Nullable Bundle mainOptions,
|
public void startTasks(int mainTaskId, @Nullable Bundle mainOptions,
|
||||||
int sideTaskId, @Nullable Bundle sideOptions,
|
int sideTaskId, @Nullable Bundle sideOptions,
|
||||||
|
|||||||
@@ -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.ACTIVITY_TYPE_HOME;
|
||||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
|
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
|
||||||
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
|
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_OPEN;
|
||||||
import static android.view.WindowManager.TRANSIT_TO_BACK;
|
import static android.view.WindowManager.TRANSIT_TO_BACK;
|
||||||
import static android.view.WindowManager.TRANSIT_TO_FRONT;
|
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.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
|
import android.app.ActivityOptions;
|
||||||
|
import android.app.ActivityTaskManager;
|
||||||
|
import android.app.WindowConfiguration;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.hardware.devicestate.DeviceStateManager;
|
import android.hardware.devicestate.DeviceStateManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
import android.os.RemoteException;
|
||||||
import android.util.Log;
|
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.SurfaceControl;
|
||||||
import android.view.SurfaceSession;
|
import android.view.SurfaceSession;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
@@ -248,6 +258,75 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
|||||||
TRANSIT_SPLIT_SCREEN_PAIR_OPEN, wct, remoteTransition, this);
|
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
|
@SplitLayout.SplitPosition
|
||||||
int getSideStagePosition() {
|
int getSideStagePosition() {
|
||||||
return mSideStagePosition;
|
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
|
@Override
|
||||||
public void dump(@NonNull PrintWriter pw, String prefix) {
|
public void dump(@NonNull PrintWriter pw, String prefix) {
|
||||||
final String innerPrefix = prefix + " ";
|
final String innerPrefix = prefix + " ";
|
||||||
|
|||||||
@@ -69,7 +69,8 @@ public class RemoteAnimationAdapterCompat {
|
|||||||
return mRemoteTransition;
|
return mRemoteTransition;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IRemoteAnimationRunner.Stub wrapRemoteAnimationRunner(
|
/** Wraps a RemoteAnimationRunnerCompat in an IRemoteAnimationRunner. */
|
||||||
|
public static IRemoteAnimationRunner.Stub wrapRemoteAnimationRunner(
|
||||||
final RemoteAnimationRunnerCompat remoteAnimationAdapter) {
|
final RemoteAnimationRunnerCompat remoteAnimationAdapter) {
|
||||||
return new IRemoteAnimationRunner.Stub() {
|
return new IRemoteAnimationRunner.Stub() {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -5069,6 +5069,34 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
|
|||||||
process.registerDisplayAreaConfigurationListener(imeContainer);
|
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 {
|
final class H extends Handler {
|
||||||
static final int REPORT_TIME_TRACKER_MSG = 1;
|
static final int REPORT_TIME_TRACKER_MSG = 1;
|
||||||
static final int UPDATE_PROCESS_ANIMATING_STATE = 2;
|
static final int UPDATE_PROCESS_ANIMATING_STATE = 2;
|
||||||
|
|||||||
@@ -77,6 +77,18 @@ public class SafeActivityOptions {
|
|||||||
: null;
|
: 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}/
|
* Constructs a new instance and records {@link Binder#getCallingPid}/
|
||||||
* {@link Binder#getCallingUid}. Thus, calling identity MUST NOT be cleared when constructing
|
* {@link Binder#getCallingUid}. Thus, calling identity MUST NOT be cleared when constructing
|
||||||
@@ -90,6 +102,17 @@ public class SafeActivityOptions {
|
|||||||
mOriginalOptions = options;
|
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}/
|
* 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
|
* {@link Binder#getCallingUid}. Thus, calling identity MUST NOT be cleared when calling this
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.server.wm;
|
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_CHILDREN_TASKS_REPARENT;
|
||||||
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT;
|
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT;
|
||||||
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_DELETE_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) {
|
if (t == null) {
|
||||||
throw new IllegalArgumentException("Null transaction passed to applySyncTransaction");
|
throw new IllegalArgumentException("Null transaction passed to applySyncTransaction");
|
||||||
}
|
}
|
||||||
|
final CallerInfo caller = new CallerInfo();
|
||||||
final long ident = Binder.clearCallingIdentity();
|
final long ident = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
synchronized (mGlobalLock) {
|
synchronized (mGlobalLock) {
|
||||||
applyTransaction(t, -1 /*syncId*/, null /*transition*/);
|
applyTransaction(t, -1 /*syncId*/, null /*transition*/, caller);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
Binder.restoreCallingIdentity(ident);
|
Binder.restoreCallingIdentity(ident);
|
||||||
@@ -159,6 +161,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
if (t == null) {
|
if (t == null) {
|
||||||
throw new IllegalArgumentException("Null transaction passed to applySyncTransaction");
|
throw new IllegalArgumentException("Null transaction passed to applySyncTransaction");
|
||||||
}
|
}
|
||||||
|
final CallerInfo caller = new CallerInfo();
|
||||||
final long ident = Binder.clearCallingIdentity();
|
final long ident = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
synchronized (mGlobalLock) {
|
synchronized (mGlobalLock) {
|
||||||
@@ -178,7 +181,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
syncId = startSyncWithOrganizer(callback);
|
syncId = startSyncWithOrganizer(callback);
|
||||||
}
|
}
|
||||||
applyTransaction(t, syncId, null /*transition*/);
|
applyTransaction(t, syncId, null /*transition*/, caller);
|
||||||
if (syncId >= 0) {
|
if (syncId >= 0) {
|
||||||
setSyncReady(syncId);
|
setSyncReady(syncId);
|
||||||
}
|
}
|
||||||
@@ -193,6 +196,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
public IBinder startTransition(int type, @Nullable IBinder transitionToken,
|
public IBinder startTransition(int type, @Nullable IBinder transitionToken,
|
||||||
@Nullable WindowContainerTransaction t) {
|
@Nullable WindowContainerTransaction t) {
|
||||||
enforceTaskPermission("startTransition()");
|
enforceTaskPermission("startTransition()");
|
||||||
|
final CallerInfo caller = new CallerInfo();
|
||||||
final long ident = Binder.clearCallingIdentity();
|
final long ident = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
synchronized (mGlobalLock) {
|
synchronized (mGlobalLock) {
|
||||||
@@ -212,7 +216,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
throw new IllegalArgumentException("Can't use legacy transitions in"
|
throw new IllegalArgumentException("Can't use legacy transitions in"
|
||||||
+ " compatibility mode with no WCT.");
|
+ " compatibility mode with no WCT.");
|
||||||
}
|
}
|
||||||
applyTransaction(t, -1 /* syncId */, null);
|
applyTransaction(t, -1 /* syncId */, null, caller);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
transition = mTransitionController.createTransition(type);
|
transition = mTransitionController.createTransition(type);
|
||||||
@@ -221,7 +225,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
if (t == null) {
|
if (t == null) {
|
||||||
t = new WindowContainerTransaction();
|
t = new WindowContainerTransaction();
|
||||||
}
|
}
|
||||||
applyTransaction(t, -1 /*syncId*/, transition);
|
applyTransaction(t, -1 /*syncId*/, transition, caller);
|
||||||
if (needsSetReady) {
|
if (needsSetReady) {
|
||||||
transition.setReady();
|
transition.setReady();
|
||||||
}
|
}
|
||||||
@@ -237,6 +241,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
@Nullable WindowContainerTransaction t,
|
@Nullable WindowContainerTransaction t,
|
||||||
@Nullable IWindowContainerTransactionCallback callback) {
|
@Nullable IWindowContainerTransactionCallback callback) {
|
||||||
enforceTaskPermission("finishTransition()");
|
enforceTaskPermission("finishTransition()");
|
||||||
|
final CallerInfo caller = new CallerInfo();
|
||||||
final long ident = Binder.clearCallingIdentity();
|
final long ident = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
synchronized (mGlobalLock) {
|
synchronized (mGlobalLock) {
|
||||||
@@ -247,7 +252,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
// apply the incoming transaction before finish in case it alters the visibility
|
// apply the incoming transaction before finish in case it alters the visibility
|
||||||
// of the participants.
|
// of the participants.
|
||||||
if (t != null) {
|
if (t != null) {
|
||||||
applyTransaction(t, syncId, null /*transition*/);
|
applyTransaction(t, syncId, null /*transition*/, caller);
|
||||||
}
|
}
|
||||||
getTransitionController().finishTransition(transitionToken);
|
getTransitionController().finishTransition(transitionToken);
|
||||||
if (syncId >= 0) {
|
if (syncId >= 0) {
|
||||||
@@ -263,9 +268,10 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
/**
|
/**
|
||||||
* @param syncId If non-null, this will be a sync-transaction.
|
* @param syncId If non-null, this will be a sync-transaction.
|
||||||
* @param transition A transition to collect changes into.
|
* @param transition A transition to collect changes into.
|
||||||
|
* @param caller Info about the calling process.
|
||||||
*/
|
*/
|
||||||
private void applyTransaction(@NonNull WindowContainerTransaction t, int syncId,
|
private void applyTransaction(@NonNull WindowContainerTransaction t, int syncId,
|
||||||
@Nullable Transition transition) {
|
@Nullable Transition transition, @Nullable CallerInfo caller) {
|
||||||
int effects = 0;
|
int effects = 0;
|
||||||
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d", syncId);
|
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d", syncId);
|
||||||
mService.deferWindowLayout();
|
mService.deferWindowLayout();
|
||||||
@@ -319,7 +325,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
final boolean isInLockTaskMode = mService.isInLockTaskMode();
|
final boolean isInLockTaskMode = mService.isInLockTaskMode();
|
||||||
for (int i = 0; i < hopSize; ++i) {
|
for (int i = 0; i < hopSize; ++i) {
|
||||||
effects |= applyHierarchyOp(hops.get(i), effects, syncId, transition,
|
effects |= applyHierarchyOp(hops.get(i), effects, syncId, transition,
|
||||||
isInLockTaskMode);
|
isInLockTaskMode, caller);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Queue-up bounds-change transactions for tasks which are now organized. Do
|
// 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,
|
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();
|
final int type = hop.getType();
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: {
|
case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: {
|
||||||
@@ -555,11 +562,17 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
effects |= sanitizeAndApplyHierarchyOp(wc, hop);
|
effects |= sanitizeAndApplyHierarchyOp(wc, hop);
|
||||||
break;
|
break;
|
||||||
case HIERARCHY_OP_TYPE_LAUNCH_TASK:
|
case HIERARCHY_OP_TYPE_LAUNCH_TASK:
|
||||||
|
mService.mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS,
|
||||||
|
"launchTask HierarchyOp");
|
||||||
final Bundle launchOpts = hop.getLaunchOptions();
|
final Bundle launchOpts = hop.getLaunchOptions();
|
||||||
final int taskId = launchOpts.getInt(
|
final int taskId = launchOpts.getInt(
|
||||||
WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
|
WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
|
||||||
launchOpts.remove(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;
|
break;
|
||||||
case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT:
|
case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT:
|
||||||
final TaskFragmentCreationParams taskFragmentCreationOptions =
|
final TaskFragmentCreationParams taskFragmentCreationOptions =
|
||||||
@@ -936,4 +949,14 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
mLaunchTaskFragments.removeAt(index);
|
mLaunchTaskFragments.removeAt(index);
|
||||||
taskFragment.removeImmediately();
|
taskFragment.removeImmediately();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class CallerInfo {
|
||||||
|
final int mPid;
|
||||||
|
final int mUid;
|
||||||
|
|
||||||
|
CallerInfo() {
|
||||||
|
mPid = Binder.getCallingPid();
|
||||||
|
mUid = Binder.getCallingUid();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ import com.android.server.wm.ActivityTaskManagerService.HotPath;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -219,6 +220,10 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
|
|||||||
/** Whether our process is currently running a {@link IRemoteAnimationRunner} */
|
/** Whether our process is currently running a {@link IRemoteAnimationRunner} */
|
||||||
private boolean mRunningRemoteAnimation;
|
private boolean mRunningRemoteAnimation;
|
||||||
|
|
||||||
|
/** List of "chained" processes that are running remote animations for this process */
|
||||||
|
private final ArrayList<WeakReference<WindowProcessController>> mRemoteAnimationDelegates =
|
||||||
|
new ArrayList<>();
|
||||||
|
|
||||||
// The bits used for mActivityStateFlags.
|
// The bits used for mActivityStateFlags.
|
||||||
private static final int ACTIVITY_STATE_FLAG_IS_VISIBLE = 1 << 16;
|
private static final int ACTIVITY_STATE_FLAG_IS_VISIBLE = 1 << 16;
|
||||||
private static final int ACTIVITY_STATE_FLAG_IS_PAUSING_OR_PAUSED = 1 << 17;
|
private static final int ACTIVITY_STATE_FLAG_IS_PAUSING_OR_PAUSED = 1 << 17;
|
||||||
@@ -1596,11 +1601,38 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
|
|||||||
updateRunningRemoteOrRecentsAnimation();
|
updateRunningRemoteOrRecentsAnimation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks another process as a "delegate" animator. This means that process is doing some part
|
||||||
|
* of a remote animation on behalf of this process.
|
||||||
|
*/
|
||||||
|
void addRemoteAnimationDelegate(WindowProcessController delegate) {
|
||||||
|
if (!isRunningRemoteTransition()) {
|
||||||
|
throw new IllegalStateException("Can't add a delegate to a process which isn't itself"
|
||||||
|
+ " running a remote animation");
|
||||||
|
}
|
||||||
|
mRemoteAnimationDelegates.add(new WeakReference<>(delegate));
|
||||||
|
}
|
||||||
|
|
||||||
void updateRunningRemoteOrRecentsAnimation() {
|
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.
|
// Posting on handler so WM lock isn't held when we call into AM.
|
||||||
mAtm.mH.sendMessage(PooledLambda.obtainMessage(
|
mAtm.mH.sendMessage(PooledLambda.obtainMessage(
|
||||||
WindowProcessListener::setRunningRemoteAnimation, mListener,
|
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. */
|
/** Adjusts scheduling group for animation. This method MUST NOT be called inside WM lock. */
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ import static org.mockito.Mockito.clearInvocations;
|
|||||||
|
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.app.ActivityManager.RunningTaskInfo;
|
import android.app.ActivityManager.RunningTaskInfo;
|
||||||
|
import android.app.ActivityOptions;
|
||||||
import android.app.ActivityTaskManager.RootTaskInfo;
|
import android.app.ActivityTaskManager.RootTaskInfo;
|
||||||
import android.app.IRequestFinishCallback;
|
import android.app.IRequestFinishCallback;
|
||||||
import android.app.PictureInPictureParams;
|
import android.app.PictureInPictureParams;
|
||||||
@@ -69,7 +70,6 @@ import android.content.pm.ParceledListSlice;
|
|||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.platform.test.annotations.Presubmit;
|
import android.platform.test.annotations.Presubmit;
|
||||||
@@ -1255,21 +1255,24 @@ public class WindowOrganizerTests extends WindowTestsBase {
|
|||||||
@Test
|
@Test
|
||||||
public void testStartTasksInTransaction() {
|
public void testStartTasksInTransaction() {
|
||||||
WindowContainerTransaction wct = new WindowContainerTransaction();
|
WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||||
Bundle testOptions = new Bundle();
|
ActivityOptions testOptions = ActivityOptions.makeBasic();
|
||||||
testOptions.putInt("test", 20);
|
testOptions.setTransientLaunch();
|
||||||
wct.startTask(1, null /* options */);
|
wct.startTask(1, null /* options */);
|
||||||
wct.startTask(2, testOptions);
|
wct.startTask(2, testOptions.toBundle());
|
||||||
spyOn(mWm.mAtmService);
|
spyOn(mWm.mAtmService.mTaskSupervisor);
|
||||||
doReturn(START_CANCELED).when(mWm.mAtmService).startActivityFromRecents(anyInt(), any());
|
doReturn(START_CANCELED).when(mWm.mAtmService.mTaskSupervisor).startActivityFromRecents(
|
||||||
|
anyInt(), anyInt(), anyInt(), any());
|
||||||
clearInvocations(mWm.mAtmService);
|
clearInvocations(mWm.mAtmService);
|
||||||
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
|
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
|
||||||
|
|
||||||
final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
|
verify(mWm.mAtmService.mTaskSupervisor, times(1)).startActivityFromRecents(
|
||||||
verify(mWm.mAtmService, times(1)).startActivityFromRecents(eq(1), bundleCaptor.capture());
|
anyInt(), anyInt(), eq(1), any());
|
||||||
assertTrue(bundleCaptor.getValue().isEmpty());
|
|
||||||
|
|
||||||
verify(mWm.mAtmService, times(1)).startActivityFromRecents(eq(2), bundleCaptor.capture());
|
final ArgumentCaptor<SafeActivityOptions> optionsCaptor =
|
||||||
assertEquals(20, bundleCaptor.getValue().getInt("test"));
|
ArgumentCaptor.forClass(SafeActivityOptions.class);
|
||||||
|
verify(mWm.mAtmService.mTaskSupervisor, times(1)).startActivityFromRecents(
|
||||||
|
anyInt(), anyInt(), eq(2), optionsCaptor.capture());
|
||||||
|
assertTrue(optionsCaptor.getValue().getOriginalOptions().getTransientLaunch());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user