From 3346e19b3bd2dc1f17f09f6665f33db6a63b3a00 Mon Sep 17 00:00:00 2001 From: Brian Isganitis Date: Mon, 10 Jul 2023 16:51:48 -0400 Subject: [PATCH] Initial Taskbar drag-n-drop support for search results. - Includes initial support for obtaining PendingIntent for ITEM_TYPE_SEARCH_ACTION. - Custom pre-drag conditions for search results can be provided through TaskbarSearchSessionController. - Added detection for telling when DragView shift animation ends for pre-drag condition usage. Test: Manual Bug: 289261756 Flag: ENABLE_ALL_APPS_SEARCH_IN_TASKBAR Change-Id: I52510a6f3ee49968134ecb591ef7c4df711b9d3d --- .../taskbar/TaskbarDragController.java | 64 ++++++++++++++----- .../allapps/TaskbarAllAppsController.java | 11 ++++ .../allapps/TaskbarSearchSessionController.kt | 5 ++ .../android/launcher3/dragndrop/DragView.java | 37 +++++++++-- .../secondarydisplay/SecondaryDragLayer.java | 5 +- 5 files changed, 99 insertions(+), 23 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java index 64ba5aa718..3c7196a36f 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java @@ -20,11 +20,13 @@ import static com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_ALL_APPS; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICTION; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT; +import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SEARCH_ACTION; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.annotation.NonNull; +import android.app.PendingIntent; import android.content.ClipData; import android.content.ClipDescription; import android.content.Intent; @@ -73,6 +75,7 @@ import com.android.launcher3.testing.shared.TestProtocol; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.IntSet; import com.android.launcher3.util.ItemInfoMatcher; +import com.android.launcher3.views.BubbleTextHolder; import com.android.quickstep.util.LogUtils; import com.android.quickstep.util.MultiValueUpdateListener; import com.android.systemui.shared.recents.model.Task; @@ -149,6 +152,9 @@ public class TaskbarDragController extends DragController im View view, @Nullable DragPreviewProvider dragPreviewProvider, @Nullable Point iconShift) { + if (view instanceof BubbleTextHolder) { + view = ((BubbleTextHolder) view).getBubbleText(); + } if (!(view instanceof BubbleTextView) || mDisallowLongClick) { return false; } @@ -193,13 +199,21 @@ public class TaskbarDragController extends DragController im dragLayerY += dragRect.top; DragOptions dragOptions = new DragOptions(); - dragOptions.preDragCondition = null; - PopupContainerWithArrow popupContainer = - mControllers.taskbarPopupController.showForIcon(btv); - if (popupContainer != null) { - dragOptions.preDragCondition = popupContainer.createPreDragCondition(false); - } + // First, see if view is a search result that needs custom pre-drag conditions. + dragOptions.preDragCondition = + mControllers.taskbarAllAppsController.createPreDragConditionForSearch(btv); + if (dragOptions.preDragCondition == null) { + // See if view supports a popup container. + PopupContainerWithArrow popupContainer = + mControllers.taskbarPopupController.showForIcon(btv); + if (popupContainer != null) { + dragOptions.preDragCondition = popupContainer.createPreDragCondition(false); + } + } + + if (dragOptions.preDragCondition == null) { + // Fallback pre-drag condition. dragOptions.preDragCondition = new DragOptions.PreDragCondition() { private DragView mDragView; @@ -213,13 +227,8 @@ public class TaskbarDragController extends DragController im mDragView = dragObject.dragView; if (!shouldStartDrag(0)) { - mDragView.setOnAnimationEndCallback(() -> { - // Drag might be cancelled during the DragView animation, so check - // mIsPreDrag again. - if (mIsInPreDrag) { - callOnDragStart(); - } - }); + mDragView.setOnScaleAnimEndCallback( + TaskbarDragController.this::onPreDragAnimationEnd); } } @@ -230,12 +239,13 @@ public class TaskbarDragController extends DragController im }; } + Point dragOffset = dragOptions.preDragCondition.getDragOffset(); return startDrag( drawable, /* view = */ null, /* originalView = */ btv, - dragLayerX, - dragLayerY, + dragLayerX + dragOffset.x, + dragLayerY + dragOffset.y, (View target, DropTarget.DragObject d, boolean success) -> {} /* DragSource */, (ItemInfo) btv.getTag(), dragRect, @@ -290,6 +300,11 @@ public class TaskbarDragController extends DragController im mDragObject.dragInfo = dragInfo; mDragObject.originalDragInfo = mDragObject.dragInfo.makeShallowCopy(); + if (mOptions.preDragCondition != null) { + dragView.setHasDragOffset(mOptions.preDragCondition.getDragOffset().x != 0 + || mOptions.preDragCondition.getDragOffset().y != 0); + } + if (dragRegion != null) { dragView.setDragRegion(new Rect(dragRegion)); } @@ -308,6 +323,14 @@ public class TaskbarDragController extends DragController im return dragView; } + /** Invoked when an animation running as part of pre-drag finishes. */ + public void onPreDragAnimationEnd() { + // Drag might be cancelled during the DragView animation, so check mIsPreDrag again. + if (mIsInPreDrag) { + callOnDragStart(); + } + } + @Override protected void callOnDragStart() { super.callOnDragStart(); @@ -383,6 +406,17 @@ public class TaskbarDragController extends DragController im item.user)); intent.putExtra(Intent.EXTRA_PACKAGE_NAME, item.getIntent().getPackage()); intent.putExtra(Intent.EXTRA_SHORTCUT_ID, deepShortcutId); + } else if (item.itemType == ITEM_TYPE_SEARCH_ACTION) { + // TODO(b/289261756): Buggy behavior when split opposite to an existing search pane. + intent.putExtra( + ClipDescription.EXTRA_PENDING_INTENT, + PendingIntent.getActivityAsUser( + mActivity, + /* requestCode= */ 0, + item.getIntent(), + PendingIntent.FLAG_MUTABLE | PendingIntent.FLAG_UPDATE_CURRENT, + /* options= */ null, + item.user)); } else { intent.putExtra(ClipDescription.EXTRA_PENDING_INTENT, launcherApps.getMainActivityLaunchIntent(item.getIntent().getComponent(), diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java index cf0b36af02..3e1fef91e8 100644 --- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java +++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java @@ -15,11 +15,14 @@ */ package com.android.launcher3.taskbar.allapps; +import android.view.View; + import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.launcher3.R; import com.android.launcher3.appprediction.PredictionRowView; +import com.android.launcher3.dragndrop.DragOptions.PreDragCondition; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.taskbar.TaskbarControllers; @@ -208,4 +211,12 @@ public final class TaskbarAllAppsController { // Allow null-pointer since this should only be null if the apps view is not showing. return mAppsView.getActiveRecyclerView().computeVerticalScrollOffset(); } + + /** @see TaskbarSearchSessionController#createPreDragConditionForSearch(View) */ + @Nullable + public PreDragCondition createPreDragConditionForSearch(View view) { + return mSearchSessionController != null + ? mSearchSessionController.createPreDragConditionForSearch(view) + : null; + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt index 324c1a2f69..52e2ce1067 100644 --- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt @@ -17,8 +17,10 @@ package com.android.launcher3.taskbar.allapps import android.content.Context +import android.view.View import com.android.launcher3.R import com.android.launcher3.config.FeatureFlags +import com.android.launcher3.dragndrop.DragOptions.PreDragCondition import com.android.launcher3.model.data.ItemInfo import com.android.launcher3.util.ResourceBasedOverride import com.android.launcher3.util.ResourceBasedOverride.Overrides @@ -38,6 +40,9 @@ open class TaskbarSearchSessionController : ResourceBasedOverride { /** Updates the search suggestions shown in the zero-state. */ open fun setZeroStateSearchSuggestions(items: List) {} + /** Creates a [PreDragCondition] for [view], if it is a search result that requires one. */ + open fun createPreDragConditionForSearch(view: View): PreDragCondition? = null + companion object { @JvmStatic fun newInstance(context: Context): TaskbarSearchSessionController { diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java index b9bb52c548..adfdc8954c 100644 --- a/src/com/android/launcher3/dragndrop/DragView.java +++ b/src/com/android/launcher3/dragndrop/DragView.java @@ -99,7 +99,9 @@ public abstract class DragView extends Fram // Whether mAnim has started. Unlike mAnim.isStarted(), this is true even after mAnim ends. private boolean mScaleAnimStarted; - private Runnable mOnAnimEndCallback = null; + private boolean mShiftAnimStarted; + private Runnable mOnScaleAnimEndCallback; + private Runnable mOnShiftAnimEndCallback; private int mLastTouchX; private int mLastTouchY; @@ -186,13 +188,26 @@ public abstract class DragView extends Fram @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); - if (mOnAnimEndCallback != null) { - mOnAnimEndCallback.run(); + if (mOnScaleAnimEndCallback != null) { + mOnScaleAnimEndCallback.run(); } } }); // Set up the shift animator. mShiftAnim = ValueAnimator.ofFloat(0f, 1f); + mShiftAnim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + mShiftAnimStarted = true; + } + + @Override + public void onAnimationEnd(Animator animation) { + if (mOnShiftAnimEndCallback != null) { + mOnShiftAnimEndCallback.run(); + } + } + }); setDragRegion(new Rect(0, 0, width, height)); @@ -211,8 +226,14 @@ public abstract class DragView extends Fram setWillNotDraw(false); } - public void setOnAnimationEndCallback(Runnable callback) { - mOnAnimEndCallback = callback; + /** Callback invoked when the scale animation ends. */ + public void setOnScaleAnimEndCallback(Runnable callback) { + mOnScaleAnimEndCallback = callback; + } + + /** Callback invoked when the shift animation ends. */ + public void setOnShiftAnimEndCallback(Runnable callback) { + mOnShiftAnimEndCallback = callback; } /** @@ -416,10 +437,16 @@ public abstract class DragView extends Fram } } + /** {@code true} if the scale animation has finished. */ public boolean isScaleAnimationFinished() { return mScaleAnimStarted && !mScaleAnim.isRunning(); } + /** {@code true} if the shift animation has finished. */ + public boolean isShiftAnimationFinished() { + return mShiftAnimStarted && !mShiftAnim.isRunning(); + } + /** * Move the window containing this view. * diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java b/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java index 717164e0ed..e8be12cba6 100644 --- a/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java +++ b/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java @@ -240,9 +240,8 @@ public class SecondaryDragLayer extends BaseDragLayer public void onPreDragStart(DropTarget.DragObject dragObject) { mDragView = dragObject.dragView; if (!shouldStartDrag(0)) { - mDragView.setOnAnimationEndCallback(() -> { - mActivity.beginDragShared(v, mActivity.getAppsView(), options); - }); + mDragView.setOnScaleAnimEndCallback(() -> + mActivity.beginDragShared(v, mActivity.getAppsView(), options)); } }