Merge "Create drop target for bubble bar" into main
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 0000000..ca37c7f
--- /dev/null
+++ b/quickstep/res/color/bubblebar_drop_target_bg_color.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ 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.
+ -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <item android:alpha="0.35" android:color="?androidprv:attr/materialColorPrimaryContainer" />
+</selector>
\ 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 0000000..79e4318
--- /dev/null
+++ b/quickstep/res/drawable/bg_bubble_bar_drop_target.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ 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.
+ -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
+ <corners android:radius="@dimen/bubblebar_drop_target_corner_radius" />
+ <solid android:color="@color/bubblebar_drop_target_bg_color" />
+ <stroke
+ android:width="1dp"
+ android:color="?androidprv:attr/materialColorPrimaryContainer" />
+</shape>
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 0000000..23f240c
--- /dev/null
+++ b/quickstep/res/layout/bubble_bar_drop_target.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ 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.
+ -->
+
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="@dimen/bubblebar_size"
+ android:layout_height="@dimen/bubblebar_size"
+ android:background="@drawable/bg_bubble_bar_drop_target"
+ android:elevation="@dimen/bubblebar_elevation" />
\ No newline at end of file
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 93ef735..caa949e 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -417,6 +417,7 @@
<!-- Container size with pointer included: bubblebar_size + bubblebar_pointer_size -->
<dimen name="bubblebar_size_with_pointer">80dp</dimen>
<dimen name="bubblebar_elevation">1dp</dimen>
+ <dimen name="bubblebar_drag_elevation">2dp</dimen>
<dimen name="bubblebar_hotseat_adjustment_threshold">90dp</dimen>
<dimen name="bubblebar_icon_size">50dp</dimen>
@@ -432,6 +433,11 @@
<dimen name="bubblebar_dismiss_target_icon_size">24dp</dimen>
<dimen name="bubblebar_dismiss_target_bottom_margin">50dp</dimen>
<dimen name="bubblebar_dismiss_floating_gradient_height">548dp</dimen>
+ <dimen name="bubblebar_dismiss_zone_width">192dp</dimen>
+ <dimen name="bubblebar_dismiss_zone_height">242dp</dimen>
+
+ <!-- Bubble bar drop target -->
+ <dimen name="bubblebar_drop_target_corner_radius">36dp</dimen>
<!-- Launcher splash screen -->
<!-- Note: keep this value in sync with the WindowManager/Shell dimens.xml -->
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index a3aa93a..8769f11 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -99,6 +99,7 @@
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;
@@ -255,7 +256,10 @@
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 0000000..8ed9949
--- /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<FrameLayout.LayoutParams> {
+ 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 c47427d..90f1be3 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 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 @@
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 @@
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 73c71c8..a40f33c 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 @@
@Nullable
private BubbleDragAnimator mAnimator;
+ @Nullable
+ private Listener mListener;
+
public BubbleDismissController(TaskbarActivityContext activity, TaskbarDragLayer dragLayer) {
mActivity = activity;
mDragLayer = dragLayer;
@@ -82,6 +85,13 @@
}
/**
+ * 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 @@
@NonNull MagnetizedObject<?> draggedObject) {
if (mAnimator == null) return;
mAnimator.animateDismissCaptured();
+ if (mListener != null) {
+ mListener.onStuckToDismissChanged(true /* stuck */);
+ }
}
@Override
@@ -197,6 +210,9 @@
float velX, float velY, boolean wasFlungOut) {
if (mAnimator == null) return;
mAnimator.animateDismissReleased();
+ if (mListener != null) {
+ mListener.onStuckToDismissChanged(false /* stuck */);
+ }
}
@Override
@@ -206,4 +222,10 @@
}
});
}
+
+ /** 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 08fd681..dab7d9d 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 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 @@
private final TaskbarActivityContext mActivity;
private BubbleBarViewController mBubbleBarViewController;
private BubbleDismissController mBubbleDismissController;
+ private BubbleBarPinController mBubbleBarPinController;
public BubbleDragController(TaskbarActivityContext activity) {
mActivity = activity;
@@ -52,6 +54,12 @@
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 @@
@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 @@
// 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);
}
});
}
@@ -170,6 +201,13 @@
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
*/
abstract void onDragEnd();
@@ -232,8 +270,10 @@
* @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 @@
}
break;
case DRAGGING:
- drag(view, event, dx, dy);
+ drag(view, event, dx, dy, rawX, rawY);
break;
}
}
@@ -293,10 +333,12 @@
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) {