Merge "Embedded Activities in TaskFragments" into sc-v2-dev am: ad40d06f0e am: 5fe212bc0d

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15020162

Change-Id: I2efd0389ee5bdff9ffa7a7828fd70b9b26ad29a5
This commit is contained in:
Jeff Chang
2021-07-08 10:30:18 +00:00
committed by Automerger Merge Worker
7 changed files with 158 additions and 53 deletions

View File

@@ -20,7 +20,6 @@ import static android.app.WindowConfiguration.WindowingMode;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.res.Configuration;
import android.os.IBinder;
import android.os.Parcel;
@@ -39,13 +38,6 @@ public final class TaskFragmentInfo implements Parcelable {
@NonNull
private final IBinder mFragmentToken;
/**
* The component name of the initial root activity of this TaskFragment, which will be used
* to configure the relationships for TaskFragments.
*/
@NonNull
private final ComponentName mInitialComponentName;
@NonNull
private final WindowContainerToken mToken;
@@ -59,14 +51,12 @@ public final class TaskFragmentInfo implements Parcelable {
private final boolean mIsVisible;
public TaskFragmentInfo(
@NonNull IBinder fragmentToken, @NonNull ComponentName initialComponentName,
@NonNull WindowContainerToken token, @NonNull Configuration configuration,
boolean isEmpty, boolean isVisible) {
if (fragmentToken == null || initialComponentName == null) {
@NonNull IBinder fragmentToken, @NonNull WindowContainerToken token,
@NonNull Configuration configuration, boolean isEmpty, boolean isVisible) {
if (fragmentToken == null) {
throw new IllegalArgumentException("Invalid TaskFragmentInfo.");
}
mFragmentToken = fragmentToken;
mInitialComponentName = initialComponentName;
mToken = token;
mConfiguration.setTo(configuration);
mIsEmpty = isEmpty;
@@ -77,10 +67,6 @@ public final class TaskFragmentInfo implements Parcelable {
return mFragmentToken;
}
public ComponentName getInitialComponentName() {
return mInitialComponentName;
}
public WindowContainerToken getToken() {
return mToken;
}
@@ -112,7 +98,6 @@ public final class TaskFragmentInfo implements Parcelable {
}
return mFragmentToken.equals(that.mFragmentToken)
&& mInitialComponentName.equals(that.mInitialComponentName)
&& mToken.equals(that.mToken)
&& mIsEmpty == that.mIsEmpty
&& mIsVisible == that.mIsVisible
@@ -121,7 +106,6 @@ public final class TaskFragmentInfo implements Parcelable {
private TaskFragmentInfo(Parcel in) {
mFragmentToken = in.readStrongBinder();
mInitialComponentName = in.readTypedObject(ComponentName.CREATOR);
mToken = in.readTypedObject(WindowContainerToken.CREATOR);
mConfiguration.readFromParcel(in);
mIsEmpty = in.readBoolean();
@@ -131,7 +115,6 @@ public final class TaskFragmentInfo implements Parcelable {
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeStrongBinder(mFragmentToken);
dest.writeTypedObject(mInitialComponentName, flags);
dest.writeTypedObject(mToken, flags);
mConfiguration.writeToParcel(dest, flags);
dest.writeBoolean(mIsEmpty);
@@ -156,7 +139,6 @@ public final class TaskFragmentInfo implements Parcelable {
public String toString() {
return "TaskFragmentInfo{"
+ " fragmentToken=" + mFragmentToken
+ " initialComponentName=" + mInitialComponentName
+ " token=" + mToken
+ " isEmpty=" + mIsEmpty
+ " isVisible=" + mIsVisible

View File

@@ -27,6 +27,7 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityOptions;
import android.app.IApplicationThread;
@@ -38,6 +39,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.UserHandle;
import android.provider.Settings;
@@ -488,6 +490,16 @@ public class ActivityStartController {
return START_SUCCESS;
}
void startActivityInTaskFragment(@NonNull TaskFragment taskFragment,
@NonNull Intent activityIntent, @Nullable Bundle activityOptions) {
obtainStarter(activityIntent, "startActivityInTaskFragment")
.setActivityOptions(activityOptions)
.setInTaskFragment(taskFragment)
.setCallingUid(Binder.getCallingUid())
.setCallingPid(Binder.getCallingPid())
.execute();
}
void registerRemoteAnimationForNextActivityStart(String packageName,
RemoteAnimationAdapter adapter) {
mPendingRemoteAnimationRegistry.addPendingAnimation(packageName, adapter);

View File

@@ -177,6 +177,7 @@ class ActivityStarter {
private int mPreferredWindowingMode;
private Task mInTask;
private TaskFragment mInTaskFragment;
@VisibleForTesting
boolean mAddingToTask;
private Task mReuseTask;
@@ -342,6 +343,7 @@ class ActivityStarter {
boolean avoidMoveToFront;
ActivityRecord[] outActivity;
Task inTask;
TaskFragment inTaskFragment;
String reason;
ProfilerInfo profilerInfo;
Configuration globalConfig;
@@ -392,6 +394,7 @@ class ActivityStarter {
componentSpecified = false;
outActivity = null;
inTask = null;
inTaskFragment = null;
reason = null;
profilerInfo = null;
globalConfig = null;
@@ -407,7 +410,7 @@ class ActivityStarter {
/**
* Adopts all values from passed in request.
*/
void set(Request request) {
void set(@NonNull Request request) {
caller = request.caller;
intent = request.intent;
intentGrants = request.intentGrants;
@@ -432,6 +435,7 @@ class ActivityStarter {
componentSpecified = request.componentSpecified;
outActivity = request.outActivity;
inTask = request.inTask;
inTaskFragment = request.inTaskFragment;
reason = request.reason;
profilerInfo = request.profilerInfo;
globalConfig = request.globalConfig;
@@ -574,6 +578,7 @@ class ActivityStarter {
mPreferredWindowingMode = starter.mPreferredWindowingMode;
mInTask = starter.mInTask;
mInTaskFragment = starter.mInTaskFragment;
mAddingToTask = starter.mAddingToTask;
mReuseTask = starter.mReuseTask;
@@ -835,6 +840,7 @@ class ActivityStarter {
final int startFlags = request.startFlags;
final SafeActivityOptions options = request.activityOptions;
Task inTask = request.inTask;
mInTaskFragment = request.inTaskFragment;
int err = ActivityManager.START_SUCCESS;
// Pull the optional Ephemeral Installer-only bundle out of the options early.
@@ -2204,6 +2210,7 @@ class ActivityStarter {
mPreferredWindowingMode = WINDOWING_MODE_UNDEFINED;
mInTask = null;
mInTaskFragment = null;
mAddingToTask = false;
mReuseTask = null;
@@ -2691,11 +2698,23 @@ class ActivityStarter {
mIntentDelivered = true;
}
private void addOrReparentStartingActivity(Task parent, String reason) {
if (mStartActivity.getTask() == null || mStartActivity.getTask() == parent) {
parent.addChild(mStartActivity);
private void addOrReparentStartingActivity(@NonNull Task task, String reason) {
TaskFragment newParent = task;
if (mInTaskFragment != null) {
// mInTaskFragment is created and added to the leaf task by task fragment organizer's
// request. If the task was resolved and different than mInTaskFragment, reparent the
// task to mInTaskFragment for embedding.
if (mInTaskFragment.getTask() != task) {
task.reparent(mInTaskFragment, POSITION_TOP);
} else {
newParent = mInTaskFragment;
}
}
if (mStartActivity.getTaskFragment() == null
|| mStartActivity.getTaskFragment() == newParent) {
newParent.addChild(mStartActivity, POSITION_TOP);
} else {
mStartActivity.reparent(parent, parent.getChildCount() /* top */, reason);
mStartActivity.reparent(newParent, newParent.getChildCount() /* top */, reason);
}
}
@@ -2927,6 +2946,11 @@ class ActivityStarter {
return this;
}
ActivityStarter setInTaskFragment(TaskFragment taskFragment) {
mRequest.inTaskFragment = taskFragment;
return this;
}
ActivityStarter setWaitResult(WaitResult result) {
mRequest.waitResult = result;
return this;
@@ -3010,5 +3034,7 @@ class ActivityStarter {
pw.print(mDoResume);
pw.print(" mAddingToTask=");
pw.println(mAddingToTask);
pw.print(" mInTaskFragment=");
pw.println(mInTaskFragment);
}
}

View File

@@ -629,7 +629,7 @@ class Task extends TaskFragment {
IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
boolean _createdByOrganizer, IBinder _launchCookie, boolean _deferTaskAppear,
boolean _removeWithTaskOrganizer) {
super(atmService, _createdByOrganizer);
super(atmService, null /* fragmentToken */, _createdByOrganizer);
mTaskId = _taskId;
mUserId = _userId;
@@ -643,7 +643,6 @@ class Task extends TaskFragment {
: new PersistedTaskSnapshotData();
// Tasks have no set orientation value (including SCREEN_ORIENTATION_UNSPECIFIED).
setOrientation(SCREEN_ORIENTATION_UNSET);
mRemoteToken = new RemoteToken(this);
affinityIntent = _affinityIntent;
affinity = _affinity;
rootAffinity = _rootAffinity;
@@ -4976,7 +4975,6 @@ class Task extends TaskFragment {
// Slot the activity into the history root task and proceed
ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Adding activity %s to task %s "
+ "callers: %s", r, task, new RuntimeException("here").fillInStackTrace());
task.positionChildAtTop(r);
// The transition animation and starting window are not needed if {@code allowMoveToFront}
// is false, because the activity won't be visible.

View File

@@ -74,7 +74,6 @@ import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.NewIntentItem;
import android.app.servertransaction.PauseActivityItem;
import android.app.servertransaction.ResumeActivityItem;
import android.content.ComponentName;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.IBinder;
@@ -155,6 +154,9 @@ class TaskFragment extends WindowContainer<WindowContainer> {
*/
int mMinHeight;
/** Avoid reentrant of {@link #removeImmediately()}. */
private boolean mRemoving;
// The TaskFragment that adjacent to this one.
private TaskFragment mAdjacentTaskFragment;
@@ -196,23 +198,13 @@ class TaskFragment extends WindowContainer<WindowContainer> {
boolean mCreatedByOrganizer;
/** Organizer that organizing this TaskFragment. */
// TODO(b/190433129) set the value when creating TaskFragment from WCT.
@Nullable
private ITaskFragmentOrganizer mTaskFragmentOrganizer;
/** Client assigned unique token for this TaskFragment if this is created by an organizer. */
// TODO(b/190433129) set the value when creating TaskFragment from WCT.
@Nullable
private IBinder mFragmentToken;
/**
* The component name of the root activity that initiated this TaskFragment, which will be used
* to configure the relationships for TaskFragments.
*/
// TODO(b/190433129) set the value when creating TaskFragment from WCT.
@Nullable
private ComponentName mInitialComponentName;
private final Rect mTmpInsets = new Rect();
private final Rect mTmpBounds = new Rect();
private final Rect mTmpFullBounds = new Rect();
@@ -260,15 +252,18 @@ class TaskFragment extends WindowContainer<WindowContainer> {
}
}
TaskFragment(ActivityTaskManagerService atmService, boolean createdByOrganizer) {
TaskFragment(ActivityTaskManagerService atmService, IBinder fragmentToken,
boolean createdByOrganizer) {
super(atmService.mWindowManager);
mAtmService = atmService;
mTaskSupervisor = atmService.mTaskSupervisor;
mTaskSupervisor = mAtmService.mTaskSupervisor;
mRootWindowContainer = mAtmService.mRootWindowContainer;
mCreatedByOrganizer = createdByOrganizer;
mTaskFragmentOrganizerController =
mAtmService.mWindowOrganizerController.mTaskFragmentOrganizerController;
mFragmentToken = fragmentToken;
mRemoteToken = new RemoteToken(this);
}
void setAdjacentTaskFragment(TaskFragment taskFragment) {
@@ -276,6 +271,10 @@ class TaskFragment extends WindowContainer<WindowContainer> {
taskFragment.mAdjacentTaskFragment = this;
}
void setTaskFragmentOrganizer(ITaskFragmentOrganizer organizer) {
mTaskFragmentOrganizer = organizer;
}
TaskFragment getAdjacentTaskFragment() {
return mAdjacentTaskFragment;
}
@@ -1981,7 +1980,6 @@ class TaskFragment extends WindowContainer<WindowContainer> {
}
}
// TODO(b/190433129) call when TaskFragment is removed from WCT#deleteTaskFragment
private void sendTaskFragmentVanished() {
if (mTaskFragmentOrganizer != null) {
mTaskFragmentOrganizerController.onTaskFragmentVanished(mTaskFragmentOrganizer, this);
@@ -1995,7 +1993,6 @@ class TaskFragment extends WindowContainer<WindowContainer> {
TaskFragmentInfo getTaskFragmentInfo() {
return new TaskFragmentInfo(
mFragmentToken,
mInitialComponentName,
mRemoteToken.toWindowContainerToken(),
getConfiguration(),
getChildCount() == 0,
@@ -2026,6 +2023,17 @@ class TaskFragment extends WindowContainer<WindowContainer> {
mMinHeight = minHeight;
}
@Override
void removeImmediately() {
if (mRemoving) {
return;
}
mRemoving = true;
super.removeImmediately();
sendTaskFragmentVanished();
mRemoving = false;
}
boolean dump(String prefix, FileDescriptor fd, PrintWriter pw, boolean dumpAll,
boolean dumpClient, String dumpPackage, final boolean needSep, Runnable header) {
boolean printed = false;

View File

@@ -48,6 +48,7 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
import android.view.SurfaceControl;
@@ -106,6 +107,11 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
final TaskFragmentOrganizerController mTaskFragmentOrganizerController;
final TransitionController mTransitionController;
/**
* A Map which manages the relationship between
* {@link TaskFragmentCreationParams.mFragmentToken fragmentToken} and {@link TaskFragment}
*/
private final ArrayMap<IBinder, TaskFragment> mLaunchTaskFragments = new ArrayMap<>();
WindowOrganizerController(ActivityTaskManagerService atm) {
mService = atm;
@@ -558,12 +564,12 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT:
final TaskFragmentCreationParams taskFragmentCreationOptions =
hop.getTaskFragmentCreationOptions();
// TODO(b/190433129) add actual implementation on WM Core
createTaskFragment(taskFragmentCreationOptions);
break;
case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT:
wc = WindowContainer.fromBinder(hop.getContainer());
if (wc == null || !wc.isAttached()) {
Slog.e(TAG, "Attempt to operate on detached container: " + wc);
Slog.e(TAG, "Attempt to operate on unknown or detached container: " + wc);
break;
}
final TaskFragment taskFragment = wc.asTaskFragment();
@@ -571,23 +577,40 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
throw new IllegalArgumentException(
"Can only delete organized TaskFragment, but not Task.");
}
// TODO(b/190433129) add actual implementation on WM Core
deleteTaskFragment(taskFragment);
break;
case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT:
fragmentToken = hop.getContainer();
if (!mLaunchTaskFragments.containsKey(fragmentToken)) {
throw new IllegalArgumentException(
"Not allowed to operate with invalid fragment token");
}
final Intent activityIntent = hop.getActivityIntent();
final Bundle activityOptions = hop.getLaunchOptions();
// TODO(b/190433129) add actual implementation on WM Core
mService.getActivityStartController()
.startActivityInTaskFragment(mLaunchTaskFragments.get(fragmentToken),
activityIntent, activityOptions);
// TODO(b/189385246) : report the failure back to the organizer if the activity
// start failed
break;
case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT:
fragmentToken = hop.getNewParent();
final ActivityRecord activity = ActivityRecord.forTokenLocked(hop.getContainer());
// TODO(b/190433129) add actual implementation on WM Core
if (!mLaunchTaskFragments.containsKey(fragmentToken) || activity == null) {
throw new IllegalArgumentException(
"Not allowed to operate with invalid fragment token or activity.");
}
activity.reparent(mLaunchTaskFragments.get(fragmentToken), POSITION_TOP);
break;
case HIERARCHY_OP_TYPE_REPARENT_CHILDREN:
final WindowContainer oldParent = WindowContainer.fromBinder(hop.getContainer());
final WindowContainer newParent = WindowContainer.fromBinder(hop.getNewParent());
// TODO(b/190433129) add actual implementation on WM Core
if (oldParent == null || !oldParent.isAttached()) {
Slog.e(TAG, "Attempt to operate on unknown or detached container: "
+ oldParent);
break;
}
reparentTaskFragment(oldParent, newParent);
break;
}
return effects;
@@ -866,4 +889,51 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
private void enforceTaskPermission(String func) {
mService.enforceTaskPermission(func);
}
void createTaskFragment(@NonNull TaskFragmentCreationParams creationParams) {
final ActivityRecord ownerActivity =
ActivityRecord.forTokenLocked(creationParams.getOwnerToken());
if (ownerActivity == null || ownerActivity.getTask() == null) {
// TODO(b/189385246) : report the failure back to the organizer
return;
}
// The ownerActivity has to belong to the same app as the root Activity of the target Task.
final ActivityRecord rootActivity = ownerActivity.getTask().getRootActivity();
if (rootActivity.getUid() != ownerActivity.getUid()) {
// TODO(b/189385246) : report the failure back to the organizer
return;
}
final TaskFragment taskFragment = new TaskFragment(mService,
creationParams.getFragmentToken(), true /* createdByOrganizer */);
ownerActivity.getTask().addChild(taskFragment, POSITION_TOP);
taskFragment.setWindowingMode(creationParams.getWindowingMode());
taskFragment.setBounds(creationParams.getInitialBounds());
taskFragment.setTaskFragmentOrganizer(creationParams.getOrganizer());
mLaunchTaskFragments.put(creationParams.getFragmentToken(), taskFragment);
}
void reparentTaskFragment(@NonNull WindowContainer oldParent,
@Nullable WindowContainer newParent) {
WindowContainer parent = newParent;
if (parent == null && oldParent.asTaskFragment() != null) {
parent = oldParent.asTaskFragment().getTask();
}
if (parent == null) {
// TODO(b/189385246) : report the failure back to the organizer
return;
}
while (oldParent.hasChild()) {
oldParent.getChildAt(0).reparent(parent, POSITION_TOP);
}
}
void deleteTaskFragment(@NonNull TaskFragment taskFragment) {
final int index = mLaunchTaskFragments.indexOfValue(taskFragment);
if (index < 0) {
throw new IllegalArgumentException(
"Not allowed to operate with invalid taskFragment");
}
mLaunchTaskFragments.removeAt(index);
taskFragment.removeImmediately();
}
}

View File

@@ -1729,6 +1729,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return mActivityRecord != null ? mActivityRecord.getTask() : null;
}
@Nullable TaskFragment getTaskFragment() {
return mActivityRecord != null ? mActivityRecord.getTaskFragment() : null;
}
@Nullable Task getRootTask() {
final Task task = getTask();
if (task != null) {
@@ -2908,9 +2912,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// means we need to intercept touches outside of that window. The dim layer
// user associated with the window (task or root task) will give us the good
// bounds, as they would be used to display the dim layer.
final Task task = getTask();
if (task != null) {
task.getDimBounds(mTmpRect);
final TaskFragment taskFragment = getTaskFragment();
if (taskFragment != null) {
final Task task = taskFragment.asTask();
if (task != null) {
task.getDimBounds(mTmpRect);
} else {
mTmpRect.set(taskFragment.getBounds());
}
} else if (getRootTask() != null) {
getRootTask().getDimBounds(mTmpRect);
}