Merge "Fix exception when opening App info on work profile" into tm-qpr-dev am: dad802aa6d
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/19035686 Change-Id: Ib47f59e4b8301b74595f7161c509ec63e5fcff19 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -79,6 +79,10 @@ import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
|
||||
import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS;
|
||||
import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY;
|
||||
import static com.android.server.wm.Task.REPARENT_MOVE_ROOT_TASK_TO_FRONT;
|
||||
import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED;
|
||||
import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION;
|
||||
import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_NEW_TASK;
|
||||
import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_UNTRUSTED_HOST;
|
||||
import static com.android.server.wm.WindowContainer.POSITION_TOP;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
@@ -132,6 +136,7 @@ import com.android.server.statusbar.StatusBarManagerInternal;
|
||||
import com.android.server.uri.NeededUriGrants;
|
||||
import com.android.server.wm.ActivityMetricsLogger.LaunchingState;
|
||||
import com.android.server.wm.LaunchParamsController.LaunchParams;
|
||||
import com.android.server.wm.TaskFragment.EmbeddingCheckResult;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.text.DateFormat;
|
||||
@@ -2074,24 +2079,6 @@ class ActivityStarter {
|
||||
}
|
||||
}
|
||||
|
||||
if (mInTaskFragment != null && !canEmbedActivity(mInTaskFragment, r, newTask, targetTask)) {
|
||||
final StringBuilder errorMsg = new StringBuilder("Permission denied: Cannot embed " + r
|
||||
+ " to " + mInTaskFragment.getTask() + ". newTask=" + newTask + ", targetTask= "
|
||||
+ targetTask);
|
||||
if (newTask && isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE,
|
||||
LAUNCH_SINGLE_INSTANCE_PER_TASK, LAUNCH_SINGLE_TASK)) {
|
||||
errorMsg.append("\nActivity tries to launch on a new task because the launch mode"
|
||||
+ " is " + launchModeToString(mLaunchMode));
|
||||
} else if (newTask && (mLaunchFlags & (FLAG_ACTIVITY_NEW_DOCUMENT
|
||||
| FLAG_ACTIVITY_NEW_TASK)) != 0) {
|
||||
errorMsg.append("\nActivity tries to launch on a new task because the launch flags"
|
||||
+ " contains FLAG_ACTIVITY_NEW_DOCUMENT or FLAG_ACTIVITY_NEW_TASK. "
|
||||
+ "mLaunchFlag=" + mLaunchFlags);
|
||||
}
|
||||
Slog.e(TAG, errorMsg.toString());
|
||||
return START_PERMISSION_DENIED;
|
||||
}
|
||||
|
||||
// Do not start the activity if target display's DWPC does not allow it.
|
||||
// We can't return fatal error code here because it will crash the caller of
|
||||
// startActivity() if they don't catch the exception. We don't expect 3P apps to make
|
||||
@@ -2118,19 +2105,21 @@ class ActivityStarter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@code true} if an activity can be embedded to the TaskFragment.
|
||||
* Returns whether embedding of {@code starting} is allowed.
|
||||
*
|
||||
* @param taskFragment the TaskFragment for embedding.
|
||||
* @param starting the starting activity.
|
||||
* @param newTask whether the starting activity is going to be launched on a new task.
|
||||
* @param targetTask the target task for launching activity, which could be different from
|
||||
* the one who hosting the embedding.
|
||||
*/
|
||||
private boolean canEmbedActivity(@NonNull TaskFragment taskFragment,
|
||||
@NonNull ActivityRecord starting, boolean newTask, Task targetTask) {
|
||||
@VisibleForTesting
|
||||
@EmbeddingCheckResult
|
||||
static int canEmbedActivity(@NonNull TaskFragment taskFragment,
|
||||
@NonNull ActivityRecord starting, @NonNull Task targetTask) {
|
||||
final Task hostTask = taskFragment.getTask();
|
||||
// Not allowed embedding a separate task or without host task.
|
||||
if (hostTask == null || newTask || targetTask != hostTask) {
|
||||
return false;
|
||||
if (hostTask == null || targetTask != hostTask) {
|
||||
return EMBEDDING_DISALLOWED_NEW_TASK;
|
||||
}
|
||||
|
||||
return taskFragment.isAllowedToEmbedActivity(starting);
|
||||
@@ -2970,19 +2959,16 @@ class ActivityStarter {
|
||||
mIntentDelivered = true;
|
||||
}
|
||||
|
||||
/** Places {@link #mStartActivity} in {@code task} or an embedded {@link TaskFragment}. */
|
||||
private void addOrReparentStartingActivity(@NonNull Task task, String reason) {
|
||||
TaskFragment newParent = task;
|
||||
if (mInTaskFragment != null) {
|
||||
// TODO(b/234351413): remove remaining embedded Task logic.
|
||||
// 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) {
|
||||
if (shouldReparentInTaskFragment(task)) {
|
||||
task.reparent(mInTaskFragment, POSITION_TOP);
|
||||
}
|
||||
} else {
|
||||
int embeddingCheckResult = canEmbedActivity(mInTaskFragment, mStartActivity, task);
|
||||
if (embeddingCheckResult == EMBEDDING_ALLOWED) {
|
||||
newParent = mInTaskFragment;
|
||||
} else {
|
||||
// Start mStartActivity to task instead if it can't be embedded to mInTaskFragment.
|
||||
sendCanNotEmbedActivityError(mInTaskFragment, embeddingCheckResult);
|
||||
}
|
||||
} else {
|
||||
TaskFragment candidateTf = mAddingToTaskFragment != null ? mAddingToTaskFragment : null;
|
||||
@@ -2994,20 +2980,12 @@ class ActivityStarter {
|
||||
}
|
||||
}
|
||||
if (candidateTf != null && candidateTf.isEmbedded()
|
||||
&& canEmbedActivity(candidateTf, mStartActivity, false /* newTask */, task)) {
|
||||
&& canEmbedActivity(candidateTf, mStartActivity, task) == EMBEDDING_ALLOWED) {
|
||||
// Use the embedded TaskFragment of the top activity as the new parent if the
|
||||
// activity can be embedded.
|
||||
newParent = candidateTf;
|
||||
}
|
||||
}
|
||||
// Start Activity to the Task if mStartActivity's min dimensions are not satisfied.
|
||||
if (newParent.isEmbedded() && newParent.smallerThanMinDimension(mStartActivity)) {
|
||||
reason += " - MinimumDimensionViolation";
|
||||
mService.mWindowOrganizerController.sendMinimumDimensionViolation(
|
||||
newParent, mStartActivity.getMinDimensions(), mRequest.errorCallbackToken,
|
||||
reason);
|
||||
newParent = task;
|
||||
}
|
||||
if (mStartActivity.getTaskFragment() == null
|
||||
|| mStartActivity.getTaskFragment() == newParent) {
|
||||
newParent.addChild(mStartActivity, POSITION_TOP);
|
||||
@@ -3016,16 +2994,41 @@ class ActivityStarter {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldReparentInTaskFragment(Task task) {
|
||||
// The task has not been embedded. We should reparent the task to TaskFragment.
|
||||
if (!task.isEmbedded()) {
|
||||
return true;
|
||||
/**
|
||||
* Notifies the client side that {@link #mStartActivity} cannot be embedded to
|
||||
* {@code taskFragment}.
|
||||
*/
|
||||
private void sendCanNotEmbedActivityError(TaskFragment taskFragment,
|
||||
@EmbeddingCheckResult int result) {
|
||||
final String errMsg;
|
||||
switch(result) {
|
||||
case EMBEDDING_DISALLOWED_NEW_TASK: {
|
||||
errMsg = "Cannot embed " + mStartActivity + " that launched on another task"
|
||||
+ ",mLaunchMode=" + launchModeToString(mLaunchMode)
|
||||
+ ",mLaunchFlag=" + Integer.toHexString(mLaunchFlags);
|
||||
break;
|
||||
}
|
||||
case EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION: {
|
||||
errMsg = "Cannot embed " + mStartActivity
|
||||
+ ". TaskFragment's bounds:" + taskFragment.getBounds()
|
||||
+ ", minimum dimensions:" + mStartActivity.getMinDimensions();
|
||||
break;
|
||||
}
|
||||
case EMBEDDING_DISALLOWED_UNTRUSTED_HOST: {
|
||||
errMsg = "The app:" + mCallingUid + "is not trusted to " + mStartActivity;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
errMsg = "Unhandled embed result:" + result;
|
||||
}
|
||||
if (taskFragment.isOrganized()) {
|
||||
mService.mWindowOrganizerController.sendTaskFragmentOperationFailure(
|
||||
taskFragment.getTaskFragmentOrganizer(), mRequest.errorCallbackToken,
|
||||
new SecurityException(errMsg));
|
||||
} else {
|
||||
// If the taskFragment is not organized, just dump error message as warning logs.
|
||||
Slog.w(TAG, errMsg);
|
||||
}
|
||||
WindowContainer<?> parent = task.getParent();
|
||||
// If the Activity is going to launch on top of embedded Task in the same TaskFragment,
|
||||
// we don't need to reparent the Task. Otherwise, the embedded Task should reparent to
|
||||
// another TaskFragment.
|
||||
return parent.asTaskFragment() != mInTaskFragment;
|
||||
}
|
||||
|
||||
private int adjustLaunchFlagsToDocumentMode(ActivityRecord r, boolean launchSingleInstance,
|
||||
|
||||
@@ -139,6 +139,45 @@ class TaskFragment extends WindowContainer<WindowContainer> {
|
||||
/** Set to false to disable the preview that is shown while a new activity is being started. */
|
||||
static final boolean SHOW_APP_STARTING_PREVIEW = true;
|
||||
|
||||
/**
|
||||
* An embedding check result of {@link #isAllowedToEmbedActivity(ActivityRecord)} or
|
||||
* {@link ActivityStarter#canEmbedActivity(TaskFragment, ActivityRecord, Task)}:
|
||||
* indicate that an Activity can be embedded successfully.
|
||||
*/
|
||||
static final int EMBEDDING_ALLOWED = 0;
|
||||
/**
|
||||
* An embedding check result of {@link #isAllowedToEmbedActivity(ActivityRecord)} or
|
||||
* {@link ActivityStarter#canEmbedActivity(TaskFragment, ActivityRecord, Task)}:
|
||||
* indicate that an Activity can't be embedded because either the Activity does not allow
|
||||
* untrusted embedding, and the embedding host app is not trusted.
|
||||
*/
|
||||
static final int EMBEDDING_DISALLOWED_UNTRUSTED_HOST = 1;
|
||||
/**
|
||||
* An embedding check result of {@link #isAllowedToEmbedActivity(ActivityRecord)} or
|
||||
* {@link ActivityStarter#canEmbedActivity(TaskFragment, ActivityRecord, Task)}:
|
||||
* indicate that an Activity can't be embedded because this taskFragment's bounds are
|
||||
* {@link #smallerThanMinDimension(ActivityRecord)}.
|
||||
*/
|
||||
static final int EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION = 2;
|
||||
/**
|
||||
* An embedding check result of
|
||||
* {@link ActivityStarter#canEmbedActivity(TaskFragment, ActivityRecord, Task)}:
|
||||
* indicate that an Activity can't be embedded because the Activity is started on a new task.
|
||||
*/
|
||||
static final int EMBEDDING_DISALLOWED_NEW_TASK = 3;
|
||||
|
||||
/**
|
||||
* Embedding check results of {@link #isAllowedToEmbedActivity(ActivityRecord)} or
|
||||
* {@link ActivityStarter#canEmbedActivity(TaskFragment, ActivityRecord, Task)}.
|
||||
*/
|
||||
@IntDef(prefix = {"EMBEDDING_"}, value = {
|
||||
EMBEDDING_ALLOWED,
|
||||
EMBEDDING_DISALLOWED_UNTRUSTED_HOST,
|
||||
EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION,
|
||||
EMBEDDING_DISALLOWED_NEW_TASK,
|
||||
})
|
||||
@interface EmbeddingCheckResult {}
|
||||
|
||||
/**
|
||||
* Indicate that the minimal width/height should use the default value.
|
||||
*
|
||||
@@ -509,20 +548,29 @@ class TaskFragment extends WindowContainer<WindowContainer> {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean isAllowedToEmbedActivity(@NonNull ActivityRecord a) {
|
||||
@EmbeddingCheckResult
|
||||
int isAllowedToEmbedActivity(@NonNull ActivityRecord a) {
|
||||
return isAllowedToEmbedActivity(a, mTaskFragmentOrganizerUid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the organized task fragment is allowed to have the specified activity, which is
|
||||
* allowed if an activity allows embedding in untrusted mode, or if the trusted mode can be
|
||||
* enabled.
|
||||
* @see #isAllowedToEmbedActivityInTrustedMode(ActivityRecord)
|
||||
* allowed if an activity allows embedding in untrusted mode, if the trusted mode can be
|
||||
* enabled, or if the organized task fragment bounds are not
|
||||
* {@link #smallerThanMinDimension(ActivityRecord)}.
|
||||
*
|
||||
* @param uid uid of the TaskFragment organizer.
|
||||
* @see #isAllowedToEmbedActivityInTrustedMode(ActivityRecord)
|
||||
*/
|
||||
boolean isAllowedToEmbedActivity(@NonNull ActivityRecord a, int uid) {
|
||||
return isAllowedToEmbedActivityInUntrustedMode(a)
|
||||
|| isAllowedToEmbedActivityInTrustedMode(a, uid);
|
||||
@EmbeddingCheckResult
|
||||
int isAllowedToEmbedActivity(@NonNull ActivityRecord a, int uid) {
|
||||
if (!isAllowedToEmbedActivityInUntrustedMode(a)
|
||||
&& !isAllowedToEmbedActivityInTrustedMode(a, uid)) {
|
||||
return EMBEDDING_DISALLOWED_UNTRUSTED_HOST;
|
||||
} else if (smallerThanMinDimension(a)) {
|
||||
return EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION;
|
||||
}
|
||||
return EMBEDDING_ALLOWED;
|
||||
}
|
||||
|
||||
boolean smallerThanMinDimension(@NonNull ActivityRecord activity) {
|
||||
@@ -539,9 +587,8 @@ class TaskFragment extends WindowContainer<WindowContainer> {
|
||||
}
|
||||
final int minWidth = minDimensions.x;
|
||||
final int minHeight = minDimensions.y;
|
||||
final boolean smaller = taskFragBounds.width() < minWidth
|
||||
return taskFragBounds.width() < minWidth
|
||||
|| taskFragBounds.height() < minHeight;
|
||||
return smaller;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -598,7 +645,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
|
||||
// The system is trusted to embed other apps securely and for all users.
|
||||
return UserHandle.getAppId(uid) == SYSTEM_UID
|
||||
// Activities from the same UID can be embedded freely by the host.
|
||||
|| uid == a.getUid();
|
||||
|| a.isUid(uid);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.server.wm;
|
||||
import static android.window.TaskFragmentOrganizer.putExceptionInBundle;
|
||||
|
||||
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
|
||||
import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED;
|
||||
import static com.android.server.wm.WindowOrganizerController.configurationsAreEqualForOrganizer;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
@@ -235,7 +236,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
+ " is not in a task belong to the organizer app.");
|
||||
return;
|
||||
}
|
||||
if (!task.isAllowedToEmbedActivity(activity, mOrganizerUid)) {
|
||||
if (task.isAllowedToEmbedActivity(activity, mOrganizerUid) != EMBEDDING_ALLOWED) {
|
||||
Slog.d(TAG, "Reparent activity=" + activity.token
|
||||
+ " is not allowed to be embedded.");
|
||||
return;
|
||||
|
||||
@@ -46,6 +46,7 @@ import static com.android.server.wm.ActivityTaskManagerService.LAYOUT_REASON_CON
|
||||
import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
|
||||
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_PINNED_TASK;
|
||||
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG;
|
||||
import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED;
|
||||
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
|
||||
import static com.android.server.wm.WindowContainer.POSITION_TOP;
|
||||
|
||||
@@ -814,7 +815,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
||||
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
|
||||
break;
|
||||
}
|
||||
if (!parent.isAllowedToEmbedActivity(activity)) {
|
||||
if (parent.isAllowedToEmbedActivity(activity) != EMBEDDING_ALLOWED) {
|
||||
final Throwable exception = new SecurityException(
|
||||
"The task fragment is not trusted to embed the given activity.");
|
||||
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
|
||||
@@ -1057,7 +1058,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
||||
}
|
||||
|
||||
/** A helper method to send minimum dimension violation error to the client. */
|
||||
void sendMinimumDimensionViolation(TaskFragment taskFragment, Point minDimensions,
|
||||
private void sendMinimumDimensionViolation(TaskFragment taskFragment, Point minDimensions,
|
||||
IBinder errorCallbackToken, String reason) {
|
||||
if (taskFragment == null || taskFragment.getTaskFragmentOrganizer() == null) {
|
||||
return;
|
||||
@@ -1672,7 +1673,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
||||
// We are reparenting activities to a new embedded TaskFragment, this operation is only
|
||||
// allowed if the new parent is trusted by all reparent activities.
|
||||
final boolean isEmbeddingDisallowed = oldParent.forAllActivities(activity ->
|
||||
!newParentTF.isAllowedToEmbedActivity(activity));
|
||||
newParentTF.isAllowedToEmbedActivity(activity) == EMBEDDING_ALLOWED);
|
||||
if (isEmbeddingDisallowed) {
|
||||
final Throwable exception = new SecurityException(
|
||||
"The new parent is not trusted to embed the activities.");
|
||||
|
||||
@@ -37,6 +37,7 @@ import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
|
||||
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
||||
import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
|
||||
import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
|
||||
import static android.content.pm.ActivityInfo.FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING;
|
||||
import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
|
||||
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
|
||||
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
|
||||
@@ -52,6 +53,11 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
|
||||
import static com.android.server.wm.ActivityStarter.canEmbedActivity;
|
||||
import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED;
|
||||
import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION;
|
||||
import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_NEW_TASK;
|
||||
import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_UNTRUSTED_HOST;
|
||||
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
|
||||
import static com.android.server.wm.WindowContainer.POSITION_TOP;
|
||||
|
||||
@@ -59,6 +65,7 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
@@ -87,6 +94,7 @@ import android.os.RemoteException;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.service.voice.IVoiceInteractionSession;
|
||||
import android.util.Pair;
|
||||
import android.util.Size;
|
||||
import android.view.Gravity;
|
||||
import android.window.TaskFragmentOrganizerToken;
|
||||
|
||||
@@ -1171,6 +1179,7 @@ public class ActivityStarterTests extends WindowTestsBase {
|
||||
null /* inTask */, taskFragment);
|
||||
|
||||
assertFalse(taskFragment.hasChild());
|
||||
assertNotNull("Target record must be started on Task.", targetRecord.getParent().asTask());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1341,6 +1350,58 @@ public class ActivityStarterTests extends WindowTestsBase {
|
||||
any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCanEmbedActivity() {
|
||||
final Size minDimensions = new Size(1000, 1000);
|
||||
final WindowLayout windowLayout = new WindowLayout(0, 0, 0, 0, 0,
|
||||
minDimensions.getWidth(), minDimensions.getHeight());
|
||||
final ActivityRecord starting = new ActivityBuilder(mAtm)
|
||||
.setUid(UNIMPORTANT_UID)
|
||||
.setWindowLayout(windowLayout)
|
||||
.build();
|
||||
|
||||
// Task fragment hasn't attached to a task yet. Start activity to a new task.
|
||||
TaskFragment taskFragment = new TaskFragmentBuilder(mAtm).build();
|
||||
final Task task = new TaskBuilder(mSupervisor).build();
|
||||
|
||||
assertEquals(EMBEDDING_DISALLOWED_NEW_TASK,
|
||||
canEmbedActivity(taskFragment, starting, task));
|
||||
|
||||
// Starting activity is going to be started on a task different from task fragment's parent
|
||||
// task. Start activity to a new task.
|
||||
task.addChild(taskFragment, POSITION_TOP);
|
||||
final Task newTask = new TaskBuilder(mSupervisor).build();
|
||||
|
||||
assertEquals(EMBEDDING_DISALLOWED_NEW_TASK,
|
||||
canEmbedActivity(taskFragment, starting, newTask));
|
||||
|
||||
// Make task fragment bounds exceed task bounds.
|
||||
final Rect taskBounds = task.getBounds();
|
||||
taskFragment.setBounds(taskBounds.left, taskBounds.top, taskBounds.right + 1,
|
||||
taskBounds.bottom + 1);
|
||||
|
||||
assertEquals(EMBEDDING_DISALLOWED_UNTRUSTED_HOST,
|
||||
canEmbedActivity(taskFragment, starting, task));
|
||||
|
||||
taskFragment.setBounds(taskBounds);
|
||||
starting.info.flags |= FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING;
|
||||
|
||||
assertEquals(EMBEDDING_ALLOWED, canEmbedActivity(taskFragment, starting, task));
|
||||
|
||||
starting.info.flags &= ~FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING;
|
||||
// Set task fragment's uid as the same as starting activity's uid.
|
||||
taskFragment.setTaskFragmentOrganizer(mock(TaskFragmentOrganizerToken.class),
|
||||
UNIMPORTANT_UID, "test");
|
||||
|
||||
assertEquals(EMBEDDING_ALLOWED, canEmbedActivity(taskFragment, starting, task));
|
||||
|
||||
// Make task fragment bounds smaller than starting activity's minimum dimensions
|
||||
taskFragment.setBounds(0, 0, minDimensions.getWidth() - 1, minDimensions.getHeight() - 1);
|
||||
|
||||
assertEquals(EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION,
|
||||
canEmbedActivity(taskFragment, starting, task));
|
||||
}
|
||||
|
||||
private static void startActivityInner(ActivityStarter starter, ActivityRecord target,
|
||||
ActivityRecord source, ActivityOptions options, Task inTask,
|
||||
TaskFragment inTaskFragment) {
|
||||
|
||||
@@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
|
||||
import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED;
|
||||
import static com.android.server.wm.WindowContainer.POSITION_TOP;
|
||||
import static com.android.server.wm.testing.Assert.assertThrows;
|
||||
|
||||
@@ -530,7 +531,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
mWindowOrganizerController.mLaunchTaskFragments
|
||||
.put(mFragmentToken, mTaskFragment);
|
||||
mTransaction.reparentActivityToTaskFragment(mFragmentToken, activity.token);
|
||||
doReturn(true).when(mTaskFragment).isAllowedToEmbedActivity(activity);
|
||||
doReturn(EMBEDDING_ALLOWED).when(mTaskFragment).isAllowedToEmbedActivity(activity);
|
||||
clearInvocations(mAtm.mRootWindowContainer);
|
||||
|
||||
mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
|
||||
@@ -920,7 +921,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
.setOrganizer(mOrganizer)
|
||||
.setBounds(mTaskFragBounds)
|
||||
.build();
|
||||
doReturn(true).when(mTaskFragment).isAllowedToEmbedActivity(activity);
|
||||
mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
|
||||
|
||||
// Reparent activity to mTaskFragment, which is smaller than activity's
|
||||
@@ -956,7 +956,6 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
.setOrganizer(mOrganizer)
|
||||
.setBounds(mTaskFragBounds)
|
||||
.build();
|
||||
doReturn(true).when(mTaskFragment).isAllowedToEmbedActivity(activity);
|
||||
mWindowOrganizerController.mLaunchTaskFragments.put(oldFragToken, oldTaskFrag);
|
||||
mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user