From c666b9587b5c43f0973c9d8a6b42f5de960c848b Mon Sep 17 00:00:00 2001 From: mpodolian Date: Mon, 24 Feb 2025 15:49:58 -0800 Subject: [PATCH] Added BubbleBarLocation drop target. A drop target for the BubbleBarLocation has been added. This implementation enables the Launcher process to handle application drag-and-drop actions onto the bubble bar. Known issues: 1) Upon dropping, the dragged icon animates back to its original taskbar position from the top-left corner. 2) The expanded view drop target is not presented. 3) When an icon is dropped on the opposite side of the bubble bar, the resulting location does not change, even though the drop target is correctly displayed. Bug: 397459664 Flag: com.android.wm.shell.enable_create_any_bubble Test: Manual. Navigate to the overview screen, drag a taskbar icon to the left or right side, targeting the bubble bar drop zone. Verify the drop target's appearance. Then, drop the icon and observe that a new application bubble is added. Change-Id: I0f64a664620959f2503ac3fd711476b354a09348 --- .../taskbar/TaskbarDragController.java | 8 +- .../bubbles/BubbleBarLocationDropTarget.kt | 96 +++++++++++++++++++ .../bubbles/BubbleBarViewController.java | 84 +++++++++++++++- src/com/android/launcher3/DropTarget.java | 6 ++ .../launcher3/dragndrop/DragController.java | 2 +- 5 files changed, 192 insertions(+), 4 deletions(-) create mode 100644 quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarLocationDropTarget.kt diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java index d531e2c5a8..9b7e320892 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java @@ -68,6 +68,7 @@ import com.android.launcher3.dragndrop.DragDriver; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.dragndrop.DragView; import com.android.launcher3.dragndrop.DraggableView; +import com.android.launcher3.folder.Folder; import com.android.launcher3.graphics.DragPreviewProvider; import com.android.launcher3.logger.LauncherAtom.ContainerInfo; import com.android.launcher3.logging.StatsLogManager; @@ -765,8 +766,11 @@ public class TaskbarDragController extends DragController im @Override public void addDropTarget(DropTarget target) { - // No-op as Taskbar currently doesn't support any drop targets internally. - // Note: if we do add internal DropTargets, we'll still need to ignore Folder. + if (target instanceof Folder) { + // we need to ignore Folder. + return; + } + super.addDropTarget(target); } @Override diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarLocationDropTarget.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarLocationDropTarget.kt new file mode 100644 index 0000000000..383f4d2020 --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarLocationDropTarget.kt @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2025 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.graphics.Rect +import android.view.View +import com.android.launcher3.DropTarget +import com.android.launcher3.dragndrop.DragOptions +import com.android.launcher3.model.data.ItemInfo +import com.android.wm.shell.shared.bubbles.BubbleBarLocation + +/** + * Implementation of the {@link DropTarget} that handles drag and drop events over the bubble bar + * locations. + */ +class BubbleBarLocationDropTarget( + private val bubbleBarLocation: BubbleBarLocation, + private val bubbleBarDragListener: BubbleBarDragListener, +) : DropTarget { + + /** Controller that takes care of the bubble bar drag events inside launcher process. */ + interface BubbleBarDragListener { + + /** Called when the drag event is over the bubble bar drop zone. */ + fun onLauncherItemDraggedOverBubbleBarDragZone(location: BubbleBarLocation) + + /** Called when the drag event leaves the bubble bar drop zone. */ + fun onLauncherItemDraggedOutsideBubbleBarDropZone() + + /** Called when the drop event happens over the bubble bar drop zone. */ + fun onLauncherItemDroppedOverBubbleBarDragZone( + location: BubbleBarLocation, + itemInfo: ItemInfo, + ) + + /** Gets the hit [rect][android.graphics.Rect] of the bubble bar location. */ + fun getBubbleBarLocationHitRect(bubbleBarLocation: BubbleBarLocation, outRect: Rect) + + /** Provides the view that will accept the drop. */ + fun getDropView(): View + } + + private var isShowingDropTarget = false + + override fun isDropEnabled(): Boolean = true + + override fun onDrop(dragObject: DropTarget.DragObject, options: DragOptions) { + val itemInfo = dragObject.dragInfo ?: return + // TODO(b/397459664) : fix task bar icon animation after drop + // TODO(b/397459664) : update bubble bar location + bubbleBarDragListener.onLauncherItemDroppedOverBubbleBarDragZone( + bubbleBarLocation, + itemInfo, + ) + } + + override fun onDragEnter(dragObject: DropTarget.DragObject) {} + + override fun onDragOver(dragObject: DropTarget.DragObject) { + if (isShowingDropTarget) return + isShowingDropTarget = true + bubbleBarDragListener.onLauncherItemDraggedOverBubbleBarDragZone(bubbleBarLocation) + } + + override fun onDragExit(dragObject: DropTarget.DragObject) { + // TODO(b/397459664) : fix the issue for no bubbles, when moving task bar icon out of + // the bubble bar drag zone drag ends and swipes gesture swipes the overview + if (!isShowingDropTarget) return + isShowingDropTarget = false + bubbleBarDragListener.onLauncherItemDraggedOutsideBubbleBarDropZone() + } + + override fun acceptDrop(dragObject: DropTarget.DragObject): Boolean = true + + override fun prepareAccessibilityDrop() {} + + override fun getHitRectRelativeToDragLayer(outRect: Rect) { + bubbleBarDragListener.getBubbleBarLocationHitRect(bubbleBarLocation, outRect) + } + + override fun getDropView(): View = bubbleBarDragListener.getDropView() +} diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java index b90a5b001a..beda30c3b3 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java @@ -24,6 +24,8 @@ import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_TRA import android.animation.Animator; import android.animation.AnimatorSet; +import android.content.Intent; +import android.content.pm.ShortcutInfo; import android.content.res.Resources; import android.graphics.Point; import android.graphics.PointF; @@ -43,11 +45,15 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.anim.RoundedRectRevealOutlineProvider; +import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.taskbar.TaskbarActivityContext; import com.android.launcher3.taskbar.TaskbarControllers; +import com.android.launcher3.taskbar.TaskbarDragController; import com.android.launcher3.taskbar.TaskbarInsetsController; import com.android.launcher3.taskbar.TaskbarSharedState; import com.android.launcher3.taskbar.TaskbarStashController; +import com.android.launcher3.taskbar.bubbles.BubbleBarLocationDropTarget.BubbleBarDragListener; import com.android.launcher3.taskbar.bubbles.animation.BubbleBarViewAnimator; import com.android.launcher3.taskbar.bubbles.flyout.BubbleBarFlyoutController; import com.android.launcher3.taskbar.bubbles.flyout.BubbleBarFlyoutPositioner; @@ -59,6 +65,7 @@ import com.android.launcher3.util.MultiValueAlpha; import com.android.quickstep.SystemUiProxy; import com.android.wm.shell.Flags; import com.android.wm.shell.shared.bubbles.BubbleBarLocation; +import com.android.wm.shell.shared.bubbles.DeviceConfig; import java.io.PrintWriter; import java.util.List; @@ -117,6 +124,61 @@ public class BubbleBarViewController { updateTranslationY(); setBubbleBarScaleAndPadding(pinningProgress); }); + private final BubbleBarDragListener mDragListener = new BubbleBarDragListener() { + + @NonNull + @Override + public void getBubbleBarLocationHitRect(@NonNull BubbleBarLocation bubbleBarLocation, + Rect outRect) { + Point screenSize = DisplayController.INSTANCE.get(mActivity).getInfo().currentSize; + outRect.top = screenSize.y - mBubbleBarDropTargetSize; + outRect.bottom = screenSize.y; + if (bubbleBarLocation.isOnLeft(mBarView.isLayoutRtl())) { + outRect.left = 0; + outRect.right = mBubbleBarDropTargetSize; + } else { + outRect.left = screenSize.x - mBubbleBarDropTargetSize; + outRect.right = screenSize.x; + } + } + + @Override + public void onLauncherItemDroppedOverBubbleBarDragZone(@NonNull BubbleBarLocation location, + @NonNull ItemInfo itemInfo) { + //TODO(b/397459664) : fix task bar icon animation after drop + //TODO(b/397459664) : update bubble bar location + ShortcutInfo shortcutInfo = null; + if (itemInfo instanceof WorkspaceItemInfo) { + shortcutInfo = ((WorkspaceItemInfo) itemInfo).getDeepShortcutInfo(); + } + Intent itemIntent = itemInfo.getIntent(); + SystemUiProxy systemUiProxy = SystemUiProxy.INSTANCE.get(mActivity); + if (shortcutInfo != null) { + systemUiProxy.showShortcutBubble(shortcutInfo); + } else if (itemIntent != null && itemIntent.getComponent() != null) { + systemUiProxy.showAppBubble(itemIntent, itemInfo.user); + } + } + + @Override + public void onLauncherItemDraggedOutsideBubbleBarDropZone() { + //TODO(b/397459664) : hide expanded view drop target + onItemDraggedOutsideBubbleBarDropZone(); + } + + @Override + public void onLauncherItemDraggedOverBubbleBarDragZone( + @NonNull BubbleBarLocation location) { + //TODO(b/397459664) : show expanded view drop target + onDragItemOverBubbleBarDragZone(location); + } + + @NonNull + @Override + public View getDropView() { + return mBarView; + } + }; // Modified when swipe up is happening on the bubble bar or task bar. private float mBubbleBarSwipeUpTranslationY; @@ -139,8 +201,12 @@ public class BubbleBarViewController { private BubbleBarFlyoutController mBubbleBarFlyoutController; private BubbleBarPinController mBubbleBarPinController; private TaskbarSharedState mTaskbarSharedState; + private TaskbarDragController mTaskbarDragController; + private final BubbleBarLocationDropTarget mBubbleBarLeftDropTarget; + private final BubbleBarLocationDropTarget mBubbleBarRightDropTarget; private final TimeSource mTimeSource = System::currentTimeMillis; private final int mTaskbarTranslationDelta; + private final int mBubbleBarDropTargetSize; @Nullable private BubbleBarBoundsChangeListener mBoundsChangeListener; @@ -158,11 +224,21 @@ public class BubbleBarViewController { R.dimen.bubblebar_transient_taskbar_min_distance); mDragElevation = res.getDimensionPixelSize(R.dimen.bubblebar_drag_elevation); mTaskbarTranslationDelta = getBubbleBarTranslationDeltaForTaskbar(activity); + if (DeviceConfig.isSmallTablet(mActivity)) { + mBubbleBarDropTargetSize = res.getDimensionPixelSize(R.dimen.drag_zone_bubble_fold); + } else { + mBubbleBarDropTargetSize = res.getDimensionPixelSize(R.dimen.drag_zone_bubble_tablet); + } + mBubbleBarLeftDropTarget = new BubbleBarLocationDropTarget(BubbleBarLocation.LEFT, + mDragListener); + mBubbleBarRightDropTarget = new BubbleBarLocationDropTarget(BubbleBarLocation.RIGHT, + mDragListener); } /** Initializes controller. */ public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers, TaskbarViewPropertiesProvider taskbarViewPropertiesProvider) { + mTaskbarDragController = controllers.taskbarDragController; mTaskbarSharedState = controllers.getSharedState(); mBubbleStashController = bubbleControllers.bubbleStashController; mBubbleBarController = bubbleControllers.bubbleBarController; @@ -264,6 +340,8 @@ public class BubbleBarViewController { mBubbleBarController.updateBubbleBarLocation(location, source); } }; + mTaskbarDragController.addDropTarget(mBubbleBarLeftDropTarget); + mTaskbarDragController.addDropTarget(mBubbleBarRightDropTarget); } /** Returns animated float property responsible for pinning transition animation. */ @@ -542,7 +620,9 @@ public class BubbleBarViewController { */ public void onDragItemOverBubbleBarDragZone(@NonNull BubbleBarLocation bubbleBarLocation) { mBarView.showDropTarget(/* isDropTarget = */ true); - mIsLocationUpdatedForDropTarget = getBubbleBarLocation() != bubbleBarLocation; + boolean isRtl = mBarView.isLayoutRtl(); + mIsLocationUpdatedForDropTarget = getBubbleBarLocation().isOnLeft(isRtl) + != bubbleBarLocation.isOnLeft(isRtl); if (mIsLocationUpdatedForDropTarget) { animateBubbleBarLocation(bubbleBarLocation); } @@ -1278,6 +1358,8 @@ public class BubbleBarViewController { /** Called when the controller is destroyed. */ public void onDestroy() { adjustTaskbarAndHotseatToBubbleBarState(/*isBubbleBarExpanded = */false); + mTaskbarDragController.removeDropTarget(mBubbleBarLeftDropTarget); + mTaskbarDragController.removeDropTarget(mBubbleBarRightDropTarget); } /** diff --git a/src/com/android/launcher3/DropTarget.java b/src/com/android/launcher3/DropTarget.java index 2d995103e7..7f0c7b50c0 100644 --- a/src/com/android/launcher3/DropTarget.java +++ b/src/com/android/launcher3/DropTarget.java @@ -18,6 +18,7 @@ package com.android.launcher3; import android.content.Context; import android.graphics.Rect; +import android.view.View; import com.android.launcher3.accessibility.DragViewStateAnnouncer; import com.android.launcher3.dragndrop.DragOptions; @@ -145,4 +146,9 @@ public interface DropTarget { // These methods are implemented in Views void getHitRectRelativeToDragLayer(Rect outRect); + + /** Returns the drop target view. By default, the implementor class is cast to the view. */ + default View getDropView() { + return (View) this; + } } diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java index c50c008f30..613b4308eb 100644 --- a/src/com/android/launcher3/dragndrop/DragController.java +++ b/src/com/android/launcher3/dragndrop/DragController.java @@ -558,7 +558,7 @@ public abstract class DragController target.getHitRectRelativeToDragLayer(r); if (r.contains(x, y)) { - mActivity.getDragLayer().mapCoordInSelfToDescendant((View) target, + mActivity.getDragLayer().mapCoordInSelfToDescendant(target.getDropView(), mCoordinatesTemp); mDragObject.x = mCoordinatesTemp[0]; mDragObject.y = mCoordinatesTemp[1];