Adding support for multiwindow drag and drop
Change-Id: I95b46e3c3f1238307d3ef5a6c81a8e530ba0987a
This commit is contained in:
@@ -259,7 +259,8 @@ public abstract class ButtonDropTarget extends TextView
|
||||
}
|
||||
};
|
||||
dragLayer.animateView(d.dragView, from, to, scale, 1f, 1f, 0.1f, 0.1f,
|
||||
DRAG_VIEW_DROP_DURATION, new DecelerateInterpolator(2),
|
||||
mLauncher.getDragController().isExternalDrag() ? 1 : DRAG_VIEW_DROP_DURATION,
|
||||
new DecelerateInterpolator(2),
|
||||
new LinearInterpolator(), onAnimationEndRunnable,
|
||||
DragLayer.ANIMATION_END_DISAPPEAR, null);
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ public class ShortcutInfo extends ItemInfo {
|
||||
*/
|
||||
Intent promisedIntent;
|
||||
|
||||
ShortcutInfo() {
|
||||
public ShortcutInfo() {
|
||||
itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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.dragndrop;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.launcher3.DragSource;
|
||||
import com.android.launcher3.DropTarget.DragObject;
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
|
||||
|
||||
/**
|
||||
* DragSource used when the drag started at another window.
|
||||
*/
|
||||
public class AnotherWindowDragSource implements DragSource {
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
AnotherWindowDragSource(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFlingToDelete() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsAppInfoDropTarget() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsDeleteDropTarget() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getIntrinsicIconScaleFactor() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFlingToDeleteCompleted() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDropCompleted(View target, DragObject d,
|
||||
boolean isFlingToDelete, boolean success) {
|
||||
if (!success) {
|
||||
Launcher.getLauncher(mContext).exitSpringLoadedDragModeDelayed(false, 0, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillInLaunchSourceData(View v, ItemInfo info, Target target, Target targetParent) {
|
||||
// TODO: Probably log something
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,6 @@ import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
import android.view.DragEvent;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.KeyEvent;
|
||||
@@ -213,6 +212,12 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
}
|
||||
mInputMethodManager.hideSoftInputFromWindow(mWindowToken, 0);
|
||||
|
||||
mOptions = options;
|
||||
if (mOptions.systemDndStartPoint != null) {
|
||||
mMotionDownX = mOptions.systemDndStartPoint.x;
|
||||
mMotionDownY = mOptions.systemDndStartPoint.y;
|
||||
}
|
||||
|
||||
final int registrationX = mMotionDownX - dragLayerX;
|
||||
final int registrationY = mMotionDownY - dragLayerY;
|
||||
|
||||
@@ -221,7 +226,6 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
|
||||
mLastDropTarget = null;
|
||||
|
||||
mOptions = options;
|
||||
mDragObject = new DropTarget.DragObject();
|
||||
|
||||
final Resources res = mLauncher.getResources();
|
||||
@@ -241,7 +245,7 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
mDragObject.yOffset = mMotionDownY - (dragLayerY + dragRegionTop);
|
||||
mDragObject.stateAnnouncer = DragViewStateAnnouncer.createFor(dragView);
|
||||
|
||||
mDragDriver = DragDriver.create(this, dragInfo, dragView);
|
||||
mDragDriver = DragDriver.create(mLauncher, this, mDragObject, mOptions);
|
||||
}
|
||||
|
||||
mDragObject.dragSource = source;
|
||||
@@ -293,6 +297,10 @@ public class DragController implements DragDriver.EventListener, TouchController
|
||||
return mDragDriver != null || (mOptions != null && mOptions.isAccessibleDrag);
|
||||
}
|
||||
|
||||
public boolean isExternalDrag() {
|
||||
return (mOptions != null && mOptions.systemDndStartPoint != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop dragging without dropping.
|
||||
*/
|
||||
|
||||
@@ -17,18 +17,19 @@
|
||||
package com.android.launcher3.dragndrop;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipDescription;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Point;
|
||||
import android.view.DragEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.launcher3.AnotherWindowDropTarget;
|
||||
import com.android.launcher3.DropTarget;
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.DropTarget.DragObject;
|
||||
import com.android.launcher3.InstallShortcutReceiver;
|
||||
import com.android.launcher3.ShortcutInfo;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Base class for driving a drag/drop operation.
|
||||
@@ -50,7 +51,7 @@ public abstract class DragDriver {
|
||||
/**
|
||||
* Handles ending of the DragView animation.
|
||||
*/
|
||||
public abstract void onDragViewAnimationEnd();
|
||||
public void onDragViewAnimationEnd() { }
|
||||
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
final int action = ev.getAction();
|
||||
@@ -89,100 +90,46 @@ public abstract class DragDriver {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static DragDriver create(
|
||||
DragController dragController, ItemInfo dragInfo, DragView dragView) {
|
||||
if (FeatureFlags.LAUNCHER3_USE_SYSTEM_DRAG_DRIVER && Utilities.isNycOrAbove()) {
|
||||
return new SystemDragDriver(dragController, dragInfo.getIntent(), dragView);
|
||||
public static DragDriver create(Context context, DragController dragController,
|
||||
DragObject dragObject, DragOptions options) {
|
||||
if (Utilities.isNycOrAbove() && options.systemDndStartPoint != null) {
|
||||
return new SystemDragDriver(dragController, context, dragObject);
|
||||
} else {
|
||||
return new InternalDragDriver(dragController);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for driving a system (i.e. framework) drag/drop operation.
|
||||
*/
|
||||
class SystemDragDriver extends DragDriver {
|
||||
/** Intent associated with the drag operation, or null is there no associated intent. */
|
||||
private final Intent mDragIntent;
|
||||
|
||||
private final DragView mDragView;
|
||||
boolean mIsFrameworkDragActive = false;
|
||||
private final DragObject mDragObject;
|
||||
private final Context mContext;
|
||||
|
||||
boolean mReceivedDropEvent = false;
|
||||
float mLastX = 0;
|
||||
float mLastY = 0;
|
||||
|
||||
public SystemDragDriver(DragController dragController, Intent dragIntent, DragView dragView) {
|
||||
public SystemDragDriver(DragController dragController, Context context, DragObject dragObject) {
|
||||
super(dragController);
|
||||
mDragIntent = dragIntent;
|
||||
mDragView = dragView;
|
||||
}
|
||||
|
||||
private static class ShadowBuilder extends View.DragShadowBuilder {
|
||||
final DragView mDragView;
|
||||
|
||||
public ShadowBuilder(DragView dragView) {
|
||||
mDragView = dragView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProvideShadowMetrics (Point size, Point touch) {
|
||||
mDragView.provideDragShadowMetrics(size, touch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDrawShadow(Canvas canvas) {
|
||||
mDragView.drawDragShadow(canvas);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onDragViewAnimationEnd() {
|
||||
// Clip data for the drag operation. If there is an intent, create an intent-based ClipData,
|
||||
// which will be passed to a global DND.
|
||||
// If there is no intent, craft a fake ClipData and start a local DND operation; this
|
||||
// ClipData will be ignored.
|
||||
final ClipData dragData = mDragIntent != null ?
|
||||
ClipData.newIntent("", mDragIntent) :
|
||||
ClipData.newPlainText("", "");
|
||||
|
||||
View.DragShadowBuilder shadowBuilder = new ShadowBuilder(mDragView);
|
||||
// TODO: DND flags are in flux, once settled, use the appropriate constant.
|
||||
final int flagGlobal = 1 << 0;
|
||||
final int flagOpaque = 1 << 9;
|
||||
final int flags = (mDragIntent != null ? flagGlobal : 0) | flagOpaque;
|
||||
|
||||
mIsFrameworkDragActive = true;
|
||||
|
||||
if (!mDragView.startDrag(dragData, shadowBuilder, null, flags)) {
|
||||
mIsFrameworkDragActive = false;
|
||||
mEventListener.onDriverDragCancel();
|
||||
return;
|
||||
}
|
||||
|
||||
// Starting from this point, the driver takes over showing the drag shadow, so hiding the
|
||||
// drag view.
|
||||
mDragView.setVisibility(View.INVISIBLE);
|
||||
mDragObject = dragObject;
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
return !mIsFrameworkDragActive && super.onTouchEvent(ev);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
return !mIsFrameworkDragActive && super.onInterceptTouchEvent(ev);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDragEvent (DragEvent event) {
|
||||
if (!mIsFrameworkDragActive) {
|
||||
// We are interested only in drag events started by this driver.
|
||||
return false;
|
||||
}
|
||||
|
||||
final int action = event.getAction();
|
||||
|
||||
switch (action) {
|
||||
@@ -192,8 +139,6 @@ class SystemDragDriver extends DragDriver {
|
||||
return true;
|
||||
|
||||
case DragEvent.ACTION_DRAG_ENTERED:
|
||||
mLastX = event.getX();
|
||||
mLastY = event.getY();
|
||||
return true;
|
||||
|
||||
case DragEvent.ACTION_DRAG_LOCATION:
|
||||
@@ -205,35 +150,66 @@ class SystemDragDriver extends DragDriver {
|
||||
case DragEvent.ACTION_DROP:
|
||||
mLastX = event.getX();
|
||||
mLastY = event.getY();
|
||||
mReceivedDropEvent = true;
|
||||
return true;
|
||||
mReceivedDropEvent =
|
||||
updateInfoFromClipData(event.getClipData(), event.getClipDescription());
|
||||
return mReceivedDropEvent;
|
||||
|
||||
case DragEvent.ACTION_DRAG_EXITED:
|
||||
mLastX = event.getX();
|
||||
mLastY = event.getY();
|
||||
mEventListener.onDriverDragExitWindow();
|
||||
return true;
|
||||
|
||||
case DragEvent.ACTION_DRAG_ENDED:
|
||||
final boolean dragAccepted = event.getResult();
|
||||
final boolean acceptedByAnotherWindow = dragAccepted && !mReceivedDropEvent;
|
||||
|
||||
// When the system drag ends, its drag shadow disappears. Resume showing the drag
|
||||
// view for the possible final animation.
|
||||
mDragView.setVisibility(View.VISIBLE);
|
||||
|
||||
final DropTarget dropTargetOverride = acceptedByAnotherWindow ?
|
||||
new AnotherWindowDropTarget(mDragView.getContext()) : null;
|
||||
|
||||
mEventListener.onDriverDragEnd(mLastX, mLastY, dropTargetOverride);
|
||||
mIsFrameworkDragActive = false;
|
||||
if (mReceivedDropEvent) {
|
||||
mEventListener.onDriverDragEnd(mLastX, mLastY, null);
|
||||
} else {
|
||||
mEventListener.onDriverDragCancel();
|
||||
}
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private boolean updateInfoFromClipData(ClipData data, ClipDescription desc) {
|
||||
if (data == null) {
|
||||
return false;
|
||||
}
|
||||
ArrayList<Intent> intents = new ArrayList<>();
|
||||
int itemCount = data.getItemCount();
|
||||
for (int i = 0; i < itemCount; i++) {
|
||||
Intent intent = data.getItemAt(i).getIntent();
|
||||
if (intent == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Give preference to shortcut intents.
|
||||
if (!Intent.ACTION_CREATE_SHORTCUT.equals(intent.getAction())) {
|
||||
intents.add(intent);
|
||||
continue;
|
||||
}
|
||||
ShortcutInfo info = InstallShortcutReceiver.fromShortcutIntent(mContext, intent);
|
||||
if (info != null) {
|
||||
mDragObject.dragInfo = info;
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try creating shortcuts just using the intent and label
|
||||
Intent fullIntent = new Intent().putExtra(Intent.EXTRA_SHORTCUT_NAME, desc.getLabel());
|
||||
for (Intent intent : intents) {
|
||||
fullIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, intent);
|
||||
ShortcutInfo info = InstallShortcutReceiver.fromShortcutIntent(mContext, fullIntent);
|
||||
if (info != null) {
|
||||
mDragObject.dragInfo = info;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for driving an internal (i.e. not using framework) drag/drop operation.
|
||||
@@ -243,9 +219,6 @@ class InternalDragDriver extends DragDriver {
|
||||
super(dragController);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDragViewAnimationEnd() {}
|
||||
|
||||
@Override
|
||||
public boolean onDragEvent (DragEvent event) { return false; }
|
||||
};
|
||||
|
||||
@@ -21,14 +21,22 @@ import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.TimeInterpolator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.animation.ValueAnimator.AnimatorUpdateListener;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.ClipDescription;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Bitmap.Config;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Region;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.DragEvent;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
@@ -45,12 +53,14 @@ import com.android.launcher3.AppWidgetResizeFrame;
|
||||
import com.android.launcher3.CellLayout;
|
||||
import com.android.launcher3.DropTargetBar;
|
||||
import com.android.launcher3.InsettableFrameLayout;
|
||||
import com.android.launcher3.InstallShortcutReceiver;
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherAppWidgetHostView;
|
||||
import com.android.launcher3.PinchToOverviewListener;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.ShortcutAndWidgetContainer;
|
||||
import com.android.launcher3.ShortcutInfo;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.Workspace;
|
||||
import com.android.launcher3.allapps.AllAppsTransitionController;
|
||||
@@ -62,6 +72,7 @@ import com.android.launcher3.shortcuts.DeepShortcutsContainer;
|
||||
import com.android.launcher3.util.Thunk;
|
||||
import com.android.launcher3.util.TouchController;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
@@ -431,8 +442,46 @@ public class DragLayer extends InsettableFrameLayout {
|
||||
return false;
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.N)
|
||||
private void handleSystemDragStart(DragEvent event) {
|
||||
if (!FeatureFlags.LAUNCHER3_USE_SYSTEM_DRAG_DRIVER || !Utilities.isNycOrAbove()) {
|
||||
return;
|
||||
}
|
||||
if (mLauncher.isWorkspaceLocked()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ClipDescription description = event.getClipDescription();
|
||||
if (!description.hasMimeType(ClipDescription.MIMETYPE_TEXT_INTENT)) {
|
||||
return;
|
||||
}
|
||||
ShortcutInfo info = new ShortcutInfo();
|
||||
// Set a dummy intent until we get the final value
|
||||
info.intent = new Intent();
|
||||
|
||||
// Since we are not going through the workspace for starting the drag, set drag related
|
||||
// information on the workspace before starting the drag.
|
||||
ExternalDragPreviewProvider previewProvider =
|
||||
new ExternalDragPreviewProvider(mLauncher, info);
|
||||
mLauncher.getWorkspace().prepareDragWithProvider(previewProvider);
|
||||
|
||||
DragOptions options = new DragOptions();
|
||||
options.systemDndStartPoint = new Point((int) event.getX(), (int) event.getY());
|
||||
|
||||
int halfPadding = previewProvider.previewPadding / 2;
|
||||
mDragController.startDrag(
|
||||
Bitmap.createBitmap(1, 1, Config.ARGB_8888),
|
||||
0, 0,
|
||||
new AnotherWindowDragSource(mLauncher), info,
|
||||
new Point(- halfPadding, halfPadding),
|
||||
previewProvider.getPreviewBounds(), 1f, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDragEvent (DragEvent event) {
|
||||
if (event.getAction() == DragEvent.ACTION_DRAG_STARTED) {
|
||||
handleSystemDragStart(event);
|
||||
}
|
||||
return mDragController.onDragEvent(event);
|
||||
}
|
||||
|
||||
@@ -758,11 +807,15 @@ public class DragLayer extends InsettableFrameLayout {
|
||||
|
||||
// If duration < 0, this is a cue to compute the duration based on the distance
|
||||
if (duration < 0) {
|
||||
duration = res.getInteger(R.integer.config_dropAnimMaxDuration);
|
||||
if (dist < maxDist) {
|
||||
duration *= mCubicEaseOutInterpolator.getInterpolation(dist / maxDist);
|
||||
if (mDragController != null && mDragController.isExternalDrag()) {
|
||||
duration = 1;
|
||||
} else {
|
||||
duration = res.getInteger(R.integer.config_dropAnimMaxDuration);
|
||||
if (dist < maxDist) {
|
||||
duration *= mCubicEaseOutInterpolator.getInterpolation(dist / maxDist);
|
||||
}
|
||||
duration = Math.max(duration, res.getInteger(R.integer.config_dropAnimMinDuration));
|
||||
}
|
||||
duration = Math.max(duration, res.getInteger(R.integer.config_dropAnimMinDuration));
|
||||
}
|
||||
|
||||
// Fall back to cubic ease out interpolator for the animation if none is specified
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.launcher3.dragndrop;
|
||||
|
||||
import android.graphics.Point;
|
||||
|
||||
/**
|
||||
* Set of options to control the drag and drop behavior.
|
||||
*/
|
||||
@@ -23,4 +25,7 @@ public class DragOptions {
|
||||
|
||||
/** Whether or not an accessible drag operation is in progress. */
|
||||
public boolean isAccessibleDrag = false;
|
||||
|
||||
/** Specifies the start location for the system DnD, null when using internal DnD */
|
||||
public Point systemDndStartPoint = null;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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.dragndrop;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.HolographicOutlineHelper;
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.graphics.DragPreviewProvider;
|
||||
|
||||
/**
|
||||
* Extension of {@link DragPreviewProvider} which provides a dummy outline when drag starts from
|
||||
* a different window.
|
||||
* It just draws an empty circle to a placeholder outline.
|
||||
*/
|
||||
public class ExternalDragPreviewProvider extends DragPreviewProvider {
|
||||
|
||||
private final Launcher mLauncher;
|
||||
private final ItemInfo mAddInfo;
|
||||
|
||||
private final int[] mOutlineSize;
|
||||
|
||||
public ExternalDragPreviewProvider(Launcher launcher, ItemInfo addInfo) {
|
||||
super(null);
|
||||
mLauncher = launcher;
|
||||
mAddInfo = addInfo;
|
||||
|
||||
mOutlineSize = mLauncher.getWorkspace().estimateItemSize(mAddInfo, false);
|
||||
}
|
||||
|
||||
public Rect getPreviewBounds() {
|
||||
Rect rect = new Rect();
|
||||
DeviceProfile dp = mLauncher.getDeviceProfile();
|
||||
rect.left = DRAG_BITMAP_PADDING / 2;
|
||||
rect.top = (mOutlineSize[1] - dp.cellHeightPx) / 2;
|
||||
rect.right = rect.left + dp.iconSizePx;
|
||||
rect.bottom = rect.top + dp.iconSizePx;
|
||||
return rect;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bitmap createDragOutline(Canvas canvas) {
|
||||
final Bitmap b = Bitmap.createBitmap(mOutlineSize[0], mOutlineSize[1], Bitmap.Config.ALPHA_8);
|
||||
canvas.setBitmap(b);
|
||||
|
||||
Paint paint = new Paint();
|
||||
paint.setColor(Color.WHITE);
|
||||
paint.setStyle(Paint.Style.FILL);
|
||||
|
||||
// Use 0.9f times the radius for the actual circle to account for icon normalization.
|
||||
float radius = getPreviewBounds().width() * 0.5f;
|
||||
canvas.drawCircle(DRAG_BITMAP_PADDING / 2 + radius,
|
||||
DRAG_BITMAP_PADDING / 2 + radius, radius * 0.9f, paint);
|
||||
|
||||
HolographicOutlineHelper.obtain(mLauncher).applyExpensiveOutlineWithBlur(b, canvas);
|
||||
canvas.setBitmap(null);
|
||||
return b;
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ public final class FeatureFlags {
|
||||
// As opposed to the new spring-loaded workspace.
|
||||
public static boolean LAUNCHER3_LEGACY_WORKSPACE_DND = false;
|
||||
public static boolean LAUNCHER3_LEGACY_FOLDER_ICON = false;
|
||||
public static boolean LAUNCHER3_USE_SYSTEM_DRAG_DRIVER = false;
|
||||
public static boolean LAUNCHER3_USE_SYSTEM_DRAG_DRIVER = true;
|
||||
public static boolean LAUNCHER3_DISABLE_PINCH_TO_OVERVIEW = false;
|
||||
public static boolean LAUNCHER3_ALL_APPS_PULL_UP = true;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user