From dec3a908bfa395095e80e4a532cff98612b624de Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 25 Jan 2017 18:23:36 -0800 Subject: Updating the preview generation logic so that it aligns better with the drag source image > Using common code for pending item drag (WidgetContainerView and PinItemDragListener) > Adding a shortcut-circuit in Workspace when a pendingItem can create a shortcut directly. Previously the multi-window drop was routing through onActivityResult which was causing some state information to be lost. Bug: 33584624 Change-Id: I0259870032185713caa9bff27092dbae6ce91199 --- src/com/android/launcher3/ButtonDropTarget.java | 2 +- src/com/android/launcher3/Launcher.java | 21 +-- src/com/android/launcher3/Workspace.java | 56 ++++-- .../launcher3/compat/LauncherAppsCompat.java | 38 ++++ .../launcher3/compat/PinItemRequestCompat.java | 4 - .../compat/ShortcutConfigActivityInfo.java | 17 +- .../launcher3/dragndrop/AddItemActivity.java | 10 +- .../launcher3/dragndrop/DragController.java | 26 --- src/com/android/launcher3/dragndrop/DragLayer.java | 12 +- src/com/android/launcher3/dragndrop/DragView.java | 4 + .../launcher3/dragndrop/PinItemDragListener.java | 79 +++------ .../dragndrop/PinShortcutRequestActivityInfo.java | 12 +- .../launcher3/widget/PendingItemDragHelper.java | 191 +++++++++++++++++++++ .../widget/PendingItemPreviewProvider.java | 76 -------- .../launcher3/widget/WidgetsContainerView.java | 72 +------- 15 files changed, 335 insertions(+), 285 deletions(-) create mode 100644 src/com/android/launcher3/widget/PendingItemDragHelper.java delete mode 100644 src/com/android/launcher3/widget/PendingItemPreviewProvider.java diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java index 85b08d116..8d69fe374 100644 --- a/src/com/android/launcher3/ButtonDropTarget.java +++ b/src/com/android/launcher3/ButtonDropTarget.java @@ -229,7 +229,7 @@ public abstract class ButtonDropTarget extends TextView } }; dragLayer.animateView(d.dragView, from, to, scale, 1f, 1f, 0.1f, 0.1f, - mLauncher.getDragController().isExternalDrag() ? 1 : DRAG_VIEW_DROP_DURATION, + DRAG_VIEW_DROP_DURATION, new DecelerateInterpolator(2), new LinearInterpolator(), onAnimationEndRunnable, DragLayer.ANIMATION_END_DISAPPEAR, null); diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index a1aafb821..11db9a0eb 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -101,7 +101,6 @@ import com.android.launcher3.dragndrop.PinItemDragListener; import com.android.launcher3.dynamicui.ExtractedColors; import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.FolderIcon; -import com.android.launcher3.graphics.LauncherIcons; import com.android.launcher3.keyboard.CustomActionsPopup; import com.android.launcher3.keyboard.ViewGroupFocusHelper; import com.android.launcher3.logging.FileLog; @@ -111,7 +110,6 @@ import com.android.launcher3.model.WidgetItem; import com.android.launcher3.pageindicators.PageIndicator; import com.android.launcher3.popup.PopupContainerWithArrow; import com.android.launcher3.shortcuts.DeepShortcutManager; -import com.android.launcher3.shortcuts.ShortcutInfoCompat; import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.userevent.nano.LauncherLogProto.Action; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; @@ -836,7 +834,7 @@ public class Launcher extends BaseActivity } @Override - public void onActivityResult( + protected void onActivityResult( final int requestCode, final int resultCode, final Intent data) { handleActivityResult(requestCode, resultCode, data); if (mLauncherCallbacks != null) { @@ -1459,21 +1457,8 @@ public class Launcher extends BaseActivity ShortcutInfo info = null; if (Utilities.isAtLeastO()) { - PinItemRequestCompat request = PinItemRequestCompat.getPinItemRequest(data); - // request.accept will initiate a shortcutChanged callback. To ensure that the model is - // consistent, that callback must be processed by the model, after the ShortcutInfo is - // added to the model. This is guaranteed here the callback comes on the UI thread, and - // we will add the shortcut on the UI thread as well. - if (request != null && - request.getRequestType() == PinItemRequestCompat.REQUEST_TYPE_SHORTCUT && - request.isValid() && request.accept()) { - ShortcutInfoCompat compat = new ShortcutInfoCompat(request.getShortcutInfo()); - info = new ShortcutInfo(compat, this); - // Apply the unbadged icon and fetch the actual icon asynchronously. - info.iconBitmap = LauncherIcons - .createShortcutIcon(compat, this, false /* badged */); - getModel().updateAndBindShortcutInfo(info, compat); - } + info = LauncherAppsCompat.createShortcutInfoFromPinItemRequest( + this, PinItemRequestCompat.getPinItemRequest(data)); } if (info == null) { diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index cd1d8d9a2..72dff6686 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -2523,7 +2523,7 @@ public class Workspace extends PagedView if (d.dragSource != this) { final int[] touchXY = new int[] { (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1] }; - onDropExternal(touchXY, d.dragInfo, dropTargetLayout, d); + onDropExternal(touchXY, dropTargetLayout, d); } else if (mDragInfo != null) { final View cell = mDragInfo.cell; boolean droppedOnOriginalCellDuringTransition = false; @@ -3226,8 +3226,7 @@ public class Workspace extends PagedView * NOTE: This can also be called when we are outside of a drag event, when we want * to add an item to one of the workspace screens. */ - private void onDropExternal(final int[] touchXY, final ItemInfo dragInfo, - final CellLayout cellLayout, DragObject d) { + private void onDropExternal(final int[] touchXY, final CellLayout cellLayout, DragObject d) { final Runnable exitSpringLoadedRunnable = new Runnable() { @Override public void run() { @@ -3236,7 +3235,15 @@ public class Workspace extends PagedView } }; - ItemInfo info = dragInfo; + if (d.dragInfo instanceof PendingAddShortcutInfo) { + ShortcutInfo si = ((PendingAddShortcutInfo) d.dragInfo) + .activityInfo.createShortcutInfo(); + if (si != null) { + d.dragInfo = si; + } + } + + ItemInfo info = d.dragInfo; int spanX = info.spanX; int spanY = info.spanY; if (mDragInfo != null) { @@ -3255,7 +3262,7 @@ public class Workspace extends PagedView } if (info instanceof PendingAddItemInfo) { - final PendingAddItemInfo pendingInfo = (PendingAddItemInfo) dragInfo; + final PendingAddItemInfo pendingInfo = (PendingAddItemInfo) info; boolean findNearestVacantCell = true; if (pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) { @@ -3318,7 +3325,7 @@ public class Workspace extends PagedView int animationStyle = ANIMATE_INTO_POSITION_AND_DISAPPEAR; if (isWidget && ((PendingAddWidgetInfo) pendingInfo).info != null && - ((PendingAddWidgetInfo) pendingInfo).info.configure != null) { + ((PendingAddWidgetInfo) pendingInfo).getHandler().needsConfigure()) { animationStyle = ANIMATE_INTO_POSITION_AND_REMAIN; } animateWidgetDrop(info, cellLayout, d.dragView, onAnimationCompleteRunnable, @@ -3433,21 +3440,32 @@ public class Workspace extends PagedView mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(layout, loc, true); resetTransitionTransform(layout); - float dragViewScaleX = 1f; - float dragViewScaleY = 1f; if (scale) { - dragViewScaleX = (1.0f * r.width()) / dragView.getMeasuredWidth(); - dragViewScaleY = (1.0f * r.height()) / dragView.getMeasuredHeight(); + float dragViewScaleX = (1.0f * r.width()) / dragView.getMeasuredWidth(); + float dragViewScaleY = (1.0f * r.height()) / dragView.getMeasuredHeight(); + + // The animation will scale the dragView about its center, so we need to center about + // the final location. + loc[0] -= (dragView.getMeasuredWidth() - cellLayoutScale * r.width()) / 2 + - Math.ceil(layout.getUnusedHorizontalSpace() / 2f); + loc[1] -= (dragView.getMeasuredHeight() - cellLayoutScale * r.height()) / 2; + scaleXY[0] = dragViewScaleX * cellLayoutScale; + scaleXY[1] = dragViewScaleY * cellLayoutScale; + } else { + // Since we are not cross-fading the dragView, align the drag view to the + // final cell position. + float dragScale = dragView.getInitialScale() * cellLayoutScale; + loc[0] += (dragScale - 1) * dragView.getWidth() / 2; + loc[1] += (dragScale - 1) * dragView.getHeight() / 2; + scaleXY[0] = scaleXY[1] = dragScale; + + // If a dragRegion was provided, offset the final position accordingly. + Rect dragRegion = dragView.getDragRegion(); + if (dragRegion != null) { + loc[0] += cellLayoutScale * dragRegion.left; + loc[1] += cellLayoutScale * dragRegion.top; + } } - - // The animation will scale the dragView about its center, so we need to center about - // the final location. - loc[0] -= (dragView.getMeasuredWidth() - cellLayoutScale * r.width()) / 2 - - Math.ceil(layout.getUnusedHorizontalSpace() / 2f); - loc[1] -= (dragView.getMeasuredHeight() - cellLayoutScale * r.height()) / 2; - - scaleXY[0] = dragViewScaleX * cellLayoutScale; - scaleXY[1] = dragViewScaleY * cellLayoutScale; } public void animateWidgetDrop(ItemInfo info, CellLayout cellLayout, final DragView dragView, diff --git a/src/com/android/launcher3/compat/LauncherAppsCompat.java b/src/com/android/launcher3/compat/LauncherAppsCompat.java index 281069af0..b9142ed16 100644 --- a/src/com/android/launcher3/compat/LauncherAppsCompat.java +++ b/src/com/android/launcher3/compat/LauncherAppsCompat.java @@ -23,8 +23,12 @@ import android.content.pm.LauncherActivityInfo; import android.graphics.Rect; import android.os.Bundle; import android.os.UserHandle; +import android.support.annotation.Nullable; +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.ShortcutInfo; import com.android.launcher3.Utilities; +import com.android.launcher3.graphics.LauncherIcons; import com.android.launcher3.shortcuts.ShortcutInfoCompat; import java.util.List; @@ -75,4 +79,38 @@ public abstract class LauncherAppsCompat { public abstract boolean isActivityEnabledForProfile(ComponentName component, UserHandle user); public abstract List getCustomShortcutActivityList(); + + /** + * request.accept() will initiate the following flow: + * -> go-to-system-process for actual processing (a) + * -> callback-to-launcher on UI thread (b) + * -> post callback on the worker thread (c) + * -> Update model and unpin (in system) any shortcut not in out model. (d) + * + * Note that (b) will take at-least one frame as it involves posting callback from binder + * thread to UI thread. + * If (d) happens before we add this shortcut to our model, we will end up unpinning + * the shortcut in the system. + * Here its the caller's responsibility to add the newly created ShortcutInfo immediately + * to the model (which may involves a single post-to-worker-thread). That will guarantee + * that (d) happens after model is updated. + */ + @Nullable + public static ShortcutInfo createShortcutInfoFromPinItemRequest( + Context context, PinItemRequestCompat request) { + if (request != null && + request.getRequestType() == PinItemRequestCompat.REQUEST_TYPE_SHORTCUT && + request.isValid() && request.accept()) { + ShortcutInfoCompat compat = new ShortcutInfoCompat(request.getShortcutInfo()); + ShortcutInfo info = new ShortcutInfo(compat, context); + // Apply the unbadged icon and fetch the actual icon asynchronously. + info.iconBitmap = LauncherIcons + .createShortcutIcon(compat, context, false /* badged */); + LauncherAppState.getInstance(context).getModel() + .updateAndBindShortcutInfo(info, compat); + return info; + } else { + return null; + } + } } diff --git a/src/com/android/launcher3/compat/PinItemRequestCompat.java b/src/com/android/launcher3/compat/PinItemRequestCompat.java index 481310a15..f76b77655 100644 --- a/src/com/android/launcher3/compat/PinItemRequestCompat.java +++ b/src/com/android/launcher3/compat/PinItemRequestCompat.java @@ -94,10 +94,6 @@ public class PinItemRequestCompat implements Parcelable { parcel.writeParcelable(mObject, i); } - public Intent toIntent() { - return new Intent().putExtra(EXTRA_PIN_ITEM_REQUEST, mObject); - } - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public PinItemRequestCompat createFromParcel(Parcel source) { diff --git a/src/com/android/launcher3/compat/ShortcutConfigActivityInfo.java b/src/com/android/launcher3/compat/ShortcutConfigActivityInfo.java index 1cfbd2061..ebe95d680 100644 --- a/src/com/android/launcher3/compat/ShortcutConfigActivityInfo.java +++ b/src/com/android/launcher3/compat/ShortcutConfigActivityInfo.java @@ -26,18 +26,15 @@ import android.content.pm.ActivityInfo; import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps; import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; import android.graphics.drawable.Drawable; -import android.os.Bundle; import android.os.Process; import android.os.UserHandle; import android.util.Log; import android.widget.Toast; import com.android.launcher3.IconCache; -import com.android.launcher3.Launcher; import com.android.launcher3.R; -import com.android.launcher3.Utilities; +import com.android.launcher3.ShortcutInfo; import java.lang.reflect.Method; @@ -68,7 +65,15 @@ public abstract class ShortcutConfigActivityInfo { public abstract Drawable getFullResIcon(IconCache cache); - public boolean startConfigActivity(Launcher activity, int requestCode) { + /** + * Return a shortcut info, if it can be created directly on drop, without requiring any + * {@link #startConfigActivity(Activity, int)}. + */ + public ShortcutInfo createShortcutInfo() { + return null; + } + + public boolean startConfigActivity(Activity activity, int requestCode) { Intent intent = new Intent(Intent.ACTION_CREATE_SHORTCUT) .setComponent(getComponent()); try { @@ -137,7 +142,7 @@ public abstract class ShortcutConfigActivityInfo { } @Override - public boolean startConfigActivity(Launcher activity, int requestCode) { + public boolean startConfigActivity(Activity activity, int requestCode) { if (getUser().equals(Process.myUserHandle())) { return super.startConfigActivity(activity, requestCode); } diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java index 423fdabfc..b80baf32f 100644 --- a/src/com/android/launcher3/dragndrop/AddItemActivity.java +++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java @@ -117,11 +117,19 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener public boolean onLongClick(View view) { // Find the position of the preview relative to the touch location. WidgetImageView img = mWidgetCell.getWidgetView(); + + // If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and + // we abort the drag. + if (img.getBitmap() == null) { + return false; + } + Rect bounds = img.getBitmapBounds(); bounds.offset(img.getLeft() - (int) mLastTouchPos.x, img.getTop() - (int) mLastTouchPos.y); // Start home and pass the draw request params - PinItemDragListener listener = new PinItemDragListener(mRequest, bounds); + PinItemDragListener listener = new PinItemDragListener(mRequest, bounds, + img.getBitmap().getWidth(), img.getWidth()); Intent homeIntent = new Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_HOME) .setPackage(getPackageName()) diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java index 5a5e7d0ab..e31c8ffdd 100644 --- a/src/com/android/launcher3/dragndrop/DragController.java +++ b/src/com/android/launcher3/dragndrop/DragController.java @@ -118,28 +118,6 @@ public class DragController implements DragDriver.EventListener, TouchController mFlingToDeleteHelper = new FlingToDeleteHelper(launcher); } - /** - * Starts a drag. - * - * @param v The view that is being dragged - * @param bmp The bitmap that represents the view being dragged - * @param source An object representing where the drag originated - * @param dragInfo The data associated with the object that is being dragged - * @param viewImageBounds the position of the image inside the view - */ - public void startDrag(View v, Bitmap bmp, DragSource source, ItemInfo dragInfo, - Rect viewImageBounds, float initialDragViewScale, DragOptions options) { - int[] loc = mCoordinatesTemp; - mLauncher.getDragLayer().getLocationInDragLayer(v, loc); - int dragLayerX = loc[0] + viewImageBounds.left - + (int) ((initialDragViewScale * bmp.getWidth() - bmp.getWidth()) / 2); - int dragLayerY = loc[1] + viewImageBounds.top - + (int) ((initialDragViewScale * bmp.getHeight() - bmp.getHeight()) / 2); - - startDrag(bmp, dragLayerX, dragLayerY, source, dragInfo, null, - null, initialDragViewScale, options); - } - /** * Starts a drag. * @@ -259,10 +237,6 @@ 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. */ diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java index de416e3bc..1be40f7e2 100644 --- a/src/com/android/launcher3/dragndrop/DragLayer.java +++ b/src/com/android/launcher3/dragndrop/DragLayer.java @@ -673,15 +673,11 @@ public class DragLayer extends InsettableFrameLayout { // If duration < 0, this is a cue to compute the duration based on the distance if (duration < 0) { - 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 = res.getInteger(R.integer.config_dropAnimMaxDuration); + if (dist < maxDist) { + duration *= mCubicEaseOutInterpolator.getInterpolation(dist / maxDist); } + duration = Math.max(duration, res.getInteger(R.integer.config_dropAnimMinDuration)); } // Fall back to cubic ease out interpolator for the animation if none is specified diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java index c94623536..3a98ae71b 100644 --- a/src/com/android/launcher3/dragndrop/DragView.java +++ b/src/com/android/launcher3/dragndrop/DragView.java @@ -392,4 +392,8 @@ public class DragView extends View { public int getBlurSizeOutline() { return mBlurSizeOutline; } + + public float getInitialScale() { + return mInitialScale; + } } diff --git a/src/com/android/launcher3/dragndrop/PinItemDragListener.java b/src/com/android/launcher3/dragndrop/PinItemDragListener.java index 9770d40e9..6e5318f2a 100644 --- a/src/com/android/launcher3/dragndrop/PinItemDragListener.java +++ b/src/com/android/launcher3/dragndrop/PinItemDragListener.java @@ -17,9 +17,6 @@ package com.android.launcher3.dragndrop; import android.content.ClipDescription; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Paint; import android.graphics.Point; import android.graphics.Rect; import android.os.Handler; @@ -32,30 +29,25 @@ import android.view.DragEvent; import android.view.View; import com.android.launcher3.DeleteDropTarget; -import com.android.launcher3.DeviceProfile; import com.android.launcher3.DragSource; import com.android.launcher3.DropTarget; import com.android.launcher3.ItemInfo; import com.android.launcher3.Launcher; -import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.PendingAddItemInfo; import com.android.launcher3.R; import com.android.launcher3.compat.PinItemRequestCompat; import com.android.launcher3.folder.Folder; -import com.android.launcher3.graphics.LauncherIcons; -import com.android.launcher3.shortcuts.ShortcutInfoCompat; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.widget.PendingAddShortcutInfo; import com.android.launcher3.widget.PendingAddWidgetInfo; -import com.android.launcher3.widget.PendingItemPreviewProvider; +import com.android.launcher3.widget.PendingItemDragHelper; import com.android.launcher3.widget.WidgetAddFlowHandler; -import com.android.launcher3.widget.WidgetHostViewLoader; import java.util.UUID; /** - * {@link DragSource} for handling drop from from a different window. This object is initialized + * {@link DragSource} for handling drop from a different window. This object is initialized * in the source window and is passed on to the Launcher activity as an Intent extra. */ public class PinItemDragListener @@ -71,6 +63,9 @@ public class PinItemDragListener // Position of preview relative to the touch location private final Rect mPreviewRect; + private final int mPreviewBitmapWidth; + private final int mPreviewViewWidth; + // Randomly generated id used to verify the drag event. private final String mId; @@ -78,15 +73,20 @@ public class PinItemDragListener private DragController mDragController; private long mDragStartTime; - public PinItemDragListener(PinItemRequestCompat request, Rect previewRect) { + public PinItemDragListener(PinItemRequestCompat request, Rect previewRect, + int previewBitmapWidth, int previewViewWidth) { mRequest = request; mPreviewRect = previewRect; + mPreviewBitmapWidth = previewBitmapWidth; + mPreviewViewWidth = previewViewWidth; mId = UUID.randomUUID().toString(); } private PinItemDragListener(Parcel parcel) { mRequest = PinItemRequestCompat.CREATOR.createFromParcel(parcel); mPreviewRect = Rect.CREATOR.createFromParcel(parcel); + mPreviewBitmapWidth = parcel.readInt(); + mPreviewViewWidth = parcel.readInt(); mId = parcel.readString(); } @@ -103,6 +103,8 @@ public class PinItemDragListener public void writeToParcel(Parcel parcel, int i) { mRequest.writeToParcel(parcel, i); mPreviewRect.writeToParcel(parcel, i); + parcel.writeInt(mPreviewBitmapWidth); + parcel.writeInt(mPreviewViewWidth); parcel.writeString(mId); } @@ -139,26 +141,9 @@ public class PinItemDragListener } final PendingAddItemInfo item; - final Bitmap preview; - final View view = new View(mLauncher); - - Point dragShift = new Point(mPreviewRect.left, mPreviewRect.top); if (mRequest.getRequestType() == PinItemRequestCompat.REQUEST_TYPE_SHORTCUT) { item = new PendingAddShortcutInfo( new PinShortcutRequestActivityInfo(mRequest, mLauncher)); - - ShortcutInfoCompat compat = new ShortcutInfoCompat(mRequest.getShortcutInfo()); - Bitmap icon = LauncherIcons.createShortcutIcon(compat, mLauncher, false /* badged */); - - // Create a preview same as the workspace cell size and draw the icon at the - // appropriate position. - int[] size = mLauncher.getWorkspace().estimateItemSize(item, true, false); - preview = Bitmap.createBitmap(size[0], size[1], Bitmap.Config.ARGB_8888); - Canvas c = new Canvas(preview); - DeviceProfile dp = mLauncher.getDeviceProfile(); - c.drawBitmap(icon, (size[0] - icon.getWidth()) / 2, - (size[1] - icon.getHeight() - dp.iconTextSizePx - dp.iconDrawablePaddingPx) / 2, - new Paint(Paint.FILTER_BITMAP_FLAG)); } else { // mRequest.getRequestType() == PinItemRequestCompat.REQUEST_TYPE_APPWIDGET LauncherAppWidgetProviderInfo providerInfo = @@ -166,46 +151,28 @@ public class PinItemDragListener mLauncher, mRequest.getAppWidgetProviderInfo(mLauncher)); final PinWidgetFlowHandler flowHandler = new PinWidgetFlowHandler(providerInfo, mRequest); - PendingAddWidgetInfo info = new PendingAddWidgetInfo(providerInfo) { + item = new PendingAddWidgetInfo(providerInfo) { @Override public WidgetAddFlowHandler getHandler() { return flowHandler; } }; - int[] size = mLauncher.getWorkspace().estimateItemSize(info, true, false); - - float minScale = 1.25f; - int maxWidth = Math.min((int) (mPreviewRect.width() * minScale), size[0]); - int[] previewSizeBeforeScale = new int[1]; - preview = LauncherAppState.getInstance(mLauncher).getWidgetCache() - .generateWidgetPreview(mLauncher, info.info, maxWidth, null, - previewSizeBeforeScale); - - dragShift.offset( - (mPreviewRect.width() - preview.getWidth()) / 2, - (mPreviewRect.height() - preview.getHeight()) / 2); - item = info; - - view.setTag(info); - mDragController.addDragListener(new WidgetHostViewLoader(mLauncher, view)); } - - PendingItemPreviewProvider previewProvider = - new PendingItemPreviewProvider(view, item, preview); - - // Since we are not going through the workspace for starting the drag, set drag related - // information on the workspace before starting the drag. - mLauncher.getWorkspace().prepareDragWithProvider(previewProvider); + View view = new View(mLauncher); + view.setTag(item); Point downPos = new Point((int) event.getX(), (int) event.getY()); DragOptions options = new DragOptions(); options.systemDndStartPoint = downPos; options.preDragCondition = this; - int x = downPos.x + dragShift.x; - int y = downPos.y + dragShift.y; - mDragController.startDrag( - preview, x, y, this, item, null, null, 1f, options); + // We use drag event position as the screenPos for the preview image. Since mPreviewRect + // already includes the view position relative to the drag event on the source window, + // and the absolute position (position relative to the screen) of drag event is same + // across windows, using drag position here give a good estimate for relative position + // to source window. + new PendingItemDragHelper(view).startDrag(new Rect(mPreviewRect), + mPreviewBitmapWidth, mPreviewViewWidth, downPos, this, options); mDragStartTime = SystemClock.uptimeMillis(); return true; } diff --git a/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java b/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java index 2121b438a..6a8c19f4b 100644 --- a/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java +++ b/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java @@ -26,8 +26,8 @@ import android.graphics.drawable.Drawable; import android.os.Build; import com.android.launcher3.IconCache; -import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; +import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.compat.PinItemRequestCompat; import com.android.launcher3.compat.ShortcutConfigActivityInfo; @@ -66,9 +66,13 @@ class PinShortcutRequestActivityInfo extends ShortcutConfigActivityInfo { } @Override - public boolean startConfigActivity(Launcher activity, int requestCode) { - activity.onActivityResult(requestCode, Activity.RESULT_OK, mRequest.toIntent()); - return true; + public com.android.launcher3.ShortcutInfo createShortcutInfo() { + return LauncherAppsCompat.createShortcutInfoFromPinItemRequest(mContext, mRequest); + } + + @Override + public boolean startConfigActivity(Activity activity, int requestCode) { + return false; } @Override diff --git a/src/com/android/launcher3/widget/PendingItemDragHelper.java b/src/com/android/launcher3/widget/PendingItemDragHelper.java new file mode 100644 index 000000000..a4698c292 --- /dev/null +++ b/src/com/android/launcher3/widget/PendingItemDragHelper.java @@ -0,0 +1,191 @@ +/* + * 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.widget; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Point; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.view.View; + +import com.android.launcher3.DeviceProfile; +import com.android.launcher3.DragSource; +import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.PendingAddItemInfo; +import com.android.launcher3.Workspace; +import com.android.launcher3.dragndrop.DragOptions; +import com.android.launcher3.graphics.DragPreviewProvider; +import com.android.launcher3.graphics.HolographicOutlineHelper; +import com.android.launcher3.graphics.LauncherIcons; + +/** + * Extension of {@link DragPreviewProvider} with logic specific to pending widgets/shortcuts + * dragged from the widget tray. + */ +public class PendingItemDragHelper extends DragPreviewProvider { + + private static final float MAX_WIDGET_SCALE = 1.25f; + + private final PendingAddItemInfo mAddInfo; + + private Bitmap mPreviewBitmap; + + public PendingItemDragHelper(View view) { + super(view); + mAddInfo = (PendingAddItemInfo) view.getTag(); + } + + /** + * Starts the drag for the pending item associated with the view. + * + * @param previewBounds The bounds where the image was displayed, + * {@link WidgetImageView#getBitmapBounds()} + * @param previewBitmapWidth The actual width of the bitmap displayed in the view. + * @param previewViewWidth The width of {@link WidgetImageView} displaying the preview + * @param screenPos Position of {@link WidgetImageView} on the screen + */ + public void startDrag(Rect previewBounds, int previewBitmapWidth, int previewViewWidth, + Point screenPos, DragSource source, DragOptions options) { + final Launcher launcher = Launcher.getLauncher(mView.getContext()); + LauncherAppState app = LauncherAppState.getInstance(launcher); + + final Bitmap preview; + final float scale; + final Point dragOffset; + final Rect dragRegion; + + + if (mAddInfo instanceof PendingAddWidgetInfo) { + PendingAddWidgetInfo createWidgetInfo = (PendingAddWidgetInfo) mAddInfo; + int[] size = launcher.getWorkspace().estimateItemSize(createWidgetInfo, true, false); + + int maxWidth = Math.min((int) (previewBitmapWidth * MAX_WIDGET_SCALE), size[0]); + + int[] previewSizeBeforeScale = new int[1]; + preview = app.getWidgetCache() .generateWidgetPreview( + launcher, createWidgetInfo.info, maxWidth, null, previewSizeBeforeScale); + + if (previewSizeBeforeScale[0] < previewBitmapWidth) { + // The icon has extra padding around it. + int padding = (previewBitmapWidth - previewSizeBeforeScale[0]) / 2; + if (previewBitmapWidth > previewViewWidth) { + padding = padding * previewViewWidth / previewBitmapWidth; + } + + previewBounds.left += padding; + previewBounds.right -= padding; + } + scale = previewBounds.width() / (float) preview.getWidth(); + launcher.getDragController().addDragListener(new WidgetHostViewLoader(launcher, mView)); + + dragOffset = null; + dragRegion = null; + } else { + PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) mAddInfo; + Drawable icon = createShortcutInfo.activityInfo.getFullResIcon(app.getIconCache()); + preview = LauncherIcons.createScaledBitmapWithoutShadow(icon, launcher); + mAddInfo.spanX = mAddInfo.spanY = 1; + scale = ((float) launcher.getDeviceProfile().iconSizePx) / preview.getWidth(); + + dragOffset = new Point(previewPadding / 2, previewPadding / 2); + + // Create a preview same as the workspace cell size and draw the icon at the + // appropriate position. + int[] size = launcher.getWorkspace().estimateItemSize(mAddInfo, false, true); + DeviceProfile dp = launcher.getDeviceProfile(); + int iconSize = dp.iconSizePx; + + dragRegion = new Rect(); + dragRegion.left = (size[0] - iconSize) / 2; + dragRegion.right = dragRegion.left + iconSize; + dragRegion.top = (size[1] - iconSize - dp.iconTextSizePx - dp.iconDrawablePaddingPx) / 2; + dragRegion.bottom = dragRegion.top + iconSize; + } + + // Since we are not going through the workspace for starting the drag, set drag related + // information on the workspace before starting the drag. + launcher.getWorkspace().prepareDragWithProvider(this); + + int dragLayerX = screenPos.x + previewBounds.left + + (int) ((scale * preview.getWidth() - preview.getWidth()) / 2); + int dragLayerY = screenPos.y + previewBounds.top + + (int) ((scale * preview.getHeight() - preview.getHeight()) / 2); + + mPreviewBitmap = preview; + // Start the drag + launcher.getDragController().startDrag(preview, dragLayerX, dragLayerY, source, mAddInfo, + dragOffset, dragRegion, scale, options); + } + + + @Override + public Bitmap createDragOutline(Canvas canvas) { + if (mAddInfo instanceof PendingAddShortcutInfo) { + int width = mPreviewBitmap.getWidth(); + int height = mPreviewBitmap.getHeight(); + Bitmap b = Bitmap.createBitmap(width + blurSizeOutline, height + blurSizeOutline, + Bitmap.Config.ALPHA_8); + canvas.setBitmap(b); + + Launcher launcher = Launcher.getLauncher(mView.getContext()); + int size = launcher.getDeviceProfile().iconSizePx; + + Rect src = new Rect(0, 0, mPreviewBitmap.getWidth(), mPreviewBitmap.getHeight()); + Rect dst = new Rect(0, 0, size, size); + dst.offset(blurSizeOutline / 2, blurSizeOutline / 2); + canvas.drawBitmap(mPreviewBitmap, src, dst, new Paint(Paint.FILTER_BITMAP_FLAG)); + + HolographicOutlineHelper.getInstance(mView.getContext()) + .applyExpensiveOutlineWithBlur(b, canvas); + + canvas.setBitmap(null); + return b; + } + + Workspace workspace = Launcher.getLauncher(mView.getContext()).getWorkspace(); + int[] size = workspace.estimateItemSize(mAddInfo, false, false); + + int w = size[0]; + int h = size[1]; + final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ALPHA_8); + canvas.setBitmap(b); + + Rect src = new Rect(0, 0, mPreviewBitmap.getWidth(), mPreviewBitmap.getHeight()); + float scaleFactor = Math.min((w - blurSizeOutline) / (float) mPreviewBitmap.getWidth(), + (h - blurSizeOutline) / (float) mPreviewBitmap.getHeight()); + int scaledWidth = (int) (scaleFactor * mPreviewBitmap.getWidth()); + int scaledHeight = (int) (scaleFactor * mPreviewBitmap.getHeight()); + Rect dst = new Rect(0, 0, scaledWidth, scaledHeight); + + // center the image + dst.offset((w - scaledWidth) / 2, (h - scaledHeight) / 2); + + canvas.drawBitmap(mPreviewBitmap, src, dst, null); + + // Don't clip alpha values for the drag outline if we're using the default widget preview + boolean clipAlpha = !(mAddInfo instanceof PendingAddWidgetInfo && + (((PendingAddWidgetInfo) mAddInfo).previewImage == 0)); + HolographicOutlineHelper.getInstance(mView.getContext()) + .applyExpensiveOutlineWithBlur(b, canvas, clipAlpha); + canvas.setBitmap(null); + + return b; + } +} diff --git a/src/com/android/launcher3/widget/PendingItemPreviewProvider.java b/src/com/android/launcher3/widget/PendingItemPreviewProvider.java deleted file mode 100644 index 3a49a6cdd..000000000 --- a/src/com/android/launcher3/widget/PendingItemPreviewProvider.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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.widget; - -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Rect; -import android.view.View; - -import com.android.launcher3.graphics.HolographicOutlineHelper; -import com.android.launcher3.Launcher; -import com.android.launcher3.PendingAddItemInfo; -import com.android.launcher3.Workspace; -import com.android.launcher3.graphics.DragPreviewProvider; - -/** - * Extension of {@link DragPreviewProvider} with logic specific to pending widgets/shortcuts - * dragged from the widget tray. - */ -public class PendingItemPreviewProvider extends DragPreviewProvider { - - private final PendingAddItemInfo mAddInfo; - private final Bitmap mPreviewBitmap; - - public PendingItemPreviewProvider(View view, PendingAddItemInfo addInfo, Bitmap preview) { - super(view); - mAddInfo = addInfo; - mPreviewBitmap = preview; - } - - @Override - public Bitmap createDragOutline(Canvas canvas) { - Workspace workspace = Launcher.getLauncher(mView.getContext()).getWorkspace(); - int[] size = workspace.estimateItemSize(mAddInfo, false, false); - - int w = size[0]; - int h = size[1]; - final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ALPHA_8); - canvas.setBitmap(b); - - Rect src = new Rect(0, 0, mPreviewBitmap.getWidth(), mPreviewBitmap.getHeight()); - float scaleFactor = Math.min((w - blurSizeOutline) / (float) mPreviewBitmap.getWidth(), - (h - blurSizeOutline) / (float) mPreviewBitmap.getHeight()); - int scaledWidth = (int) (scaleFactor * mPreviewBitmap.getWidth()); - int scaledHeight = (int) (scaleFactor * mPreviewBitmap.getHeight()); - Rect dst = new Rect(0, 0, scaledWidth, scaledHeight); - - // center the image - dst.offset((w - scaledWidth) / 2, (h - scaledHeight) / 2); - - canvas.drawBitmap(mPreviewBitmap, src, dst, null); - - // Don't clip alpha values for the drag outline if we're using the default widget preview - boolean clipAlpha = !(mAddInfo instanceof PendingAddWidgetInfo && - (((PendingAddWidgetInfo) mAddInfo).previewImage == 0)); - HolographicOutlineHelper.getInstance(mView.getContext()) - .applyExpensiveOutlineWithBlur(b, canvas, clipAlpha); - canvas.setBitmap(null); - - return b; - } -} diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java index d1421e05a..b2321a7d3 100644 --- a/src/com/android/launcher3/widget/WidgetsContainerView.java +++ b/src/com/android/launcher3/widget/WidgetsContainerView.java @@ -17,9 +17,7 @@ package com.android.launcher3.widget; import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; +import android.graphics.Point; import android.support.v7.widget.LinearLayoutManager; import android.util.AttributeSet; import android.util.Log; @@ -35,17 +33,13 @@ import com.android.launcher3.IconCache; import com.android.launcher3.ItemInfo; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; -import com.android.launcher3.PendingAddItemInfo; import com.android.launcher3.R; import com.android.launcher3.Utilities; -import com.android.launcher3.WidgetPreviewLoader; import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.folder.Folder; -import com.android.launcher3.graphics.LauncherIcons; import com.android.launcher3.model.PackageItemInfo; import com.android.launcher3.model.WidgetItem; -import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.userevent.nano.LauncherLogProto.Target; import com.android.launcher3.util.MultiHashMap; @@ -71,9 +65,6 @@ public class WidgetsContainerView extends BaseContainerView /* Touch handling related member variables. */ private Toast mWidgetInstructionToast; - /* Rendering related. */ - private WidgetPreviewLoader mWidgetPreviewLoader; - public WidgetsContainerView(Context context) { this(context, null); } @@ -174,7 +165,6 @@ public class WidgetsContainerView extends BaseContainerView private boolean beginDraggingWidget(WidgetCell v) { // Get the widget preview as the drag representation WidgetImageView image = (WidgetImageView) v.findViewById(R.id.widget_preview); - PendingAddItemInfo createItemInfo = (PendingAddItemInfo) v.getTag(); // If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and // we abort the drag. @@ -182,55 +172,12 @@ public class WidgetsContainerView extends BaseContainerView return false; } - // Compose the drag image - Bitmap preview; - final float scale; - final Rect bounds = image.getBitmapBounds(); - - if (createItemInfo instanceof PendingAddWidgetInfo) { - // This can happen in some weird cases involving multi-touch. We can't start dragging - // the widget if this is null, so we break out. - - PendingAddWidgetInfo createWidgetInfo = (PendingAddWidgetInfo) createItemInfo; - int[] size = mLauncher.getWorkspace().estimateItemSize(createWidgetInfo, true, false); - - Bitmap icon = image.getBitmap(); - float minScale = 1.25f; - int maxWidth = Math.min((int) (icon.getWidth() * minScale), size[0]); - - int[] previewSizeBeforeScale = new int[1]; - preview = getWidgetPreviewLoader().generateWidgetPreview(mLauncher, - createWidgetInfo.info, maxWidth, null, previewSizeBeforeScale); - - if (previewSizeBeforeScale[0] < icon.getWidth()) { - // The icon has extra padding around it. - int padding = (icon.getWidth() - previewSizeBeforeScale[0]) / 2; - if (icon.getWidth() > image.getWidth()) { - padding = padding * image.getWidth() / icon.getWidth(); - } - - bounds.left += padding; - bounds.right -= padding; - } - scale = bounds.width() / (float) preview.getWidth(); + int[] loc = new int[2]; + mLauncher.getDragLayer().getLocationInDragLayer(image, loc); - mLauncher.getDragController().addDragListener(new WidgetHostViewLoader(mLauncher, v)); - } else { - PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) v.getTag(); - Drawable icon = createShortcutInfo.activityInfo.getFullResIcon(mIconCache); - preview = LauncherIcons.createIconBitmap(icon, mLauncher); - createItemInfo.spanX = createItemInfo.spanY = 1; - scale = ((float) mLauncher.getDeviceProfile().iconSizePx) / preview.getWidth(); - } - - // Since we are not going through the workspace for starting the drag, set drag related - // information on the workspace before starting the drag. - mLauncher.getWorkspace().prepareDragWithProvider( - new PendingItemPreviewProvider(v, createItemInfo, preview)); - - // Start the drag - mDragController.startDrag(image, preview, this, createItemInfo, - bounds, scale, new DragOptions()); + new PendingItemDragHelper(v).startDrag( + image.getBitmapBounds(), image.getBitmap().getWidth(), image.getWidth(), + new Point(loc[0], loc[1]), this, new DragOptions()); return true; } @@ -294,13 +241,6 @@ public class WidgetsContainerView extends BaseContainerView return mAdapter.getItemCount() == 0; } - private WidgetPreviewLoader getWidgetPreviewLoader() { - if (mWidgetPreviewLoader == null) { - mWidgetPreviewLoader = LauncherAppState.getInstance(getContext()).getWidgetCache(); - } - return mWidgetPreviewLoader; - } - @Override public void fillInLogContainerData(View v, ItemInfo info, Target target, Target targetParent) { targetParent.containerType = ContainerType.WIDGETS; -- cgit v1.2.3