mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-03-01 00:06:47 +00:00
Disable Drag from Taskbar in Overview
* Still need to disable drag from all apps in overview * Disallow any taskbar icon long click when in split select Bug: 251747761 Test: Drag from hotseat and predicted icons in overview, snaps back to position Change-Id: Ib9b068e4914b9197614c8e8f49b7899bb964f92b
This commit is contained in:
@@ -18,10 +18,12 @@ package com.android.launcher3.taskbar;
|
||||
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.anim.Interpolators.FAST_OUT_SLOW_IN;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.NonNull;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipDescription;
|
||||
import android.content.Intent;
|
||||
@@ -49,7 +51,6 @@ import com.android.launcher3.DragSource;
|
||||
import com.android.launcher3.DropTarget;
|
||||
import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.accessibility.DragViewStateAnnouncer;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
@@ -70,6 +71,7 @@ import com.android.launcher3.testing.shared.TestProtocol;
|
||||
import com.android.launcher3.util.IntSet;
|
||||
import com.android.launcher3.util.ItemInfoMatcher;
|
||||
import com.android.quickstep.util.LogUtils;
|
||||
import com.android.quickstep.util.MultiValueUpdateListener;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
@@ -83,7 +85,8 @@ import java.util.function.Predicate;
|
||||
public class TaskbarDragController extends DragController<BaseTaskbarContext> implements
|
||||
TaskbarControllers.LoggableTaskbarController {
|
||||
|
||||
private static boolean DEBUG_DRAG_SHADOW_SURFACE = false;
|
||||
private static final boolean DEBUG_DRAG_SHADOW_SURFACE = false;
|
||||
private static final int ANIM_DURATION_RETURN_ICON_TO_TASKBAR = 300;
|
||||
|
||||
private final int mDragIconSize;
|
||||
private final int[] mTempXY = new int[2];
|
||||
@@ -99,6 +102,8 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im
|
||||
|
||||
// Animation for the drag shadow back into position after an unsuccessful drag
|
||||
private ValueAnimator mReturnAnimator;
|
||||
private boolean mDisallowGlobalDrag;
|
||||
private boolean mDisallowLongClick;
|
||||
|
||||
public TaskbarDragController(BaseTaskbarContext activity) {
|
||||
super(activity);
|
||||
@@ -110,6 +115,14 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im
|
||||
mControllers = controllers;
|
||||
}
|
||||
|
||||
public void setDisallowGlobalDrag(boolean disallowGlobalDrag) {
|
||||
mDisallowGlobalDrag = disallowGlobalDrag;
|
||||
}
|
||||
|
||||
public void setDisallowLongClick(boolean disallowLongClick) {
|
||||
mDisallowLongClick = disallowLongClick;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to start a system drag and drop operation for the given View, using its tag to
|
||||
* generate the ClipDescription and Intent.
|
||||
@@ -131,7 +144,7 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im
|
||||
View view,
|
||||
@Nullable DragPreviewProvider dragPreviewProvider,
|
||||
@Nullable Point iconShift) {
|
||||
if (!(view instanceof BubbleTextView)) {
|
||||
if (!(view instanceof BubbleTextView) || mDisallowLongClick) {
|
||||
return false;
|
||||
}
|
||||
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onTaskbarItemLongClick");
|
||||
@@ -293,6 +306,7 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im
|
||||
}
|
||||
|
||||
private void startSystemDrag(BubbleTextView btv) {
|
||||
if (mDisallowGlobalDrag) return;
|
||||
View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(btv) {
|
||||
|
||||
@Override
|
||||
@@ -421,6 +435,45 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void endDrag() {
|
||||
if (mDisallowGlobalDrag) {
|
||||
// We need to explicitly set deferDragViewCleanupPostAnimation to true here so the
|
||||
// super call doesn't remove it from the drag layer before the animation completes.
|
||||
// This variable gets set in to false in super.dispatchDropComplete() because it
|
||||
// (rightfully so, perhaps) thinks this drag operation has failed, and does its own
|
||||
// internal cleanup.
|
||||
// Another way to approach this would be to make all of overview a drop target and
|
||||
// accept the drop as successful and then run the setupReturnDragAnimator to simulate
|
||||
// drop failure to the user
|
||||
mDragObject.deferDragViewCleanupPostAnimation = true;
|
||||
|
||||
float fromX = mDragObject.x - mDragObject.xOffset;
|
||||
float fromY = mDragObject.y - mDragObject.yOffset;
|
||||
DragView dragView = mDragObject.dragView;
|
||||
setupReturnDragAnimator(fromX, fromY, (View) mDragObject.originalView,
|
||||
(x, y, scale, alpha) -> {
|
||||
dragView.setTranslationX(x);
|
||||
dragView.setTranslationY(y);
|
||||
dragView.setScaleX(scale);
|
||||
dragView.setScaleY(scale);
|
||||
dragView.setAlpha(alpha);
|
||||
});
|
||||
mReturnAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
callOnDragEnd();
|
||||
dragView.remove();
|
||||
dragView.clearAnimation();
|
||||
mReturnAnimator = null;
|
||||
|
||||
}
|
||||
});
|
||||
mReturnAnimator.start();
|
||||
}
|
||||
super.endDrag();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void callOnDragEnd() {
|
||||
super.callOnDragEnd();
|
||||
@@ -432,56 +485,20 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im
|
||||
SurfaceControl dragSurface = dragEvent.getDragSurface();
|
||||
|
||||
// For top level icons, the target is the icon itself
|
||||
View target = btv;
|
||||
Object tag = btv.getTag();
|
||||
if (tag instanceof ItemInfo) {
|
||||
ItemInfo item = (ItemInfo) tag;
|
||||
TaskbarViewController taskbarViewController = mControllers.taskbarViewController;
|
||||
if (item.container == CONTAINER_ALL_APPS || item.container == CONTAINER_PREDICTION) {
|
||||
// Since all apps closes when the drag starts, target the all apps button instead.
|
||||
target = taskbarViewController.getAllAppsButtonView();
|
||||
} else if (item.container >= 0) {
|
||||
// Since folders close when the drag starts, target the folder icon instead.
|
||||
Predicate<ItemInfo> matcher = ItemInfoMatcher.forFolderMatch(
|
||||
ItemInfoMatcher.ofItemIds(IntSet.wrap(item.id)));
|
||||
target = taskbarViewController.getFirstIconMatch(matcher);
|
||||
} else if (item.itemType == ITEM_TYPE_DEEP_SHORTCUT) {
|
||||
// Find first icon with same package/user as the deep shortcut.
|
||||
Predicate<ItemInfo> packageUserMatcher = ItemInfoMatcher.ofPackages(
|
||||
Collections.singleton(item.getTargetPackage()), item.user);
|
||||
target = taskbarViewController.getFirstIconMatch(packageUserMatcher);
|
||||
}
|
||||
}
|
||||
|
||||
// Finish any pending return animation before starting a new drag
|
||||
if (mReturnAnimator != null) {
|
||||
mReturnAnimator.end();
|
||||
}
|
||||
View target = findTaskbarTargetForIconView(btv);
|
||||
|
||||
float fromX = dragEvent.getX() - dragEvent.getOffsetX();
|
||||
float fromY = dragEvent.getY() - dragEvent.getOffsetY();
|
||||
int[] toPosition = target.getLocationOnScreen();
|
||||
float toScale = (float) target.getWidth() / mDragIconSize;
|
||||
float toAlpha = (target == btv) ? 1f : 0f;
|
||||
final ViewRootImpl viewRoot = target.getViewRootImpl();
|
||||
SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
|
||||
mReturnAnimator = ValueAnimator.ofFloat(0f, 1f);
|
||||
mReturnAnimator.setDuration(300);
|
||||
mReturnAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
|
||||
mReturnAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
float t = animation.getAnimatedFraction();
|
||||
float accelT = Interpolators.ACCEL_2.getInterpolation(t);
|
||||
float scale = 1f - t * (1f - toScale);
|
||||
float alpha = 1f - accelT * (1f - toAlpha);
|
||||
tx.setPosition(dragSurface, Utilities.mapRange(t, fromX, toPosition[0]),
|
||||
Utilities.mapRange(t, fromY, toPosition[1]));
|
||||
tx.setScale(dragSurface, scale, scale);
|
||||
tx.setAlpha(dragSurface, alpha);
|
||||
tx.apply();
|
||||
}
|
||||
});
|
||||
setupReturnDragAnimator(fromX, fromY, btv,
|
||||
(x, y, scale, alpha) -> {
|
||||
tx.setPosition(dragSurface, x, y);
|
||||
tx.setScale(dragSurface, scale, scale);
|
||||
tx.setAlpha(dragSurface, alpha);
|
||||
tx.apply();
|
||||
});
|
||||
|
||||
mReturnAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
private boolean mCanceled = false;
|
||||
|
||||
@@ -517,6 +534,63 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im
|
||||
mReturnAnimator.start();
|
||||
}
|
||||
|
||||
private View findTaskbarTargetForIconView(@NonNull View iconView) {
|
||||
Object tag = iconView.getTag();
|
||||
if (tag instanceof ItemInfo) {
|
||||
ItemInfo item = (ItemInfo) tag;
|
||||
TaskbarViewController taskbarViewController = mControllers.taskbarViewController;
|
||||
if (item.container == CONTAINER_ALL_APPS || item.container == CONTAINER_PREDICTION) {
|
||||
// Since all apps closes when the drag starts, target the all apps button instead.
|
||||
return taskbarViewController.getAllAppsButtonView();
|
||||
} else if (item.container >= 0) {
|
||||
// Since folders close when the drag starts, target the folder icon instead.
|
||||
Predicate<ItemInfo> matcher = ItemInfoMatcher.forFolderMatch(
|
||||
ItemInfoMatcher.ofItemIds(IntSet.wrap(item.id)));
|
||||
return taskbarViewController.getFirstIconMatch(matcher);
|
||||
} else if (item.itemType == ITEM_TYPE_DEEP_SHORTCUT) {
|
||||
// Find first icon with same package/user as the deep shortcut.
|
||||
Predicate<ItemInfo> packageUserMatcher = ItemInfoMatcher.ofPackages(
|
||||
Collections.singleton(item.getTargetPackage()), item.user);
|
||||
return taskbarViewController.getFirstIconMatch(packageUserMatcher);
|
||||
}
|
||||
}
|
||||
return iconView;
|
||||
}
|
||||
|
||||
private void setupReturnDragAnimator(float fromX, float fromY, View originalView,
|
||||
TaskbarReturnPropertiesListener animListener) {
|
||||
// Finish any pending return animation before starting a new return
|
||||
if (mReturnAnimator != null) {
|
||||
mReturnAnimator.end();
|
||||
}
|
||||
|
||||
// For top level icons, the target is the icon itself
|
||||
View target = findTaskbarTargetForIconView(originalView);
|
||||
|
||||
int[] toPosition = target.getLocationOnScreen();
|
||||
float toScale = (float) target.getWidth() / mDragIconSize;
|
||||
float toAlpha = (target == originalView) ? 1f : 0f;
|
||||
MultiValueUpdateListener listener = new MultiValueUpdateListener() {
|
||||
final FloatProp mDx = new FloatProp(fromX, toPosition[0], 0,
|
||||
ANIM_DURATION_RETURN_ICON_TO_TASKBAR, Interpolators.FAST_OUT_SLOW_IN);
|
||||
final FloatProp mDy = new FloatProp(fromY, toPosition[1], 0,
|
||||
ANIM_DURATION_RETURN_ICON_TO_TASKBAR,
|
||||
FAST_OUT_SLOW_IN);
|
||||
final FloatProp mScale = new FloatProp(1f, toScale, 0,
|
||||
ANIM_DURATION_RETURN_ICON_TO_TASKBAR, FAST_OUT_SLOW_IN);
|
||||
final FloatProp mAlpha = new FloatProp(1f, toAlpha, 0,
|
||||
ANIM_DURATION_RETURN_ICON_TO_TASKBAR, Interpolators.ACCEL_2);
|
||||
@Override
|
||||
public void onUpdate(float percent, boolean initOnly) {
|
||||
animListener.updateDragShadow(mDx.value, mDy.value, mScale.value, mAlpha.value);
|
||||
}
|
||||
};
|
||||
mReturnAnimator = ValueAnimator.ofFloat(0f, 1f);
|
||||
mReturnAnimator.setDuration(ANIM_DURATION_RETURN_ICON_TO_TASKBAR);
|
||||
mReturnAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
|
||||
mReturnAnimator.addUpdateListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getX(MotionEvent ev) {
|
||||
// We will resize to fill the screen while dragging, so use screen coordinates. This ensures
|
||||
@@ -540,7 +614,7 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im
|
||||
|
||||
@Override
|
||||
protected void exitDrag() {
|
||||
if (mDragObject != null) {
|
||||
if (mDragObject != null && !mDisallowGlobalDrag) {
|
||||
mActivity.getDragLayer().removeView(mDragObject.dragView);
|
||||
}
|
||||
}
|
||||
@@ -556,6 +630,10 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im
|
||||
return null;
|
||||
}
|
||||
|
||||
interface TaskbarReturnPropertiesListener {
|
||||
void updateDragShadow(float x, float y, float scale, float alpha);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dumpLogs(String prefix, PrintWriter pw) {
|
||||
pw.println(prefix + "TaskbarDragController:");
|
||||
@@ -566,5 +644,7 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im
|
||||
pw.println(prefix + "\tmRegistrationY=" + mRegistrationY);
|
||||
pw.println(prefix + "\tmIsSystemDragInProgress=" + mIsSystemDragInProgress);
|
||||
pw.println(prefix + "\tisInternalDragInProgess=" + super.isDragging());
|
||||
pw.println(prefix + "\tmDisallowGlobalDrag=" + mDisallowGlobalDrag);
|
||||
pw.println(prefix + "\tmDisallowLongClick=" + mDisallowLongClick);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user