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

Commit 8a2f913a authored by Robert Carr's avatar Robert Carr
Browse files

Introduce TaskOrganizer

A first take at the TaskOrganizer API for allowing SysUI to control task presentation.
In this CL we introduce the first two primitives:
        1. The interface itself for implementation by SysUI
        2. Support for organizing a given windowing mode (but atm really only PIP)
We include a sample app that manages the PIP from an APPLICATION_OVERLAY window.

Bug: 139371701
Test: wmtests/TaskOrganizerTests. TaskOrganizerPipTest
Change-Id: I44a8ed311bc5f06285bba2c6ff3b37a7d19a9190
parent b130bfbe
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ import android.os.StrictMode;
import android.os.WorkSource;
import android.service.voice.IVoiceInteractionSession;
import android.view.IRecentsAnimationRunner;
import android.view.ITaskOrganizer;
import android.view.RemoteAnimationDefinition;
import android.view.RemoteAnimationAdapter;
import android.view.WindowContainerTransaction;
@@ -121,6 +122,9 @@ interface IActivityTaskManager {
            in Intent intent, in String resolvedType, in IBinder resultTo, in String resultWho,
            int requestCode, int flags, in ProfilerInfo profilerInfo, in Bundle options,
            IBinder permissionToken, boolean ignoreTargetSecurity, int userId);

    void registerTaskOrganizer(in ITaskOrganizer organizer, int windowingMode);

    boolean isActivityStartAllowedOnDisplay(int displayId, in Intent intent, in String resolvedType,
            int userId);

+38 −0
Original line number Diff line number Diff line
/* //device/java/android/android/view/ITaskOrganizer.aidl
**
** Copyright 2019, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/

package android.view;

import android.view.IWindowContainer;
import android.view.SurfaceControl;
import android.app.ActivityManager;

/**
 * Interface for ActivityTaskManager/WindowManager to delegate control of tasks.
 * {@hide}
 */
oneway interface ITaskOrganizer {
    void taskAppeared(in IWindowContainer container,
        in ActivityManager.RunningTaskInfo taskInfo);
    void taskVanished(in IWindowContainer container);

    /**
     * Called upon completion of
     * ActivityTaskManagerService#applyTaskOrganizerTransaction
     */
    void transactionReady(int id, in SurfaceControl.Transaction t);
}
 No newline at end of file
+33 −0
Original line number Diff line number Diff line
@@ -62,6 +62,18 @@ public class WindowContainerTransaction implements Parcelable {
        return this;
    }

    /**
     * Notify activies within the hiearchy of a container that they have entered picture-in-picture
     * mode with the given bounds.
     */
    public WindowContainerTransaction scheduleFinishEnterPip(IWindowContainer container,
            Rect bounds) {
        Change chg = getOrCreateChange(container.asBinder());
        chg.mSchedulePipCallback = true;
        chg.mPinnedBounds = new Rect(bounds);
        return this;
    }

    public Map<IBinder, Change> getChanges() {
        return mChanges;
    }
@@ -104,12 +116,20 @@ public class WindowContainerTransaction implements Parcelable {
        private @ActivityInfo.Config int mConfigSetMask = 0;
        private @WindowConfiguration.WindowConfig int mWindowSetMask = 0;

        private boolean mSchedulePipCallback = false;
        private Rect mPinnedBounds = null;

        public Change() {}

        protected Change(Parcel in) {
            mConfiguration.readFromParcel(in);
            mConfigSetMask = in.readInt();
            mWindowSetMask = in.readInt();
            mSchedulePipCallback = (in.readInt() != 0);
            if (mSchedulePipCallback ) {
                mPinnedBounds = new Rect();
                mPinnedBounds.readFromParcel(in);
            }
        }

        public Configuration getConfiguration() {
@@ -126,6 +146,14 @@ public class WindowContainerTransaction implements Parcelable {
            return mWindowSetMask;
        }

        /**
         * Returns the bounds to be used for scheduling the enter pip callback
         * or null if no callback is to be scheduled.
         */
        public Rect getEnterPipBounds() {
            return mPinnedBounds;
        }

        @Override
        public String toString() {
            final boolean changesBounds =
@@ -151,6 +179,11 @@ public class WindowContainerTransaction implements Parcelable {
            mConfiguration.writeToParcel(dest, flags);
            dest.writeInt(mConfigSetMask);
            dest.writeInt(mWindowSetMask);

            dest.writeInt(mSchedulePipCallback ? 1 : 0);
            if (mSchedulePipCallback ) {
                mPinnedBounds.writeToParcel(dest, flags);
            }
        }

        @Override
+47 −0
Original line number Diff line number Diff line
@@ -163,6 +163,7 @@ import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.view.ITaskOrganizer;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -803,6 +804,16 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn
        setWindowingMode(windowingMode, false /* animate */, false /* showRecents */,
                false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */,
                false /* creating */);

        windowingMode = getWindowingMode();
        /*
         * Different windowing modes may be managed by different task organizers. If
         * getTaskOrganizer returns null, we still call transferToTaskOrganizer to
         * make sure we clear it.
         */
        final ITaskOrganizer org =
            mWmService.mAtmService.mTaskOrganizerController.getTaskOrganizer(windowingMode);
        transferToTaskOrganizer(org);
    }

    /**
@@ -1649,6 +1660,33 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn
        return topActivity != null && topActivity.mVisibleRequested;
    }

    /**
     * Indicate whether the first task in this stack is controlled by a TaskOrganizer. We aren't
     * expecting to use the TaskOrganizer in multiple task per stack scenarios so checking
     * the first one is ok.
     */
    boolean isControlledByTaskOrganizer() {
        return getChildCount() > 0 && getTopMostTask().mTaskOrganizer != null;
    }

    private static void transferSingleTaskToOrganizer(Task tr, ITaskOrganizer organizer) {
        tr.setTaskOrganizer(organizer);
    }

    /**
     * Transfer control of the leashes and IWindowContainers to the given ITaskOrganizer.
     * This will (or shortly there-after) invoke the taskAppeared callbacks.
     * If the tasks had a previous TaskOrganizer, setTaskOrganizer will take care of
     * emitting the taskVanished callbacks.
     */
    void transferToTaskOrganizer(ITaskOrganizer organizer) {
        final PooledConsumer c = PooledLambda.obtainConsumer(
                ActivityStack::transferSingleTaskToOrganizer,
                PooledLambda.__(Task.class), organizer);
        forAllTasks(c);
        c.recycle();
    }

    /**
     * Returns true if the stack should be visible.
     *
@@ -3577,6 +3615,15 @@ class ActivityStack extends WindowContainer<WindowContainer> implements BoundsAn
    void animateResizePinnedStack(Rect toBounds, Rect sourceHintBounds, int animationDuration,
            boolean fromFullscreen) {
        if (!inPinnedWindowingMode()) return;

        /**
         * TODO(b/146594635): Remove all PIP animation code from WM once SysUI handles animation.
         * If this PIP Task is controlled by a TaskOrganizer, the animation occurs entirely
         * on the TaskOrganizer side, so we just hand over the leash without doing any animation.
         * We have to be careful to not schedule the enter-pip callback as the TaskOrganizer
         * needs to have flexibility to schedule that at an appropriate point in the animation.
         */
        if (isControlledByTaskOrganizer()) return;
        if (toBounds == null /* toFullscreen */) {
            final Configuration parentConfig = getParent().getConfiguration();
            final ActivityRecord top = topRunningNonOverlayTaskActivity();
+1 −0
Original line number Diff line number Diff line
@@ -2574,6 +2574,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
        final PooledConsumer c = PooledLambda.obtainConsumer(
                ActivityRecord::updatePictureInPictureMode,
                PooledLambda.__(ActivityRecord.class), targetStackBounds, forceUpdate);
        task.getStack().setBounds(targetStackBounds);
        task.forAllActivities(c);
        c.recycle();
    }
Loading