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

Commit 079a0044 authored by Wale Ogunwale's avatar Wale Ogunwale
Browse files

API for moving top activity in a stack to pinned stack.

* AMS.moveTopStackActivityToPinnedStack can be used to move the top
activity in a stack to the pinned stack and also specify the bounds
the pinned stack should be sized to.
* 'am stack move-top-activity-to-pinned-stack' command for testing
AMS.moveTopStackActivityToPinnedStack API

Bug: 25006507
Change-Id: I8392b4c39d8542153e691be7a627b7f35fd44884
parent 99db1863
Loading
Loading
Loading
Loading
+42 −75
Original line number Diff line number Diff line
@@ -154,7 +154,7 @@ public class Am extends BaseCommand {
                "       am stack movetask <TASK_ID> <STACK_ID> [true|false]\n" +
                "       am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
                "       am stack size-docked-stack-test: <STEP_SIZE> <l|t|r|b> [DELAY_MS]\n" +
                "       am stack split <STACK_ID> <v|h> [INTENT]\n" +
                "       am stack move-top-activity-to-pinned-stack: <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
                "       am stack positiontask <TASK_ID> <STACK_ID> <POSITION>\n" +
                "       am stack list\n" +
                "       am stack info <STACK_ID>\n" +
@@ -297,11 +297,9 @@ public class Am extends BaseCommand {
                "   <STEP_SIZE> increments from the side <l>eft, <t>op, <r>ight, or <b>ottom\n" +
                "   applying the optional [DELAY_MS] between each step.\n" +
                "\n" +
                "am stack split: split <STACK_ID> into 2 stacks <v>ertically or <h>orizontally\n" +
                "   starting the new stack with [INTENT] if specified. If [INTENT] isn't\n" +
                "   specified and the current stack has more than one task, then the top task\n" +
                "   of the current task will be moved to the new stack. Command will also force\n" +
                "   all current tasks in both stacks to be resizeable.\n" +
                "am stack move-top-activity-to-pinned-stack: moves the top activity from\n" +
                "   <STACK_ID> to the pinned stack using <LEFT,TOP,RIGHT,BOTTOM> for the\n" +
                "   bounds of the pinned stack.\n" +
                "\n" +
                "am stack positiontask: place <TASK_ID> in <STACK_ID> at <POSITION>" +
                "\n" +
@@ -1954,25 +1952,34 @@ public class Am extends BaseCommand {

    private void runStack() throws Exception {
        String op = nextArgRequired();
        if (op.equals("start")) {
        switch (op) {
            case "start":
                runStackStart();
        } else if (op.equals("movetask")) {
                break;
            case "movetask":
                runStackMoveTask();
        } else if (op.equals("resize")) {
                break;
            case "resize":
                runStackResize();
        } else if (op.equals("positiontask")) {
                break;
            case "positiontask":
                runStackPositionTask();
        } else if (op.equals("list")) {
                break;
            case "list":
                runStackList();
        } else if (op.equals("info")) {
                break;
            case "info":
                runStackInfo();
        } else if (op.equals("split")) {
            runStackSplit();
        } else if (op.equals("size-docked-stack-test")) {
                break;
            case "move-top-activity-to-pinned-stack":
                runMoveTopActivityToPinnedStack();
                break;
            case "size-docked-stack-test":
                runStackSizeDockedStackTest();
        } else {
                break;
            default:
                showError("Error: unknown command '" + op + "'");
            return;
                break;
        }
    }

@@ -2072,61 +2079,21 @@ public class Am extends BaseCommand {
        }
    }

    private void runStackSplit() throws Exception {
        final int stackId = Integer.valueOf(nextArgRequired());
        final String splitDirection = nextArgRequired();
        Intent intent = null;
        try {
            intent = makeIntent(UserHandle.USER_CURRENT);
        } catch (IllegalArgumentException e) {
            // no intent supplied.
        }

        try {
            final StackInfo currentStackInfo = mAm.getStackInfo(stackId);
            // Calculate bounds for new and current stack.
            final Rect currentStackBounds = new Rect(currentStackInfo.bounds);
            final Rect newStackBounds = new Rect(currentStackInfo.bounds);
            if ("v".equals(splitDirection)) {
                currentStackBounds.right = newStackBounds.left = currentStackInfo.bounds.centerX();
            } else if ("h".equals(splitDirection)) {
                currentStackBounds.bottom = newStackBounds.top = currentStackInfo.bounds.centerY();
            } else {
                showError("Error: unknown split direction '" + splitDirection + "'");
    private void runMoveTopActivityToPinnedStack() throws Exception {
        int stackId = Integer.valueOf(nextArgRequired());
        final Rect bounds = getBounds();
        if (bounds == null) {
            System.err.println("Error: invalid input bounds");
            return;
        }

            // Create new stack
            IActivityContainer container = mAm.createStackOnDisplay(currentStackInfo.displayId);
            if (container == null) {
                showError("Error: Unable to create new stack...");
            }

            final int newStackId = container.getStackId();

            if (intent != null) {
                container.startActivity(intent);
            } else if (currentStackInfo.taskIds != null && currentStackInfo.taskIds.length > 1) {
                // Move top task over to new stack
                mAm.moveTaskToStack(currentStackInfo.taskIds[currentStackInfo.taskIds.length - 1],
                        newStackId, true);
            }

            final StackInfo newStackInfo = mAm.getStackInfo(newStackId);

            // Make all tasks in the stacks resizeable.
            for (int taskId : currentStackInfo.taskIds) {
                mAm.setTaskResizeable(taskId, true);
            }

            for (int taskId : newStackInfo.taskIds) {
                mAm.setTaskResizeable(taskId, true);
        try {
            if (!mAm.moveTopActivityToPinnedStack(stackId, bounds)) {
                showError("Didn't move top activity to pinned stack.");
            }

            // Resize stacks
            mAm.resizeStack(currentStackInfo.stackId, currentStackBounds, false);
            mAm.resizeStack(newStackInfo.stackId, newStackBounds, false);
        } catch (RemoteException e) {
            showError("Unable to move top activity: " + e);
            return;
        }
    }

+26 −0
Original line number Diff line number Diff line
@@ -755,6 +755,16 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
            return true;
        }

        case MOVE_TOP_ACTIVITY_TO_PINNED_STACK: {
            data.enforceInterface(IActivityManager.descriptor);
            final int stackId = data.readInt();
            final Rect r = Rect.CREATOR.createFromParcel(data);
            final boolean res = moveTopActivityToPinnedStack(stackId, r);
            reply.writeNoException();
            reply.writeInt(res ? 1 : 0);
            return true;
        }

        case RESIZE_STACK_TRANSACTION: {
            data.enforceInterface(IActivityManager.descriptor);
            final int stackId = data.readInt();
@@ -3555,6 +3565,22 @@ class ActivityManagerProxy implements IActivityManager
        reply.recycle();
    }
    @Override
    public boolean moveTopActivityToPinnedStack(int stackId, Rect r)
        throws RemoteException
    {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeInt(stackId);
        r.writeToParcel(data, 0);
        mRemote.transact(MOVE_TOP_ACTIVITY_TO_PINNED_STACK, data, reply, 0);
        reply.readException();
        final boolean res = reply.readInt() != 0;
        data.recycle();
        reply.recycle();
        return res;
    }
    @Override
    public void resizeStack(int stackId, Rect r, boolean allowResizeInDockedMode)
            throws RemoteException
    {
+2 −0
Original line number Diff line number Diff line
@@ -143,6 +143,7 @@ public interface IActivityManager extends IInterface {
    public void moveTaskToStack(int taskId, int stackId, boolean toTop) throws RemoteException;
    public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop)
            throws RemoteException;
    public boolean moveTopActivityToPinnedStack(int stackId, Rect bounds) throws RemoteException;
    public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode) throws RemoteException;
    public void positionTaskInStack(int taskId, int stackId, int position) throws RemoteException;
    public List<StackInfo> getAllStackInfos() throws RemoteException;
@@ -898,4 +899,5 @@ public interface IActivityManager extends IInterface {
    int MOVE_TASK_TO_DOCKED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 346;
    int SUPPRESS_RESIZE_CONFIG_CHANGES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 347;
    int REMOVE_STACK = IBinder.FIRST_CALL_TRANSACTION + 348;
    int MOVE_TOP_ACTIVITY_TO_PINNED_STACK = IBinder.FIRST_CALL_TRANSACTION + 349;
}
+23 −0
Original line number Diff line number Diff line
@@ -9083,6 +9083,29 @@ public final class ActivityManagerService extends ActivityManagerNative
        }
    }
    /**
     * Moves the top activity in the input stackId to the pinned stack.
     *
     * @param stackId Id of stack to move the top activity to pinned stack.
     * @param bounds Bounds to use for pinned stack.
     *
     * @return True if the top activity of the input stack was successfully moved to the pinned
     *          stack.
     */
    @Override
    public boolean moveTopActivityToPinnedStack(int stackId, Rect bounds) {
        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
                "moveTopActivityToPinnedStack()");
        synchronized (this) {
            long ident = Binder.clearCallingIdentity();
            try {
                return mStackSupervisor.moveTopStackActivityToPinnedStackLocked(stackId, bounds);
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }
    }
    @Override
    public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode) {
        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
+45 −0
Original line number Diff line number Diff line
@@ -4642,6 +4642,51 @@ final class ActivityStack {
        r.taskConfigOverride = task.mOverrideConfig;
    }

    void setFocusAndResumeStateIfNeeded(
            ActivityRecord r, boolean setFocus, boolean setResume, String reason) {
        // If the activity had focus before move focus to this stack.
        if (setFocus) {
            // If the activity owns the last resumed activity, transfer that together,
            // so that we don't resume the same activity again in the new stack.
            // Apps may depend on onResume()/onPause() being called in pairs.
            if (setResume) {
                mResumedActivity = r;
                // Move the stack in which we are placing the activity to the front. We don't use
                // ActivityManagerService.setFocusedActivityLocked, because if the activity is
                // already focused, the call will short-circuit and do nothing.
                moveToFront(reason);
            } else {
                // We need to not only move the stack to the front, but also have the activity
                // focused. This will achieve both goals.
                mService.setFocusedActivityLocked(r, reason);
            }
        }
    }

    /**
     * Moves the input activity from its current stack to this one.
     * NOTE: The current task of the activity isn't moved to this stack. Instead a new task is
     * created on this stack which the activity is added to.
     * */
    void moveActivityToStack(ActivityRecord r) {
        final ActivityStack prevStack = r.task.stack;
        if (prevStack.mStackId == mStackId) {
            // You are already in the right stack silly...
            return;
        }

        final boolean wasFocused = mStackSupervisor.isFrontStack(prevStack)
                && (mStackSupervisor.topRunningActivityLocked() == r);
        final boolean wasResumed = wasFocused && (prevStack.mResumedActivity == r);

        final TaskRecord task = createTaskRecord(
                mStackSupervisor.getNextTaskId(), r.info, r.intent, null, null, true);
        r.setTask(task, null);
        task.addActivityToTop(r);
        setAppTask(r, task);
        setFocusAndResumeStateIfNeeded(r, wasFocused, wasResumed, "moveActivityToStack");
    }

    private void setAppTask(ActivityRecord r, TaskRecord task) {
        final Rect bounds = task.getLaunchBounds();
        task.updateOverrideConfiguration(bounds);
Loading