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

Commit 718bc598 authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 9470583 from 0bd7fc99 to tm-qpr3-release

Change-Id: I6f2f3081ee18d4dbd61abd0b26b160328f606e82
parents 4b7c8fce 0bd7fc99
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"
}
+154 −75
Original line number Diff line number Diff line
@@ -9,6 +9,8 @@ import static com.android.launcher3.icons.BitmapInfo.FLAG_INSTANT;
import static com.android.launcher3.icons.BitmapInfo.FLAG_WORK;
import static com.android.launcher3.icons.ShadowGenerator.BLUR_FACTOR;

import static java.lang.annotation.RetentionPolicy.SOURCE;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
@@ -31,12 +33,17 @@ import android.os.Build;
import android.os.UserHandle;
import android.util.SparseBooleanArray;

import androidx.annotation.ColorInt;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.android.launcher3.icons.BitmapInfo.Extender;
import com.android.launcher3.util.FlagOp;

import java.lang.annotation.Retention;
import java.util.Objects;

/**
 * This class will be moved to androidx library. There shouldn't be any dependency outside
 * this package.
@@ -45,27 +52,47 @@ 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;
    public static final int MODE_DEFAULT = 0;
    public static final int MODE_ALPHA = 1;
    public static final int MODE_WITH_SHADOW = 2;
    public static final int MODE_HARDWARE = 3;
    public static final int MODE_HARDWARE_WITH_SHADOW = 4;

    @Retention(SOURCE)
    @IntDef({MODE_DEFAULT, MODE_ALPHA, MODE_WITH_SHADOW, MODE_HARDWARE_WITH_SHADOW, MODE_HARDWARE})
    @interface BitmapGenerationMode {}

    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;
    protected final int mIconBitmapSize;

    protected boolean mMonoIconEnabled;

    @Nullable
    private IconNormalizer mNormalizer;

    @Nullable
    private ShadowGenerator mShadowGenerator;

    private final boolean mShapeDetection;

    // Shadow bitmap used as background for theme icons
@@ -97,9 +124,9 @@ public class BaseIconFactory implements AutoCloseable {

    protected void clear() {
        mWrapperBackgroundColor = DEFAULT_WRAPPER_BACKGROUND;
        mDisableColorExtractor = false;
    }

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

    @NonNull
    public IconNormalizer getNormalizer() {
        if (mNormalizer == null) {
            mNormalizer = new IconNormalizer(mContext, mIconBitmapSize, mShapeDetection);
@@ -149,12 +177,13 @@ public class BaseIconFactory implements AutoCloseable {
            icon = createIconBitmap(new BitmapDrawable(mContext.getResources(), icon), 1f);
        }

        return BitmapInfo.of(icon, extractColor(icon));
        return BitmapInfo.of(icon, mColorExtractor.findDominantColorByHue(icon));
    }

    /**
     * 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();
@@ -164,6 +193,7 @@ public class BaseIconFactory implements AutoCloseable {
        return createBadgedIconBitmap(d, options);
    }

    @NonNull
    public BitmapInfo createBadgedIconBitmap(@NonNull Drawable icon) {
        return createBadgedIconBitmap(icon, null);
    }
@@ -176,32 +206,46 @@ 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], BITMAP_GENERATION_MODE_WITH_SHADOW);
        Bitmap bitmap = createIconBitmap(icon, scale[0], MODE_WITH_SHADOW);

        int color = extractColor(bitmap);
        int color = (options != null && options.mExtractedColor != null)
                ? options.mExtractedColor : mColorExtractor.findDominantColorByHue(bitmap);
        BitmapInfo info = BitmapInfo.of(bitmap, color);

        if (icon instanceof BitmapInfo.Extender) {
            info = ((BitmapInfo.Extender) icon).getExtendedInfo(bitmap, color, this, scale[0]);
        } else if (mMonoIconEnabled && IconProvider.ATLEAST_T
                && icon instanceof AdaptiveIconDrawable) {
            Drawable mono = ((AdaptiveIconDrawable) icon).getMonochrome();
        } else if (IconProvider.ATLEAST_T && mMonoIconEnabled) {
            Drawable mono = getMonochromeDrawable(icon);
            if (mono != null) {
                // Convert mono drawable to bitmap
                Drawable paddedMono = new ClippedMonoDrawable(mono);
                info.setMonoIcon(
                        createIconBitmap(paddedMono, scale[0], BITMAP_GENERATION_MODE_ALPHA), this);
                info.setMonoIcon(createIconBitmap(mono, scale[0], MODE_ALPHA), this);
            }
        }
        info = info.withFlags(getBitmapFlagOp(options));
        return info;
    }

    /**
     * Returns a monochromatic version of the given drawable or null, if it is not supported
     * @param base the original icon
     */
    @TargetApi(Build.VERSION_CODES.TIRAMISU)
    protected Drawable getMonochromeDrawable(Drawable base) {
        if (base instanceof AdaptiveIconDrawable) {
            Drawable mono = ((AdaptiveIconDrawable) base).getMonochrome();
            if (mono != null) {
                return new ClippedMonoDrawable(mono);
            }
        }
        return null;
    }

    @NonNull
    public FlagOp getBitmapFlagOp(@Nullable IconOptions options) {
        FlagOp op = FlagOp.NO_OP;
        if (options != null) {
@@ -227,47 +271,36 @@ public class BaseIconFactory implements AutoCloseable {
        return op;
    }

    /** package private */
    Bitmap getWhiteShadowLayer() {
    @NonNull
    public Bitmap getWhiteShadowLayer() {
        if (mWhiteShadowLayer == null) {
            mWhiteShadowLayer = createScaledBitmapWithShadow(
                    new AdaptiveIconDrawable(new ColorDrawable(Color.WHITE), null));
            mWhiteShadowLayer = createScaledBitmap(
                    new AdaptiveIconDrawable(new ColorDrawable(Color.WHITE), null),
                    MODE_HARDWARE_WITH_SHADOW);
        }
        return mWhiteShadowLayer;
    }

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

    public Bitmap createScaledBitmapWithoutShadow(Drawable icon) {
    @NonNull
    public Bitmap createScaledBitmap(@NonNull Drawable icon, @BitmapGenerationMode int mode) {
        RectF iconBounds = new RectF();
        float[] scale = new float[1];
        icon = normalizeAndWrapToAdaptiveIcon(icon, true, iconBounds, scale);
        return createIconBitmap(icon,
                Math.min(scale[0], ShadowGenerator.getScaleForBounds(iconBounds)));
                Math.min(scale[0], ShadowGenerator.getScaleForBounds(iconBounds)), mode);
    }

    /**
     * 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;
    }

    /**
     * Disables the dominant color extraction for all icons loaded.
     */
    public void disableColorExtraction() {
        mDisableColorExtractor = true;
    }

    protected 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;
        }
@@ -298,20 +331,26 @@ public class BaseIconFactory implements AutoCloseable {
        return icon;
    }

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

    protected Bitmap createIconBitmap(@NonNull Drawable icon, float scale,
            int bitmapGenerationMode) {
    @NonNull
    protected Bitmap createIconBitmap(@Nullable final Drawable icon, final float scale,
            @BitmapGenerationMode int bitmapGenerationMode) {
        final int size = mIconBitmapSize;

        final Bitmap bitmap;
        switch (bitmapGenerationMode) {
            case BITMAP_GENERATION_MODE_ALPHA:
            case MODE_ALPHA:
                bitmap = Bitmap.createBitmap(size, size, Config.ALPHA_8);
                break;
            case BITMAP_GENERATION_MODE_WITH_SHADOW:
            case MODE_HARDWARE:
            case MODE_HARDWARE_WITH_SHADOW: {
                return BitmapRenderer.createHardwareBitmap(size, size, canvas ->
                        drawIconBitmap(canvas, icon, scale, bitmapGenerationMode, null));
            }
            case MODE_WITH_SHADOW:
            default:
                bitmap = Bitmap.createBitmap(size, size, Config.ARGB_8888);
                break;
@@ -320,6 +359,15 @@ public class BaseIconFactory implements AutoCloseable {
            return bitmap;
        }
        mCanvas.setBitmap(bitmap);
        drawIconBitmap(mCanvas, icon, scale, bitmapGenerationMode, bitmap);
        mCanvas.setBitmap(null);
        return bitmap;
    }

    private void drawIconBitmap(@NonNull Canvas canvas, @Nullable final Drawable icon,
            final float scale, @BitmapGenerationMode int bitmapGenerationMode,
            @Nullable Bitmap targetBitmap) {
        final int size = mIconBitmapSize;
        mOldBounds.set(icon.getBounds());

        if (icon instanceof AdaptiveIconDrawable) {
@@ -327,19 +375,20 @@ public class BaseIconFactory implements AutoCloseable {
                    Math.round(size * (1 - scale) / 2));
            // b/211896569: AdaptiveIconDrawable do not work properly for non top-left bounds
            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) {
            int count = canvas.save();
            canvas.translate(offset, offset);
            if (bitmapGenerationMode == MODE_WITH_SHADOW
                    || bitmapGenerationMode == MODE_HARDWARE_WITH_SHADOW) {
                getShadowGenerator().addPathShadow(
                        ((AdaptiveIconDrawable) icon).getIconMask(), mCanvas);
                        ((AdaptiveIconDrawable) icon).getIconMask(), canvas);
            }

            if (icon instanceof BitmapInfo.Extender) {
                ((Extender) icon).drawForPersistence(mCanvas);
                ((Extender) icon).drawForPersistence(canvas);
            } else {
                icon.draw(mCanvas);
                icon.draw(canvas);
            }
            mCanvas.restoreToCount(count);
            canvas.restoreToCount(count);
        } else {
            if (icon instanceof BitmapDrawable) {
                BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
@@ -365,15 +414,24 @@ public class BaseIconFactory implements AutoCloseable {
            final int left = (size - width) / 2;
            final int top = (size - height) / 2;
            icon.setBounds(left, top, left + width, top + height);
            mCanvas.save();
            mCanvas.scale(scale, scale, size / 2, size / 2);
            icon.draw(mCanvas);
            mCanvas.restore();

            canvas.save();
            canvas.scale(scale, scale, size / 2, size / 2);
            icon.draw(canvas);
            canvas.restore();

            if (bitmapGenerationMode == MODE_WITH_SHADOW && targetBitmap != null) {
                // Shadow extraction only works in software mode
                getShadowGenerator().drawShadow(targetBitmap, canvas);

                // Draw the icon again on top:
                canvas.save();
                canvas.scale(scale, scale, size / 2, size / 2);
                icon.draw(canvas);
                canvas.restore();
            }
        }
        icon.setBounds(mOldBounds);
        mCanvas.setBitmap(null);
        return bitmap;
    }

    @Override
@@ -381,36 +439,40 @@ 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);
    }

    private int extractColor(Bitmap bitmap) {
        return mDisableColorExtractor ? 0 : mColorExtractor.findDominantColorByHue(bitmap);
    @NonNull
    public static Drawable getFullResDefaultActivityIcon(final int iconDpi) {
        return Objects.requireNonNull(Resources.getSystem().getDrawableForDensity(
                android.R.drawable.sym_def_app_icon, iconDpi));
    }

    /**
     * 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;
        UserHandle mUserHandle;

        @Nullable UserHandle mUserHandle;

        @ColorInt
        @Nullable Integer mExtractedColor;

        /**
         * 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;
        }
@@ -418,7 +480,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;
        }
@@ -426,10 +489,20 @@ 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;
        }

        /**
         * Disables auto color extraction and overrides the color to the provided value
         */
        @NonNull
        public IconOptions setExtractedColor(@ColorInt int color) {
            mExtractedColor = color;
            return this;
        }
    }

    /**
@@ -439,7 +512,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);
        }

@@ -466,11 +539,12 @@ public class BaseIconFactory implements AutoCloseable {
        }
    }

    private static class ClippedMonoDrawable extends InsetDrawable {
    protected 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);
        }
@@ -487,11 +561,16 @@ public class BaseIconFactory implements AutoCloseable {

    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(String text, int color) {
        CenterTextDrawable(@NonNull final String text, final int color) {
            mText = text;
            mTextPaint.setColor(color);
        }
+2 −1
Original line number Diff line number Diff line
@@ -214,7 +214,8 @@ public class ClockDrawableWrapper extends AdaptiveIconDrawable implements Bitmap
            BaseIconFactory iconFactory, float normalizationScale) {
        AdaptiveIconDrawable background = new AdaptiveIconDrawable(
                getBackground().getConstantState().newDrawable(), null);
        Bitmap flattenBG = iconFactory.createScaledBitmapWithShadow(background);
        Bitmap flattenBG = iconFactory.createScaledBitmap(background,
                BaseIconFactory.MODE_HARDWARE_WITH_SHADOW);

        // Only pass theme info if mono-icon is enabled
        AnimationInfo themeInfo = iconFactory.mMonoIconEnabled ? mThemeInfo : 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) {
    protected 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);
+1 −5
Original line number Diff line number Diff line
@@ -58,7 +58,7 @@ public class ShadowGenerator {
        mDefaultBlurMaskFilter = new BlurMaskFilter(mIconSize * BLUR_FACTOR, Blur.NORMAL);
    }

    public synchronized void recreateIcon(Bitmap icon, Canvas out) {
    public synchronized void drawShadow(Bitmap icon, Canvas out) {
        if (ENABLE_SHADOWS) {
            int[] offset = new int[2];
            mBlurPaint.setMaskFilter(mDefaultBlurMaskFilter);
@@ -73,10 +73,6 @@ public class ShadowGenerator {
            out.drawBitmap(shadow, offset[0], offset[1] + KEY_SHADOW_DISTANCE * mIconSize,
                    mDrawPaint);
        }

        // Draw the icon
        mDrawPaint.setAlpha(255);
        out.drawBitmap(icon, 0, 0, mDrawPaint);
    }

    /** package private **/
Loading