diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index 77f6612c1c..ee21313981 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -54,6 +54,7 @@ import com.android.launcher3.accessibility.WorkspaceAccessibilityHelper; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.config.ProviderConfig; import com.android.launcher3.folder.FolderIcon; +import com.android.launcher3.graphics.DragPreviewProvider; import com.android.launcher3.util.CellAndSpan; import com.android.launcher3.util.GridOccupancy; import com.android.launcher3.util.ParcelableSparseArray; @@ -1047,15 +1048,16 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler { return false; } - void visualizeDropLocation(View v, Bitmap dragOutline, int cellX, int cellY, int spanX, - int spanY, boolean resize, DropTarget.DragObject dragObject) { + void visualizeDropLocation(View v, DragPreviewProvider outlineProvider, int cellX, int cellY, + int spanX, int spanY, boolean resize, DropTarget.DragObject dragObject) { final int oldDragCellX = mDragCell[0]; final int oldDragCellY = mDragCell[1]; - if (dragOutline == null && v == null) { + if (outlineProvider == null || outlineProvider.gerenatedDragOutline == null) { return; } + Bitmap dragOutline = outlineProvider.gerenatedDragOutline; if (cellX != oldDragCellX || cellY != oldDragCellY) { Point dragOffset = dragObject.dragView.getDragVisualizeOffset(); Rect dragRegion = dragObject.dragView.getDragRegion(); diff --git a/src/com/android/launcher3/HolographicOutlineHelper.java b/src/com/android/launcher3/HolographicOutlineHelper.java index 427acea769..6822311984 100644 --- a/src/com/android/launcher3/HolographicOutlineHelper.java +++ b/src/com/android/launcher3/HolographicOutlineHelper.java @@ -84,7 +84,7 @@ public class HolographicOutlineHelper { applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, true); } - void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color, + public void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color, int outlineColor, boolean clipAlpha) { // We start by removing most of the alpha channel so as to ignore shadows, and diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 886c5f0a26..334db4a2cb 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -2809,7 +2809,7 @@ public class Launcher extends Activity mDragLayer.onAccessibilityStateChanged(enabled); } - public void onDragStarted(View view) { + public void onDragStarted() { if (isOnCustomContent()) { // Custom content screen doesn't participate in drag and drop. If on custom // content screen, move to default. diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 6f61688f8c..4c2d4bb928 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -69,12 +69,12 @@ import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.config.ProviderConfig; import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragLayer; -import com.android.launcher3.graphics.DragPreviewProvider; import com.android.launcher3.dragndrop.DragScroller; import com.android.launcher3.dragndrop.DragView; import com.android.launcher3.dragndrop.SpringLoadedDragController; import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.FolderIcon; +import com.android.launcher3.graphics.DragPreviewProvider; import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.shortcuts.DeepShortcutManager; import com.android.launcher3.shortcuts.ShortcutsContainerListener; @@ -247,8 +247,7 @@ public class Workspace extends PagedView /** Is the user is dragging an item near the edge of a page? */ private boolean mInScrollArea = false; - private HolographicOutlineHelper mOutlineHelper; - @Thunk Bitmap mDragOutline = null; + private DragPreviewProvider mOutlineProvider = null; public static final int DRAG_BITMAP_PADDING = DragPreviewProvider.DRAG_BITMAP_PADDING; private boolean mWorkspaceFadeInAdjacentScreens; @@ -343,8 +342,6 @@ public class Workspace extends PagedView public Workspace(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - mOutlineHelper = HolographicOutlineHelper.obtain(context); - mLauncher = (Launcher) context; mStateTransitionAnimation = new WorkspaceStateTransitionAnimation(mLauncher, this); final Resources res = getResources(); @@ -417,7 +414,13 @@ public class Workspace extends PagedView enfoceDragParity("onDragStart", 0, 0); } + if (mOutlineProvider != null) { + // The outline is used to visualize where the item will land if dropped + mOutlineProvider.generateDragOutline(mCanvas); + } + updateChildrenLayersEnabled(false); + mLauncher.onDragStarted(); mLauncher.lockScreenOrientation(); mLauncher.onInteractionBegin(); // Prevent any Un/InstallShortcutReceivers from updating the db while we are dragging @@ -426,6 +429,27 @@ public class Workspace extends PagedView if (mAddNewPageOnDrag) { mDeferRemoveExtraEmptyScreen = false; addExtraEmptyScreenOnDrag(); + + if (source != this && info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET) { + // When dragging a widget from different source, move to a page which has + // enough space to place this widget (after rearranging/resizing). We special case + // widgets as they cannot be placed inside a folder. + // Start at the current page and search right (on LTR) until finding a page with + // enough space. Since an empty screen is the furthest right, a page must be found. + int currentPage = getPageNearestToCenterOfScreen(); + for (int pageIndex = currentPage; pageIndex < getPageCount(); pageIndex++) { + CellLayout page = (CellLayout) getPageAt(pageIndex); + if (page.hasReorderSolution(info)) { + setCurrentPage(pageIndex); + break; + } + } + } + } + + if (!FeatureFlags.LAUNCHER3_LEGACY_WORKSPACE_DND) { + // Always enter the spring loaded mode + mLauncher.enterSpringLoadedDragMode(); } } @@ -1999,23 +2023,8 @@ public class Workspace extends PagedView position[0], position[1], 0, null); } - public void onDragStartedWithItem(PendingAddItemInfo info, Bitmap b, boolean clipAlpha) { - // Find a page that has enough space to place this widget (after rearranging/resizing). - // Start at the current page and search right (on LTR) until finding a page with enough - // space. Since an empty screen is the furthest right, a page must be found. - int currentPageInOverview = getPageNearestToCenterOfScreen(); - for (int pageIndex = currentPageInOverview; pageIndex < getPageCount(); pageIndex++) { - CellLayout page = (CellLayout) getPageAt(pageIndex); - if (page.hasReorderSolution(info)) { - setCurrentPage(pageIndex); - break; - } - } - - int[] size = estimateItemSize(info, false); - - // The outline is used to visualize where the item will land if dropped - mDragOutline = createDragOutline(b, DRAG_BITMAP_PADDING, size[0], size[1], clipAlpha); + public void prepareDragWithProvider(DragPreviewProvider outlineProvider) { + mOutlineProvider = outlineProvider; } public void exitWidgetResizeMode() { @@ -2271,34 +2280,6 @@ public class Workspace extends PagedView return null; } - /** - * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location. - * Responsibility for the bitmap is transferred to the caller. - */ - private Bitmap createDragOutline(Bitmap orig, int padding, int w, int h, - boolean clipAlpha) { - final int outlineColor = getResources().getColor(R.color.outline_color); - final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); - mCanvas.setBitmap(b); - - Rect src = new Rect(0, 0, orig.getWidth(), orig.getHeight()); - float scaleFactor = Math.min((w - padding) / (float) orig.getWidth(), - (h - padding) / (float) orig.getHeight()); - int scaledWidth = (int) (scaleFactor * orig.getWidth()); - int scaledHeight = (int) (scaleFactor * orig.getHeight()); - Rect dst = new Rect(0, 0, scaledWidth, scaledHeight); - - // center the image - dst.offset((w - scaledWidth) / 2, (h - scaledHeight) / 2); - - mCanvas.drawBitmap(orig, src, dst, null); - mOutlineHelper.applyExpensiveOutlineWithBlur(b, mCanvas, outlineColor, outlineColor, - clipAlpha); - mCanvas.setBitmap(null); - - return b; - } - public void startDrag(CellLayout.CellInfo cellInfo) { startDrag(cellInfo, false); } @@ -2337,11 +2318,8 @@ public class Workspace extends PagedView ItemInfo dragObject, DragPreviewProvider previewProvider) { child.clearFocus(); child.setPressed(false); + mOutlineProvider = previewProvider; - // The outline is used to visualize where the item will land if dropped - mDragOutline = previewProvider.createDragOutline(mCanvas); - - mLauncher.onDragStarted(child); // The drag bitmap follows the touch point around on the screen final Bitmap b = previewProvider.createDragBitmap(mCanvas); int halfPadding = previewProvider.previewPadding / 2; @@ -2384,12 +2362,7 @@ public class Workspace extends PagedView dragObject, DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, scale, accessible); dv.setIntrinsicIconScaleFactor(source.getIntrinsicIconScaleFactor()); - b.recycle(); - - if (!FeatureFlags.LAUNCHER3_LEGACY_WORKSPACE_DND) { - mLauncher.enterSpringLoadedDragMode(); - } return dv; } @@ -3180,7 +3153,7 @@ public class Workspace extends PagedView item.spanY, child, mTargetCell); if (!nearestDropOccupied) { - mDragTargetLayout.visualizeDropLocation(child, mDragOutline, + mDragTargetLayout.visualizeDropLocation(child, mOutlineProvider, mTargetCell[0], mTargetCell[1], item.spanX, item.spanY, false, d); } else if ((mDragMode == DRAG_MODE_NONE || mDragMode == DRAG_MODE_REORDER) && !mReorderAlarm.alarmPending() && (mLastReorderX != reorderX || @@ -3325,7 +3298,7 @@ public class Workspace extends PagedView } boolean resize = resultSpan[0] != spanX || resultSpan[1] != spanY; - mDragTargetLayout.visualizeDropLocation(child, mDragOutline, + mDragTargetLayout.visualizeDropLocation(child, mOutlineProvider, mTargetCell[0], mTargetCell[1], resultSpan[0], resultSpan[1], resize, dragObject); } } @@ -3716,7 +3689,7 @@ public class Workspace extends PagedView && mDragInfo.cell != null) { mDragInfo.cell.setVisibility(VISIBLE); } - mDragOutline = null; + mOutlineProvider = null; mDragInfo = null; if (!isFlingToDelete) { diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java index b90c2fd39f..e078d9b155 100644 --- a/src/com/android/launcher3/graphics/DragPreviewProvider.java +++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java @@ -29,6 +29,7 @@ import com.android.launcher3.Launcher; import com.android.launcher3.PreloadIconDrawable; import com.android.launcher3.R; import com.android.launcher3.Workspace; +import com.android.launcher3.config.ProviderConfig; import com.android.launcher3.folder.FolderIcon; /** @@ -45,6 +46,8 @@ public class DragPreviewProvider { // The padding added to the drag view during the preview generation. public final int previewPadding; + public Bitmap gerenatedDragOutline; + public DragPreviewProvider(View view) { mView = view; @@ -118,6 +121,14 @@ public class DragPreviewProvider { return b; } + public final void generateDragOutline(Canvas canvas) { + if (ProviderConfig.IS_DOGFOOD_BUILD && gerenatedDragOutline != null) { + throw new RuntimeException("Drag outline generated twice"); + } + + gerenatedDragOutline = createDragOutline(canvas); + } + /** * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location. * Responsibility for the bitmap is transferred to the caller. diff --git a/src/com/android/launcher3/widget/PendingItemPreviewProvider.java b/src/com/android/launcher3/widget/PendingItemPreviewProvider.java new file mode 100644 index 0000000000..8739390c48 --- /dev/null +++ b/src/com/android/launcher3/widget/PendingItemPreviewProvider.java @@ -0,0 +1,78 @@ +/* + * 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.HolographicOutlineHelper; +import com.android.launcher3.Launcher; +import com.android.launcher3.PendingAddItemInfo; +import com.android.launcher3.R; +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); + + int w = size[0]; + int h = size[1]; + final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); + canvas.setBitmap(b); + + Rect src = new Rect(0, 0, mPreviewBitmap.getWidth(), mPreviewBitmap.getHeight()); + float scaleFactor = Math.min((w - DRAG_BITMAP_PADDING) / (float) mPreviewBitmap.getWidth(), + (h - DRAG_BITMAP_PADDING) / (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)); + final int outlineColor = mView.getResources().getColor(R.color.outline_color); + HolographicOutlineHelper.obtain(mView.getContext()) + .applyExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor, 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 34bee1b47b..352cea479f 100644 --- a/src/com/android/launcher3/widget/WidgetsContainerView.java +++ b/src/com/android/launcher3/widget/WidgetsContainerView.java @@ -205,7 +205,7 @@ public class WidgetsContainerView extends BaseContainerView // Compose the drag image Bitmap preview; - float scale = 1f; + final float scale; final Rect bounds = image.getBitmapBounds(); if (createItemInfo instanceof PendingAddWidgetInfo) { @@ -242,19 +242,14 @@ public class WidgetsContainerView extends BaseContainerView scale = ((float) mLauncher.getDeviceProfile().iconSizePx) / preview.getWidth(); } - // Don't clip alpha values for the drag outline if we're using the default widget preview - boolean clipAlpha = !(createItemInfo instanceof PendingAddWidgetInfo && - (((PendingAddWidgetInfo) createItemInfo).previewImage == 0)); + // 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 - mLauncher.lockScreenOrientation(); mDragController.startDrag(image, preview, this, createItemInfo, bounds, DragController.DRAG_ACTION_COPY, scale); - // This call expects the extra empty screen to already be created, which is why we call it - // after mDragController.startDrag(). - mLauncher.getWorkspace().onDragStartedWithItem(createItemInfo, preview, clipAlpha); - - preview.recycle(); return true; }