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 8def8ff1ab010..4ea5e7785cb6b 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 351319f5fb5eb..b4ed9d075d884 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 @@ -31,8 +31,12 @@ interface IBubbles { oneway void showBubble(in String key, in int bubbleBarOffsetX, in int bubbleBarOffsetY) = 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