diff options
Diffstat (limited to 'src/com')
8 files changed, 262 insertions, 51 deletions
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index cb4ad55c7..bd239690f 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -108,7 +108,6 @@ public class DeviceProfile { public int folderChildIconSizePx; public int folderChildTextSizePx; public int folderChildDrawablePaddingPx; - public final int folderChildDrawablePaddingOriginalPx; // Hotseat public int hotseatCellHeightPx; @@ -221,9 +220,6 @@ public class DeviceProfile { hotseatLandRightNavBarGutterPx = res.getDimensionPixelSize( R.dimen.dynamic_grid_hotseat_land_right_nav_bar_gutter_width); - folderChildDrawablePaddingOriginalPx = - res.getDimensionPixelSize(R.dimen.folder_child_icon_drawable_padding); - // Determine sizes. widthPx = width; heightPx = height; @@ -403,15 +399,15 @@ public class DeviceProfile { folderChildIconSizePx = (int) (Utilities.pxFromDp(inv.iconSize, dm) * scale); folderChildTextSizePx = (int) (res.getDimensionPixelSize(R.dimen.folder_child_text_size) * scale); - folderChildDrawablePaddingPx = (int) (folderChildDrawablePaddingOriginalPx * scale); int textHeight = Utilities.calculateTextHeight(folderChildTextSizePx); int cellPaddingX = (int) (res.getDimensionPixelSize(R.dimen.folder_cell_x_padding) * scale); int cellPaddingY = (int) (res.getDimensionPixelSize(R.dimen.folder_cell_y_padding) * scale); folderCellWidthPx = folderChildIconSizePx + 2 * cellPaddingX; - folderCellHeightPx = folderChildIconSizePx + 2 * cellPaddingY + textHeight - + folderChildDrawablePaddingPx; + folderCellHeightPx = folderChildIconSizePx + 2 * cellPaddingY + textHeight; + folderChildDrawablePaddingPx = Math.max(0, + (folderCellHeightPx - folderChildIconSizePx - textHeight) / 3); } public void updateInsets(Rect insets) { diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 97f1ead86..4b3148626 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -1465,23 +1465,25 @@ public class Launcher extends BaseActivity mWorkspace.addInScreen(view, info); } else { // Adding a shortcut to a Folder. - final long folderIconId = container; - FolderIcon folderIcon = (FolderIcon) mWorkspace.getFirstMatch(new ItemOperator() { - @Override - public boolean evaluate(ItemInfo info, View view) { - return info != null && info.id == folderIconId; - } - }); - + FolderIcon folderIcon = findFolderIcon(container); if (folderIcon != null) { FolderInfo folderInfo = (FolderInfo) folderIcon.getTag(); folderInfo.add(info, args.rank, false); } else { - Log.e(TAG, "Could not find folder with id " + folderIconId + " to add shortcut."); + Log.e(TAG, "Could not find folder with id " + container + " to add shortcut."); } } } + public FolderIcon findFolderIcon(final long folderIconId) { + return (FolderIcon) mWorkspace.getFirstMatch(new ItemOperator() { + @Override + public boolean evaluate(ItemInfo info, View view) { + return info != null && info.id == folderIconId; + } + }); + } + /** * Add a widget to the workspace. * 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; + } + } +} diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java index d7f5c2b64..69705d594 100644 --- a/src/com/android/launcher3/folder/FolderAnimationManager.java +++ b/src/com/android/launcher3/folder/FolderAnimationManager.java @@ -120,7 +120,6 @@ public class FolderAnimationManager { final DragLayer.LayoutParams lp = (DragLayer.LayoutParams) mFolder.getLayoutParams(); FolderIcon.PreviewLayoutRule rule = mFolderIcon.getLayoutRule(); final List<BubbleTextView> itemsInPreview = mFolderIcon.getPreviewItems(); - BubbleTextView btv = itemsInPreview.get(0); // Match position of the FolderIcon final Rect folderIconPos = new Rect(); @@ -132,7 +131,7 @@ public class FolderAnimationManager { // Match size/scale of icons in the preview float previewScale = rule.scaleForItem(0, itemsInPreview.size()); float previewSize = rule.getIconSize() * previewScale; - float initialScale = previewSize / btv.getIconSize() + float initialScale = previewSize / itemsInPreview.get(0).getIconSize() * scaleRelativeToDragLayer; final float finalScale = 1f; float scale = mIsOpening ? initialScale : finalScale; @@ -149,12 +148,10 @@ public class FolderAnimationManager { previewItemOffsetX = (int) (lp.width * initialScale - initialSize - previewItemOffsetX); } - // Note that we do not include btv.getPaddingLeft() in the calculation, since it is - // handled in addPreviewItemAnimators as part of iconOffsetX. final int paddingOffsetX = (int) ((mFolder.getPaddingLeft() + mContent.getPaddingLeft()) * initialScale); - final int paddingOffsetY = (int) ((mFolder.getPaddingTop() + mContent.getPaddingTop() - + btv.getPaddingTop()) * initialScale); + final int paddingOffsetY = (int) ((mFolder.getPaddingTop() + mContent.getPaddingTop()) + * initialScale); int initialX = folderIconPos.left + mPreviewBackground.getOffsetX() - paddingOffsetX - previewItemOffsetX; diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java index 84ec18410..6533b0463 100644 --- a/src/com/android/launcher3/folder/FolderIcon.java +++ b/src/com/android/launcher3/folder/FolderIcon.java @@ -440,6 +440,14 @@ public class FolderIcon extends FrameLayout implements FolderListener { invalidate(); } + public PreviewBackground getFolderBackground() { + return mBackground; + } + + public PreviewItemManager getPreviewItemManager() { + return mPreviewItemManager; + } + @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); @@ -463,14 +471,11 @@ public class FolderIcon extends FrameLayout implements FolderListener { } else { saveCount = canvas.save(Canvas.CLIP_SAVE_FLAG); if (mPreviewLayoutRule.clipToBackground()) { - mBackground.clipCanvasSoftware(canvas, Region.Op.INTERSECT); + canvas.clipPath(mBackground.getClipPath(), Region.Op.INTERSECT); } } - // The items are drawn in coordinates relative to the preview offset - canvas.translate(mBackground.basePreviewOffsetX, mBackground.basePreviewOffsetY); mPreviewItemManager.draw(canvas); - canvas.translate(-mBackground.basePreviewOffsetX, -mBackground.basePreviewOffsetY); if (mPreviewLayoutRule.clipToBackground() && canvas.isHardwareAccelerated()) { mBackground.clipCanvasHardware(canvas); @@ -481,6 +486,10 @@ public class FolderIcon extends FrameLayout implements FolderListener { mBackground.drawBackgroundStroke(canvas); } + drawBadge(canvas); + } + + public void drawBadge(Canvas canvas) { if ((mBadgeInfo != null && mBadgeInfo.hasBadge()) || mBadgeScale > 0) { int offsetX = mBackground.getOffsetX(); int offsetY = mBackground.getOffsetY(); diff --git a/src/com/android/launcher3/folder/PreviewBackground.java b/src/com/android/launcher3/folder/PreviewBackground.java index 61490eee8..eba5d984d 100644 --- a/src/com/android/launcher3/folder/PreviewBackground.java +++ b/src/com/android/launcher3/folder/PreviewBackground.java @@ -195,19 +195,28 @@ public class PreviewBackground { invalidate(); } + public int getBgColor() { + int alpha = (int) Math.min(MAX_BG_OPACITY, BG_OPACITY * mColorMultiplier); + return ColorUtils.setAlphaComponent(mBgColor, alpha); + } + public void drawBackground(Canvas canvas) { mPaint.setStyle(Paint.Style.FILL); - int alpha = (int) Math.min(MAX_BG_OPACITY, BG_OPACITY * mColorMultiplier); - mPaint.setColor(ColorUtils.setAlphaComponent(mBgColor, alpha)); + mPaint.setColor(getBgColor()); drawCircle(canvas, 0 /* deltaRadius */); - // Draw shadow. + drawShadow(canvas); + } + + public void drawShadow(Canvas canvas) { if (mShadowShader == null) { return; } + float radius = getScaledRadius(); float shadowRadius = radius + mStrokeWidth; + mPaint.setStyle(Paint.Style.FILL); mPaint.setColor(Color.BLACK); int offsetX = getOffsetX(); int offsetY = getOffsetY(); @@ -219,7 +228,7 @@ public class PreviewBackground { } else { saveCount = canvas.save(Canvas.CLIP_SAVE_FLAG); - clipCanvasSoftware(canvas, Region.Op.DIFFERENCE); + canvas.clipPath(getClipPath(), Region.Op.DIFFERENCE); } mShaderMatrix.setScale(shadowRadius, shadowRadius); @@ -295,12 +304,11 @@ public class PreviewBackground { radius - deltaRadius, mPaint); } - // It is the callers responsibility to save and restore the canvas layers. - void clipCanvasSoftware(Canvas canvas, Region.Op op) { + public Path getClipPath() { mPath.reset(); float r = getScaledRadius(); mPath.addCircle(r + getOffsetX(), r + getOffsetY(), r, Path.Direction.CW); - canvas.clipPath(mPath, op); + return mPath; } // It is the callers responsibility to save and restore the canvas layers. diff --git a/src/com/android/launcher3/folder/PreviewItemManager.java b/src/com/android/launcher3/folder/PreviewItemManager.java index 2ecb54ca8..2d979a661 100644 --- a/src/com/android/launcher3/folder/PreviewItemManager.java +++ b/src/com/android/launcher3/folder/PreviewItemManager.java @@ -146,6 +146,10 @@ public class PreviewItemManager { } public void draw(Canvas canvas) { + // The items are drawn in coordinates relative to the preview offset + PreviewBackground bg = mIcon.getFolderBackground(); + canvas.translate(bg.basePreviewOffsetX, bg.basePreviewOffsetY); + float firstPageItemsTransX = 0; if (mShouldSlideInFirstPage) { drawParams(canvas, mCurrentPageParams, mCurrentPageItemsTransX); @@ -154,6 +158,7 @@ public class PreviewItemManager { } drawParams(canvas, mFirstPageParams, firstPageItemsTransX); + canvas.translate(-bg.basePreviewOffsetX, -bg.basePreviewOffsetY); } public void onParamsChanged() { |