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:
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user