From f221b8a7ded082722b2f774c0f007f87f4213acc Mon Sep 17 00:00:00 2001 From: Ats Jenk Date: Tue, 26 Mar 2024 16:56:43 -0700 Subject: [PATCH] Create drop target for bubble bar When dragging bubble bar in launcher, show drop target when drag passes middle of the screen. Bug: 330585397 Flag: ACONFIG com.android.wm.shell.enable_bubble_bar DEVELOPMENT Test: manual Change-Id: I52c3e9ac0b7c36e2207640baf75dc44300b522ef --- .../color/bubblebar_drop_target_bg_color.xml | 19 ++++ .../drawable/bg_bubble_bar_drop_target.xml | 24 ++++ .../res/layout/bubble_bar_drop_target.xml | 21 ++++ quickstep/res/values/dimens.xml | 6 + .../taskbar/TaskbarActivityContext.java | 6 +- .../taskbar/bubbles/BubbleBarPinController.kt | 104 ++++++++++++++++++ .../taskbar/bubbles/BubbleControllers.java | 6 +- .../bubbles/BubbleDismissController.java | 22 ++++ .../taskbar/bubbles/BubbleDragController.java | 52 ++++++++- 9 files changed, 253 insertions(+), 7 deletions(-) create mode 100644 quickstep/res/color/bubblebar_drop_target_bg_color.xml create mode 100644 quickstep/res/drawable/bg_bubble_bar_drop_target.xml create mode 100644 quickstep/res/layout/bubble_bar_drop_target.xml create mode 100644 quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt diff --git a/quickstep/res/color/bubblebar_drop_target_bg_color.xml b/quickstep/res/color/bubblebar_drop_target_bg_color.xml new file mode 100644 index 0000000000..ca37c7ffff --- /dev/null +++ b/quickstep/res/color/bubblebar_drop_target_bg_color.xml @@ -0,0 +1,19 @@ + + + + \ No newline at end of file diff --git a/quickstep/res/drawable/bg_bubble_bar_drop_target.xml b/quickstep/res/drawable/bg_bubble_bar_drop_target.xml new file mode 100644 index 0000000000..79e43187f4 --- /dev/null +++ b/quickstep/res/drawable/bg_bubble_bar_drop_target.xml @@ -0,0 +1,24 @@ + + + + + + diff --git a/quickstep/res/layout/bubble_bar_drop_target.xml b/quickstep/res/layout/bubble_bar_drop_target.xml new file mode 100644 index 0000000000..23f240c67d --- /dev/null +++ b/quickstep/res/layout/bubble_bar_drop_target.xml @@ -0,0 +1,21 @@ + + + \ No newline at end of file diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml index 93ef735700..caa949eebf 100644 --- a/quickstep/res/values/dimens.xml +++ b/quickstep/res/values/dimens.xml @@ -417,6 +417,7 @@ 80dp 1dp + 2dp 90dp 50dp @@ -432,6 +433,11 @@ 24dp 50dp 548dp + 192dp + 242dp + + + 36dp diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index 26212c1934..b7a92eef7f 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -98,6 +98,7 @@ import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.AutohideSu import com.android.launcher3.taskbar.TaskbarTranslationController.TransitionCallback; import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController; import com.android.launcher3.taskbar.bubbles.BubbleBarController; +import com.android.launcher3.taskbar.bubbles.BubbleBarPinController; import com.android.launcher3.taskbar.bubbles.BubbleBarView; import com.android.launcher3.taskbar.bubbles.BubbleBarViewController; import com.android.launcher3.taskbar.bubbles.BubbleControllers; @@ -254,7 +255,10 @@ public class TaskbarActivityContext extends BaseTaskbarContext { new BubbleStashController(this), new BubbleStashedHandleViewController(this, bubbleHandleView), new BubbleDragController(this), - new BubbleDismissController(this, mDragLayer))); + new BubbleDismissController(this, mDragLayer), + new BubbleBarPinController(this, mDragLayer, + () -> getDeviceProfile().getDisplayInfo().currentSize) + )); } // Construct controllers. diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt new file mode 100644 index 0000000000..8ed994966c --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher3.taskbar.bubbles + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Point +import android.graphics.RectF +import android.view.Gravity.BOTTOM +import android.view.Gravity.LEFT +import android.view.Gravity.RIGHT +import android.view.LayoutInflater +import android.view.View +import android.widget.FrameLayout +import androidx.core.view.updateLayoutParams +import com.android.launcher3.R +import com.android.wm.shell.common.bubbles.BaseBubblePinController +import com.android.wm.shell.common.bubbles.BubbleBarLocation + +/** + * Controller to manage pinning bubble bar to left or right when dragging starts from the bubble bar + */ +class BubbleBarPinController( + private val context: Context, + private val container: FrameLayout, + private val screenSizeProvider: () -> Point +) : BaseBubblePinController() { + + private lateinit var bubbleBarViewController: BubbleBarViewController + private lateinit var bubbleStashController: BubbleStashController + private var dropTargetView: View? = null + + fun init(bubbleControllers: BubbleControllers) { + bubbleBarViewController = bubbleControllers.bubbleBarViewController + bubbleStashController = bubbleControllers.bubbleStashController + } + + override fun getScreenCenterX(): Int { + return screenSizeProvider.invoke().x / 2 + } + + override fun getExclusionRect(): RectF { + val rect = + RectF( + 0f, + 0f, + context.resources.getDimension(R.dimen.bubblebar_dismiss_zone_width), + context.resources.getDimension(R.dimen.bubblebar_dismiss_zone_height) + ) + val screenSize = screenSizeProvider.invoke() + val middleX = screenSize.x / 2 + // Center it around the bottom center of the screen + rect.offsetTo(middleX - rect.width() / 2, screenSize.y - rect.height()) + return rect + } + + override fun createDropTargetView(): View { + return LayoutInflater.from(context) + .inflate(R.layout.bubble_bar_drop_target, container, false) + .also { view -> + dropTargetView = view + container.addView(view) + } + } + + override fun getDropTargetView(): View? { + return dropTargetView + } + + override fun removeDropTargetView(view: View) { + container.removeView(view) + dropTargetView = null + } + + @SuppressLint("RtlHardcoded") + override fun updateLocation(location: BubbleBarLocation) { + val onLeft = location.isOnLeft(container.isLayoutRtl) + + val bounds = bubbleBarViewController.bubbleBarBounds + val horizontalMargin = bubbleBarViewController.horizontalMargin + dropTargetView?.updateLayoutParams { + width = bounds.width() + height = bounds.height() + gravity = BOTTOM or (if (onLeft) LEFT else RIGHT) + leftMargin = horizontalMargin + rightMargin = horizontalMargin + bottomMargin = -bubbleStashController.bubbleBarTranslationY.toInt() + } + } +} diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java index c47427d4fb..90f1be36cb 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java @@ -29,6 +29,7 @@ public class BubbleControllers { public final BubbleStashedHandleViewController bubbleStashedHandleViewController; public final BubbleDragController bubbleDragController; public final BubbleDismissController bubbleDismissController; + public final BubbleBarPinController bubbleBarPinController; private final RunnableList mPostInitRunnables = new RunnableList(); @@ -43,13 +44,15 @@ public class BubbleControllers { BubbleStashController bubbleStashController, BubbleStashedHandleViewController bubbleStashedHandleViewController, BubbleDragController bubbleDragController, - BubbleDismissController bubbleDismissController) { + BubbleDismissController bubbleDismissController, + BubbleBarPinController bubbleBarPinController) { this.bubbleBarController = bubbleBarController; this.bubbleBarViewController = bubbleBarViewController; this.bubbleStashController = bubbleStashController; this.bubbleStashedHandleViewController = bubbleStashedHandleViewController; this.bubbleDragController = bubbleDragController; this.bubbleDismissController = bubbleDismissController; + this.bubbleBarPinController = bubbleBarPinController; } /** @@ -64,6 +67,7 @@ public class BubbleControllers { bubbleStashController.init(taskbarControllers, this); bubbleDragController.init(/* bubbleControllers = */ this); bubbleDismissController.init(/* bubbleControllers = */ this); + bubbleBarPinController.init(this); mPostInitRunnables.executeAllAndDestroy(); } diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java index 73c71c8edf..a40f33c595 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java @@ -67,6 +67,9 @@ public class BubbleDismissController { @Nullable private BubbleDragAnimator mAnimator; + @Nullable + private Listener mListener; + public BubbleDismissController(TaskbarActivityContext activity, TaskbarDragLayer dragLayer) { mActivity = activity; mDragLayer = dragLayer; @@ -81,6 +84,13 @@ public class BubbleDismissController { mBubbleBarViewController = bubbleControllers.bubbleBarViewController; } + /** + * Set listener to be notified of dismiss events + */ + public void setListener(@Nullable Listener listener) { + mListener = listener; + } + /** * Setup the dismiss view and magnetized object that will be attracted to magnetic target. * Should be called before handling events or showing/hiding dismiss view. @@ -189,6 +199,9 @@ public class BubbleDismissController { @NonNull MagnetizedObject draggedObject) { if (mAnimator == null) return; mAnimator.animateDismissCaptured(); + if (mListener != null) { + mListener.onStuckToDismissChanged(true /* stuck */); + } } @Override @@ -197,6 +210,9 @@ public class BubbleDismissController { float velX, float velY, boolean wasFlungOut) { if (mAnimator == null) return; mAnimator.animateDismissReleased(); + if (mListener != null) { + mListener.onStuckToDismissChanged(false /* stuck */); + } } @Override @@ -206,4 +222,10 @@ public class BubbleDismissController { } }); } + + /** Interface to receive updates about the dismiss state */ + public interface Listener { + /** Called when view is stuck or unstuck from dismiss target */ + void onStuckToDismissChanged(boolean stuck); + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java index 08fd681b4c..dab7d9d07a 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java @@ -25,10 +25,11 @@ import android.view.ViewConfiguration; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.android.launcher3.R; import com.android.launcher3.taskbar.TaskbarActivityContext; /** - * Controls bubble bar drag to dismiss interaction. + * Controls bubble bar drag interactions. * Interacts with {@link BubbleDismissController}, used by {@link BubbleBarViewController}. * Supported interactions: * - Drag a single bubble view into dismiss target to remove it. @@ -39,6 +40,7 @@ public class BubbleDragController { private final TaskbarActivityContext mActivity; private BubbleBarViewController mBubbleBarViewController; private BubbleDismissController mBubbleDismissController; + private BubbleBarPinController mBubbleBarPinController; public BubbleDragController(TaskbarActivityContext activity) { mActivity = activity; @@ -52,6 +54,12 @@ public class BubbleDragController { public void init(@NonNull BubbleControllers bubbleControllers) { mBubbleBarViewController = bubbleControllers.bubbleBarViewController; mBubbleDismissController = bubbleControllers.bubbleDismissController; + mBubbleBarPinController = bubbleControllers.bubbleBarPinController; + mBubbleBarPinController.setListener(location -> { + // TODO(b/330585397): update bubble bar location in shell + }); + mBubbleDismissController.setListener( + stuck -> mBubbleBarPinController.setDropTargetHidden(stuck)); } /** @@ -88,6 +96,10 @@ public class BubbleDragController { @SuppressLint("ClickableViewAccessibility") public void setupBubbleBarView(@NonNull BubbleBarView bubbleBarView) { PointF initialRelativePivot = new PointF(); + final int restingElevation = bubbleBarView.getResources().getDimensionPixelSize( + R.dimen.bubblebar_elevation); + final int dragElevation = bubbleBarView.getResources().getDimensionPixelSize( + R.dimen.bubblebar_drag_elevation); bubbleBarView.setOnTouchListener(new BubbleTouchListener() { @Override protected boolean onTouchDown(@NonNull View view, @NonNull MotionEvent event) { @@ -102,12 +114,31 @@ public class BubbleDragController { // By default the bubble bar view pivot is in bottom right corner, while dragging // it should be centered in order to align it with the dismiss target view bubbleBarView.setRelativePivot(/* x = */ 0.5f, /* y = */ 0.5f); + bubbleBarView.setElevation(dragElevation); + mBubbleBarPinController.onDragStart( + bubbleBarView.getBubbleBarLocation().isOnLeft(bubbleBarView.isLayoutRtl())); + } + + @Override + protected void onDragUpdate(float x, float y) { + mBubbleBarPinController.onDragUpdate(x, y); + } + + @Override + protected void onDragRelease() { + mBubbleBarPinController.onDragEnd(); + } + + @Override + protected void onDragDismiss() { + mBubbleBarPinController.onDragEnd(); } @Override void onDragEnd() { // Restoring the initial pivot for the bubble bar view bubbleBarView.setRelativePivot(initialRelativePivot.x, initialRelativePivot.y); + bubbleBarView.setElevation(restingElevation); } }); } @@ -169,6 +200,13 @@ public class BubbleDragController { */ abstract void onDragStart(); + /** + * Called when bubble is dragged to new coordinates. + * Not called while bubble is stuck to the dismiss target. + */ + protected void onDragUpdate(float x, float y) { + } + /** * Called when the dragging interaction has ended and all the animations have completed */ @@ -232,8 +270,10 @@ public class BubbleDragController { * @param event the motion event */ protected void onTouchMove(@NonNull View view, @NonNull MotionEvent event) { - final float dx = event.getRawX() - mTouchDownLocation.x; - final float dy = event.getRawY() - mTouchDownLocation.y; + float rawX = event.getRawX(); + float rawY = event.getRawY(); + final float dx = rawX - mTouchDownLocation.x; + final float dy = rawY - mTouchDownLocation.y; switch (mState) { case TOUCHED: final boolean movedOut = Math.hypot(dx, dy) > mTouchSlop; @@ -244,7 +284,7 @@ public class BubbleDragController { } break; case DRAGGING: - drag(view, event, dx, dy); + drag(view, event, dx, dy, rawX, rawY); break; } } @@ -293,10 +333,12 @@ public class BubbleDragController { mBubbleDismissController.showDismissView(); } - private void drag(@NonNull View view, @NonNull MotionEvent event, float dx, float dy) { + private void drag(@NonNull View view, @NonNull MotionEvent event, float dx, float dy, + float x, float y) { if (mBubbleDismissController.handleTouchEvent(event)) return; view.setTranslationX(mViewInitialPosition.x + dx); view.setTranslationY(mViewInitialPosition.y + dy); + onDragUpdate(x, y); } private void stopDragging(@NonNull View view, @NonNull MotionEvent event) {