Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f9a9c3f6 authored by Sunny Goyal's avatar Sunny Goyal Committed by Android (Google) Code Review
Browse files

Merge "Adding spring effect for folder icons when dragging similar to adaptive...

Merge "Adding spring effect for folder icons when dragging similar to adaptive icons" into ub-launcher3-dorval-polish2
parents 87b60258 e29897f5
Loading
Loading
Loading
Loading
+11 −9
Original line number Diff line number Diff line
@@ -1465,21 +1465,23 @@ 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;
            }
        });
    }

    /**
+37 −18
Original line number Diff line number Diff line
@@ -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,6 +421,8 @@ public class DragView extends View {
    @Override
    protected void onDraw(Canvas canvas) {
        mHasDrawn = true;

        if (mDrawBitmap) {
            // Always draw the bitmap to mask anti aliasing due to clipPath
            boolean crossFade = mCrossFadeProgress > 0 && mCrossFadeBitmap != null;
            if (crossFade) {
@@ -421,6 +439,7 @@ public class DragView extends View {
                canvas.drawBitmap(mCrossFadeBitmap, 0.0f, 0.0f, mPaint);
                canvas.restoreToCount(saveCount);
            }
        }

        if (mScaledMaskPath != null) {
            int cnt = canvas.save();
+175 −0
Original line number Diff line number Diff line
/*
 * 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;
        }
    }
}
+13 −4
Original line number Diff line number Diff line
@@ -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();
+15 −7
Original line number Diff line number Diff line
@@ -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.
Loading