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

Commit baa78228 authored by Xin Li's avatar Xin Li
Browse files

Merge tm-qpr-dev-plus-aosp-without-vendor@9129937

Bug: 248070379
Merged-In: I67328c973d97974bcea340943f7ce02c55550d8e
Change-Id: I32ef7f390aea7d46b7645b5cd1668a3d04b4e791
parents db307591 202bb60c
Loading
Loading
Loading
Loading
+4 −15
Original line number Diff line number Diff line
apply plugin: 'com.android.library'

android {
    compileSdkVersion COMPILE_SDK
    buildToolsVersion BUILD_TOOLS_VERSION

    defaultConfig {
        minSdkVersion 26
        targetSdkVersion 28
plugins {
    id 'sysuigradleproject.android-library-conventions'
}

android {
    sourceSets {
        main {
            java.srcDirs = ['src', 'src_full_lib']
@@ -24,13 +18,8 @@ android {
    tasks.withType(JavaCompile) {
        options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    implementation "androidx.core:core:${ANDROID_X_VERSION}"
    implementation "androidx.core:core"
}
+116 −56
Original line number Diff line number Diff line
package com.android.launcher3.icons;

import static android.graphics.Paint.ANTI_ALIAS_FLAG;
import static android.graphics.Paint.DITHER_FLAG;
import static android.graphics.Paint.FILTER_BITMAP_FLAG;
import static android.graphics.drawable.AdaptiveIconDrawable.getExtraInsetFraction;
@@ -36,6 +37,8 @@ import androidx.annotation.Nullable;
import com.android.launcher3.icons.BitmapInfo.Extender;
import com.android.launcher3.util.FlagOp;

import java.util.Objects;

/**
 * This class will be moved to androidx library. There shouldn't be any dependency outside
 * this package.
@@ -44,14 +47,30 @@ public class BaseIconFactory implements AutoCloseable {

    private static final int DEFAULT_WRAPPER_BACKGROUND = Color.WHITE;

    protected static final int BITMAP_GENERATION_MODE_DEFAULT = 0;
    protected static final int BITMAP_GENERATION_MODE_ALPHA = 1;
    protected static final int BITMAP_GENERATION_MODE_WITH_SHADOW = 2;

    private static final float ICON_BADGE_SCALE = 0.444f;

    @NonNull
    private final Rect mOldBounds = new Rect();

    @NonNull
    private final SparseBooleanArray mIsUserBadged = new SparseBooleanArray();

    @NonNull
    protected final Context mContext;

    @NonNull
    private final Canvas mCanvas;

    @NonNull
    private final PackageManager mPm;

    @NonNull
    private final ColorExtractor mColorExtractor;

    private boolean mDisableColorExtractor;

    protected final int mFillResIconDpi;
@@ -59,8 +78,12 @@ public class BaseIconFactory implements AutoCloseable {

    protected boolean mMonoIconEnabled;

    @Nullable
    private IconNormalizer mNormalizer;

    @Nullable
    private ShadowGenerator mShadowGenerator;

    private final boolean mShapeDetection;

    // Shadow bitmap used as background for theme icons
@@ -69,8 +92,6 @@ public class BaseIconFactory implements AutoCloseable {
    private Drawable mWrapperIcon;
    private int mWrapperBackgroundColor = DEFAULT_WRAPPER_BACKGROUND;

    private final Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
    private static final float PLACEHOLDER_TEXT_SIZE = 20f;
    private static int PLACEHOLDER_BACKGROUND_COLOR = Color.rgb(245, 245, 245);

    protected BaseIconFactory(Context context, int fillResIconDpi, int iconBitmapSize,
@@ -85,10 +106,6 @@ public class BaseIconFactory implements AutoCloseable {

        mCanvas = new Canvas();
        mCanvas.setDrawFilter(new PaintFlagsDrawFilter(DITHER_FLAG, FILTER_BITMAP_FLAG));
        mTextPaint.setTextAlign(Paint.Align.CENTER);
        mTextPaint.setColor(PLACEHOLDER_BACKGROUND_COLOR);
        mTextPaint.setTextSize(context.getResources().getDisplayMetrics().density *
                PLACEHOLDER_TEXT_SIZE);
        clear();
    }

@@ -101,6 +118,7 @@ public class BaseIconFactory implements AutoCloseable {
        mDisableColorExtractor = false;
    }

    @NonNull
    public ShadowGenerator getShadowGenerator() {
        if (mShadowGenerator == null) {
            mShadowGenerator = new ShadowGenerator(mIconBitmapSize);
@@ -108,6 +126,7 @@ public class BaseIconFactory implements AutoCloseable {
        return mShadowGenerator;
    }

    @NonNull
    public IconNormalizer getNormalizer() {
        if (mNormalizer == null) {
            mNormalizer = new IconNormalizer(mContext, mIconBitmapSize, mShapeDetection);
@@ -138,16 +157,11 @@ public class BaseIconFactory implements AutoCloseable {
     * @return
     */
    public BitmapInfo createIconBitmap(String placeholder, int color) {
        Bitmap placeholderBitmap = Bitmap.createBitmap(mIconBitmapSize, mIconBitmapSize,
                Bitmap.Config.ARGB_8888);
        mTextPaint.setColor(color);
        Canvas canvas = new Canvas(placeholderBitmap);
        canvas.drawText(placeholder, mIconBitmapSize / 2, mIconBitmapSize * 5 / 8, mTextPaint);
        AdaptiveIconDrawable drawable = new AdaptiveIconDrawable(
                new ColorDrawable(PLACEHOLDER_BACKGROUND_COLOR),
                new BitmapDrawable(mContext.getResources(), placeholderBitmap));
                new CenterTextDrawable(placeholder, color));
        Bitmap icon = createIconBitmap(drawable, IconNormalizer.ICON_VISIBLE_AREA_FACTOR);
        return BitmapInfo.of(icon, extractColor(icon));
        return BitmapInfo.of(icon, color);
    }

    public BitmapInfo createIconBitmap(Bitmap icon) {
@@ -161,6 +175,7 @@ public class BaseIconFactory implements AutoCloseable {
    /**
     * Creates an icon from the bitmap cropped to the current device icon shape
     */
    @NonNull
    public BitmapInfo createShapedIconBitmap(Bitmap icon, IconOptions options) {
        Drawable d = new FixedSizeBitmapDrawable(icon);
        float inset = getExtraInsetFraction();
@@ -170,6 +185,7 @@ public class BaseIconFactory implements AutoCloseable {
        return createBadgedIconBitmap(d, options);
    }

    @NonNull
    public BitmapInfo createBadgedIconBitmap(@NonNull Drawable icon) {
        return createBadgedIconBitmap(icon, null);
    }
@@ -182,17 +198,13 @@ public class BaseIconFactory implements AutoCloseable {
     * @return a bitmap suitable for disaplaying as an icon at various system UIs.
     */
    @TargetApi(Build.VERSION_CODES.TIRAMISU)
    @NonNull
    public BitmapInfo createBadgedIconBitmap(@NonNull Drawable icon,
            @Nullable IconOptions options) {
        boolean shrinkNonAdaptiveIcons = options == null || options.mShrinkNonAdaptiveIcons;
        float[] scale = new float[1];
        icon = normalizeAndWrapToAdaptiveIcon(icon, shrinkNonAdaptiveIcons, null, scale);
        Bitmap bitmap = createIconBitmap(icon, scale[0]);
        if (icon instanceof AdaptiveIconDrawable) {
            mCanvas.setBitmap(bitmap);
            getShadowGenerator().recreateIcon(Bitmap.createBitmap(bitmap), mCanvas);
            mCanvas.setBitmap(null);
        }
        Bitmap bitmap = createIconBitmap(icon, scale[0], BITMAP_GENERATION_MODE_WITH_SHADOW);

        int color = extractColor(bitmap);
        BitmapInfo info = BitmapInfo.of(bitmap, color);
@@ -206,14 +218,14 @@ public class BaseIconFactory implements AutoCloseable {
                // Convert mono drawable to bitmap
                Drawable paddedMono = new ClippedMonoDrawable(mono);
                info.setMonoIcon(
                        createIconBitmap(paddedMono, scale[0], mIconBitmapSize, Config.ALPHA_8),
                        this);
                        createIconBitmap(paddedMono, scale[0], BITMAP_GENERATION_MODE_ALPHA), this);
            }
        }
        info = info.withFlags(getBitmapFlagOp(options));
        return info;
    }

    @NonNull
    public FlagOp getBitmapFlagOp(@Nullable IconOptions options) {
        FlagOp op = FlagOp.NO_OP;
        if (options != null) {
@@ -240,6 +252,7 @@ public class BaseIconFactory implements AutoCloseable {
    }

    /** package private */
    @NonNull
    Bitmap getWhiteShadowLayer() {
        if (mWhiteShadowLayer == null) {
            mWhiteShadowLayer = createScaledBitmapWithShadow(
@@ -248,17 +261,16 @@ public class BaseIconFactory implements AutoCloseable {
        return mWhiteShadowLayer;
    }

    /** package private */
    public Bitmap createScaledBitmapWithShadow(Drawable d) {
    @NonNull
    public Bitmap createScaledBitmapWithShadow(@NonNull final Drawable d) {
        float scale = getNormalizer().getScale(d, null, null, null);
        Bitmap bitmap = createIconBitmap(d, scale);
        mCanvas.setBitmap(bitmap);
        getShadowGenerator().recreateIcon(Bitmap.createBitmap(bitmap), mCanvas);
        mCanvas.setBitmap(null);
        return bitmap;
        return BitmapRenderer.createHardwareBitmap(bitmap.getWidth(), bitmap.getHeight(),
                canvas -> getShadowGenerator().recreateIcon(bitmap, canvas));
    }

    public Bitmap createScaledBitmapWithoutShadow(Drawable icon) {
    @NonNull
    public Bitmap createScaledBitmapWithoutShadow(@Nullable Drawable icon) {
        RectF iconBounds = new RectF();
        float[] scale = new float[1];
        icon = normalizeAndWrapToAdaptiveIcon(icon, true, iconBounds, scale);
@@ -269,7 +281,7 @@ public class BaseIconFactory implements AutoCloseable {
    /**
     * Sets the background color used for wrapped adaptive icon
     */
    public void setWrapperBackgroundColor(int color) {
    public void setWrapperBackgroundColor(final int color) {
        mWrapperBackgroundColor = (Color.alpha(color) < 255) ? DEFAULT_WRAPPER_BACKGROUND : color;
    }

@@ -280,8 +292,10 @@ public class BaseIconFactory implements AutoCloseable {
        mDisableColorExtractor = true;
    }

    private Drawable normalizeAndWrapToAdaptiveIcon(@NonNull Drawable icon,
            boolean shrinkNonAdaptiveIcons, RectF outIconBounds, float[] outScale) {
    @Nullable
    protected Drawable normalizeAndWrapToAdaptiveIcon(@Nullable Drawable icon,
            final boolean shrinkNonAdaptiveIcons, @Nullable final RectF outIconBounds,
            @NonNull final float[] outScale) {
        if (icon == null) {
            return null;
        }
@@ -312,21 +326,26 @@ public class BaseIconFactory implements AutoCloseable {
        return icon;
    }

    private Bitmap createIconBitmap(Drawable icon, float scale) {
        return createIconBitmap(icon, scale, mIconBitmapSize);
    @NonNull
    protected Bitmap createIconBitmap(@Nullable final Drawable icon, final float scale) {
        return createIconBitmap(icon, scale, BITMAP_GENERATION_MODE_DEFAULT);
    }

    /**
     * @param icon drawable that should be flattened to a bitmap
     * @param scale the scale to apply before drawing {@param icon} on the canvas
     */
    public Bitmap createIconBitmap(@NonNull Drawable icon, float scale, int size) {
        return createIconBitmap(icon, scale, size, Bitmap.Config.ARGB_8888);
    }
    @NonNull
    protected Bitmap createIconBitmap(@Nullable final Drawable icon, final float scale,
            final int bitmapGenerationMode) {
        final int size = mIconBitmapSize;

    private Bitmap createIconBitmap(@NonNull Drawable icon, float scale, int size,
            Bitmap.Config config) {
        Bitmap bitmap = Bitmap.createBitmap(size, size, config);
        final Bitmap bitmap;
        switch (bitmapGenerationMode) {
            case BITMAP_GENERATION_MODE_ALPHA:
                bitmap = Bitmap.createBitmap(size, size, Config.ALPHA_8);
                break;
            case BITMAP_GENERATION_MODE_WITH_SHADOW:
            default:
                bitmap = Bitmap.createBitmap(size, size, Config.ARGB_8888);
                break;
        }
        if (icon == null) {
            return bitmap;
        }
@@ -340,6 +359,10 @@ public class BaseIconFactory implements AutoCloseable {
            icon.setBounds(0, 0, size - offset - offset, size - offset - offset);
            int count = mCanvas.save();
            mCanvas.translate(offset, offset);
            if (bitmapGenerationMode == BITMAP_GENERATION_MODE_WITH_SHADOW) {
                getShadowGenerator().addPathShadow(
                        ((AdaptiveIconDrawable) icon).getIconMask(), mCanvas);
            }

            if (icon instanceof BitmapInfo.Extender) {
                ((Extender) icon).drawForPersistence(mCanvas);
@@ -351,7 +374,7 @@ public class BaseIconFactory implements AutoCloseable {
            if (icon instanceof BitmapDrawable) {
                BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
                Bitmap b = bitmapDrawable.getBitmap();
                if (bitmap != null && b.getDensity() == Bitmap.DENSITY_NONE) {
                if (b != null && b.getDensity() == Bitmap.DENSITY_NONE) {
                    bitmapDrawable.setTargetDensity(mContext.getResources().getDisplayMetrics());
                }
            }
@@ -388,36 +411,42 @@ public class BaseIconFactory implements AutoCloseable {
        clear();
    }

    @NonNull
    public BitmapInfo makeDefaultIcon() {
        return createBadgedIconBitmap(getFullResDefaultActivityIcon(mFillResIconDpi));
    }

    public static Drawable getFullResDefaultActivityIcon(int iconDpi) {
        return Resources.getSystem().getDrawableForDensity(
                android.R.drawable.sym_def_app_icon, iconDpi);
    @NonNull
    public static Drawable getFullResDefaultActivityIcon(final int iconDpi) {
        return Objects.requireNonNull(Resources.getSystem().getDrawableForDensity(
                android.R.drawable.sym_def_app_icon, iconDpi));
    }

    private int extractColor(Bitmap bitmap) {
    private int extractColor(@NonNull final Bitmap bitmap) {
        return mDisableColorExtractor ? 0 : mColorExtractor.findDominantColorByHue(bitmap);
    }

    /**
     * Returns the correct badge size given an icon size
     */
    public static int getBadgeSizeForIconSize(int iconSize) {
    public static int getBadgeSizeForIconSize(final int iconSize) {
        return (int) (ICON_BADGE_SCALE * iconSize);
    }

    public static class IconOptions {

        boolean mShrinkNonAdaptiveIcons = true;

        boolean mIsInstantApp;

        @Nullable
        UserHandle mUserHandle;

        /**
         * Set to false if non-adaptive icons should not be treated
         */
        public IconOptions setShrinkNonAdaptiveIcons(boolean shrink) {
        @NonNull
        public IconOptions setShrinkNonAdaptiveIcons(final boolean shrink) {
            mShrinkNonAdaptiveIcons = shrink;
            return this;
        }
@@ -425,7 +454,8 @@ public class BaseIconFactory implements AutoCloseable {
        /**
         * User for this icon, in case of badging
         */
        public IconOptions setUser(UserHandle user) {
        @NonNull
        public IconOptions setUser(@Nullable final UserHandle user) {
            mUserHandle = user;
            return this;
        }
@@ -433,7 +463,8 @@ public class BaseIconFactory implements AutoCloseable {
        /**
         * If this icon represents an instant app
         */
        public IconOptions setInstantApp(boolean instantApp) {
        @NonNull
        public IconOptions setInstantApp(final boolean instantApp) {
            mIsInstantApp = instantApp;
            return this;
        }
@@ -446,7 +477,7 @@ public class BaseIconFactory implements AutoCloseable {
     */
    private static class FixedSizeBitmapDrawable extends BitmapDrawable {

        public FixedSizeBitmapDrawable(Bitmap bitmap) {
        public FixedSizeBitmapDrawable(@Nullable final Bitmap bitmap) {
            super(null, bitmap);
        }

@@ -475,9 +506,10 @@ public class BaseIconFactory implements AutoCloseable {

    private static class ClippedMonoDrawable extends InsetDrawable {

        @NonNull
        private final AdaptiveIconDrawable mCrop;

        public ClippedMonoDrawable(Drawable base) {
        public ClippedMonoDrawable(@Nullable final Drawable base) {
            super(base, -getExtraInsetFraction());
            mCrop = new AdaptiveIconDrawable(new ColorDrawable(Color.BLACK), null);
        }
@@ -491,4 +523,32 @@ public class BaseIconFactory implements AutoCloseable {
            canvas.restoreToCount(saveCount);
        }
    }

    private static class CenterTextDrawable extends ColorDrawable {

        @NonNull
        private final Rect mTextBounds = new Rect();

        @NonNull
        private final Paint mTextPaint = new Paint(ANTI_ALIAS_FLAG | FILTER_BITMAP_FLAG);

        @NonNull
        private final String mText;

        CenterTextDrawable(@NonNull final String text, final int color) {
            mText = text;
            mTextPaint.setColor(color);
        }

        @Override
        public void draw(Canvas canvas) {
            Rect bounds = getBounds();
            mTextPaint.setTextSize(bounds.height() / 3f);
            mTextPaint.getTextBounds(mText, 0, mText.length(), mTextBounds);
            canvas.drawText(mText,
                    bounds.exactCenterX() - mTextBounds.exactCenterX(),
                    bounds.exactCenterY() - mTextBounds.exactCenterY(),
                    mTextPaint);
        }
    }
}
+10 −3
Original line number Diff line number Diff line
@@ -387,7 +387,8 @@ public class ClockDrawableWrapper extends AdaptiveIconDrawable implements Bitmap
            mBgPaint.setColorFilter(cs.mBgFilter);
            mThemedFgColor = cs.mThemedFgColor;

            mFullDrawable = (AdaptiveIconDrawable) mAnimInfo.baseDrawableState.newDrawable();
            mFullDrawable =
                    (AdaptiveIconDrawable) mAnimInfo.baseDrawableState.newDrawable().mutate();
            mFG = (LayerDrawable) mFullDrawable.getForeground();

            // Time needs to be applied here since drawInternal is NOT guaranteed to be called
@@ -396,6 +397,13 @@ public class ClockDrawableWrapper extends AdaptiveIconDrawable implements Bitmap
            mCanvasScale = 1 - 2 * mBoundsOffset;
        }

        @Override
        public void setAlpha(int alpha) {
            super.setAlpha(alpha);
            mBgPaint.setAlpha(alpha);
            mFG.setAlpha(alpha);
        }

        @Override
        protected void onBoundsChange(Rect bounds) {
            super.onBoundsChange(bounds);
@@ -434,8 +442,7 @@ public class ClockDrawableWrapper extends AdaptiveIconDrawable implements Bitmap
        protected void updateFilter() {
            super.updateFilter();
            int alpha = mIsDisabled ? (int) (mDisabledAlpha * FULLY_OPAQUE) : FULLY_OPAQUE;
            mBgPaint.setAlpha(alpha);
            mFG.setAlpha(alpha);
            setAlpha(alpha);
            mBgPaint.setColorFilter(mIsDisabled ? getDisabledColorFilter() : mBgFilter);
            mFG.setColorFilter(mIsDisabled ? getDisabledColorFilter() : null);
        }
+13 −2
Original line number Diff line number Diff line
@@ -18,6 +18,9 @@ package com.android.launcher3.icons;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.util.SparseArray;

import androidx.annotation.NonNull;

import java.util.Arrays;

/**
@@ -26,16 +29,24 @@ import java.util.Arrays;
public class ColorExtractor {

    private final int NUM_SAMPLES = 20;

    @NonNull
    private final float[] mTmpHsv = new float[3];

    @NonNull
    private final float[] mTmpHueScoreHistogram = new float[360];

    @NonNull
    private final int[] mTmpPixels = new int[NUM_SAMPLES];

    @NonNull
    private final SparseArray<Float> mTmpRgbScores = new SparseArray<>();

    /**
     * This picks a dominant color, looking for high-saturation, high-value, repeated hues.
     * @param bitmap The bitmap to scan
     */
    public int findDominantColorByHue(Bitmap bitmap) {
    public int findDominantColorByHue(@NonNull final Bitmap bitmap) {
        return findDominantColorByHue(bitmap, NUM_SAMPLES);
    }

@@ -43,7 +54,7 @@ public class ColorExtractor {
     * This picks a dominant color, looking for high-saturation, high-value, repeated hues.
     * @param bitmap The bitmap to scan
     */
    public int findDominantColorByHue(Bitmap bitmap, int samples) {
    public int findDominantColorByHue(@NonNull final Bitmap bitmap, final int samples) {
        final int height = bitmap.getHeight();
        final int width = bitmap.getWidth();
        int sampleStride = (int) Math.sqrt((height * width) / samples);
+24 −8
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.graphics.BlurMaskFilter.Blur;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
@@ -58,22 +59,17 @@ public class ShadowGenerator {
    }

    public synchronized void recreateIcon(Bitmap icon, Canvas out) {
        recreateIcon(icon, mDefaultBlurMaskFilter, AMBIENT_SHADOW_ALPHA, KEY_SHADOW_ALPHA, out);
    }

    public synchronized void recreateIcon(Bitmap icon, BlurMaskFilter blurMaskFilter,
            int ambientAlpha, int keyAlpha, Canvas out) {
        if (ENABLE_SHADOWS) {
            int[] offset = new int[2];
            mBlurPaint.setMaskFilter(blurMaskFilter);
            mBlurPaint.setMaskFilter(mDefaultBlurMaskFilter);
            Bitmap shadow = icon.extractAlpha(mBlurPaint, offset);

            // Draw ambient shadow
            mDrawPaint.setAlpha(ambientAlpha);
            mDrawPaint.setAlpha(AMBIENT_SHADOW_ALPHA);
            out.drawBitmap(shadow, offset[0], offset[1], mDrawPaint);

            // Draw key shadow
            mDrawPaint.setAlpha(keyAlpha);
            mDrawPaint.setAlpha(KEY_SHADOW_ALPHA);
            out.drawBitmap(shadow, offset[0], offset[1] + KEY_SHADOW_DISTANCE * mIconSize,
                    mDrawPaint);
        }
@@ -83,6 +79,26 @@ public class ShadowGenerator {
        out.drawBitmap(icon, 0, 0, mDrawPaint);
    }

    /** package private **/
    void addPathShadow(Path path, Canvas out) {
        if (ENABLE_SHADOWS) {
            mDrawPaint.setMaskFilter(mDefaultBlurMaskFilter);

            // Draw ambient shadow
            mDrawPaint.setAlpha(AMBIENT_SHADOW_ALPHA);
            out.drawPath(path, mDrawPaint);

            // Draw key shadow
            int save = out.save();
            mDrawPaint.setAlpha(KEY_SHADOW_ALPHA);
            out.translate(0, KEY_SHADOW_DISTANCE * mIconSize);
            out.drawPath(path, mDrawPaint);
            out.restoreToCount(save);

            mDrawPaint.setMaskFilter(null);
        }
    }

    /**
     * Returns the minimum amount by which an icon with {@param bounds} should be scaled
     * so that the shadows do not get clipped.
Loading