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];