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

Commit 339e4155 authored by Wale Ogunwale's avatar Wale Ogunwale Committed by Android (Google) Code Review
Browse files

Merge "Added support for docked stack"

parents 06f5e07a b34a7ad1
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -428,11 +428,17 @@ public class ActivityManager {
     */
    public static final int FREEFORM_WORKSPACE_STACK_ID = FULLSCREEN_WORKSPACE_STACK_ID + 1;

    /**
     * ID of stack that occupies a dedicated region of the screen.
     * @hide
     */
    public static final int DOCKED_STACK_ID = FREEFORM_WORKSPACE_STACK_ID + 1;

    /**
     * Last static stack stack ID.
     * @hide
     */
    public static final int LAST_STATIC_STACK_ID = FREEFORM_WORKSPACE_STACK_ID;
    public static final int LAST_STATIC_STACK_ID = DOCKED_STACK_ID;

    /**
     * Start of ID range used by stacks that are created dynamically.
+2 −2
Original line number Diff line number Diff line
@@ -3528,12 +3528,12 @@ class ActivityManagerProxy implements IActivityManager
        reply.recycle();
    }
    @Override
    public void resizeStack(int stackBoxId, Rect r) throws RemoteException
    public void resizeStack(int stackId, Rect r) throws RemoteException
    {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeInt(stackBoxId);
        data.writeInt(stackId);
        r.writeToParcel(data, 0);
        mRemote.transact(RESIZE_STACK_TRANSACTION, data, reply, 0);
        reply.readException();
+13 −13
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.am;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
import static android.app.ActivityManager.DOCKED_STACK_ID;
import static android.app.ActivityManager.HOME_STACK_ID;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static com.android.internal.util.XmlUtils.readBooleanAttribute;
@@ -29,6 +30,7 @@ import static com.android.internal.util.XmlUtils.writeIntAttribute;
import static com.android.internal.util.XmlUtils.writeLongAttribute;
import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
import static com.android.server.am.ActivityManagerDebugConfig.*;
import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS;
import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
@@ -8653,8 +8655,12 @@ public final class ActivityManagerService extends ActivityManagerNative
                    Slog.e(TAG, "setActivityBounds: No TaskRecord for the ActivityRecord r=" + r);
                    return;
                }
                if (task.stack != null && task.stack.mStackId == DOCKED_STACK_ID) {
                    mStackSupervisor.resizeStackLocked(task.stack.mStackId, bounds);
                } else {
                    mStackSupervisor.resizeTaskLocked(task, bounds);
                }
            }
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
@@ -9010,7 +9016,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    public void moveActivityToStack(IBinder token, int stackId) throws RemoteException {
        if (stackId == HOME_STACK_ID) {
            throw new IllegalArgumentException(
                    "moveTaskToStack: Attempt to move token " + token + " to home stack");
                    "moveActivityToStack: Attempt to move token " + token + " to home stack");
        }
        synchronized (this) {
            long ident = Binder.clearCallingIdentity();
@@ -9022,13 +9028,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                }
                if (DEBUG_STACK) Slog.d(TAG_STACK, "moveActivityToStack: moving r=" + r
                        + " to stackId=" + stackId);
                mStackSupervisor.moveTaskToStackLocked(r.task.taskId, stackId, ON_TOP);
                if (mFocusedActivity != r) {
                    setFocusedActivityLocked(r, "moveActivityToStack");
                } else {
                    mStackSupervisor.setFocusedStack(r, "moveActivityToStack");
                }
                mStackSupervisor.resumeTopActivitiesLocked(r.task.stack, null, null);
                mStackSupervisor.moveTaskToStackLocked(r.task.taskId, stackId, ON_TOP, FORCE_FOCUS);
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
@@ -9048,7 +9048,7 @@ public final class ActivityManagerService extends ActivityManagerNative
            try {
                if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToStack: moving task=" + taskId
                        + " to stackId=" + stackId + " toTop=" + toTop);
                mStackSupervisor.moveTaskToStackLocked(taskId, stackId, toTop);
                mStackSupervisor.moveTaskToStackLocked(taskId, stackId, toTop, !FORCE_FOCUS);
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
@@ -9074,9 +9074,9 @@ public final class ActivityManagerService extends ActivityManagerNative
        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
                "positionTaskInStack()");
        if (stackId == HOME_STACK_ID) {
            Slog.e(TAG, "positionTaskInStack: Attempt to change the position of task "
                    + taskId + " in/to home stack",
                    new RuntimeException("here").fillInStackTrace());
            throw new IllegalArgumentException(
                    "positionTaskInStack: Attempt to change the position of task "
                    + taskId + " in/to home stack");
        }
        synchronized (this) {
            long ident = Binder.clearCallingIdentity();
+70 −15
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.am;

import static android.app.ActivityManager.DOCKED_STACK_ID;
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;
@@ -229,6 +230,8 @@ final class ActivityStack {

    // Whether or not this stack covers the entire screen; by default stacks are fullscreen
    boolean mFullscreen = true;
    // Current bounds of the stack or null if fullscreen.
    Rect mBounds = null;

    long mLaunchStartTime = 0;
    long mFullyDrawnStartTime = 0;
@@ -1227,8 +1230,42 @@ final class ActivityStack {
        return null;
    }

    // Checks if any of the stacks above this one has a fullscreen activity behind it.
    // If so, this stack is hidden, otherwise it is visible.
    /** Returns true if the stack contains a fullscreen task. */
    private boolean hasFullscreenTask() {
        for (int i = mTaskHistory.size() - 1; i >= 0; --i) {
            final TaskRecord task = mTaskHistory.get(i);
            if (task.mFullscreen) {
                return true;
            }
        }
        return false;
    }

    /** Return true if this stack is hidden by the presence of a docked stack. */
    private boolean isHiddenByDockedStack() {
        final ActivityStack dockedStack = mStackSupervisor.getStack(DOCKED_STACK_ID);
        if (dockedStack != null) {
            final int dockedStackIndex = mStacks.indexOf(dockedStack);
            final int stackIndex = mStacks.indexOf(this);
            if (dockedStackIndex > stackIndex) {
                // Fullscreen stacks or stacks with fullscreen task below the docked stack are not
                // visible. We do this so we don't have the 2 stacks and their tasks overlap.
                if (mFullscreen) {
                    return true;
                }

                // We need to also check the tasks in the stack because they can be fullscreen
                // even though their stack isn't due to their root activity not been resizeable
                // (i.e. doesn't support multi-window mode).
                if (hasFullscreenTask()) {
                    return true;
                }
            }
        }
        return false;
    }

    /** Returns true if the stack is considered visible. */
    private boolean isStackVisibleLocked() {
        if (!isAttached()) {
            return false;
@@ -1238,12 +1275,15 @@ final class ActivityStack {
            return true;
        }

        // Any stack that isn't the front stack is not visible, except for the case of the home
        // stack behind the main application stack since we can have dialog activities on the
        // main application stack that need the home stack to display behind them.
        // TODO(multi-window): Also need to add exception for side-by-side stacks.
        final boolean homeStack = mStackId == HOME_STACK_ID;
        if (!homeStack) {
        final int stackIndex = mStacks.indexOf(this);

        if (stackIndex == mStacks.size() - 1) {
            Slog.wtf(TAG,
                    "Stack=" + this + " isn't front stack but is at the top of the stack list");
            return false;
        }

        if (isHiddenByDockedStack()) {
            return false;
        }

@@ -1252,13 +1292,24 @@ final class ActivityStack {
         * fullscreen activity, or a translucent activity that requested the
         * wallpaper to be shown behind it.
         */
        for (int i = mStacks.indexOf(this) + 1; i < mStacks.size(); i++) {
        for (int i = stackIndex + 1; i < mStacks.size(); i++) {
            final ActivityStack stack = mStacks.get(i);
            if (stack.mStackId != FULLSCREEN_WORKSPACE_STACK_ID) {
            final ArrayList<TaskRecord> tasks = stack.getAllTasks();

            if (!stack.mFullscreen && !stack.hasFullscreenTask()) {
                continue;
            }

            if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID
                    || stack.mStackId == HOME_STACK_ID) {
                // The freeform and home stacks can't have any other stack visible behind them
                // when they are fullscreen since they act as base/cut-off points for visibility.
                // NOTE: we don't cut-off at the FULLSCREEN_WORKSPACE_STACK_ID because the home
                // stack sometimes needs to be visible behind it when it is displaying a dialog
                // activity. We let it fall through to the logic below to determine visibility.
                return false;
            }

            final ArrayList<TaskRecord> tasks = stack.getAllTasks();
            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
                final TaskRecord task = tasks.get(taskNdx);
                // task above isn't fullscreen, so, we assume we're still visible.
@@ -2680,9 +2731,10 @@ final class ActivityStack {
            ActivityRecord next = topRunningActivityLocked(null);
            final String myReason = reason + " adjustFocus";
            if (next != r) {
                if (next != null && mStackId == FREEFORM_WORKSPACE_STACK_ID) {
                    // For freeform stack we always keep the focus within the stack as long as
                    // there is a running activity in the stack that we can adjust focus to.
                if (next != null && (mStackId == FREEFORM_WORKSPACE_STACK_ID
                        || mStackId == DOCKED_STACK_ID)) {
                    // For freeform and docked stacks we always keep the focus within the stack as
                    // long as there is a running activity in the stack that we can adjust focus to.
                    mService.setFocusedActivityLocked(next, myReason);
                    return;
                } else {
@@ -4321,7 +4373,10 @@ final class ActivityStack {
            printed |= ActivityStackSupervisor.dumpHistoryList(fd, pw,
                    mTaskHistory.get(taskNdx).mActivities, "    ", "Hist", true, !dumpAll,
                    dumpClient, dumpPackage, needSep, header,
                    "    Task id #" + task.taskId);
                    "    Task id #" + task.taskId + "\n" +
                    "    mFullscreen=" + task.mFullscreen + "\n" +
                    "    mBounds=" + task.mBounds + "\n" +
                    "    mLastNonFullscreenBounds=" + task.mLastNonFullscreenBounds);
            if (printed) {
                header = null;
            }
+87 −16
Original line number Diff line number Diff line
@@ -184,6 +184,9 @@ public final class ActivityStackSupervisor implements DisplayListener {
    // (e.g. stack) is due to it moving to another container.
    static final boolean MOVING = true;

    // Force the focus to change to the stack we are moving a task to..
    static final boolean FORCE_FOCUS = true;

    // Activity actions an app cannot start if it uses a permission which is not granted.
    private static final ArrayMap<String, String> ACTION_TO_RUNTIME_PERMISSION =
            new ArrayMap<>();
@@ -328,6 +331,9 @@ public final class ActivityStackSupervisor implements DisplayListener {
    /** Used to keep resumeTopActivityLocked() from being entered recursively */
    boolean inResumeTopActivity;

    // temp. rect used during resize calculation so we don't need to create a new object each time.
    private final Rect tempRect = new Rect();

    /**
     * Description of a request to start a new activity, which has been held
     * due to app switches being disabled.
@@ -2908,16 +2914,13 @@ public final class ActivityStackSupervisor implements DisplayListener {
            return;
        }

        final ActivityRecord r = stack.topRunningActivityLocked(null);
        if (r != null && !r.task.mResizeable) {
            Slog.w(TAG, "resizeStack: top task " + r.task + " not resizeable.");
            return;
        }
        ActivityRecord r = stack.topRunningActivityLocked(null);
        final boolean resizeTasks = r != null && r.task.mResizeable;

        final IntArray changedTaskIds = new IntArray(stack.numTasks());
        final List<Configuration> newTaskConfigs = new ArrayList<>(stack.numTasks());
        stack.mFullscreen =
                mWindowManager.resizeStack(stackId, bounds, changedTaskIds, newTaskConfigs);
        stack.mFullscreen = mWindowManager.resizeStack(
                stackId, bounds, resizeTasks, changedTaskIds, newTaskConfigs);
        for (int i = changedTaskIds.size() - 1; i >= 0; i--) {
            final TaskRecord task = anyTaskForIdLocked(changedTaskIds.get(i), false);
            if (task == null) {
@@ -2927,6 +2930,55 @@ public final class ActivityStackSupervisor implements DisplayListener {
            task.updateOverrideConfiguration(newTaskConfigs.get(i), bounds);
        }

        if (stack.mStackId == DOCKED_STACK_ID) {
            // Dock stack funness...Yay!
            if (stack.mFullscreen) {
                // The dock stack went fullscreen which is kinda like dismissing it.
                // In this case we make all other static stacks fullscreen and move all
                // docked stack tasks to the fullscreen stack.
                for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
                    if (i != DOCKED_STACK_ID) {
                        resizeStackLocked(i, null);
                    }
                }

                final ArrayList<TaskRecord> tasks = stack.getAllTasks();
                final int count = tasks.size();
                for (int i = 0; i < count; i++) {
                    moveTaskToStackLocked(tasks.get(i).taskId,
                            FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, FORCE_FOCUS);
                }

                // stack shouldn't contain anymore activities, so nothing to resume.
                r = null;
            } else {
                // Docked stacks occupy a dedicated region on screen so the size of all other
                // static stacks need to be adjusted so they don't overlap with the docked stack.
                final int leftChange = stack.mBounds.left - bounds.left;
                final int rightChange = stack.mBounds.right - bounds.right;
                final int topChange = stack.mBounds.top - bounds.top;
                final int bottomChange = stack.mBounds.bottom - bounds.bottom;

                for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
                    if (i != DOCKED_STACK_ID) {
                        ActivityStack otherStack = getStack(i);
                        if (otherStack != null) {
                            tempRect.set(otherStack.mBounds);
                            // We adjust the opposing sides of the other stacks to
                            // the side in the dock stack that changed.
                            tempRect.left -= rightChange;
                            tempRect.right -= leftChange;
                            tempRect.top -= bottomChange;
                            tempRect.bottom -= topChange;
                            resizeStackLocked(i, tempRect);
                        }
                    }
                }

            }
        }
        stack.mBounds = stack.mFullscreen ? null : new Rect(bounds);

        if (r != null) {
            final boolean updated = stack.ensureActivityConfigurationLocked(r, 0);
            // And we need to make sure at this point that all other activities
@@ -2968,7 +3020,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
        final boolean wasFrontStack = isFrontStack(task.stack);
        if (bounds == null && stackId != FULLSCREEN_WORKSPACE_STACK_ID) {
            stackId = FULLSCREEN_WORKSPACE_STACK_ID;
        } else if (bounds != null && task.stack.mStackId != FREEFORM_WORKSPACE_STACK_ID) {
        } else if (bounds != null
                && stackId != FREEFORM_WORKSPACE_STACK_ID && stackId != DOCKED_STACK_ID) {
            stackId = FREEFORM_WORKSPACE_STACK_ID;
        }
        if (stackId != task.stack.mStackId) {
@@ -3069,8 +3122,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
     */
    private ActivityStack moveTaskToStackUncheckedLocked(
            TaskRecord task, int stackId, boolean toTop, String reason) {
        final ActivityStack stack =
                getStack(stackId, CREATE_IF_NEEDED, toTop);
        final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, toTop);
        mWindowManager.moveTaskToStack(task.taskId, stack.mStackId, toTop);
        if (task.stack != null) {
            task.stack.removeTask(task, reason, MOVING);
@@ -3079,26 +3131,39 @@ public final class ActivityStackSupervisor implements DisplayListener {
        return stack;
    }

    void moveTaskToStackLocked(int taskId, int stackId, boolean toTop) {
    void moveTaskToStackLocked(int taskId, int stackId, boolean toTop, boolean forceFocus) {
        final TaskRecord task = anyTaskForIdLocked(taskId);
        if (task == null) {
            Slog.w(TAG, "moveTaskToStack: no task for id=" + taskId);
            return;
        }
        ActivityStack stack =
                moveTaskToStackUncheckedLocked(task, stackId, toTop, "moveTaskToStack");
        final String reason = "moveTaskToStack";
        final ActivityRecord top = task.topRunningActivityLocked(null);
        final boolean adjustFocus = forceFocus || mService.mFocusedActivity == top;
        final ActivityStack stack =
                moveTaskToStackUncheckedLocked(task, stackId, toTop, reason);

        // Make sure the task has the appropriate bounds/size for the stack it is in.
        if (stackId == FULLSCREEN_WORKSPACE_STACK_ID && task.mBounds != null) {
            resizeTaskLocked(task, null);
            resizeTaskLocked(task, stack.mBounds);
        } else if (stackId == FREEFORM_WORKSPACE_STACK_ID
                && task.mBounds == null && task.mLastNonFullscreenBounds != null) {
            resizeTaskLocked(task, task.mLastNonFullscreenBounds);
        } else if (stackId == DOCKED_STACK_ID) {
            resizeTaskLocked(task, stack.mBounds);
        }

        if (top != null && adjustFocus) {
            if (mService.mFocusedActivity != top) {
                mService.setFocusedActivityLocked(top, reason);
            } else {
                setFocusedStack(top, reason);
            }
        }

        // The task might have already been running and its visibility needs to be synchronized with
        // the visibility of the stack / windows.
        stack.ensureActivitiesVisibleLocked(null, 0);
        ensureActivitiesVisibleLocked(null, 0);
        resumeTopActivitiesLocked();
    }

@@ -3659,6 +3724,10 @@ public final class ActivityStackSupervisor implements DisplayListener {
                stackHeader.append("  Stack #");
                stackHeader.append(stack.mStackId);
                stackHeader.append(":");
                stackHeader.append("\n");
                stackHeader.append("  mFullscreen=" + stack.mFullscreen);
                stackHeader.append("\n");
                stackHeader.append("  mBounds=" + stack.mBounds);
                printed |= stack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage,
                        needSep, stackHeader.toString());
                printed |= dumpHistoryList(fd, pw, stack.mLRUActivities, "    ", "Run", false,
@@ -4313,7 +4382,9 @@ public final class ActivityStackSupervisor implements DisplayListener {
            mStack.mStacks = activityDisplay.mStacks;

            activityDisplay.attachActivities(mStack, onTop);
            mStack.mBounds =
                    mWindowManager.attachStack(mStackId, activityDisplay.mDisplayId, onTop);
            mStack.mFullscreen = mStack.mBounds == null;
        }

        @Override
Loading