Merge "Allow ActivityEmbedding to finish Activity through WCT" into tm-qpr-dev
This commit is contained in:
@@ -3406,6 +3406,7 @@ package android.window {
|
||||
method @NonNull public android.window.WindowContainerTransaction createTaskFragment(@NonNull android.window.TaskFragmentCreationParams);
|
||||
method @NonNull public android.window.WindowContainerTransaction deleteTaskFragment(@NonNull android.window.WindowContainerToken);
|
||||
method public int describeContents();
|
||||
method @NonNull public android.window.WindowContainerTransaction finishActivity(@NonNull android.os.IBinder);
|
||||
method @NonNull public android.window.WindowContainerTransaction removeTask(@NonNull android.window.WindowContainerToken);
|
||||
method @NonNull public android.window.WindowContainerTransaction reorder(@NonNull android.window.WindowContainerToken, boolean);
|
||||
method @NonNull public android.window.WindowContainerTransaction reparent(@NonNull android.window.WindowContainerToken, @Nullable android.window.WindowContainerToken, boolean);
|
||||
|
||||
@@ -705,6 +705,23 @@ public final class WindowContainerTransaction implements Parcelable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finishes the Activity.
|
||||
* Comparing to directly calling {@link android.app.Activity#finish()}, calling this can make
|
||||
* sure the finishing happens in the same transaction with other operations.
|
||||
* @param activityToken activity to be finished.
|
||||
*/
|
||||
@NonNull
|
||||
public WindowContainerTransaction finishActivity(@NonNull IBinder activityToken) {
|
||||
final HierarchyOp hierarchyOp =
|
||||
new HierarchyOp.Builder(
|
||||
HierarchyOp.HIERARCHY_OP_TYPE_FINISH_ACTIVITY)
|
||||
.setContainer(activityToken)
|
||||
.build();
|
||||
mHierarchyOps.add(hierarchyOp);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets/removes the always on top flag for this {@code windowContainer}. See
|
||||
* {@link com.android.server.wm.ConfigurationContainer#setAlwaysOnTop(boolean)}.
|
||||
@@ -1163,6 +1180,7 @@ public final class WindowContainerTransaction implements Parcelable {
|
||||
public static final int HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT = 18;
|
||||
public static final int HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP = 19;
|
||||
public static final int HIERARCHY_OP_TYPE_REMOVE_TASK = 20;
|
||||
public static final int HIERARCHY_OP_TYPE_FINISH_ACTIVITY = 21;
|
||||
|
||||
// The following key(s) are for use with mLaunchOptions:
|
||||
// When launching a task (eg. from recents), this is the taskId to be launched.
|
||||
@@ -1484,6 +1502,8 @@ public final class WindowContainerTransaction implements Parcelable {
|
||||
+ " alwaysOnTop=" + mAlwaysOnTop + "}";
|
||||
case HIERARCHY_OP_TYPE_REMOVE_TASK:
|
||||
return "{RemoveTask: task=" + mContainer + "}";
|
||||
case HIERARCHY_OP_TYPE_FINISH_ACTIVITY:
|
||||
return "{finishActivity: activity=" + mContainer + "}";
|
||||
default:
|
||||
return "{mType=" + mType + " container=" + mContainer + " reparent=" + mReparent
|
||||
+ " mToTop=" + mToTop
|
||||
|
||||
@@ -432,7 +432,7 @@ class TaskFragmentContainer {
|
||||
// In case we have requested to reparent the activity to another container (as
|
||||
// pendingAppeared), we don't want to finish it with this container.
|
||||
&& mController.getContainerWithActivity(activity) == this) {
|
||||
activity.finish();
|
||||
wct.finishActivity(activity.getActivityToken());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -457,7 +457,7 @@ class TaskFragmentContainer {
|
||||
|| controller.shouldRetainAssociatedActivity(this, activity)) {
|
||||
continue;
|
||||
}
|
||||
activity.finish();
|
||||
wct.finishActivity(activity.getActivityToken());
|
||||
}
|
||||
mActivitiesToFinishOnExit.clear();
|
||||
}
|
||||
|
||||
@@ -207,7 +207,7 @@ public class SplitControllerTest {
|
||||
|
||||
verify(mSplitPresenter, never()).deleteTaskFragment(any(), any());
|
||||
verify(mSplitController).removeContainer(tf);
|
||||
verify(mActivity, never()).finish();
|
||||
verify(mTransaction, never()).finishActivity(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1004,9 +1004,9 @@ public class SplitControllerTest {
|
||||
assertTrue(primaryContainer.isFinished());
|
||||
assertTrue(secondaryContainer0.isFinished());
|
||||
assertTrue(secondaryContainer1.isFinished());
|
||||
verify(mActivity).finish();
|
||||
verify(secondaryActivity0).finish();
|
||||
verify(secondaryActivity1).finish();
|
||||
verify(mTransaction).finishActivity(mActivity.getActivityToken());
|
||||
verify(mTransaction).finishActivity(secondaryActivity0.getActivityToken());
|
||||
verify(mTransaction).finishActivity(secondaryActivity1.getActivityToken());
|
||||
assertTrue(taskContainer.mContainers.isEmpty());
|
||||
assertTrue(taskContainer.mSplitContainers.isEmpty());
|
||||
}
|
||||
|
||||
@@ -107,30 +107,29 @@ public class TaskFragmentContainerTest {
|
||||
final TaskFragmentContainer container = new TaskFragmentContainer(mActivity,
|
||||
null /* pendingAppearedIntent */, taskContainer, mController);
|
||||
doReturn(container).when(mController).getContainerWithActivity(mActivity);
|
||||
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||
|
||||
// Only remove the activity, but not clear the reference until appeared.
|
||||
container.finish(true /* shouldFinishDependent */, mPresenter, wct, mController);
|
||||
container.finish(true /* shouldFinishDependent */, mPresenter, mTransaction, mController);
|
||||
|
||||
verify(mActivity).finish();
|
||||
verify(mTransaction).finishActivity(mActivity.getActivityToken());
|
||||
verify(mPresenter, never()).deleteTaskFragment(any(), any());
|
||||
verify(mController, never()).removeContainer(any());
|
||||
|
||||
// Calling twice should not finish activity again.
|
||||
clearInvocations(mActivity);
|
||||
container.finish(true /* shouldFinishDependent */, mPresenter, wct, mController);
|
||||
clearInvocations(mTransaction);
|
||||
container.finish(true /* shouldFinishDependent */, mPresenter, mTransaction, mController);
|
||||
|
||||
verify(mActivity, never()).finish();
|
||||
verify(mTransaction, never()).finishActivity(any());
|
||||
verify(mPresenter, never()).deleteTaskFragment(any(), any());
|
||||
verify(mController, never()).removeContainer(any());
|
||||
|
||||
// Remove all references after the container has appeared in server.
|
||||
doReturn(new ArrayList<>()).when(mInfo).getActivities();
|
||||
container.setInfo(mTransaction, mInfo);
|
||||
container.finish(true /* shouldFinishDependent */, mPresenter, wct, mController);
|
||||
container.finish(true /* shouldFinishDependent */, mPresenter, mTransaction, mController);
|
||||
|
||||
verify(mActivity, never()).finish();
|
||||
verify(mPresenter).deleteTaskFragment(wct, container.getTaskFragmentToken());
|
||||
verify(mTransaction, never()).finishActivity(any());
|
||||
verify(mPresenter).deleteTaskFragment(mTransaction, container.getTaskFragmentToken());
|
||||
verify(mController).removeContainer(container);
|
||||
}
|
||||
|
||||
@@ -150,7 +149,7 @@ public class TaskFragmentContainerTest {
|
||||
// The activity is requested to be reparented, so don't finish it.
|
||||
container0.finish(true /* shouldFinishDependent */, mPresenter, wct, mController);
|
||||
|
||||
verify(mActivity, never()).finish();
|
||||
verify(mTransaction, never()).finishActivity(any());
|
||||
verify(mPresenter).deleteTaskFragment(wct, container0.getTaskFragmentToken());
|
||||
verify(mController).removeContainer(container0);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP
|
||||
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;
|
||||
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_FINISH_ACTIVITY;
|
||||
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_LAUNCH_TASK;
|
||||
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_PENDING_INTENT;
|
||||
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REMOVE_INSETS_PROVIDER;
|
||||
@@ -1007,6 +1008,20 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
||||
isInLockTaskMode);
|
||||
break;
|
||||
}
|
||||
case HIERARCHY_OP_TYPE_FINISH_ACTIVITY: {
|
||||
final ActivityRecord activity = ActivityRecord.forTokenLocked(hop.getContainer());
|
||||
if (activity == null || activity.finishing) {
|
||||
break;
|
||||
}
|
||||
if (activity.isVisible()) {
|
||||
// Prevent the transition from being executed too early if the activity is
|
||||
// visible.
|
||||
activity.finishIfPossible("finish-activity-op", false /* oomAdj */);
|
||||
} else {
|
||||
activity.destroyIfPossible("finish-activity-op");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case HIERARCHY_OP_TYPE_LAUNCH_TASK: {
|
||||
mService.mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS,
|
||||
"launchTask HierarchyOp");
|
||||
@@ -1620,6 +1635,9 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
||||
organizer);
|
||||
}
|
||||
break;
|
||||
case HIERARCHY_OP_TYPE_FINISH_ACTIVITY:
|
||||
// Allow finish activity if it has the activity token.
|
||||
break;
|
||||
default:
|
||||
// Other types of hierarchy changes are not allowed.
|
||||
String msg = "Permission Denial: " + func + " from pid="
|
||||
|
||||
@@ -729,6 +729,16 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
assertEquals(activity0, mDisplayContent.mFocusedApp);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyTransaction_finishActivity() {
|
||||
final ActivityRecord activity = createActivityRecord(mDisplayContent);
|
||||
|
||||
mTransaction.finishActivity(activity.token);
|
||||
assertApplyTransactionAllowed(mTransaction);
|
||||
|
||||
assertTrue(activity.finishing);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyTransaction_skipTransactionForUnregisterOrganizer() {
|
||||
mController.unregisterOrganizer(mIOrganizer);
|
||||
|
||||
Reference in New Issue
Block a user