From 85d3998aa39f412f269806114b3e6154ccbee73f Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Fri, 24 Feb 2017 15:21:25 -0800 Subject: [PATCH] Prevent PiP movement while the resize animation is running. - This was causing numerous artifacts when the user starts touching while transitioning into PiP where the move rects clobber the animating rect. Bug: 35764922 Test: Try touching the PiP while it is entering or exiting PiP Change-Id: I5a72b5bea694b01aab401d2bb78a493688a9c655 --- core/java/android/app/IActivityManager.aidl | 1 + core/java/android/app/ITaskStackListener.aidl | 5 ++ core/java/android/app/TaskStackListener.java | 4 ++ .../systemui/pip/phone/PipManager.java | 9 +++- .../systemui/pip/phone/PipTouchHandler.java | 17 +++++++ .../systemui/pip/phone/PipTouchState.java | 48 +++++++++++++++++-- .../recents/misc/SystemServicesProxy.java | 14 ++++++ .../server/am/ActivityManagerService.java | 6 +++ .../am/TaskChangeNotificationController.java | 17 +++++++ .../java/com/android/server/wm/TaskStack.java | 9 ++++ 10 files changed, 126 insertions(+), 4 deletions(-) diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 8538330547468..dad2061e004f0 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -522,6 +522,7 @@ interface IActivityManager { void startLocalVoiceInteraction(in IBinder token, in Bundle options); void stopLocalVoiceInteraction(in IBinder token); boolean supportsLocalVoiceInteraction(); + void notifyPinnedStackAnimationStarted(); void notifyPinnedStackAnimationEnded(); void removeStack(int stackId); void makePackageIdle(String packageName, int userId); diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl index 983435024a9b2..d8d4bb906fba2 100644 --- a/core/java/android/app/ITaskStackListener.aidl +++ b/core/java/android/app/ITaskStackListener.aidl @@ -37,6 +37,11 @@ oneway interface ITaskStackListener { */ void onPinnedActivityRestartAttempt(String launchedFromPackage); + /** + * Called whenever the pinned stack is starting animating a resize. + */ + void onPinnedStackAnimationStarted(); + /** * Called whenever the pinned stack is done animating a resize. */ diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java index 5a0845f02b29c..7a569fc322a66 100644 --- a/core/java/android/app/TaskStackListener.java +++ b/core/java/android/app/TaskStackListener.java @@ -38,6 +38,10 @@ public abstract class TaskStackListener extends ITaskStackListener.Stub { public void onPinnedActivityRestartAttempt(String launchedFromPackage) throws RemoteException { } + @Override + public void onPinnedStackAnimationStarted() throws RemoteException { + } + @Override public void onPinnedStackAnimationEnded() throws RemoteException { } 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 ae402efabc7f8..e7256d14de770 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -70,9 +70,16 @@ public class PipManager implements BasePipManager { mMediaController.onActivityPinned(); } + @Override + public void onPinnedStackAnimationStarted() { + // Disable touches while the animation is running + mTouchHandler.setTouchEnabled(false); + } + @Override public void onPinnedStackAnimationEnded() { - // TODO(winsonc): Disable touch interaction with the PiP until the animation ends + // Re-enable touches after the animation completes + mTouchHandler.setTouchEnabled(true); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index d832810e48126..4100b66b07b64 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -181,6 +181,10 @@ public class PipTouchHandler { registerInputConsumer(); } + public void setTouchEnabled(boolean enabled) { + mTouchState.setAllowTouches(enabled); + } + public void onActivityPinned() { // Reset some states once we are pinned if (mIsTappingThrough) { @@ -294,6 +298,7 @@ public class PipTouchHandler { // Fall through to clean up } case MotionEvent.ACTION_CANCEL: { + mTouchState.reset(); break; } } @@ -418,6 +423,10 @@ public class PipTouchHandler { @Override public void onDown(PipTouchState touchState) { + if (!touchState.isUserInteracting()) { + return; + } + if (ENABLE_DRAG_TO_DISMISS) { mDismissViewController.createDismissTarget(); mHandler.postDelayed(mShowDismissAffordance, SHOW_DISMISS_AFFORDANCE_DELAY); @@ -426,6 +435,10 @@ public class PipTouchHandler { @Override boolean onMove(PipTouchState touchState) { + if (!touchState.isUserInteracting()) { + return false; + } + if (touchState.startedDragging()) { mSavedSnapFraction = -1f; } @@ -458,6 +471,10 @@ public class PipTouchHandler { @Override public boolean onUp(PipTouchState touchState) { + if (!touchState.isUserInteracting()) { + return false; + } + try { if (ENABLE_DRAG_TO_DISMISS) { mHandler.removeCallbacks(mShowDismissAffordance); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java index 702ad0af04476..a317dc32ba455 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java @@ -37,6 +37,7 @@ public class PipTouchState { private final PointF mLastTouch = new PointF(); private final PointF mLastDelta = new PointF(); private final PointF mVelocity = new PointF(); + private boolean mAllowTouches = true; private boolean mIsUserInteracting = false; private boolean mIsDragging = false; private boolean mStartedDragging = false; @@ -47,24 +48,42 @@ public class PipTouchState { mViewConfig = viewConfig; } + /** + * Resets this state. + */ + public void reset() { + mAllowDraggingOffscreen = false; + mIsDragging = false; + mStartedDragging = false; + mIsUserInteracting = false; + } + /** * Processess a given touch event and updates the state. */ public void onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: { + if (!mAllowTouches) { + return; + } + // Initialize the velocity tracker initOrResetVelocityTracker(); + mActivePointerId = ev.getPointerId(0); mLastTouch.set(ev.getX(), ev.getY()); mDownTouch.set(mLastTouch); - mIsDragging = false; - mStartedDragging = false; mAllowDraggingOffscreen = true; mIsUserInteracting = true; break; } case MotionEvent.ACTION_MOVE: { + // Skip event if we did not start processing this touch gesture + if (!mIsUserInteracting) { + break; + } + // Update the velocity tracker mVelocityTracker.addMovement(ev); int pointerIndex = ev.findPointerIndex(mActivePointerId); @@ -86,6 +105,11 @@ public class PipTouchState { break; } case MotionEvent.ACTION_POINTER_UP: { + // Skip event if we did not start processing this touch gesture + if (!mIsUserInteracting) { + break; + } + // Update the velocity tracker mVelocityTracker.addMovement(ev); @@ -100,6 +124,11 @@ public class PipTouchState { break; } case MotionEvent.ACTION_UP: { + // Skip event if we did not start processing this touch gesture + if (!mIsUserInteracting) { + break; + } + // Update the velocity tracker mVelocityTracker.addMovement(ev); mVelocityTracker.computeCurrentVelocity(1000, @@ -112,7 +141,6 @@ public class PipTouchState { // Fall through to clean up } case MotionEvent.ACTION_CANCEL: { - mIsUserInteracting = false; recycleVelocityTracker(); break; } @@ -170,6 +198,19 @@ public class PipTouchState { return mStartedDragging; } + /** + * Sets whether touching is currently allowed. + */ + public void setAllowTouches(boolean allowTouches) { + mAllowTouches = allowTouches; + + // If the user happens to touch down before this is sent from the system during a transition + // then block any additional handling by resetting the state now + if (mIsUserInteracting) { + reset(); + } + } + /** * Disallows dragging offscreen for the duration of the current gesture. */ @@ -202,6 +243,7 @@ public class PipTouchState { public void dump(PrintWriter pw, String prefix) { final String innerPrefix = prefix + " "; pw.println(prefix + TAG); + pw.println(innerPrefix + "mAllowTouches=" + mAllowTouches); pw.println(innerPrefix + "mDownTouch=" + mDownTouch); pw.println(innerPrefix + "mDownDelta=" + mDownDelta); pw.println(innerPrefix + "mLastTouch=" + mLastTouch); 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 cda902b6fb69c..1042356042f8d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -154,6 +154,7 @@ public class SystemServicesProxy { public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) { } public void onActivityPinned() { } public void onPinnedActivityRestartAttempt(String launchedFromPackage) { } + public void onPinnedStackAnimationStarted() { } public void onPinnedStackAnimationEnded() { } public void onActivityForcedResizable(String packageName, int taskId) { } public void onActivityDismissingDockedStack() { } @@ -205,6 +206,12 @@ public class SystemServicesProxy { .sendToTarget(); } + @Override + public void onPinnedStackAnimationStarted() throws RemoteException { + mHandler.removeMessages(H.ON_PINNED_STACK_ANIMATION_STARTED); + mHandler.sendEmptyMessage(H.ON_PINNED_STACK_ANIMATION_STARTED); + } + @Override public void onPinnedStackAnimationEnded() throws RemoteException { mHandler.removeMessages(H.ON_PINNED_STACK_ANIMATION_ENDED); @@ -1219,6 +1226,7 @@ public class SystemServicesProxy { 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; + private static final int ON_PINNED_STACK_ANIMATION_STARTED = 9; @Override public void handleMessage(Message msg) { @@ -1248,6 +1256,12 @@ public class SystemServicesProxy { } break; } + case ON_PINNED_STACK_ANIMATION_STARTED: { + for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { + mTaskStackListeners.get(i).onPinnedStackAnimationStarted(); + } + break; + } case ON_PINNED_STACK_ANIMATION_ENDED: { for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { mTaskStackListeners.get(i).onPinnedStackAnimationEnded(); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 9a0194219e49f..47985ccc0ca75 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -12078,6 +12078,12 @@ public class ActivityManagerService extends IActivityManager.Stub mRecentTasks.notifyTaskPersisterLocked(task, flush); } + /** Notifies all listeners when the pinned stack animation starts. */ + @Override + public void notifyPinnedStackAnimationStarted() { + mTaskChangeNotificationController.notifyPinnedStackAnimationStarted(); + } + /** Notifies all listeners when the pinned stack animation ends. */ @Override public void notifyPinnedStackAnimationEnded() { diff --git a/services/core/java/com/android/server/am/TaskChangeNotificationController.java b/services/core/java/com/android/server/am/TaskChangeNotificationController.java index 9dfc7cd84f401..9a98bc6ec6f85 100644 --- a/services/core/java/com/android/server/am/TaskChangeNotificationController.java +++ b/services/core/java/com/android/server/am/TaskChangeNotificationController.java @@ -46,6 +46,7 @@ class TaskChangeNotificationController { static final int NOTIFY_TASK_REMOVAL_STARTED_LISTENERS = 13; static final int NOTIFY_TASK_PROFILE_LOCKED_LISTENERS_MSG = 14; static final int NOTIFY_TASK_SNAPSHOT_CHANGED_LISTENERS_MSG = 15; + static final int NOTIFY_PINNED_STACK_ANIMATION_STARTED_LISTENERS_MSG = 16; // Delay in notifying task stack change listeners (in millis) static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100; @@ -100,6 +101,10 @@ class TaskChangeNotificationController { l.onPinnedActivityRestartAttempt((String) m.obj); }; + private final TaskStackConsumer mNotifyPinnedStackAnimationStarted = (l, m) -> { + l.onPinnedStackAnimationStarted(); + }; + private final TaskStackConsumer mNotifyPinnedStackAnimationEnded = (l, m) -> { l.onPinnedStackAnimationEnded(); }; @@ -166,6 +171,9 @@ class TaskChangeNotificationController { case NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG: forAllRemoteListeners(mNotifyPinnedActivityRestartAttempt, msg); break; + case NOTIFY_PINNED_STACK_ANIMATION_STARTED_LISTENERS_MSG: + forAllRemoteListeners(mNotifyPinnedStackAnimationStarted, msg); + break; case NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG: forAllRemoteListeners(mNotifyPinnedStackAnimationEnded, msg); break; @@ -276,6 +284,15 @@ class TaskChangeNotificationController { msg.sendToTarget(); } + /** Notifies all listeners when the pinned stack animation starts. */ + void notifyPinnedStackAnimationStarted() { + mHandler.removeMessages(NOTIFY_PINNED_STACK_ANIMATION_STARTED_LISTENERS_MSG); + final Message msg = + mHandler.obtainMessage(NOTIFY_PINNED_STACK_ANIMATION_STARTED_LISTENERS_MSG); + forAllLocalListeners(mNotifyPinnedStackAnimationStarted, msg); + msg.sendToTarget(); + } + /** Notifies all listeners when the pinned stack animation ends. */ void notifyPinnedStackAnimationEnded() { mHandler.removeMessages(NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG); diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index 6cc2efb78526f..7588b71dced71 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -1439,6 +1439,14 @@ public class TaskStack extends WindowContainer implements DimLayer.DimLaye mBoundsAnimating = true; mBoundsAnimatingToFullscreen = toFullscreen; } + + if (mStackId == PINNED_STACK_ID) { + try { + mService.mActivityManager.notifyPinnedStackAnimationStarted(); + } catch (RemoteException e) { + // I don't believe you... + } + } } @Override // AnimatesBounds @@ -1448,6 +1456,7 @@ public class TaskStack extends WindowContainer implements DimLayer.DimLaye mBoundsAnimationTarget.setEmpty(); mService.requestTraversal(); } + if (mStackId == PINNED_STACK_ID) { try { mService.mActivityManager.notifyPinnedStackAnimationEnded();