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

Commit 706ed793 authored by Wale Ogunwale's avatar Wale Ogunwale
Browse files

Support creating/launching a task with non-fullscreen bounds

Change-Id: Icc6d6b25b5f6f236030e654a3eb3ec7f00287d2f
parent ba7881c8
Loading
Loading
Loading
Loading
+30 −3
Original line number Diff line number Diff line
@@ -80,10 +80,37 @@ interface IWindowManager
    void setEventDispatching(boolean enabled);
    void addWindowToken(IBinder token, int type);
    void removeWindowToken(IBinder token);
    void addAppToken(int addPos, IApplicationToken token, int groupId, int stackId,
    /**
     * Adds an application token to the specified task Id.
     * @param addPos The position to add the token to in the task.
     * @param token The token to add.
     * @param taskId The Id of the task we are adding the token to.
     * @param stackId Stack Id to create a new Task with the input task Id on
     *                if the task doesn't exist yet.
     * @param requestedOrientation Orientation to use.
     * @param fullscreen True if the application token is fullscreen.
     * @param showWhenLocked True if the application token should be shown when locked.
     * @param userId Id of user to associate the token with.
     * @param configChanges Input configuration changes.
     * @param voiceInteraction True if the token is in voice interaction mode.
     * @param launchTaskBehind True if the token is been launched from behind.
     * @param taskBounds Bounds to use when creating a new Task with the input task Id if
     *                   the task doesn't exist yet.
     * @return The configuration of the task if it was newly created. null otherwise.
     */
    Configuration addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
            int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
            int configChanges, boolean voiceInteraction, boolean launchTaskBehind);
    void setAppTask(IBinder token, int taskId);
            int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
            in Rect taskBounds);
    /**
     *
     * @param token The token we are adding to the input task Id.
     * @param taskId The Id of the task we are adding the token to.
     * @param taskBounds Bounds to use when creating a new Task with the input task Id if
     *                   the task doesn't exist yet.
     * @return The configuration of the task if it was newly created. null otherwise.
     */
    Configuration setAppTask(IBinder token, int taskId, in Rect taskBounds);
    void setAppOrientation(IApplicationToken token, int requestedOrientation);
    int getAppOrientation(IApplicationToken token);
    void setFocusedApp(IBinder token, boolean moveFocusNow);
+33 −18
Original line number Diff line number Diff line
@@ -25,7 +25,9 @@ import static com.android.server.am.ActivityManagerDebugConfig.*;
import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;

import android.graphics.Rect;
import android.util.ArraySet;
import android.view.IApplicationToken;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.content.ReferrerIntent;
import com.android.internal.os.BatteryStatsImpl;
@@ -2157,11 +2159,7 @@ final class ActivityStack {
                                + task, new RuntimeException("here").fillInStackTrace());
                        task.addActivityToTop(r);
                        r.putInHistory();
                        mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
                                r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
                                (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0,
                                r.userId, r.info.configChanges, task.voiceSession != null,
                                r.mLaunchTaskBehind);
                        addAppToken(r, task);
                        if (VALIDATE_TOKENS) {
                            validateAppTokensLocked();
                        }
@@ -2221,10 +2219,7 @@ final class ActivityStack {
                        : AppTransition.TRANSIT_ACTIVITY_OPEN, keepCurTransition);
                mNoAnimActivities.remove(r);
            }
            mWindowManager.addAppToken(task.mActivities.indexOf(r),
                    r.appToken, r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
                    (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId,
                    r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind);
            addAppToken(r, task);
            boolean doShow = true;
            if (newTask) {
                // Even though this activity is starting fresh, we still need
@@ -2273,10 +2268,7 @@ final class ActivityStack {
        } else {
            // If this is the first activity, don't do any fancy animations,
            // because there is nothing for it to animate on top of.
            mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
                    r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
                    (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId,
                    r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind);
            addAppToken(r, task);
            ActivityOptions.abort(options);
            options = null;
        }
@@ -2390,8 +2382,7 @@ final class ActivityStack {
                            + " out to new task " + target.task);
                }

                final int targetTaskId = targetTask.taskId;
                mWindowManager.setAppTask(target.appToken, targetTaskId);
                setAppTask(target, targetTask);

                boolean noOptions = canMoveOptions;
                final int start = replyChainEnd < 0 ? i : replyChainEnd;
@@ -2416,10 +2407,10 @@ final class ActivityStack {
                    p.setTask(targetTask, null);
                    targetTask.addActivityAtBottom(p);

                    mWindowManager.setAppTask(p.appToken, targetTaskId);
                    setAppTask(p, targetTask);
                }

                mWindowManager.moveTaskToBottom(targetTaskId);
                mWindowManager.moveTaskToBottom(targetTask.taskId);
                if (VALIDATE_TOKENS) {
                    validateAppTokensLocked();
                }
@@ -2558,7 +2549,7 @@ final class ActivityStack {
                                + " callers=" + Debug.getCallers(3));
                        if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Pulling activity " + p
                                + " from " + srcPos + " in to resetting task " + task);
                        mWindowManager.setAppTask(p.appToken, taskId);
                        setAppTask(p, task);
                    }
                    mWindowManager.moveTaskToTop(taskId);
                    if (VALIDATE_TOKENS) {
@@ -4420,6 +4411,30 @@ final class ActivityStack {
        }
    }

    void addAppToken(ActivityRecord r, TaskRecord task) {
        final Rect bounds = task.getLaunchBounds();
        final Configuration config =
                mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
                        r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
                        (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId,
                        r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind,
                        bounds);
        if (config != null) {
            task.updateOverrideConfiguration(config, bounds);
        }
        r.taskConfigOverride = task.mOverrideConfig;
    }

    private void setAppTask(ActivityRecord r, TaskRecord task) {
        final Rect bounds = task.getLaunchBounds();
        final Configuration config =
                mWindowManager.setAppTask(r.appToken, task.taskId, task.getLaunchBounds());
        if (config != null) {
            task.updateOverrideConfiguration(config, bounds);
        }
        r.taskConfigOverride = task.mOverrideConfig;
    }

    public int getStackId() {
        return mStackId;
    }
+31 −22
Original line number Diff line number Diff line
@@ -1789,20 +1789,22 @@ public final class ActivityStackSupervisor implements DisplayListener {
                return mFocusedStack;
            }

            // We first try to put the task in the first dynamic stack.
            final ArrayList<ActivityStack> homeDisplayStacks = mHomeStack.mStacks;
            for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
                stack = homeDisplayStacks.get(stackNdx);
                if (!stack.isHomeStack()) {
                final boolean isDynamicStack = stack.mStackId >= FIRST_DYNAMIC_STACK_ID;
                if (isDynamicStack) {
                    if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
                            "computeStackFocus: Setting focused stack=" + stack);
                    return stack;
                }
            }

            // TODO (multi-window): Change to select task id based on if the task should on in
            // fullscreen, freefrom, or sid-by-side stack.
            // If there is no suitable dynamic stack then we figure out which static stack to use.
            stack = getStack(
                    FULLSCREEN_WORKSPACE_STACK_ID,
                    task != null
                            ? task.getLaunchStackId(mFocusedStack) : FULLSCREEN_WORKSPACE_STACK_ID,
                    true /*createStaticStackIfNeeded*/,
                    true /*createOnTop*/);
            if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: New stack r="
@@ -2899,7 +2901,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
                Slog.wtf(TAG, "Task in WindowManager, but not in ActivityManager???");
                continue;
            }
            task.updateOverrideConfiguration(newTaskConfigs.get(i));
            task.updateOverrideConfiguration(newTaskConfigs.get(i), bounds);
        }

        if (r != null) {
@@ -2924,16 +2926,20 @@ public final class ActivityStackSupervisor implements DisplayListener {
            return;
        }

        task.mBounds = new Rect(bounds);

        if (!mWindowManager.isValidTaskId(task.taskId)) {
            // Task doesn't exist in window manager yet (e.g. was restored from recents).
            // No need to do anything else until we add the task to window manager.
            // All we can do for now is update the bounds so it can be used when the task is
            // added to window manager.
            task.mBounds = task.mLastNonFullscreenBounds = new Rect(bounds);
            if (task.stack != null && task.stack.mStackId != FREEFORM_WORKSPACE_STACK_ID) {
                // re-restore the task so it can have the proper stack association.
                restoreRecentTaskLocked(task);
            }
            return;
        }

        final Configuration overrideConfig = mWindowManager.resizeTask(task.taskId, bounds);
        if (task.updateOverrideConfiguration(overrideConfig)) {
        if (task.updateOverrideConfiguration(overrideConfig, bounds)) {
            ActivityRecord r = task.topRunningActivityLocked(null);
            if (r != null) {
                final ActivityStack stack = task.stack;
@@ -2972,13 +2978,21 @@ public final class ActivityStackSupervisor implements DisplayListener {
    }

    private boolean restoreRecentTaskLocked(TaskRecord task) {
        // TODO (multi-window): Change to select task id based on if the task should on in
        // fullscreen, freefrom, or sid-by-side stack.
        // Always put task for lean back device in home stack since they only have one stack,
        // else use the preferred stack ID to get the stack we should use if it already exists.
        ActivityStack stack = mLeanbackOnlyDevice ? mHomeStack :
                getStack(FULLSCREEN_WORKSPACE_STACK_ID,
                        true /*createStaticStackIfNeeded*/, false /*createOnTop*/);
        final int stackId =
                mLeanbackOnlyDevice ? mHomeStack.mStackId : task.getLaunchStackId(mFocusedStack);
        if (task.stack != null) {
            // Task has already been restored once. See if we need to do anything more
            if (task.stack.mStackId == stackId) {
                // Nothing else to do since it is already restored in the right stack.
                return true;
            }
            // Remove current stack association, so we can re-associate the task with the
            // right stack below.
            task.stack.removeTask(task, "restoreRecentTaskLocked", false /*notMoving*/);
        }

        ActivityStack stack =
                getStack(stackId, true /*createStaticStackIfNeeded*/, false /*createOnTop*/);

        if (stack == null) {
            // What does this mean??? Not sure how we would get here...
@@ -2992,12 +3006,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
                "Added restored task=" + task + " to stack=" + stack);
        final ArrayList<ActivityRecord> activities = task.mActivities;
        for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
            final ActivityRecord r = activities.get(activityNdx);
            mWindowManager.addAppToken(0, r.appToken, task.taskId, stack.mStackId,
                    r.info.screenOrientation, r.fullscreen,
                    (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0,
                    r.userId, r.info.configChanges, task.voiceSession != null,
                    r.mLaunchTaskBehind);
            stack.addAppToken(activities.get(activityNdx), task);
        }
        return true;
    }
+51 −6
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package com.android.server.am;

import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.FULLSCREEN_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.HOME_STACK_ID;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
@@ -94,7 +97,7 @@ final class TaskRecord {
    private static final String ATTR_CALLING_PACKAGE = "calling_package";
    private static final String ATTR_RESIZEABLE = "resizeable";
    private static final String ATTR_PRIVILEGED = "privileged";
    private static final String ATTR_BOUNDS = "bounds";
    private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds";

    private static final String TASK_THUMBNAIL_SUFFIX = "_task_thumbnail";

@@ -207,6 +210,10 @@ final class TaskRecord {

    // Bounds of the Task. null for fullscreen tasks.
    Rect mBounds = null;
    // Last non-fullscreen bounds the task was launched in or resized to.
    // The information is persisted and used to determine the appropriate stack to launch the
    // task into on restore.
    Rect mLastNonFullscreenBounds = null;

    Configuration mOverrideConfig = Configuration.EMPTY;

@@ -301,7 +308,7 @@ final class TaskRecord {
        mCallingPackage = callingPackage;
        mResizeable = resizeable;
        mPrivileged = privileged;
        mBounds = bounds;
        mBounds = mLastNonFullscreenBounds = bounds;
    }

    void touchActiveTime() {
@@ -963,8 +970,9 @@ final class TaskRecord {
        out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage);
        out.attribute(null, ATTR_RESIZEABLE, String.valueOf(mResizeable));
        out.attribute(null, ATTR_PRIVILEGED, String.valueOf(mPrivileged));
        if (mBounds != null) {
            out.attribute(null, ATTR_BOUNDS, mBounds.flattenToString());
        if (mLastNonFullscreenBounds != null) {
            out.attribute(
                    null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString());
        }

        if (affinityIntent != null) {
@@ -1084,7 +1092,7 @@ final class TaskRecord {
                resizeable = Boolean.valueOf(attrValue);
            } else if (ATTR_PRIVILEGED.equals(attrName)) {
                privileged = Boolean.valueOf(attrValue);
            } else if (ATTR_BOUNDS.equals(attrName)) {
            } else if (ATTR_NON_FULLSCREEN_BOUNDS.equals(attrName)) {
                bounds = Rect.unflattenFromString(attrValue);
            } else {
                Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName);
@@ -1155,16 +1163,53 @@ final class TaskRecord {
        return task;
    }

    boolean updateOverrideConfiguration(Configuration newConfig) {
    boolean updateOverrideConfiguration(Configuration newConfig, Rect bounds) {
        Configuration oldConfig = mOverrideConfig;
        mOverrideConfig = (newConfig == null) ? Configuration.EMPTY : newConfig;
        // We override the configuration only when the task's dimensions are different from the
        // display. In this manner, we know that if the override configuration is empty, the task
        // is necessarily fullscreen.
        mFullscreen = Configuration.EMPTY.equals(mOverrideConfig);
        if (mFullscreen) {
            if (mBounds != null) {
                mLastNonFullscreenBounds = mBounds;
            }
            mBounds = null;
        } else {
            mBounds = mLastNonFullscreenBounds = new Rect(bounds);
        }
        return !mOverrideConfig.equals(oldConfig);
    }

    /** Returns the stack that should be used to launch this task. */
    int getLaunchStackId(ActivityStack focusStack) {
        if (stack != null) {
            // We are already in a stack silly...
            return stack.mStackId;
        }
        if (isHomeTask()) {
            return HOME_STACK_ID;
        }
        if (focusStack != null && focusStack.mStackId != HOME_STACK_ID) {
            // Like it or not you are going in the focused stack!
            return focusStack.mStackId;
        }
        if (mBounds != null || mLastNonFullscreenBounds != null) {
            return FREEFORM_WORKSPACE_STACK_ID;
        }
        return FULLSCREEN_WORKSPACE_STACK_ID;
    }

    /** Returns the bounds that should be used to launch this task. */
    Rect getLaunchBounds() {
        if (stack == null
                || stack.mStackId == HOME_STACK_ID
                || stack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID) {
            return null;
        }
        return mLastNonFullscreenBounds;
    }

    void dump(PrintWriter pw, String prefix) {
        pw.print(prefix); pw.print("userId="); pw.print(userId);
                pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid);
+2 −1
Original line number Diff line number Diff line
@@ -76,12 +76,13 @@ class Task implements DimLayer.DimLayerUser {
    // of creating a new object per fullscreen task on a display.
    private static final SparseArray<DimLayer> sSharedFullscreenDimLayers = new SparseArray<>();

    Task(int taskId, TaskStack stack, int userId, WindowManagerService service) {
    Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds) {
        mTaskId = taskId;
        mStack = stack;
        mUserId = userId;
        mService = service;
        mOverrideConfig = Configuration.EMPTY;
        setBounds(bounds);
    }

    DisplayContent getDisplayContent() {
Loading