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
This commit is contained in:
Ats Jenk
2024-03-28 14:21:33 -07:00
parent 1e6d1112ba
commit f221b8a7de
9 changed files with 253 additions and 7 deletions
@@ -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.
@@ -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<FrameLayout.LayoutParams> {
width = bounds.width()
height = bounds.height()
gravity = BOTTOM or (if (onLeft) LEFT else RIGHT)
leftMargin = horizontalMargin
rightMargin = horizontalMargin
bottomMargin = -bubbleStashController.bubbleBarTranslationY.toInt()
}
}
}
@@ -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();
}
@@ -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);
}
}
@@ -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) {