use of com.android.launcher3.icons.IconNormalizer 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();
}
use of com.android.launcher3.icons.IconNormalizer in project android_packages_apps_404Launcher by P-404.
the class AdaptiveIconWrapper method wrap.
@TargetApi(26)
public Drawable wrap(Drawable icon, int backgroundColor) {
if (Utilities.ATLEAST_OREO && !(icon instanceof AdaptiveIconDrawable)) {
boolean[] outShape = new boolean[1];
mWrapper.setBounds(0, 0, 1, 1);
LauncherIcons icons = LauncherIcons.obtain(mContext);
IconNormalizer normalizer = icons.getNormalizer();
float scale = normalizer.getScale(icon, null, mWrapper.getIconMask(), outShape);
icons.recycle();
if (!outShape[0]) {
FixedScaleDrawable fsd = ((FixedScaleDrawable) mWrapper.getForeground());
fsd.setDrawable(icon);
fsd.setScale(scale);
((ColorDrawable) mWrapper.getBackground()).setColor(backgroundColor);
return mWrapper;
}
}
return icon;
}
Aggregations