diff options
author | Sunny Goyal <sunnygoyal@google.com> | 2017-07-20 10:09:42 -0700 |
---|---|---|
committer | Sunny Goyal <sunnygoyal@google.com> | 2017-07-25 14:30:54 -0700 |
commit | e29897f503d54866fac279aa366922219d60b834 (patch) | |
tree | 91cac889ec300d4310b91e54e8cd985b4b9395cd /src/com/android/launcher3/dragndrop | |
parent | 4560d2f731f3e0a5c377a7dc5824ee66a58b3e04 (diff) | |
download | android_packages_apps_Trebuchet-e29897f503d54866fac279aa366922219d60b834.tar.gz android_packages_apps_Trebuchet-e29897f503d54866fac279aa366922219d60b834.tar.bz2 android_packages_apps_Trebuchet-e29897f503d54866fac279aa366922219d60b834.zip |
Adding spring effect for folder icons when dragging similar to adaptive icons
Bug: 63889144
Change-Id: Idd1fd13c6343bf3e0a3a0e5ff0be730d41996575
Diffstat (limited to 'src/com/android/launcher3/dragndrop')
-rw-r--r-- | src/com/android/launcher3/dragndrop/DragView.java | 55 | ||||
-rw-r--r-- | src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java | 175 |
2 files changed, 212 insertions, 18 deletions
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java index c11287a0a..49854131f 100644 --- a/src/com/android/launcher3/dragndrop/DragView.java +++ b/src/com/android/launcher3/dragndrop/DragView.java @@ -78,6 +78,7 @@ public class DragView extends View { @Thunk static float sDragAlpha = 1f; + private boolean mDrawBitmap = true; private Bitmap mBitmap; private Bitmap mCrossFadeBitmap; @Thunk Paint mPaint; @@ -187,7 +188,8 @@ public class DragView extends View { } /** - * Initialize {@code #mIconDrawable} only if the icon type is app icon (not shortcut or folder). + * Initialize {@code #mIconDrawable} if the item can be represented using + * an {@link AdaptiveIconDrawable} or {@link FolderAdaptiveIcon}. */ @TargetApi(Build.VERSION_CODES.O) public void setItemInfo(final ItemInfo info) { @@ -195,7 +197,8 @@ public class DragView extends View { return; } if (info.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION && - info.itemType != LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) { + info.itemType != LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT && + info.itemType != LauncherSettings.Favorites.ITEM_TYPE_FOLDER) { return; } // Load the adaptive icon on a background thread and add the view in ui thread. @@ -205,7 +208,7 @@ public class DragView extends View { public void run() { LauncherAppState appState = LauncherAppState.getInstance(mLauncher); Object[] outObj = new Object[1]; - Drawable dr = getFullDrawable(info, appState, outObj); + final Drawable dr = getFullDrawable(info, appState, outObj); if (dr instanceof AdaptiveIconDrawable) { int w = mBitmap.getWidth(); @@ -249,6 +252,9 @@ public class DragView extends View { // Assign the variable on the UI thread to avoid race conditions. mScaledMaskPath = mask; + // Do not draw the background in case of folder as its translucent + mDrawBitmap = !(dr instanceof FolderAdaptiveIcon); + if (info.isDisabled()) { FastBitmapDrawable d = new FastBitmapDrawable(null); d.setIsDisabled(true); @@ -323,6 +329,14 @@ public class DragView extends View { return sm.getShortcutIconDrawable(si.get(0), appState.getInvariantDeviceProfile().fillResIconDpi); } + } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) { + FolderAdaptiveIcon icon = FolderAdaptiveIcon.createFolderAdaptiveIcon( + mLauncher, info.id, new Point(mBitmap.getWidth(), mBitmap.getHeight())); + if (icon == null) { + return null; + } + outObj[0] = icon; + return icon; } else { return null; } @@ -350,6 +364,8 @@ public class DragView extends View { float insetFraction = (iconSize - badgeSize) / iconSize; return new InsetDrawable(new FastBitmapDrawable(badge), insetFraction, insetFraction, 0, 0); + } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) { + return ((FolderAdaptiveIcon) obj).getBadge(); } else { return mLauncher.getPackageManager() .getUserBadgedIcon(new FixedSizeEmptyDrawable(iconSize), info.user); @@ -405,21 +421,24 @@ public class DragView extends View { @Override protected void onDraw(Canvas canvas) { mHasDrawn = true; - // Always draw the bitmap to mask anti aliasing due to clipPath - boolean crossFade = mCrossFadeProgress > 0 && mCrossFadeBitmap != null; - if (crossFade) { - int alpha = crossFade ? (int) (255 * (1 - mCrossFadeProgress)) : 255; - mPaint.setAlpha(alpha); - } - canvas.drawBitmap(mBitmap, 0.0f, 0.0f, mPaint); - if (crossFade) { - mPaint.setAlpha((int) (255 * mCrossFadeProgress)); - final int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG); - float sX = (mBitmap.getWidth() * 1.0f) / mCrossFadeBitmap.getWidth(); - float sY = (mBitmap.getHeight() * 1.0f) / mCrossFadeBitmap.getHeight(); - canvas.scale(sX, sY); - canvas.drawBitmap(mCrossFadeBitmap, 0.0f, 0.0f, mPaint); - canvas.restoreToCount(saveCount); + + if (mDrawBitmap) { + // Always draw the bitmap to mask anti aliasing due to clipPath + boolean crossFade = mCrossFadeProgress > 0 && mCrossFadeBitmap != null; + if (crossFade) { + int alpha = crossFade ? (int) (255 * (1 - mCrossFadeProgress)) : 255; + mPaint.setAlpha(alpha); + } + canvas.drawBitmap(mBitmap, 0.0f, 0.0f, mPaint); + if (crossFade) { + mPaint.setAlpha((int) (255 * mCrossFadeProgress)); + final int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG); + float sX = (mBitmap.getWidth() * 1.0f) / mCrossFadeBitmap.getWidth(); + float sY = (mBitmap.getHeight() * 1.0f) / mCrossFadeBitmap.getHeight(); + canvas.scale(sX, sY); + canvas.drawBitmap(mCrossFadeBitmap, 0.0f, 0.0f, mPaint); + canvas.restoreToCount(saveCount); + } } if (mScaledMaskPath != null) { diff --git a/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java new file mode 100644 index 000000000..c90546088 --- /dev/null +++ b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2017 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.annotation.TargetApi; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PixelFormat; +import android.graphics.Point; +import android.graphics.drawable.AdaptiveIconDrawable; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.util.Log; + +import com.android.launcher3.Launcher; +import com.android.launcher3.MainThreadExecutor; +import com.android.launcher3.R; +import com.android.launcher3.folder.FolderIcon; +import com.android.launcher3.folder.PreviewBackground; +import com.android.launcher3.util.Preconditions; + +import java.util.concurrent.Callable; + +/** + * {@link AdaptiveIconDrawable} representation of a {@link FolderIcon} + */ +@TargetApi(Build.VERSION_CODES.O) +public class FolderAdaptiveIcon extends AdaptiveIconDrawable { + private static final String TAG = "FolderAdaptiveIcon"; + + private final Drawable mBadge; + private final Path mMask; + + private FolderAdaptiveIcon(Drawable bg, Drawable fg, Drawable badge, Path mask) { + super(bg, fg); + mBadge = badge; + mMask = mask; + } + + @Override + public Path getIconMask() { + return mMask; + } + + public Drawable getBadge() { + return mBadge; + } + + public static FolderAdaptiveIcon createFolderAdaptiveIcon( + final Launcher launcher, final long folderId, Point dragViewSize) { + Preconditions.assertNonUiThread(); + int margin = launcher.getResources() + .getDimensionPixelSize(R.dimen.blur_size_medium_outline); + + // Allocate various bitmaps on the background thread, because why not! + final Bitmap badge = Bitmap.createBitmap( + dragViewSize.x - margin, dragViewSize.y - margin, Bitmap.Config.ARGB_8888); + + // The bitmap for the preview is generated larger than needed to allow for the spring effect + float sizeScaleFactor = 1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction(); + final Bitmap preview = Bitmap.createBitmap( + (int) (dragViewSize.x * sizeScaleFactor), (int) (dragViewSize.y * sizeScaleFactor), + Bitmap.Config.ARGB_8888); + + // Create the actual drawable on the UI thread to avoid race conditions with + // FolderIcon draw pass + try { + return new MainThreadExecutor().submit(new Callable<FolderAdaptiveIcon>() { + @Override + public FolderAdaptiveIcon call() throws Exception { + FolderIcon icon = launcher.findFolderIcon(folderId); + return icon == null ? null : createDrawableOnUiThread(icon, badge, preview); + } + }).get(); + } catch (Exception e) { + Log.e(TAG, "Unable to create folder icon", e); + return null; + } + } + + /** + * Initializes various bitmaps on the UI thread and returns the final drawable. + */ + private static FolderAdaptiveIcon createDrawableOnUiThread(FolderIcon icon, + Bitmap badgeBitmap, Bitmap previewBitmap) { + Preconditions.assertUIThread(); + float margin = icon.getResources().getDimension(R.dimen.blur_size_medium_outline) / 2; + + Canvas c = new Canvas(); + PreviewBackground bg = icon.getFolderBackground(); + + // Initialize badge + c.setBitmap(badgeBitmap); + bg.drawShadow(c); + bg.drawBackgroundStroke(c); + icon.drawBadge(c); + + // Initialize preview + float shiftFactor = AdaptiveIconDrawable.getExtraInsetFraction() / + (1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction()); + float previewShiftX = shiftFactor * previewBitmap.getWidth(); + float previewShiftY = shiftFactor * previewBitmap.getHeight(); + + c.setBitmap(previewBitmap); + c.translate(previewShiftX, previewShiftY); + icon.getPreviewItemManager().draw(c); + c.setBitmap(null); + + // Initialize mask + Path mask = new Path(); + Matrix m = new Matrix(); + m.setTranslate(margin, margin); + bg.getClipPath().transform(m, mask); + + ShiftedBitmapDrawable badge = new ShiftedBitmapDrawable(badgeBitmap, margin, margin); + ShiftedBitmapDrawable foreground = new ShiftedBitmapDrawable(previewBitmap, + margin - previewShiftX, margin - previewShiftY); + + return new FolderAdaptiveIcon(new ColorDrawable(bg.getBgColor()), foreground, badge, mask); + } + + /** + * A simple drawable which draws a bitmap at a fixed position irrespective of the bounds + */ + private static class ShiftedBitmapDrawable extends Drawable { + + private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG); + private final Bitmap mBitmap; + private final float mShiftX; + private final float mShiftY; + + ShiftedBitmapDrawable(Bitmap bitmap, float shiftX, float shiftY) { + mBitmap = bitmap; + mShiftX = shiftX; + mShiftY = shiftY; + } + + @Override + public void draw(Canvas canvas) { + canvas.drawBitmap(mBitmap, mShiftX, mShiftY, mPaint); + } + + @Override + public void setAlpha(int i) { } + + @Override + public void setColorFilter(ColorFilter colorFilter) { + mPaint.setColorFilter(colorFilter); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + } +} |