Merge "Adding spring effect for folder icons when dragging similar to adaptive icons" into ub-launcher3-dorval-polish2
This commit is contained in:
commit
f9a9c3f69c
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in New Issue