Search in sources :

Example 1 with AdaptiveIconCompat

use of com.android.launcher3.AdaptiveIconCompat in project Neo-Launcher by NeoApplications.

the class BaseIconFactory method normalizeAndWrapToAdaptiveIcon.

private Drawable normalizeAndWrapToAdaptiveIcon(@NonNull Drawable icon, boolean shrinkNonAdaptiveIcons, RectF outIconBounds, float[] outScale) {
    float scale;
    if (shrinkNonAdaptiveIcons && ATLEAST_OREO) {
        if (mWrapperIcon == null || !((AdaptiveIconCompat) mWrapperIcon).isMaskValid()) {
            mWrapperIcon = AdaptiveIconCompat.wrap(mContext.getDrawable(R.drawable.adaptive_icon_drawable_wrapper).mutate());
        }
        AdaptiveIconCompat dr = (AdaptiveIconCompat) mWrapperIcon;
        dr.setBounds(0, 0, 1, 1);
        boolean[] outShape = new boolean[1];
        scale = getNormalizer().getScale(icon, outIconBounds, dr.getIconMask(), outShape);
        if (!outShape[0] && (icon instanceof NonAdaptiveIconDrawable)) {
            FixedScaleDrawable fsd = ((FixedScaleDrawable) dr.getForeground());
            fsd.setDrawable(icon);
            fsd.setScale(scale);
            icon = dr;
            scale = getNormalizer().getScale(icon, outIconBounds, null, null);
            ((ColorDrawable) dr.getBackground()).setColor(mWrapperBackgroundColor);
        }
    } else {
        scale = getNormalizer().getScale(icon, outIconBounds, null, null);
    }
    outScale[0] = scale;
    return icon;
}
Also used : ColorDrawable(android.graphics.drawable.ColorDrawable) AdaptiveIconCompat(com.android.launcher3.AdaptiveIconCompat)

Example 2 with AdaptiveIconCompat

use of com.android.launcher3.AdaptiveIconCompat in project Neo-Launcher by NeoApplications.

the class BaseIconFactory method createBadgedIconBitmap.

/**
 * Creates bitmap using the source drawable and various parameters.
 * The bitmap is visually normalized with other icons and has enough spacing to add shadow.
 *
 * @param icon                   source of the icon
 * @param user                   info can be used for a badge
 * @param shrinkNonAdaptiveIcons {@code true} if non adaptive icons should be treated
 * @param isInstantApp           info can be used for a badge
 * @param scale                  returns the scale result from normalization
 * @return a bitmap suitable for disaplaying as an icon at various system UIs.
 */
public BitmapInfo createBadgedIconBitmap(@NonNull Drawable icon, UserHandle user, boolean shrinkNonAdaptiveIcons, boolean isInstantApp, float[] scale) {
    if (scale == null) {
        scale = new float[1];
    }
    icon = normalizeAndWrapToAdaptiveIcon(icon, shrinkNonAdaptiveIcons, null, scale);
    Bitmap bitmap = createIconBitmap(icon, scale[0]);
    if (ATLEAST_OREO && icon instanceof AdaptiveIconCompat) {
        mCanvas.setBitmap(bitmap);
        getShadowGenerator().recreateIcon(Bitmap.createBitmap(bitmap), mCanvas);
        mCanvas.setBitmap(null);
    }
    if (isInstantApp) {
        badgeWithDrawable(bitmap, mContext.getDrawable(R.drawable.ic_instant_app_badge));
    }
    if (user != null) {
        BitmapDrawable drawable = new FixedSizeBitmapDrawable(bitmap);
        Drawable badged = mPm.getUserBadgedIcon(drawable, user);
        if (badged instanceof BitmapDrawable) {
            bitmap = ((BitmapDrawable) badged).getBitmap();
        } else {
            bitmap = createIconBitmap(badged, 1f);
        }
    }
    return BitmapInfo.fromBitmap(bitmap, mDisableColorExtractor ? null : mColorExtractor);
}
Also used : Bitmap(android.graphics.Bitmap) AdaptiveIconDrawable(android.graphics.drawable.AdaptiveIconDrawable) ColorDrawable(android.graphics.drawable.ColorDrawable) BitmapDrawable(android.graphics.drawable.BitmapDrawable) Drawable(android.graphics.drawable.Drawable) BitmapDrawable(android.graphics.drawable.BitmapDrawable) AdaptiveIconCompat(com.android.launcher3.AdaptiveIconCompat)

Example 3 with AdaptiveIconCompat

use of com.android.launcher3.AdaptiveIconCompat in project Neo-Launcher by NeoApplications.

the class AdaptiveIconGenerator method loop.

private void loop() {
    if (Utilities.ATLEAST_OREO && shouldWrap) {
        if (roundIcon != null && roundIcon instanceof AdaptiveIconCompat) {
            icon = roundIcon;
        }
        Drawable extractee = icon;
        if (icon instanceof AdaptiveIconCompat) {
            if (!treatWhite) {
                onExitLoop();
                return;
            }
            AdaptiveIconCompat aid = (AdaptiveIconCompat) extractee;
            // we still check this seperately as this is the only information we need from the background
            if (!isSingleColor(aid.getBackground(), Color.WHITE)) {
                onExitLoop();
                return;
            }
            isBackgroundWhite = true;
            extractee = aid.getForeground();
        }
        if (extractee == null) {
            Log.e("AdaptiveIconGenerator", "extractee is null, skipping.");
            onExitLoop();
            return;
        }
        LauncherIcons li = LauncherIcons.obtain(context);
        IconNormalizer normalizer = li.getNormalizer();
        li.recycle();
        boolean[] outShape = new boolean[1];
        RectF bounds = new RectF();
        initTmpIfNeeded();
        // scale = normalizer.getScale(extractee, bounds, tmp.getIconMask(), outShape);
        scale = normalizer.getScale(extractee, bounds, tmp.getIconMask(), outShape, MIN_VISIBLE_ALPHA);
        matchesMaskShape = outShape[0];
        if (extractee instanceof ColorDrawable) {
            isFullBleed = true;
            fullBleedChecked = true;
        }
        width = extractee.getIntrinsicWidth();
        height = extractee.getIntrinsicHeight();
        aWidth = width * (1 - (bounds.left + bounds.right));
        aHeight = height * (1 - (bounds.top + bounds.bottom));
        // Check if the icon is squareish
        final float ratio = aHeight / aWidth;
        boolean isSquareish = 0.999 < ratio && ratio < 1.0001;
        boolean almostSquarish = isSquareish || (0.97 < ratio && ratio < 1.005);
        if (!isSquareish) {
            isFullBleed = false;
            fullBleedChecked = true;
        }
        final Bitmap bitmap = Utilities.drawableToBitmap(extractee);
        if (bitmap == null) {
            onExitLoop();
            return;
        }
        if (!bitmap.hasAlpha()) {
            isFullBleed = true;
            fullBleedChecked = true;
        }
        final int size = height * width;
        SparseIntArray rgbScoreHistogram = new SparseIntArray(NUMBER_OF_COLORS_GUESSTIMATION);
        final int[] pixels = new int[size];
        bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
        /*
             *   Calculate the number of padding pixels around the actual icon (i)
             *   +----------------+
             *   |      top       |
             *   +---+--------+---+
             *   |   |        |   |
             *   | l |    i   | r |
             *   |   |        |   |
             *   +---+--------+---+
             *   |     bottom     |
             *   +----------------+
             */
        float adjHeight = height - bounds.top - bounds.bottom;
        float l = bounds.left * width * adjHeight;
        float top = bounds.top * height * width;
        float r = bounds.right * width * adjHeight;
        float bottom = bounds.bottom * height * width;
        int addPixels = Math.round(l + top + r + bottom);
        // Any icon with less than 10% transparent pixels (padding excluded) is considered "full-bleed-ish"
        final int maxTransparent = (int) (round(size * .10) + addPixels);
        // Any icon with less than 27% transparent pixels (padding excluded) doesn't need a color mix-in
        final int noMixinScore = (int) (round(size * .27) + addPixels);
        int highScore = 0;
        int bestRGB = 0;
        int transparentScore = 0;
        for (int pixel : pixels) {
            int alpha = 0xFF & (pixel >> 24);
            if (alpha < MIN_VISIBLE_ALPHA) {
                // Drop mostly-transparent pixels.
                transparentScore++;
                if (transparentScore > maxTransparent) {
                    isFullBleed = false;
                    fullBleedChecked = true;
                    if (!extractColor && transparentScore > noMixinScore) {
                        break;
                    }
                }
                continue;
            }
            // Reduce color complexity.
            int rgb = ColorExtractor.posterize(pixel);
            if (rgb < 0) {
                // Defensively avoid array bounds violations.
                continue;
            }
            int currentScore = rgbScoreHistogram.get(rgb) + 1;
            rgbScoreHistogram.append(rgb, currentScore);
            if (currentScore > highScore) {
                highScore = currentScore;
                bestRGB = rgb;
            }
        }
        // add back the alpha channel
        bestRGB |= 0xff << 24;
        // not yet checked = not set to false = has to be full bleed, isBackgroundWhite = true = is adaptive
        isFullBleed |= !fullBleedChecked && !isBackgroundWhite;
        // return early if a mix-in isnt needed
        noMixinNeeded = !isFullBleed && !isBackgroundWhite && almostSquarish && transparentScore <= noMixinScore;
        if (isFullBleed || noMixinNeeded) {
            backgroundColor = bestRGB;
            onExitLoop();
            return;
        }
        if (!extractColor) {
            backgroundColor = Color.WHITE;
            onExitLoop();
            return;
        }
        // "single color"
        final int numColors = rgbScoreHistogram.size();
        boolean singleColor = numColors <= SINGLE_COLOR_LIMIT;
        // Convert to HSL to get the lightness and adjust the color
        final float[] hsl = new float[3];
        ColorUtils.colorToHSL(bestRGB, hsl);
        float lightness = hsl[2];
        boolean light = lightness > .5;
        // Apply dark background to mostly white icons
        boolean veryLight = lightness > .75 && singleColor;
        // Apply light background to mostly dark icons
        boolean veryDark = lightness < .35 && singleColor;
        // Adjust color to reach suitable contrast depending on the relationship between the colors
        final int opaqueSize = size - transparentScore;
        final float pxPerColor = opaqueSize / (float) numColors;
        float mixRatio = min(max(pxPerColor / highScore, .15f), .7f);
        // Vary color mix-in based on lightness and amount of colors
        int fill = (light && !veryLight) || veryDark ? 0xFFFFFFFF : 0xFF333333;
        backgroundColor = ColorUtils.blendARGB(bestRGB, fill, mixRatio);
    // backgroundColor = Utilities.findDominantColorByHue(bitmap, 20);
    }
    onExitLoop();
}
Also used : IconNormalizer(com.android.launcher3.icons.IconNormalizer) ColorDrawable(android.graphics.drawable.ColorDrawable) Drawable(android.graphics.drawable.Drawable) FixedScaleDrawable(com.android.launcher3.icons.FixedScaleDrawable) AdaptiveIconCompat(com.android.launcher3.AdaptiveIconCompat) RectF(android.graphics.RectF) Bitmap(android.graphics.Bitmap) ColorDrawable(android.graphics.drawable.ColorDrawable) SparseIntArray(android.util.SparseIntArray) LauncherIcons(com.android.launcher3.icons.LauncherIcons)

Example 4 with AdaptiveIconCompat

use of com.android.launcher3.AdaptiveIconCompat in project Neo-Launcher by NeoApplications.

the class IconNormalizer method getScale.

/**
 * Returns the amount by which the {@param d} should be scaled (in both dimensions) so that it
 * matches the design guidelines for a launcher icon.
 * <p>
 * We first calculate the convex hull of the visible portion of the icon.
 * This hull then compared with the bounding rectangle of the hull to find how closely it
 * resembles a circle and a square, by comparing the ratio of the areas. Note that this is not an
 * ideal solution but it gives satisfactory result without affecting the performance.
 * <p>
 * This closeness is used to determine the ratio of hull area to the full icon size.
 * Refer {@link #MAX_CIRCLE_AREA_FACTOR} and {@link #MAX_SQUARE_AREA_FACTOR}
 *
 * @param outBounds optional rect to receive the fraction distance from each edge.
 */
public synchronized float getScale(@NonNull Drawable d, @Nullable RectF outBounds, @Nullable Path path, @Nullable boolean[] outMaskShape, int minVisibleAlpha) {
    if (BaseIconFactory.ATLEAST_OREO && d instanceof AdaptiveIconCompat) {
        if (mAdaptiveIconScale == SCALE_NOT_INITIALIZED) {
            mAdaptiveIconScale = normalizeAdaptiveIcon(d, mMaxSize, mAdaptiveIconBounds);
        }
        if (outBounds != null) {
            outBounds.set(mAdaptiveIconBounds);
        }
        return mAdaptiveIconScale;
    }
    int width = d.getIntrinsicWidth();
    int height = d.getIntrinsicHeight();
    if (width <= 0 || height <= 0) {
        width = width <= 0 || width > mMaxSize ? mMaxSize : width;
        height = height <= 0 || height > mMaxSize ? mMaxSize : height;
    } else if (width > mMaxSize || height > mMaxSize) {
        int max = Math.max(width, height);
        width = mMaxSize * width / max;
        height = mMaxSize * height / max;
    }
    mBitmap.eraseColor(Color.TRANSPARENT);
    d.setBounds(0, 0, width, height);
    d.draw(mCanvas);
    ByteBuffer buffer = ByteBuffer.wrap(mPixels);
    buffer.rewind();
    mBitmap.copyPixelsToBuffer(buffer);
    // Overall bounds of the visible icon.
    int topY = -1;
    int bottomY = -1;
    int leftX = mMaxSize + 1;
    int rightX = -1;
    // Create border by going through all pixels one row at a time and for each row find
    // the first and the last non-transparent pixel. Set those values to mLeftBorder and
    // mRightBorder and use -1 if there are no visible pixel in the row.
    // buffer position
    int index = 0;
    // buffer shift after every row, width of buffer = mMaxSize
    int rowSizeDiff = mMaxSize - width;
    // first and last position for any row.
    int firstX, lastX;
    for (int y = 0; y < height; y++) {
        firstX = lastX = -1;
        for (int x = 0; x < width; x++) {
            if ((mPixels[index] & 0xFF) > minVisibleAlpha) {
                if (firstX == -1) {
                    firstX = x;
                }
                lastX = x;
            }
            index++;
        }
        index += rowSizeDiff;
        mLeftBorder[y] = firstX;
        mRightBorder[y] = lastX;
        // If there is at least one visible pixel, update the overall bounds.
        if (firstX != -1) {
            bottomY = y;
            if (topY == -1) {
                topY = y;
            }
            leftX = Math.min(leftX, firstX);
            rightX = Math.max(rightX, lastX);
        }
    }
    if (topY == -1 || rightX == -1) {
        // No valid pixels found. Do not scale.
        return 1;
    }
    convertToConvexArray(mLeftBorder, 1, topY, bottomY);
    convertToConvexArray(mRightBorder, -1, topY, bottomY);
    // Area of the convex hull
    float area = 0;
    for (int y = 0; y < height; y++) {
        if (mLeftBorder[y] <= -1) {
            continue;
        }
        area += mRightBorder[y] - mLeftBorder[y] + 1;
    }
    mBounds.left = leftX;
    mBounds.right = rightX;
    mBounds.top = topY;
    mBounds.bottom = bottomY;
    if (outBounds != null) {
        outBounds.set(((float) mBounds.left) / width, ((float) mBounds.top) / height, 1 - ((float) mBounds.right) / width, 1 - ((float) mBounds.bottom) / height);
    }
    if (outMaskShape != null && mEnableShapeDetection && outMaskShape.length > 0) {
        outMaskShape[0] = isShape(path, minVisibleAlpha);
    }
    // Area of the rectangle required to fit the convex hull
    float rectArea = (bottomY + 1 - topY) * (rightX + 1 - leftX);
    return getScale(area, rectArea, width * height);
}
Also used : ByteBuffer(java.nio.ByteBuffer) Paint(android.graphics.Paint) AdaptiveIconCompat(com.android.launcher3.AdaptiveIconCompat)

Example 5 with AdaptiveIconCompat

use of com.android.launcher3.AdaptiveIconCompat in project Neo-Launcher by NeoApplications.

the class AdaptiveIconGenerator method genResult.

private Drawable genResult() {
    if (!Utilities.ATLEAST_OREO || !shouldWrap) {
        if (roundIcon != null) {
            if (icon instanceof AdaptiveIconCompat && !(roundIcon instanceof AdaptiveIconCompat)) {
                return icon;
            }
            return roundIcon;
        }
        return icon;
    }
    if (icon instanceof AdaptiveIconCompat) {
        if (!treatWhite || !isBackgroundWhite) {
            return icon;
        }
        if (((AdaptiveIconCompat) icon).getBackground() instanceof ColorDrawable) {
            AdaptiveIconCompat mutIcon = (AdaptiveIconCompat) icon.mutate();
            ((ColorDrawable) mutIcon.getBackground()).setColor(backgroundColor);
            return mutIcon;
        }
        return new AdaptiveIconCompat(new ColorDrawable(backgroundColor), ((AdaptiveIconCompat) icon).getForeground());
    }
    initTmpIfNeeded();
    ((FixedScaleDrawable) tmp.getForeground()).setDrawable(icon);
    if (matchesMaskShape || isFullBleed || noMixinNeeded) {
        float scale;
        if (noMixinNeeded) {
            float upScale = min(width / aWidth, height / aHeight);
            scale = NO_MIXIN_ICON_SCALE * upScale;
        } else {
            float upScale = max(width / aWidth, height / aHeight);
            scale = FULL_BLEED_ICON_SCALE * upScale;
        }
        ((FixedScaleDrawable) tmp.getForeground()).setScale(scale);
    } else {
        ((FixedScaleDrawable) tmp.getForeground()).setScale(scale);
    }
    ((ColorDrawable) tmp.getBackground()).setColor(backgroundColor);
    return tmp;
}
Also used : ColorDrawable(android.graphics.drawable.ColorDrawable) AdaptiveIconCompat(com.android.launcher3.AdaptiveIconCompat) FixedScaleDrawable(com.android.launcher3.icons.FixedScaleDrawable)

Aggregations

AdaptiveIconCompat (com.android.launcher3.AdaptiveIconCompat)5 ColorDrawable (android.graphics.drawable.ColorDrawable)4 Bitmap (android.graphics.Bitmap)2 Drawable (android.graphics.drawable.Drawable)2 FixedScaleDrawable (com.android.launcher3.icons.FixedScaleDrawable)2 Paint (android.graphics.Paint)1 RectF (android.graphics.RectF)1 AdaptiveIconDrawable (android.graphics.drawable.AdaptiveIconDrawable)1 BitmapDrawable (android.graphics.drawable.BitmapDrawable)1 SparseIntArray (android.util.SparseIntArray)1 IconNormalizer (com.android.launcher3.icons.IconNormalizer)1 LauncherIcons (com.android.launcher3.icons.LauncherIcons)1 ByteBuffer (java.nio.ByteBuffer)1