Skip to content

Commit

Permalink
Merge pull request #2245 from marunjar/shape_enum
Browse files Browse the repository at this point in the history
Shape enum
  • Loading branch information
marunjar authored Feb 4, 2024
2 parents df574d1 + 155a697 commit 222d5c4
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 72 deletions.
55 changes: 26 additions & 29 deletions app/src/main/java/fr/neamar/kiss/IconsHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import fr.neamar.kiss.db.AppRecord;
import fr.neamar.kiss.db.DBHelper;
Expand All @@ -38,6 +37,7 @@
import fr.neamar.kiss.result.AppResult;
import fr.neamar.kiss.result.TagDummyResult;
import fr.neamar.kiss.utils.DrawableUtils;
import fr.neamar.kiss.utils.IconShape;
import fr.neamar.kiss.utils.UserHandle;
import fr.neamar.kiss.utils.Utilities;

Expand All @@ -57,7 +57,7 @@ public class IconsHandler {
private final SystemIconPack mSystemPack = new SystemIconPack();
private boolean mForceAdaptive = false;
private boolean mContactPackMask = false;
private int mContactsShape = DrawableUtils.SHAPE_SYSTEM;
private IconShape mContactsShape = IconShape.SHAPE_SYSTEM;
private boolean mForceShape = false;
private Utilities.AsyncRun mLoadIconsPackTask = null;
private volatile Map<String, Long> customIconIds = null;
Expand Down Expand Up @@ -101,11 +101,13 @@ public void onPrefChanged(SharedPreferences pref, String key) {
}
}

private static int getAdaptiveShape(SharedPreferences pref, String key) {
@NonNull
private static IconShape getAdaptiveShape(SharedPreferences pref, String key) {
try {
return Integer.parseInt(pref.getString(key, String.valueOf(DrawableUtils.SHAPE_SYSTEM)));
int shapeId = Integer.parseInt(pref.getString(key, String.valueOf(IconShape.SHAPE_SYSTEM.getId())));
return IconShape.valueById(shapeId);
} catch (Exception e) {
return DrawableUtils.SHAPE_SYSTEM;
return IconShape.SHAPE_SYSTEM;
}
}

Expand Down Expand Up @@ -222,7 +224,7 @@ public Drawable getBackgroundDrawable(@ColorInt int backgroundColor) {
return null;
}

final int shape = getShapeForGeneratingDrawable();
final IconShape shape = getShapeForGeneratingDrawable();
Drawable drawable = DrawableUtils.generateBackgroundDrawable(ctx, backgroundColor, shape);
return forceIconMask(drawable, shape);
}
Expand All @@ -232,7 +234,7 @@ public Drawable getDrawableIconForCodepoint(int codePoint, @ColorInt int textCol
if (mIconPack != null && !mIconPack.isLoaded()) {
return null;
}
final int shape = getShapeForGeneratingDrawable();
final IconShape shape = getShapeForGeneratingDrawable();
Drawable drawable = DrawableUtils.generateCodepointDrawable(ctx, codePoint, textColor, backgroundColor, shape);
return forceIconMask(drawable, shape);
}
Expand Down Expand Up @@ -272,7 +274,7 @@ public Drawable applyBadge(@NonNull Drawable drawable, @NonNull UserHandle userH
}

public Drawable applyContactMask(@NonNull Context ctx, @NonNull Drawable drawable) {
final int shape = getContactsShape();
final IconShape shape = getContactsShape();

if (mContactPackMask && mIconPack != null && mIconPack.hasMask()) {
// if the icon pack has a mask, use that instead of the adaptive shape
Expand All @@ -292,7 +294,7 @@ public Drawable applyContactMask(@NonNull Context ctx, @NonNull Drawable drawabl
* @param drawable drawable to mask
* @return masked drawable
*/
private Drawable forceIconMask(@NonNull Drawable drawable, int shape) {
private Drawable forceIconMask(@NonNull Drawable drawable, @NonNull IconShape shape) {
// apply mask
if (mIconPack != null && mIconPack.hasMask()) {
// if the icon pack has a mask, use that instead of the adaptive shape
Expand All @@ -305,42 +307,37 @@ private Drawable forceIconMask(@NonNull Drawable drawable, int shape) {

/**
* Get shape used for contact icons with fallbacks.
* If contacts shape is {@link DrawableUtils#SHAPE_SYSTEM} app shape is used.
* If app shape is {@link DrawableUtils#SHAPE_SYSTEM} too and no icon mask can be configured for device, used shape is a circle.
* If contacts shape is {@link IconShape#SHAPE_SYSTEM} app shape is used.
* If app shape is {@link IconShape#SHAPE_SYSTEM} too and no icon mask can be configured for device, used shape is a circle.
*
* @return shape
*/
private int getContactsShape() {
int shape = mContactsShape;
if (shape == DrawableUtils.SHAPE_SYSTEM) {
@NonNull
private IconShape getContactsShape() {
IconShape shape = mContactsShape;
if (shape == IconShape.SHAPE_SYSTEM) {
shape = mSystemPack.getAdaptiveShape();
}
if (shape == DrawableUtils.SHAPE_SYSTEM && !DrawableUtils.hasDeviceConfiguredMask()) {
shape = DrawableUtils.SHAPE_CIRCLE;
// contacts have square images, so fallback to circle explicitly
if (shape == IconShape.SHAPE_SYSTEM && !DrawableUtils.hasDeviceConfiguredMask()) {
shape = IconShape.SHAPE_CIRCLE;
}
return shape;
}

/**
* Get shape used for generating drawables with fallbacks.
* If icon pack has mask then {@link DrawableUtils#SHAPE_SYSTEM} is used.
* If shape is {@link DrawableUtils#SHAPE_SYSTEM} too and no icon mask can be configured for device, used shape is a circle.
* If icon pack has mask then {@link IconShape#SHAPE_SYSTEM} is used.
* If shape is {@link IconShape#SHAPE_SYSTEM} too and no icon mask can be configured for device, used shape is a circle.
*
* @return shape
*/
private int getShapeForGeneratingDrawable() {
int shape = mSystemPack.getAdaptiveShape();
@NonNull
private IconShape getShapeForGeneratingDrawable() {
IconShape shape = mSystemPack.getAdaptiveShape();
if (mIconPack != null && mIconPack.hasMask()) {
shape = DrawableUtils.SHAPE_SYSTEM;
shape = IconShape.SHAPE_SYSTEM;
}
if (shape == DrawableUtils.SHAPE_SYSTEM && !DrawableUtils.hasDeviceConfiguredMask()) {
shape = DrawableUtils.SHAPE_CIRCLE;
}
if (shape == DrawableUtils.SHAPE_TEARDROP_RND) {
Random r = new Random();
shape = DrawableUtils.SHAPE_TEARDROP_BR + r.nextInt(4);
}

return shape;
}

Expand Down
8 changes: 5 additions & 3 deletions app/src/main/java/fr/neamar/kiss/icons/SystemIconPack.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@

import fr.neamar.kiss.ui.GoogleCalendarIcon;
import fr.neamar.kiss.utils.DrawableUtils;
import fr.neamar.kiss.utils.IconShape;
import fr.neamar.kiss.utils.PackageManagerUtils;
import fr.neamar.kiss.utils.UserHandle;

public class SystemIconPack implements IconPack<Void> {

private static final String TAG = SystemIconPack.class.getSimpleName();
private final String packageName;
private int mAdaptiveShape = DrawableUtils.SHAPE_SYSTEM;
private IconShape mAdaptiveShape = IconShape.SHAPE_SYSTEM;

public SystemIconPack(String packageName) {
this.packageName = packageName;
Expand All @@ -40,11 +41,12 @@ public String getPackPackageName() {
public void load(PackageManager packageManager) {
}

public int getAdaptiveShape() {
@NonNull
public IconShape getAdaptiveShape() {
return mAdaptiveShape;
}

public void setAdaptiveShape(int shape) {
public void setAdaptiveShape(@NonNull IconShape shape) {
mAdaptiveShape = shape;
}

Expand Down
75 changes: 35 additions & 40 deletions app/src/main/java/fr/neamar/kiss/utils/DrawableUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,24 +29,12 @@

public class DrawableUtils {

public static final int SHAPE_SYSTEM = 0;
public static final int SHAPE_CIRCLE = 1;
public static final int SHAPE_SQUARE = 2;
public static final int SHAPE_SQUIRCLE = 3;
public static final int SHAPE_ROUND_RECT = 4;
public static final int SHAPE_TEARDROP_BR = 5;
private static final int SHAPE_TEARDROP_BL = 6;
private static final int SHAPE_TEARDROP_TL = 7;
private static final int SHAPE_TEARDROP_TR = 8;
public static final int SHAPE_TEARDROP_RND = 9;
public static final int SHAPE_HEXAGON = 10;
public static final int SHAPE_OCTAGON = 11;

private static final Paint PAINT = new Paint();
private static final Path SHAPE_PATH = new Path();
private static final RectF RECT_F = new RectF();
public static final String KEY_THEMED_ICONS = "themed-icons";
private static final String TAG = DrawableUtils.class.getSimpleName();
private static final IconShape[] TEARDROP_SHAPES = {IconShape.SHAPE_TEARDROP_BR, IconShape.SHAPE_TEARDROP_BL, IconShape.SHAPE_TEARDROP_TL, IconShape.SHAPE_TEARDROP_TR};

// https://stackoverflow.com/questions/3035692/how-to-convert-a-drawable-to-a-bitmap
public static Bitmap drawableToBitmap(@NonNull Drawable drawable) {
Expand Down Expand Up @@ -78,7 +66,7 @@ public static Bitmap drawableToBitmap(@NonNull Drawable drawable) {
* @param shape from SHAPE_*
* @return margin size
*/
private static float getScaleToFit(int shape) {
private static float getScaleToFit(IconShape shape) {
switch (shape) {
case SHAPE_SYSTEM:
case SHAPE_CIRCLE:
Expand All @@ -95,8 +83,9 @@ private static float getScaleToFit(int shape) {
return 0.26f;
case SHAPE_OCTAGON:
return 0.25f;
default:
return 0f;
}
return 0.f;
}

/**
Expand All @@ -110,12 +99,11 @@ private static float getScaleToFit(int shape) {
* @return shaped icon
*/
@NonNull
public static Drawable applyIconMaskShape(@NonNull Context ctx, @NonNull Drawable icon, int shape, boolean fitInside, @ColorInt int backgroundColor) {
if (shape == SHAPE_SYSTEM && !hasDeviceConfiguredMask())
public static Drawable applyIconMaskShape(@NonNull Context ctx, @NonNull Drawable icon, @NonNull IconShape shape, boolean fitInside, @ColorInt int backgroundColor) {
if (shape == IconShape.SHAPE_SYSTEM && !hasDeviceConfiguredMask()) {
// if no icon mask can be configured for device, then use icon as is
return icon;
if (shape == SHAPE_TEARDROP_RND)
shape = SHAPE_TEARDROP_BR + (icon.hashCode() % 4);
}

Bitmap outputBitmap;
Canvas outputCanvas;
Expand All @@ -134,7 +122,7 @@ public static Drawable applyIconMaskShape(@NonNull Context ctx, @NonNull Drawabl
outputBitmap = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
outputCanvas = new Canvas(outputBitmap);

setIconShapeAndDrawBackground(outputCanvas, backgroundColor, shape, false);
setIconShapeAndDrawBackground(outputCanvas, backgroundColor, shape, false, icon.hashCode());

// Stretch adaptive layers because they are 108dp and the icon size is 48dp
if (bgDrawable != null) {
Expand All @@ -148,7 +136,7 @@ public static Drawable applyIconMaskShape(@NonNull Context ctx, @NonNull Drawabl
}
}
// If icon is not adaptive, put it in a colored canvas to make it have a unified shape
else if (icon != null) {
else {
// Shrink icon fit inside the shape
int iconSize;
int iconOffset = 0;
Expand All @@ -167,19 +155,12 @@ else if (icon != null) {
outputBitmap = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
outputCanvas = new Canvas(outputBitmap);

setIconShapeAndDrawBackground(outputCanvas, backgroundColor, shape, true);
setIconShapeAndDrawBackground(outputCanvas, backgroundColor, shape, true, icon.hashCode());

// Shrink icon so that it fits the shape
int bottomRightCorner = iconSize - iconOffset;
icon.setBounds(iconOffset, iconOffset, bottomRightCorner, bottomRightCorner);
icon.draw(outputCanvas);
} else {
int iconSize = ctx.getResources().getDimensionPixelSize(R.dimen.result_icon_size);

outputBitmap = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
outputCanvas = new Canvas(outputBitmap);

setIconShapeAndDrawBackground(outputCanvas, Color.BLACK, shape, true);
}
return new BitmapDrawable(ctx.getResources(), outputBitmap);
}
Expand All @@ -189,8 +170,11 @@ else if (icon != null) {
* Synchronized because class fields like {@link DrawableUtils#SHAPE_PATH}, {@link DrawableUtils#RECT_F} and {@link DrawableUtils#PAINT} are reused for every call, which may result in unexpected behaviour if method is called from different threads running in parallel.
*
* @param shape type of shape: DrawableUtils.SHAPE_*
* @param hash, for pseudo random shape if applicable
*/
private synchronized static void setIconShapeAndDrawBackground(Canvas canvas, @ColorInt int backgroundColor, int shape, boolean drawBackground) {
private synchronized static void setIconShapeAndDrawBackground(Canvas canvas, @ColorInt int backgroundColor, @NonNull IconShape shape, boolean drawBackground, int hash) {
shape = getFinalShape(shape, hash);

int iconSize = canvas.getHeight();
final Path path = SHAPE_PATH;
path.rewind();
Expand Down Expand Up @@ -348,16 +332,16 @@ public static boolean isThemedIconEnabled(Context ctx) {
}

@NonNull
public synchronized static Drawable generateBackgroundDrawable(@NonNull Context ctx, @ColorInt int backgroundColor, int shape) {
Bitmap bitmap = generateBackgroundBitmap(ctx, backgroundColor, shape);
public synchronized static Drawable generateBackgroundDrawable(@NonNull Context ctx, @ColorInt int backgroundColor, @NonNull IconShape shape) {
Bitmap bitmap = generateBackgroundBitmap(ctx, backgroundColor, shape, backgroundColor);
return new BitmapDrawable(ctx.getResources(), bitmap);
}

@NonNull
public static Drawable generateCodepointDrawable(@NonNull Context ctx, int codepoint, @ColorInt int textColor, @ColorInt int backgroundColor, int shape) {
public static Drawable generateCodepointDrawable(@NonNull Context ctx, int codepoint, @ColorInt int textColor, @ColorInt int backgroundColor, @NonNull IconShape shape) {
int iconSize = ctx.getResources().getDimensionPixelSize(R.dimen.result_icon_size);

Bitmap bitmap = generateBackgroundBitmap(ctx, backgroundColor, shape);
Bitmap bitmap = generateBackgroundBitmap(ctx, backgroundColor, shape, codepoint);
// create a canvas from a bitmap
Canvas canvas = new Canvas(bitmap);

Expand Down Expand Up @@ -422,19 +406,30 @@ else if (!Character.UnicodeBlock.BASIC_LATIN.toString().equals(blockString)) {
}

@NonNull
private synchronized static Bitmap generateBackgroundBitmap(@NonNull Context ctx, @ColorInt int backgroundColor, int shape) {
private synchronized static Bitmap generateBackgroundBitmap(@NonNull Context ctx, @ColorInt int backgroundColor, @NonNull IconShape shape, int hash) {
int iconSize = ctx.getResources().getDimensionPixelSize(R.dimen.result_icon_size);
// create a canvas from a bitmap
Bitmap bitmap = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);

if (shape == SHAPE_SYSTEM && !hasDeviceConfiguredMask()) {
shape = SHAPE_CIRCLE;
}

setIconShapeAndDrawBackground(canvas, backgroundColor, shape, true);
setIconShapeAndDrawBackground(canvas, backgroundColor, shape, true, hash);

return bitmap;
}

public static IconShape getFinalShape(IconShape shape, int hash) {
switch (shape) {
case SHAPE_SYSTEM:
if (!hasDeviceConfiguredMask()) {
return IconShape.SHAPE_CIRCLE;
}
return shape;
case SHAPE_TEARDROP_RND:
return TEARDROP_SHAPES[Math.abs(hash % 4)];
default:
return shape;
}
}


}
40 changes: 40 additions & 0 deletions app/src/main/java/fr/neamar/kiss/utils/IconShape.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package fr.neamar.kiss.utils;

import androidx.annotation.NonNull;

public enum IconShape {

SHAPE_SYSTEM(0),
SHAPE_CIRCLE(1),
SHAPE_SQUARE(2),
SHAPE_SQUIRCLE(3),
SHAPE_ROUND_RECT(4),
SHAPE_TEARDROP_BR(5),
SHAPE_TEARDROP_BL(6),
SHAPE_TEARDROP_TL(7),
SHAPE_TEARDROP_TR(8),
SHAPE_TEARDROP_RND(9),
SHAPE_HEXAGON(10),
SHAPE_OCTAGON(11);

private final int id;

IconShape(int id) {
this.id = id;
}

@NonNull
public static IconShape valueById(int shapeId) {
for (IconShape shape : values()) {
if (shape.getId() == shapeId) {
return shape;
}
}
return SHAPE_SYSTEM;
}

public int getId() {
return id;
}

}

0 comments on commit 222d5c4

Please sign in to comment.