diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl index 28b28dad5b828..145d5139cdc26 100644 --- a/core/java/android/app/ITaskStackListener.aidl +++ b/core/java/android/app/ITaskStackListener.aidl @@ -37,13 +37,15 @@ oneway interface ITaskStackListener { /** * Called whenever IActivityManager.startActivity is called on an activity that is already - * running in the pinned stack and the activity is not actually started, but the task is either - * brought to the front or a new Intent is delivered to it. + * running, but the task is either brought to the front or a new Intent is delivered to it. * + * @param task information about the task the activity was relaunched into + * @param homeVisible whether or not the home task is visible * @param clearedTask whether or not the launch activity also cleared the task as a part of * starting */ - void onPinnedActivityRestartAttempt(boolean clearedTask); + void onActivityRestartAttempt(in ActivityManager.RunningTaskInfo task, boolean homeTaskVisible, + boolean clearedTask); /** * Called when we launched an activity that we forced to be resizable. diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java index b892b8e51c887..93772de0ba30e 100644 --- a/core/java/android/app/TaskStackListener.java +++ b/core/java/android/app/TaskStackListener.java @@ -16,6 +16,7 @@ package android.app; +import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityManager.TaskSnapshot; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; @@ -53,7 +54,8 @@ public abstract class TaskStackListener extends ITaskStackListener.Stub { @Override @UnsupportedAppUsage - public void onPinnedActivityRestartAttempt(boolean clearedTask) throws RemoteException { + public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible, + boolean clearedTask) throws RemoteException { } @Override @@ -68,14 +70,14 @@ public abstract class TaskStackListener extends ITaskStackListener.Stub { } @Override - public void onActivityLaunchOnSecondaryDisplayFailed(ActivityManager.RunningTaskInfo taskInfo, + public void onActivityLaunchOnSecondaryDisplayFailed(RunningTaskInfo taskInfo, int requestedDisplayId) throws RemoteException { onActivityLaunchOnSecondaryDisplayFailed(); } /** * @deprecated see {@link - * #onActivityLaunchOnSecondaryDisplayFailed(ActivityManager.RunningTaskInfo, int)} + * #onActivityLaunchOnSecondaryDisplayFailed(RunningTaskInfo, int)} */ @Deprecated @UnsupportedAppUsage @@ -84,7 +86,7 @@ public abstract class TaskStackListener extends ITaskStackListener.Stub { @Override @UnsupportedAppUsage - public void onActivityLaunchOnSecondaryDisplayRerouted(ActivityManager.RunningTaskInfo taskInfo, + public void onActivityLaunchOnSecondaryDisplayRerouted(RunningTaskInfo taskInfo, int requestedDisplayId) throws RemoteException { } @@ -98,13 +100,13 @@ public abstract class TaskStackListener extends ITaskStackListener.Stub { } @Override - public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) + public void onTaskMovedToFront(RunningTaskInfo taskInfo) throws RemoteException { onTaskMovedToFront(taskInfo.taskId); } /** - * @deprecated see {@link #onTaskMovedToFront(ActivityManager.RunningTaskInfo)} + * @deprecated see {@link #onTaskMovedToFront(RunningTaskInfo)} */ @Deprecated @UnsupportedAppUsage @@ -112,26 +114,26 @@ public abstract class TaskStackListener extends ITaskStackListener.Stub { } @Override - public void onTaskRemovalStarted(ActivityManager.RunningTaskInfo taskInfo) + public void onTaskRemovalStarted(RunningTaskInfo taskInfo) throws RemoteException { onTaskRemovalStarted(taskInfo.taskId); } /** - * @deprecated see {@link #onTaskRemovalStarted(ActivityManager.RunningTaskInfo)} + * @deprecated see {@link #onTaskRemovalStarted(RunningTaskInfo)} */ @Deprecated public void onTaskRemovalStarted(int taskId) throws RemoteException { } @Override - public void onTaskDescriptionChanged(ActivityManager.RunningTaskInfo taskInfo) + public void onTaskDescriptionChanged(RunningTaskInfo taskInfo) throws RemoteException { onTaskDescriptionChanged(taskInfo.taskId, taskInfo.taskDescription); } /** - * @deprecated see {@link #onTaskDescriptionChanged(ActivityManager.RunningTaskInfo)} + * @deprecated see {@link #onTaskDescriptionChanged(RunningTaskInfo)} */ @Deprecated public void onTaskDescriptionChanged(int taskId, ActivityManager.TaskDescription td) @@ -166,7 +168,7 @@ public abstract class TaskStackListener extends ITaskStackListener.Stub { } @Override - public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) + public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) throws RemoteException { } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java index 1c6223b847de2..9e9b9dc4f3b00 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java @@ -37,7 +37,8 @@ public abstract class TaskStackChangeListener { public void onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) { } public void onActivityPinned(String packageName, int userId, int taskId, int stackId) { } public void onActivityUnpinned() { } - public void onPinnedActivityRestartAttempt(boolean clearedTask) { } + public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible, + boolean clearedTask) { } public void onActivityForcedResizable(String packageName, int taskId, int reason) { } public void onActivityDismissingDockedStack() { } public void onActivityLaunchOnSecondaryDisplayFailed() { } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java index cbdd3f8191f41..ce9cbabaa5e92 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java @@ -30,6 +30,7 @@ import android.os.RemoteException; import android.os.Trace; import android.util.Log; +import com.android.internal.os.SomeArgs; import com.android.systemui.shared.recents.model.ThumbnailData; import java.util.ArrayList; @@ -120,11 +121,14 @@ public class TaskStackChangeListeners extends TaskStackListener { } @Override - public void onPinnedActivityRestartAttempt(boolean clearedTask) - throws RemoteException { - mHandler.removeMessages(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT); - mHandler.obtainMessage(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT, clearedTask ? 1 : 0, 0) - .sendToTarget(); + public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible, + boolean clearedTask) throws RemoteException { + final SomeArgs args = SomeArgs.obtain(); + args.arg1 = task; + args.argi1 = homeTaskVisible ? 1 : 0; + args.argi2 = clearedTask ? 1 : 0; + mHandler.removeMessages(H.ON_ACTIVITY_RESTART_ATTEMPT); + mHandler.obtainMessage(H.ON_ACTIVITY_RESTART_ATTEMPT, args).sendToTarget(); } @Override @@ -236,7 +240,7 @@ public class TaskStackChangeListeners extends TaskStackListener { private static final int ON_TASK_STACK_CHANGED = 1; private static final int ON_TASK_SNAPSHOT_CHANGED = 2; private static final int ON_ACTIVITY_PINNED = 3; - private static final int ON_PINNED_ACTIVITY_RESTART_ATTEMPT = 4; + private static final int ON_ACTIVITY_RESTART_ATTEMPT = 4; private static final int ON_ACTIVITY_FORCED_RESIZABLE = 6; private static final int ON_ACTIVITY_DISMISSING_DOCKED_STACK = 7; private static final int ON_TASK_PROFILE_LOCKED = 8; @@ -296,10 +300,14 @@ public class TaskStackChangeListeners extends TaskStackListener { } break; } - case ON_PINNED_ACTIVITY_RESTART_ATTEMPT: { + case ON_ACTIVITY_RESTART_ATTEMPT: { + final SomeArgs args = (SomeArgs) msg.obj; + final RunningTaskInfo task = (RunningTaskInfo) args.arg1; + final boolean homeTaskVisible = args.argi1 != 0; + final boolean clearedTask = args.argi2 != 0; for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { - mTaskStackListeners.get(i).onPinnedActivityRestartAttempt( - msg.arg1 != 0); + mTaskStackListeners.get(i).onActivityRestartAttempt(task, + homeTaskVisible, clearedTask); } break; } @@ -419,6 +427,9 @@ public class TaskStackChangeListeners extends TaskStackListener { } } } + if (msg.obj instanceof SomeArgs) { + ((SomeArgs) msg.obj).recycle(); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java index 22c2c7ee97502..ae1438ee9bbd6 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -1226,6 +1226,17 @@ public class BubbleController implements ConfigurationController.ConfigurationLi } } + @Override + public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible, + boolean clearedTask) { + for (Bubble b : mBubbleData.getBubbles()) { + if (b.getDisplayId() == task.displayId) { + expandStackAndSelectBubble(b.getKey()); + return; + } + } + } + @Override public void onActivityLaunchOnSecondaryDisplayRerouted() { if (mStackView != null) { diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java index eed81bfc07f94..1fdf92ee3832d 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -128,7 +128,12 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio } @Override - public void onPinnedActivityRestartAttempt(boolean clearedTask) { + public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task, + boolean homeTaskVisible, boolean clearedTask) { + if (task.configuration.windowConfiguration.getWindowingMode() + != WINDOWING_MODE_PINNED) { + return; + } mTouchHandler.getMotionHelper().expandPip(clearedTask /* skipAnimation */); } }; diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java index a5e9dbc419242..0c5a4d782e697 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java @@ -680,7 +680,12 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio } @Override - public void onPinnedActivityRestartAttempt(boolean clearedTask) { + public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible, + boolean clearedTask) { + if (task.configuration.windowConfiguration.getWindowingMode() + != WINDOWING_MODE_PINNED) { + return; + } if (DEBUG) Log.d(TAG, "onPinnedActivityRestartAttempt()"); // If PIPed activity is launched again by Launcher or intent, make it fullscreen. diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java index f3e2f104621e4..5bf44c6a3003f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java @@ -20,6 +20,8 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; + import android.annotation.Nullable; import android.app.ActivityManager; import android.app.trust.TrustManager; @@ -37,6 +39,7 @@ import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.shared.recents.IOverviewProxy; import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.stackdivider.Divider; import com.android.systemui.statusbar.phone.StatusBar; @@ -63,6 +66,21 @@ public class OverviewProxyRecentsImpl implements RecentsImplementation { private TrustManager mTrustManager; private OverviewProxyService mOverviewProxyService; + private TaskStackChangeListener mListener = new TaskStackChangeListener() { + @Override + public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task, + boolean homeTaskVisible, boolean clearedTask) { + if (task.configuration.windowConfiguration.getWindowingMode() + != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { + return; + } + + if (homeTaskVisible) { + showRecentApps(false /* triggeredFromAltTab */); + } + } + }; + @SuppressWarnings("OptionalUsedAsFieldOrParameterType") @Inject public OverviewProxyRecentsImpl(Optional> statusBarLazy, @@ -77,6 +95,7 @@ public class OverviewProxyRecentsImpl implements RecentsImplementation { mHandler = new Handler(); mTrustManager = (TrustManager) context.getSystemService(Context.TRUST_SERVICE); mOverviewProxyService = Dependency.get(OverviewProxyService.class); + ActivityManagerWrapper.getInstance().registerTaskStackListener(mListener); } @Override diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 688c9ae705d7e..c7a139176f6cb 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -29,7 +29,6 @@ import static android.app.ActivityManager.START_SUCCESS; import static android.app.ActivityManager.START_TASK_TO_FRONT; import static android.app.WaitResult.LAUNCH_STATE_COLD; import static android.app.WaitResult.LAUNCH_STATE_HOT; -import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; @@ -178,6 +177,9 @@ class ActivityStarter { private Intent mNewTaskIntent; private ActivityStack mSourceStack; private ActivityStack mTargetStack; + // The task that the last activity was started into. We currently reset the actual start + // activity's task and as a result may not have a reference to the task in all cases + private Task mTargetTask; private boolean mMovedToFront; private boolean mNoAnimation; private boolean mKeepCurTransition; @@ -545,6 +547,7 @@ class ActivityStarter { mNewTaskIntent = starter.mNewTaskIntent; mSourceStack = starter.mSourceStack; + mTargetTask = starter.mTargetTask; mTargetStack = starter.mTargetStack; mMovedToFront = starter.mMovedToFront; mNoAnimation = starter.mNoAnimation; @@ -1368,7 +1371,10 @@ class ActivityStarter { // it waits for the new activity to become visible instead, {@link #waitResultIfNeeded}. mSupervisor.reportWaitingActivityLaunchedIfNeeded(r, result); - if (startedActivityStack == null) { + final Task targetTask = r.getTask() != null + ? r.getTask() + : mTargetTask; + if (startedActivityStack == null || targetTask == null) { return; } @@ -1379,19 +1385,10 @@ class ActivityStarter { // The activity was already running so it wasn't started, but either brought to the // front or the new intent was delivered to it since it was already in front. Notify // anyone interested in this piece of information. - switch (startedActivityStack.getWindowingMode()) { - case WINDOWING_MODE_PINNED: - mService.getTaskChangeNotificationController().notifyPinnedActivityRestartAttempt( - clearedTask); - break; - case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: - final ActivityStack homeStack = - startedActivityStack.getDisplay().getOrCreateRootHomeTask(); - if (homeStack != null && homeStack.shouldBeVisible(null /* starting */)) { - mService.mWindowManager.showRecentApps(); - } - break; - } + final ActivityStack homeStack = targetTask.getDisplayContent().getRootHomeTask(); + final boolean homeTaskVisible = homeStack != null && homeStack.shouldBeVisible(null); + mService.getTaskChangeNotificationController().notifyActivityRestartAttempt( + targetTask.getTaskInfo(), homeTaskVisible, clearedTask); } } @@ -1517,6 +1514,7 @@ class ActivityStarter { // Compute if there is an existing task that should be used for. final Task targetTask = reusedTask != null ? reusedTask : computeTargetTask(); final boolean newTask = targetTask == null; + mTargetTask = targetTask; computeLaunchParams(r, sourceRecord, targetTask); @@ -2018,6 +2016,7 @@ class ActivityStarter { mSourceStack = null; mTargetStack = null; + mTargetTask = null; mMovedToFront = false; mNoAnimation = false; mKeepCurTransition = false; diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java index 96a9127344e8d..e4f10d9840b2e 100644 --- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java +++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java @@ -30,13 +30,15 @@ import android.os.Message; import android.os.RemoteCallbackList; import android.os.RemoteException; +import com.android.internal.os.SomeArgs; + import java.util.ArrayList; class TaskChangeNotificationController { private static final int LOG_STACK_STATE_MSG = 1; private static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG = 2; private static final int NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG = 3; - private static final int NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG = 4; + private static final int NOTIFY_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG = 4; private static final int NOTIFY_FORCED_RESIZABLE_MSG = 6; private static final int NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG = 7; private static final int NOTIFY_TASK_ADDED_LISTENERS_MSG = 8; @@ -118,8 +120,10 @@ class TaskChangeNotificationController { l.onActivityUnpinned(); }; - private final TaskStackConsumer mNotifyPinnedActivityRestartAttempt = (l, m) -> { - l.onPinnedActivityRestartAttempt(m.arg1 != 0); + private final TaskStackConsumer mNotifyActivityRestartAttempt = (l, m) -> { + SomeArgs args = (SomeArgs) m.obj; + l.onActivityRestartAttempt((RunningTaskInfo) args.arg1, args.argi1 != 0, + args.argi2 != 0); }; private final TaskStackConsumer mNotifyActivityForcedResizable = (l, m) -> { @@ -220,8 +224,8 @@ class TaskChangeNotificationController { case NOTIFY_ACTIVITY_UNPINNED_LISTENERS_MSG: forAllRemoteListeners(mNotifyActivityUnpinned, msg); break; - case NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG: - forAllRemoteListeners(mNotifyPinnedActivityRestartAttempt, msg); + case NOTIFY_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG: + forAllRemoteListeners(mNotifyActivityRestartAttempt, msg); break; case NOTIFY_FORCED_RESIZABLE_MSG: forAllRemoteListeners(mNotifyActivityForcedResizable, msg); @@ -266,6 +270,9 @@ class TaskChangeNotificationController { forAllRemoteListeners(mNotifyTaskFocusChanged, msg); break; } + if (msg.obj instanceof SomeArgs) { + ((SomeArgs) msg.obj).recycle(); + } } } @@ -358,15 +365,18 @@ class TaskChangeNotificationController { /** * Notifies all listeners when an attempt was made to start an an activity that is already - * running in the pinned stack and the activity was not actually started, but the task is - * either brought to the front or a new Intent is delivered to it. + * running, but the task is either brought to the front or a new Intent is delivered to it. */ - void notifyPinnedActivityRestartAttempt(boolean clearedTask) { - mHandler.removeMessages(NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG); - final Message msg = - mHandler.obtainMessage(NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG, - clearedTask ? 1 : 0, 0); - forAllLocalListeners(mNotifyPinnedActivityRestartAttempt, msg); + void notifyActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible, + boolean clearedTask) { + mHandler.removeMessages(NOTIFY_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG); + final SomeArgs args = SomeArgs.obtain(); + args.arg1 = task; + args.argi1 = homeTaskVisible ? 1 : 0; + args.argi2 = clearedTask ? 1 : 0; + final Message msg = mHandler.obtainMessage(NOTIFY_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG, + args); + forAllLocalListeners(mNotifyActivityRestartAttempt, msg); msg.sendToTarget(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index 9f3bf02384b05..1c267a03c1211 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -18,6 +18,7 @@ package com.android.server.wm; import static android.app.ActivityManager.PROCESS_STATE_TOP; import static android.app.ActivityManager.START_ABORTED; +import static android.app.ActivityManager.START_CANCELED; import static android.app.ActivityManager.START_CLASS_NOT_FOUND; import static android.app.ActivityManager.START_DELIVERED_TO_TOP; import static android.app.ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT; @@ -892,7 +893,7 @@ public class ActivityStarterTests extends ActivityTestsBase { .execute(); // Simulate a failed start - starter.postStartActivityProcessing(null, START_ABORTED, null); + starter.postStartActivityProcessing(null, START_CANCELED, null); verify(recentTasks, times(1)).setFreezeTaskListReordering(); verify(recentTasks, times(1)).resetFreezeTaskListReorderingOnTimeout();