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

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

Merge "Add launch cookie support to activities/tasks"

parents 6b30447a 0227500a
Loading
Loading
Loading
Loading
+31 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import android.graphics.Rect;
import android.hardware.HardwareBuffer;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.Parcel;
import android.os.Parcelable;
@@ -306,6 +307,12 @@ public class ActivityOptions {
    private static final String KEY_REMOTE_ANIMATION_ADAPTER
            = "android:activity.remoteAnimationAdapter";

    /**
     * @see #setLaunchCookie
     * @hide
     */
    private static final String KEY_LAUNCH_COOKIE = "android.activity.launchCookie";

    /** @hide */
    public static final int ANIM_UNDEFINED = -1;
    /** @hide */
@@ -381,6 +388,7 @@ public class ActivityOptions {
    private Bundle mAppVerificationBundle;
    private IAppTransitionAnimationSpecsFuture mSpecsFuture;
    private RemoteAnimationAdapter mRemoteAnimationAdapter;
    private IBinder mLaunchCookie;

    /**
     * Create an ActivityOptions specifying a custom animation to run when
@@ -1071,6 +1079,7 @@ public class ActivityOptions {
                    KEY_SPECS_FUTURE));
        }
        mRemoteAnimationAdapter = opts.getParcelable(KEY_REMOTE_ANIMATION_ADAPTER);
        mLaunchCookie = opts.getBinder(KEY_LAUNCH_COOKIE);
    }

    /**
@@ -1495,6 +1504,25 @@ public class ActivityOptions {
        return mApplyActivityFlagsForBubbles;
    }

    /**
     * Sets a launch cookie that can be used to track the activity and task that are launch as a
     * result of this option.
     *
     * @hide
     */
    public void setLaunchCookie(IBinder launchCookie) {
        mLaunchCookie = launchCookie;
    }

    /**
     * @return The launch tracking cookie if set or {@code null} otherwise.
     *
     * @hide
     */
    public IBinder getLaunchCookie() {
        return mLaunchCookie;
    }

    /**
     * Update the current values in this ActivityOptions from those supplied
     * in <var>otherOptions</var>.  Any values
@@ -1717,6 +1745,9 @@ public class ActivityOptions {
        if (mRemoteAnimationAdapter != null) {
            b.putParcelable(KEY_REMOTE_ANIMATION_ADAPTER, mRemoteAnimationAdapter);
        }
        if (mLaunchCookie != null) {
            b.putBinder(KEY_LAUNCH_COOKIE, mLaunchCookie);
        }
        return b;
    }

+27 −37
Original line number Diff line number Diff line
@@ -24,11 +24,14 @@ import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;
import android.window.WindowContainerToken;

import java.util.ArrayList;

/**
 * Stores information about a particular Task.
 */
@@ -177,6 +180,13 @@ public class TaskInfo {
     */
    public boolean isResizeable;

    /**
     * The launch cookies associated with activities in this task if any.
     * @see ActivityOptions#setLaunchCookie(IBinder)
     * @hide
     */
    public ArrayList<IBinder> launchCookies = new ArrayList<>();

    TaskInfo() {
        // Do nothing
    }
@@ -213,6 +223,11 @@ public class TaskInfo {
        return configuration;
    }

    /** @hide */
    public void addLaunchCookie(IBinder cookie) {
        launchCookies.add(cookie);
    }

    /**
     * Reads the TaskInfo from a parcel.
     */
@@ -222,9 +237,7 @@ public class TaskInfo {
        taskId = source.readInt();
        displayId = source.readInt();
        isRunning = source.readBoolean();
        baseIntent = source.readInt() != 0
                ? Intent.CREATOR.createFromParcel(source)
                : null;
        baseIntent = source.readTypedObject(Intent.CREATOR);
        baseActivity = ComponentName.readFromParcel(source);
        topActivity = ComponentName.readFromParcel(source);
        origActivity = ComponentName.readFromParcel(source);
@@ -233,21 +246,16 @@ public class TaskInfo {
        numActivities = source.readInt();
        lastActiveTime = source.readLong();

        taskDescription = source.readInt() != 0
                ? ActivityManager.TaskDescription.CREATOR.createFromParcel(source)
                : null;
        taskDescription = source.readTypedObject(ActivityManager.TaskDescription.CREATOR);
        supportsSplitScreenMultiWindow = source.readBoolean();
        resizeMode = source.readInt();
        configuration.readFromParcel(source);
        token = WindowContainerToken.CREATOR.createFromParcel(source);
        topActivityType = source.readInt();
        pictureInPictureParams = source.readInt() != 0
                ? PictureInPictureParams.CREATOR.createFromParcel(source)
                : null;
        topActivityInfo = source.readInt() != 0
                ? ActivityInfo.CREATOR.createFromParcel(source)
                : null;
        pictureInPictureParams = source.readTypedObject(PictureInPictureParams.CREATOR);
        topActivityInfo = source.readTypedObject(ActivityInfo.CREATOR);
        isResizeable = source.readBoolean();
        source.readBinderList(launchCookies);
    }

    /**
@@ -259,13 +267,8 @@ public class TaskInfo {
        dest.writeInt(taskId);
        dest.writeInt(displayId);
        dest.writeBoolean(isRunning);
        dest.writeTypedObject(baseIntent, 0);

        if (baseIntent != null) {
            dest.writeInt(1);
            baseIntent.writeToParcel(dest, 0);
        } else {
            dest.writeInt(0);
        }
        ComponentName.writeToParcel(baseActivity, dest);
        ComponentName.writeToParcel(topActivity, dest);
        ComponentName.writeToParcel(origActivity, dest);
@@ -274,30 +277,16 @@ public class TaskInfo {
        dest.writeInt(numActivities);
        dest.writeLong(lastActiveTime);

        if (taskDescription != null) {
            dest.writeInt(1);
            taskDescription.writeToParcel(dest, flags);
        } else {
            dest.writeInt(0);
        }
        dest.writeTypedObject(taskDescription, flags);
        dest.writeBoolean(supportsSplitScreenMultiWindow);
        dest.writeInt(resizeMode);
        configuration.writeToParcel(dest, flags);
        token.writeToParcel(dest, flags);
        dest.writeInt(topActivityType);
        if (pictureInPictureParams == null) {
            dest.writeInt(0);
        } else {
            dest.writeInt(1);
            pictureInPictureParams.writeToParcel(dest, flags);
        }
        if (topActivityInfo == null) {
            dest.writeInt(0);
        } else {
            dest.writeInt(1);
            topActivityInfo.writeToParcel(dest, flags);
        }
        dest.writeTypedObject(pictureInPictureParams, flags);
        dest.writeTypedObject(topActivityInfo, flags);
        dest.writeBoolean(isResizeable);
        dest.writeBinderList(launchCookies);
    }

    @Override
@@ -316,6 +305,7 @@ public class TaskInfo {
                + " token=" + token
                + " topActivityType=" + topActivityType
                + " pictureInPictureParams=" + pictureInPictureParams
                + " topActivityInfo=" + topActivityInfo;
                + " topActivityInfo=" + topActivityInfo
                + " launchCookies" + launchCookies;
    }
}
+24 −22
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_MULTI_W
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityTaskManager;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.Log;
@@ -30,6 +31,8 @@ import android.window.WindowContainerToken;

import com.android.wm.shell.ShellTaskOrganizer;

import java.util.ArrayList;

/**
 * Manages tasks that are displayed in multi-window (e.g. bubbles). These are displayed in a
 * {@link TaskView}.
@@ -68,7 +71,7 @@ public class MultiWindowTaskListener implements ShellTaskOrganizer.TaskListener
    private final ShellTaskOrganizer mTaskOrganizer;
    private final ArrayMap<WindowContainerToken, TaskData> mTasks = new ArrayMap<>();

    private MultiWindowTaskListener.Listener mPendingListener;
    private ArrayMap<IBinder, Listener> mLaunchCookieToListener = new ArrayMap<>();

    /**
     * Create a listener for tasks in multi-window mode.
@@ -86,10 +89,8 @@ public class MultiWindowTaskListener implements ShellTaskOrganizer.TaskListener
        return mTaskOrganizer;
    }

    // TODO(b/129067201): track launches for bubbles
    // Once we have key in ActivityOptions, match listeners via that key
    public void setPendingListener(Listener listener) {
        mPendingListener = listener;
    public void setPendingLaunchCookieListener(IBinder cookie, Listener listener) {
        mLaunchCookieToListener.put(cookie, listener);
    }

    /**
@@ -99,9 +100,6 @@ public class MultiWindowTaskListener implements ShellTaskOrganizer.TaskListener
        if (DEBUG) {
            Log.d(TAG, "removeListener: listener=" + listener);
        }
        if (mPendingListener == listener) {
            mPendingListener = null;
        }
        for (int i = 0; i < mTasks.size(); i++) {
            if (mTasks.valueAt(i).listener == listener) {
                mTasks.removeAt(i);
@@ -112,28 +110,32 @@ public class MultiWindowTaskListener implements ShellTaskOrganizer.TaskListener
    @Override
    public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
        if (DEBUG) {
            Log.d(TAG, "onTaskAppeared: taskInfo=" + taskInfo
                    + " mPendingListener=" + mPendingListener);
        }
        if (mPendingListener == null) {
            // If there is no pending listener, then we are either receiving this task as a part of
            // registering the task org again (ie. after SysUI dies) or the previously started
            // task is no longer needed (ie. bubble is closed soon after), for now, just finish the
            // associated task
            try {
                ActivityTaskManager.getService().removeTask(taskInfo.taskId);
            } catch (RemoteException e) {
                Log.w(TAG, "Failed to remove taskId " + taskInfo.taskId);
            Log.d(TAG, "onTaskAppeared: taskInfo=" + taskInfo);
        }

        // We only care about task we launch which should all have a tracking launch cookie.
        final ArrayList<IBinder> launchCookies = taskInfo.launchCookies;
        if (launchCookies.isEmpty()) return;

        // See if this task has one of our launch cookies.
        Listener listener = null;
        for (int i = launchCookies.size() - 1; i >= 0; --i) {
            final IBinder cookie = launchCookies.get(i);
            listener = mLaunchCookieToListener.get(cookie);
            if (listener != null) {
                mLaunchCookieToListener.remove(cookie);
                break;
            }
            return;
        }

        // This is either not a task we launched or we have handled it previously.
        if (listener == null) return;

        mTaskOrganizer.setInterceptBackPressedOnTaskRoot(taskInfo.token, true);

        final TaskData data = new TaskData(taskInfo, mPendingListener);
        final TaskData data = new TaskData(taskInfo, listener);
        mTasks.put(taskInfo.token, data);
        mHandler.post(() -> data.listener.onTaskAppeared(taskInfo, leash));
        mPendingListener = null;
    }

    @Override
+4 −2
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.pm.ShortcutInfo;
import android.graphics.Rect;
import android.os.Binder;
import android.view.SurfaceControl;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
@@ -111,7 +112,6 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
     */
    public void startShortcutActivity(@NonNull ShortcutInfo shortcut,
            @NonNull ActivityOptions options, @Nullable Rect sourceBounds) {
        mMultiWindowTaskListener.setPendingListener(this);
        prepareActivityOptions(options);
        LauncherApps service = mContext.getSystemService(LauncherApps.class);
        try {
@@ -130,7 +130,6 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
     */
    public void startActivity(@NonNull PendingIntent pendingIntent, @Nullable Intent fillInIntent,
            @NonNull ActivityOptions options) {
        mMultiWindowTaskListener.setPendingListener(this);
        prepareActivityOptions(options);
        try {
            pendingIntent.send(mContext, 0 /* code */, fillInIntent,
@@ -142,6 +141,9 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
    }

    private void prepareActivityOptions(ActivityOptions options) {
        final Binder launchCookie = new Binder();
        mMultiWindowTaskListener.setPendingLaunchCookieListener(launchCookie, this);
        options.setLaunchCookie(launchCookie);
        options.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
        options.setTaskAlwaysOnTop(true);
    }
+4 −1
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;

import android.app.ActivityManager;
import android.os.Binder;
import android.os.Handler;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -78,7 +79,9 @@ public class MultiWindowTaskListenerTest extends SysuiTestCase {
    }

    private void addTaskAndVerify() {
        mTaskListener.setPendingListener(mPendingListener);
        final Binder cookie = new Binder();
        mTaskInfo.addLaunchCookie(cookie);
        mTaskListener.setPendingLaunchCookieListener(cookie, mPendingListener);
        mTaskListener.onTaskAppeared(mTaskInfo, mLeash);
        mTestableLooper.processAllMessages();
        verify(mPendingListener).onTaskAppeared(eq(mTaskInfo), eq(mLeash));
Loading