Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bd5e4df7 authored by Charles Chen's avatar Charles Chen Committed by Automerger Merge Worker
Browse files

Merge "Fix exception when opening App info on work profile" into tm-dev am: 9b6a9578

parents 3a24a74a 9b6a9578
Loading
Loading
Loading
Loading
+54 −39
Original line number Original line Diff line number Diff line
@@ -78,6 +78,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_BOUNDS;
import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY;
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.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 static com.android.server.wm.WindowContainer.POSITION_TOP;


import android.annotation.NonNull;
import android.annotation.NonNull;
@@ -131,6 +135,7 @@ import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.uri.NeededUriGrants;
import com.android.server.uri.NeededUriGrants;
import com.android.server.wm.ActivityMetricsLogger.LaunchingState;
import com.android.server.wm.ActivityMetricsLogger.LaunchingState;
import com.android.server.wm.LaunchParamsController.LaunchParams;
import com.android.server.wm.LaunchParamsController.LaunchParams;
import com.android.server.wm.TaskFragment.EmbeddingCheckResult;


import java.io.PrintWriter;
import java.io.PrintWriter;
import java.text.DateFormat;
import java.text.DateFormat;
@@ -2038,12 +2043,6 @@ class ActivityStarter {
            }
            }
        }
        }


        if (mInTaskFragment != null && !canEmbedActivity(mInTaskFragment, r, newTask, targetTask)) {
            Slog.e(TAG, "Permission denied: Cannot embed " + r + " to " + mInTaskFragment.getTask()
                    + " targetTask= " + targetTask);
            return START_PERMISSION_DENIED;
        }

        // Do not start the activity if target display's DWPC does not allow it.
        // 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
        // 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
        // startActivity() if they don't catch the exception. We don't expect 3P apps to make
@@ -2070,19 +2069,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 taskFragment the TaskFragment for embedding.
     * @param starting the starting activity.
     * @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
     * @param targetTask the target task for launching activity, which could be different from
     *                   the one who hosting the embedding.
     *                   the one who hosting the embedding.
     */
     */
    private boolean canEmbedActivity(@NonNull TaskFragment taskFragment,
    @VisibleForTesting
            @NonNull ActivityRecord starting, boolean newTask, Task targetTask) {
    @EmbeddingCheckResult
    static int canEmbedActivity(@NonNull TaskFragment taskFragment,
            @NonNull ActivityRecord starting, @NonNull Task targetTask) {
        final Task hostTask = taskFragment.getTask();
        final Task hostTask = taskFragment.getTask();
        // Not allowed embedding a separate task or without host task.
        // Not allowed embedding a separate task or without host task.
        if (hostTask == null || newTask || targetTask != hostTask) {
        if (hostTask == null || targetTask != hostTask) {
            return false;
            return EMBEDDING_DISALLOWED_NEW_TASK;
        }
        }


        return taskFragment.isAllowedToEmbedActivity(starting);
        return taskFragment.isAllowedToEmbedActivity(starting);
@@ -2894,19 +2895,16 @@ class ActivityStarter {
        mIntentDelivered = true;
        mIntentDelivered = true;
    }
    }


    /** Places {@link #mStartActivity} in {@code task} or an embedded {@link TaskFragment}. */
    private void addOrReparentStartingActivity(@NonNull Task task, String reason) {
    private void addOrReparentStartingActivity(@NonNull Task task, String reason) {
        TaskFragment newParent = task;
        TaskFragment newParent = task;
        if (mInTaskFragment != null) {
        if (mInTaskFragment != null) {
            // TODO(b/234351413): remove remaining embedded Task logic.
            int embeddingCheckResult = canEmbedActivity(mInTaskFragment, mStartActivity, task);
            // mInTaskFragment is created and added to the leaf task by task fragment organizer's
            if (embeddingCheckResult == EMBEDDING_ALLOWED) {
            // 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 {
                newParent = mInTaskFragment;
                newParent = mInTaskFragment;
            } else {
                // Start mStartActivity to task instead if it can't be embedded to mInTaskFragment.
                sendCanNotEmbedActivityError(mInTaskFragment, embeddingCheckResult);
            }
            }
        } else {
        } else {
            TaskFragment candidateTf = mAddingToTaskFragment != null ? mAddingToTaskFragment : null;
            TaskFragment candidateTf = mAddingToTaskFragment != null ? mAddingToTaskFragment : null;
@@ -2918,20 +2916,12 @@ class ActivityStarter {
                }
                }
            }
            }
            if (candidateTf != null && candidateTf.isEmbedded()
            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
                // Use the embedded TaskFragment of the top activity as the new parent if the
                // activity can be embedded.
                // activity can be embedded.
                newParent = candidateTf;
                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
        if (mStartActivity.getTaskFragment() == null
                || mStartActivity.getTaskFragment() == newParent) {
                || mStartActivity.getTaskFragment() == newParent) {
            newParent.addChild(mStartActivity, POSITION_TOP);
            newParent.addChild(mStartActivity, POSITION_TOP);
@@ -2940,16 +2930,41 @@ class ActivityStarter {
        }
        }
    }
    }


    private boolean shouldReparentInTaskFragment(Task task) {
    /**
        // The task has not been embedded. We should reparent the task to TaskFragment.
     * Notifies the client side that {@link #mStartActivity} cannot be embedded to
        if (!task.isEmbedded()) {
     * {@code taskFragment}.
            return true;
     */
    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=" + 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,
    private int adjustLaunchFlagsToDocumentMode(ActivityRecord r, boolean launchSingleInstance,
+57 −10
Original line number Original line Diff line number Diff line
@@ -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. */
    /** 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;
    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.
     * Indicate that the minimal width/height should use the default value.
     *
     *
@@ -520,20 +559,29 @@ class TaskFragment extends WindowContainer<WindowContainer> {
        return false;
        return false;
    }
    }


    boolean isAllowedToEmbedActivity(@NonNull ActivityRecord a) {
    @EmbeddingCheckResult
    int isAllowedToEmbedActivity(@NonNull ActivityRecord a) {
        return isAllowedToEmbedActivity(a, mTaskFragmentOrganizerUid);
        return isAllowedToEmbedActivity(a, mTaskFragmentOrganizerUid);
    }
    }


    /**
    /**
     * Checks if the organized task fragment is allowed to have the specified activity, which is
     * 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
     * allowed if an activity allows embedding in untrusted mode, if the trusted mode can be
     * enabled.
     * enabled, or if the organized task fragment bounds are not
     * @see #isAllowedToEmbedActivityInTrustedMode(ActivityRecord)
     * {@link #smallerThanMinDimension(ActivityRecord)}.
     *
     * @param uid   uid of the TaskFragment organizer.
     * @param uid   uid of the TaskFragment organizer.
     * @see #isAllowedToEmbedActivityInTrustedMode(ActivityRecord)
     */
     */
    boolean isAllowedToEmbedActivity(@NonNull ActivityRecord a, int uid) {
    @EmbeddingCheckResult
        return isAllowedToEmbedActivityInUntrustedMode(a)
    int isAllowedToEmbedActivity(@NonNull ActivityRecord a, int uid) {
                || isAllowedToEmbedActivityInTrustedMode(a, 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) {
    boolean smallerThanMinDimension(@NonNull ActivityRecord activity) {
@@ -550,9 +598,8 @@ class TaskFragment extends WindowContainer<WindowContainer> {
        }
        }
        final int minWidth = minDimensions.x;
        final int minWidth = minDimensions.x;
        final int minHeight = minDimensions.y;
        final int minHeight = minDimensions.y;
        final boolean smaller = taskFragBounds.width() < minWidth
        return taskFragBounds.width() < minWidth
                || taskFragBounds.height() < minHeight;
                || taskFragBounds.height() < minHeight;
        return smaller;
    }
    }


    /**
    /**
@@ -609,7 +656,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
        // The system is trusted to embed other apps securely and for all users.
        // The system is trusted to embed other apps securely and for all users.
        return UserHandle.getAppId(uid) == SYSTEM_UID
        return UserHandle.getAppId(uid) == SYSTEM_UID
                // Activities from the same UID can be embedded freely by the host.
                // Activities from the same UID can be embedded freely by the host.
                || uid == a.getUid();
                || a.isUid(uid);
    }
    }


    /**
    /**
+2 −1
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.wm;
import static android.window.TaskFragmentOrganizer.putExceptionInBundle;
import static android.window.TaskFragmentOrganizer.putExceptionInBundle;


import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
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 static com.android.server.wm.WindowOrganizerController.configurationsAreEqualForOrganizer;


import android.annotation.IntDef;
import android.annotation.IntDef;
@@ -235,7 +236,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
                        + " is not in a task belong to the organizer app.");
                        + " is not in a task belong to the organizer app.");
                return;
                return;
            }
            }
            if (!task.isAllowedToEmbedActivity(activity, mOrganizerUid)) {
            if (task.isAllowedToEmbedActivity(activity, mOrganizerUid) != EMBEDDING_ALLOWED) {
                Slog.d(TAG, "Reparent activity=" + activity.token
                Slog.d(TAG, "Reparent activity=" + activity.token
                        + " is not allowed to be embedded.");
                        + " is not allowed to be embedded.");
                return;
                return;
+4 −3
Original line number Original line Diff line number Diff line
@@ -44,6 +44,7 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANI
import static com.android.server.wm.ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED;
import static com.android.server.wm.ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED;
import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG;
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_BOTTOM;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static com.android.server.wm.WindowContainer.POSITION_TOP;


@@ -756,7 +757,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
                    sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
                    sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
                    break;
                    break;
                }
                }
                if (!parent.isAllowedToEmbedActivity(activity)) {
                if (parent.isAllowedToEmbedActivity(activity) != EMBEDDING_ALLOWED) {
                    final Throwable exception = new SecurityException(
                    final Throwable exception = new SecurityException(
                            "The task fragment is not trusted to embed the given activity.");
                            "The task fragment is not trusted to embed the given activity.");
                    sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
                    sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
@@ -988,7 +989,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
    }
    }


    /** A helper method to send minimum dimension violation error to the client. */
    /** 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) {
            IBinder errorCallbackToken, String reason) {
        if (taskFragment == null || taskFragment.getTaskFragmentOrganizer() == null) {
        if (taskFragment == null || taskFragment.getTaskFragmentOrganizer() == null) {
            return;
            return;
@@ -1582,7 +1583,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
            // We are reparenting activities to a new embedded TaskFragment, this operation is only
            // We are reparenting activities to a new embedded TaskFragment, this operation is only
            // allowed if the new parent is trusted by all reparent activities.
            // allowed if the new parent is trusted by all reparent activities.
            final boolean isEmbeddingDisallowed = oldParent.forAllActivities(activity ->
            final boolean isEmbeddingDisallowed = oldParent.forAllActivities(activity ->
                    !newParentTF.isAllowedToEmbedActivity(activity));
                    newParentTF.isAllowedToEmbedActivity(activity) == EMBEDDING_ALLOWED);
            if (isEmbeddingDisallowed) {
            if (isEmbeddingDisallowed) {
                final Throwable exception = new SecurityException(
                final Throwable exception = new SecurityException(
                        "The new parent is not trusted to embed the activities.");
                        "The new parent is not trusted to embed the activities.");
+61 −0
Original line number Original line Diff line number Diff line
@@ -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_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
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_MULTIPLE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
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.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
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_BOTTOM;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
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.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -87,6 +94,7 @@ import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.Presubmit;
import android.service.voice.IVoiceInteractionSession;
import android.service.voice.IVoiceInteractionSession;
import android.util.Pair;
import android.util.Pair;
import android.util.Size;
import android.view.Gravity;
import android.view.Gravity;
import android.window.TaskFragmentOrganizerToken;
import android.window.TaskFragmentOrganizerToken;


@@ -1172,6 +1180,7 @@ public class ActivityStarterTests extends WindowTestsBase {
                null /* inTask */, taskFragment);
                null /* inTask */, taskFragment);


        assertFalse(taskFragment.hasChild());
        assertFalse(taskFragment.hasChild());
        assertNotNull("Target record must be started on Task.", targetRecord.getParent().asTask());
    }
    }


    @Test
    @Test
@@ -1342,6 +1351,58 @@ public class ActivityStarterTests extends WindowTestsBase {
                any());
                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,
    private static void startActivityInner(ActivityStarter starter, ActivityRecord target,
            ActivityRecord source, ActivityOptions options, Task inTask,
            ActivityRecord source, ActivityOptions options, Task inTask,
            TaskFragment inTaskFragment) {
            TaskFragment inTaskFragment) {
Loading