From e6385a23d7d7e0628544c9751c59507d1df7885c Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Tue, 2 May 2017 18:15:16 -0700 Subject: [PATCH] Workaround launching PiP task with CLEAR_TASK & NEW_TASK flag. - When launching an activity with CLEAR_TASK and NEW_TASK, the result code of the start is START_SUCCESS, but we still need to notify SystemUI to expand the PiP. However, because the PiP transition now waits for the first draw, this can cause severe jank and delay if the original activity is a trampoline activity. As a workaround, we immediately move the task to the fullscreen stack when clearing and restarting the task to ensure that the new task shows without delay. Bug: 37501224 Test: Open YT in PIP, launch sub-shortcut from Home Change-Id: I16bebf19b082f30695e99da1d93bc4adf5e9df0c --- core/java/android/app/ITaskStackListener.aidl | 5 ++++- core/java/android/app/TaskStackListener.java | 2 +- .../systemui/pip/phone/PipManager.java | 4 ++-- .../systemui/pip/phone/PipMotionHelper.java | 19 +++++++++++++++---- .../android/systemui/pip/tv/PipManager.java | 2 +- .../recents/misc/SystemServicesProxy.java | 10 ++++++---- .../server/am/ActivityManagerService.java | 5 +++-- .../android/server/am/ActivityStarter.java | 9 ++++++--- .../am/TaskChangeNotificationController.java | 7 ++++--- 9 files changed, 42 insertions(+), 21 deletions(-) diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl index f369955cdc31e..4994fbb0da3a0 100644 --- a/core/java/android/app/ITaskStackListener.aidl +++ b/core/java/android/app/ITaskStackListener.aidl @@ -39,8 +39,11 @@ 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. + * + * @param clearedTask whether or not the launch activity also cleared the task as a part of + * starting */ - void onPinnedActivityRestartAttempt(); + void onPinnedActivityRestartAttempt(boolean clearedTask); /** * Called whenever the pinned stack is starting animating a resize. diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java index 307fc9128ed22..2df011fb856ee 100644 --- a/core/java/android/app/TaskStackListener.java +++ b/core/java/android/app/TaskStackListener.java @@ -39,7 +39,7 @@ public abstract class TaskStackListener extends ITaskStackListener.Stub { } @Override - public void onPinnedActivityRestartAttempt() throws RemoteException { + public void onPinnedActivityRestartAttempt(boolean clearedTask) throws RemoteException { } @Override 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 df03fdc46d064..bdc08718d37f0 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -107,12 +107,12 @@ public class PipManager implements BasePipManager { } @Override - public void onPinnedActivityRestartAttempt() { + public void onPinnedActivityRestartAttempt(boolean clearedTask) { if (!checkCurrentUserId(false /* debug */)) { return; } - mTouchHandler.getMotionHelper().expandPip(); + mTouchHandler.getMotionHelper().expandPip(clearedTask /* skipAnimation */); } }; diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java index fc52a2ec59945..5121c8d0a3759 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java @@ -140,14 +140,25 @@ public class PipMotionHelper { * Resizes the pinned stack back to fullscreen. */ void expandPip() { + expandPip(false /* skipAnimation */); + } + + /** + * Resizes the pinned stack back to fullscreen. + */ + void expandPip(boolean skipAnimation) { cancelAnimations(); mHandler.post(() -> { try { - mActivityManager.resizeStack(PINNED_STACK_ID, null /* bounds */, - true /* allowResizeInDockedMode */, true /* preserveWindows */, - true /* animate */, EXPAND_STACK_TO_FULLSCREEN_DURATION); + if (skipAnimation) { + mActivityManager.moveTasksToFullscreenStack(PINNED_STACK_ID, true /* onTop */); + } else { + mActivityManager.resizeStack(PINNED_STACK_ID, null /* bounds */, + true /* allowResizeInDockedMode */, true /* preserveWindows */, + true /* animate */, EXPAND_STACK_TO_FULLSCREEN_DURATION); + } } catch (RemoteException e) { - Log.e(TAG, "Error showing PiP menu activity", e); + Log.e(TAG, "Error expanding PiP activity", e); } }); } 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 657f08be8b529..9735bfc666d73 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java @@ -625,7 +625,7 @@ public class PipManager implements BasePipManager { } @Override - public void onPinnedActivityRestartAttempt() { + public void onPinnedActivityRestartAttempt(boolean clearedTask) { if (DEBUG) Log.d(TAG, "onPinnedActivityRestartAttempt()"); if (!checkCurrentUserId(DEBUG)) { return; diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index a9e1f61b7d473..f431517cfe77d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -158,7 +158,7 @@ public class SystemServicesProxy { public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) { } public void onActivityPinned(String packageName) { } public void onActivityUnpinned() { } - public void onPinnedActivityRestartAttempt() { } + public void onPinnedActivityRestartAttempt(boolean clearedTask) { } public void onPinnedStackAnimationStarted() { } public void onPinnedStackAnimationEnded() { } public void onActivityForcedResizable(String packageName, int taskId, int reason) { } @@ -223,10 +223,11 @@ public class SystemServicesProxy { } @Override - public void onPinnedActivityRestartAttempt() + public void onPinnedActivityRestartAttempt(boolean clearedTask) throws RemoteException{ mHandler.removeMessages(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT); - mHandler.sendEmptyMessage(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT); + mHandler.obtainMessage(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT, clearedTask ? 1 : 0, 0) + .sendToTarget(); } @Override @@ -1294,7 +1295,8 @@ public class SystemServicesProxy { } case ON_PINNED_ACTIVITY_RESTART_ATTEMPT: { for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { - mTaskStackListeners.get(i).onPinnedActivityRestartAttempt(); + mTaskStackListeners.get(i).onPinnedActivityRestartAttempt( + msg.arg1 != 0); } break; } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index d46a24bec6cb9..4e7cb7dc40ec8 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -19890,8 +19890,9 @@ public class ActivityManagerService extends IActivityManager.Stub } /** - * NOTE: For the pinned stack, this method is only called after the bounds animation has - * animated the stack to the fullscreen. + * NOTE: For the pinned stack, this method is usually called after the bounds animation has + * animated the stack to the fullscreen, but can also be called if we are relaunching an + * activity and clearing the task at the same time. */ @Override public void moveTasksToFullscreenStack(int fromStackId, boolean onTop) { diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 19b9b452df7e1..fcc2b78ef406c 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -575,12 +575,15 @@ class ActivityStarter { return; } - if (startedActivityStackId == PINNED_STACK_ID - && (result == START_TASK_TO_FRONT || result == START_DELIVERED_TO_TOP)) { + boolean clearedTask = (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) + == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK); + if (startedActivityStackId == PINNED_STACK_ID && (result == START_TASK_TO_FRONT + || result == START_DELIVERED_TO_TOP || clearedTask)) { // The activity was already running in the pinned stack 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. - mService.mTaskChangeNotificationController.notifyPinnedActivityRestartAttempt(); + mService.mTaskChangeNotificationController.notifyPinnedActivityRestartAttempt( + clearedTask); return; } } diff --git a/services/core/java/com/android/server/am/TaskChangeNotificationController.java b/services/core/java/com/android/server/am/TaskChangeNotificationController.java index 7d2bc5b51c2e4..f5d7b6858b83d 100644 --- a/services/core/java/com/android/server/am/TaskChangeNotificationController.java +++ b/services/core/java/com/android/server/am/TaskChangeNotificationController.java @@ -104,7 +104,7 @@ class TaskChangeNotificationController { }; private final TaskStackConsumer mNotifyPinnedActivityRestartAttempt = (l, m) -> { - l.onPinnedActivityRestartAttempt(); + l.onPinnedActivityRestartAttempt(m.arg1 != 0); }; private final TaskStackConsumer mNotifyPinnedStackAnimationStarted = (l, m) -> { @@ -300,10 +300,11 @@ class TaskChangeNotificationController { * 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. */ - void notifyPinnedActivityRestartAttempt() { + 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); + mHandler.obtainMessage(NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG, + clearedTask ? 1 : 0, 0); forAllLocalListeners(mNotifyPinnedActivityRestartAttempt, msg); msg.sendToTarget(); }