From 4767b38a9b844d9d351cd68c0350386b0da7dcdb Mon Sep 17 00:00:00 2001 From: Ivan Tkachenko Date: Mon, 10 Jul 2023 21:14:17 +0100 Subject: [PATCH] Bubble bar drag to dismiss * Extended `IBubbles` interface to enable collapsing of expanded buble while dragging and removal of all bubbles. * Added `onCancel` optional event handler to `RelativeTouchListener` to enable cancel motion events handling. * Added collapse animation cancellation when expand is called that caused crashes. * Implemented `IBubbles` methods in `IBubblesImpl` Bug: 271466616 Test: manual, TBD Flag: WM_BUBBLE_BAR Change-Id: I24c011361dbca43a2265b11fd8f25f57ec147872 --- .../wm/shell/bubbles/BubbleController.java | 40 ++++++++++++++++++- .../android/wm/shell/bubbles/IBubbles.aidl | 8 +++- .../bubbles/bar/BubbleBarAnimationHelper.java | 8 ++++ .../shell/bubbles/bar/BubbleBarLayerView.java | 6 +++ .../common/bubbles/RelativeTouchListener.kt | 19 +++++++++ 5 files changed, 77 insertions(+), 4 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java index 6385fd3fd811d..38e35cb6f5bab 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java @@ -1049,6 +1049,20 @@ public class BubbleController implements ConfigurationChangeListener, mBubbleData.setExpanded(false /* expanded */); } + /** + * Update expanded state when a single bubble is dragged in Launcher. + * Will be called only when bubble bar is expanded. + * @param bubbleKey key of the bubble to collapse/expand + * @param collapse whether to collapse or expand + */ + public void collapseWhileDragging(String bubbleKey, boolean collapse) { + if (mBubbleData.getSelectedBubble() != null + && mBubbleData.getSelectedBubble().getKey().equals(bubbleKey)) { + // Should collapse/expand only if equals to selected bubble. + mBubbleBarViewCallback.expansionChanged(/* isExpanded = */ !collapse); + } + } + @VisibleForTesting public boolean isBubbleNotificationSuppressedFromShade(String key, String groupKey) { boolean isSuppressedBubble = (mBubbleData.hasAnyBubbleWithKey(key) @@ -1434,6 +1448,17 @@ public class BubbleController implements ConfigurationChangeListener, } } + /** + * Removes all the bubbles. + *

+ * Must be called from the main thread. + */ + @VisibleForTesting + @MainThread + public void removeAllBubbles(@Bubbles.DismissReason int reason) { + mBubbleData.dismissAll(reason); + } + private void onEntryAdded(BubbleEntry entry) { if (canLaunchInTaskView(mContext, entry)) { updateBubble(entry); @@ -2095,14 +2120,25 @@ public class BubbleController implements ConfigurationChangeListener, } @Override - public void removeBubble(String key, int reason) { - // TODO (b/271466616) allow removals from launcher + public void removeBubble(String key) { + mMainExecutor.execute( + () -> mController.removeBubble(key, Bubbles.DISMISS_USER_GESTURE)); + } + + @Override + public void removeAllBubbles() { + mMainExecutor.execute(() -> mController.removeAllBubbles(Bubbles.DISMISS_USER_GESTURE)); } @Override public void collapseBubbles() { mMainExecutor.execute(() -> mController.collapseStack()); } + + @Override + public void collapseWhileDragging(String bubbleKey, boolean collapse) { + mMainExecutor.execute(() -> mController.collapseWhileDragging(bubbleKey, collapse)); + } } private class BubblesImpl implements Bubbles { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl index 59332f4be6271..375a8f80bf410 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl @@ -32,8 +32,12 @@ interface IBubbles { oneway void showBubble(in String key, in int bubbleBarXCoordinate, in int bubbleBarYCoordinate) = 3; - oneway void removeBubble(in String key, in int reason) = 4; + oneway void removeBubble(in String key) = 4; - oneway void collapseBubbles() = 5; + oneway void removeAllBubbles() = 5; + + oneway void collapseBubbles() = 6; + + oneway void collapseWhileDragging(in String key, in boolean collapse) = 7; } \ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java index b3602b30072d7..689323b725ae7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java @@ -215,6 +215,14 @@ public class BubbleBarAnimationHelper { mExpandedViewAlphaAnimator.reverse(); } + /** + * Cancel current animations + */ + public void cancelAnimations() { + PhysicsAnimator.getInstance(mExpandedViewContainerMatrix).cancel(); + mExpandedViewAlphaAnimator.cancel(); + } + private void updateExpandedView() { if (mExpandedBubble == null || mExpandedBubble.getBubbleBarExpandedView() == null) { Log.w(TAG, "Trying to update the expanded view without a bubble"); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java index 8ead18b139de3..bc04bfc8c18b4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java @@ -150,6 +150,12 @@ public class BubbleBarLayerView extends FrameLayout mExpandedView = null; } if (mExpandedView == null) { + if (expandedView.getParent() != null) { + // Expanded view might be animating collapse and is still attached + // Cancel current animations and remove from parent + mAnimationHelper.cancelAnimations(); + removeView(expandedView); + } mExpandedBubble = b; mExpandedView = expandedView; boolean isOverflowExpanded = b.getKey().equals(BubbleOverflow.KEY); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/RelativeTouchListener.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/RelativeTouchListener.kt index cc37bd3a4589e..c98d0bae89585 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/RelativeTouchListener.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/RelativeTouchListener.kt @@ -78,6 +78,24 @@ abstract class RelativeTouchListener : View.OnTouchListener { velY: Float ) + /** + * Called when an ACTION_CANCEL event is received for the given view. This signals that the + * current gesture has been aborted. + * + * @param viewInitialX The view's translationX value when this touch gesture started. + * @param viewInitialY The view's translationY value when this touch gesture started. + * @param dx Horizontal distance covered since the initial ACTION_DOWN event, in pixels. + * @param dy Vertical distance covered since the initial ACTION_DOWN event, in pixels. + */ + open fun onCancel( + v: View, + ev: MotionEvent, + viewInitialX: Float, + viewInitialY: Float, + dx: Float, + dy: Float + ) {} + /** The raw coordinates of the last ACTION_DOWN event. */ private val touchDown = PointF() @@ -146,6 +164,7 @@ abstract class RelativeTouchListener : View.OnTouchListener { } MotionEvent.ACTION_CANCEL -> { + onCancel(v, ev, viewPositionOnTouchDown.x, viewPositionOnTouchDown.y, dx, dy) v.handler.removeCallbacksAndMessages(null) velocityTracker.clear() movedEnough = false