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

Commit e3204b42 authored by d34d's avatar d34d Committed by Clark Scheff
Browse files

Themes: Add rotation and translation to composed icons

This feature allows a theme to specify a rotation and translation
in addition to scaling the original icon when composing.

To use this new feature a theme designer will need to include the
<rotate /> and/or <translate /> tags with the following syntax:

<rotate angle="angle_to_rotate" />
    where angle_to_rotate can be from 0 to 360 degrees

<translate xOffset="x_value" yOffset="y_value" />
    where x_value and y_value are device indipendent pixels
    and can be any value (both positive and negative depending
    on which way you want to move the icon)

ex:
<rotate angle="45"/>
<translate xOffset="-10" yTranslate="15"/>

Change-Id: I37ccf7861d22ee3aa21fce25e7e1b1afc49b3bcc
parent 83670bf2
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -23,6 +23,9 @@ public class ComposedIconInfo implements Parcelable {
    public int iconUpon, iconMask;
    public int[] iconBacks;
    public float iconScale;
    public float iconRotation;
    public float iconTranslationX;
    public float iconTranslationY;
    public int iconDensity;
    public int iconSize;
    public float[] colorFilter;
@@ -36,10 +39,16 @@ public class ComposedIconInfo implements Parcelable {
        super();
        iconPaletteBack = 0;
        swatchType = SwatchType.None;
        iconRotation = 0;
        iconTranslationX = 0;
        iconTranslationY = 0;
    }

    private ComposedIconInfo(Parcel source) {
        iconScale = source.readFloat();
        iconRotation = source.readFloat();
        iconTranslationX = source.readFloat();
        iconTranslationY = source.readFloat();
        iconDensity = source.readInt();
        iconSize = source.readInt();
        int backCount = source.readInt();
@@ -77,6 +86,9 @@ public class ComposedIconInfo implements Parcelable {
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeFloat(iconScale);
        dest.writeFloat(iconRotation);
        dest.writeFloat(iconTranslationX);
        dest.writeFloat(iconTranslationY);
        dest.writeInt(iconDensity);
        dest.writeInt(iconSize);
        dest.writeInt(iconBacks != null ? iconBacks.length : 0);
+65 −4
Original line number Diff line number Diff line
@@ -72,6 +72,8 @@ public class IconPackHelper {
    private static final String ICON_BACK_TAG = "iconback";
    private static final String ICON_UPON_TAG = "iconupon";
    private static final String ICON_SCALE_TAG = "scale";
    private static final String ICON_ROTATE_TAG = "rotate";
    private static final String ICON_TRANSLATE_TAG = "translate";
    private static final String ICON_BACK_FORMAT = "iconback%d";

    // Palettized icon background constants
@@ -87,6 +89,11 @@ public class IconPackHelper {
    private static final String MUTED_DARK_VALUE = "mutedDark";
    private static final int NUM_PALETTE_COLORS = 32;

    // Rotation and translation constants
    private static final String ANGLE_ATTR = "angle";
    private static final String TRANSLATE_X_ATTR = "xOffset";
    private static final String TRANSLATE_Y_ATTR = "yOffset";

    private static final ComponentName ICON_BACK_COMPONENT;
    private static final ComponentName ICON_MASK_COMPONENT;
    private static final ComponentName ICON_UPON_COMPONENT;
@@ -150,6 +157,14 @@ public class IconPackHelper {
                continue;
            }

            if (parseRotationComponent(parser, mComposedIconInfo)) {
                continue;
            }

            if (parseTranslationComponent(parser, mComposedIconInfo)) {
                continue;
            }

            if (!parser.getName().equalsIgnoreCase("item")) {
                continue;
            }
@@ -277,6 +292,42 @@ public class IconPackHelper {
        }
    }

    private boolean parseRotationComponent(XmlPullParser parser, ComposedIconInfo iconInfo) {
        if (!parser.getName().equalsIgnoreCase(ICON_ROTATE_TAG)) return false;
        String angle = parser.getAttributeValue(null, ANGLE_ATTR);
        if (angle != null) {
            try {
                iconInfo.iconRotation = Float.valueOf(angle);
            } catch (NumberFormatException e) {
                Log.w(TAG, "Error parsing angle", e);
            }
        }
        return true;
    }

    private boolean parseTranslationComponent(XmlPullParser parser, ComposedIconInfo iconInfo) {
        if (!parser.getName().equalsIgnoreCase(ICON_TRANSLATE_TAG)) return false;

        final float density = mContext.getResources().getDisplayMetrics().density;
        String translateX = parser.getAttributeValue(null, TRANSLATE_X_ATTR);
        String translateY = parser.getAttributeValue(null, TRANSLATE_Y_ATTR);
        if (translateX != null) {
            try {
                iconInfo.iconTranslationX = Float.valueOf(translateX) * density;
            } catch (NumberFormatException e) {
                Log.w(TAG, "Error parsing " + TRANSLATE_X_ATTR, e);
            }
        }
        if (translateY != null) {
            try {
                iconInfo.iconTranslationY = Float.valueOf(translateY) * density;
            } catch (NumberFormatException e) {
                Log.w(TAG, "Error parsing " + TRANSLATE_Y_ATTR, e);
            }
        }
        return true;
    }

    public void loadIconPack(String packageName) throws NameNotFoundException {
        if (packageName == null) {
            mLoadedIconPackResource = null;
@@ -284,6 +335,9 @@ public class IconPackHelper {
            mComposedIconInfo.iconBacks = null;
            mComposedIconInfo.iconMask = mComposedIconInfo.iconUpon = 0;
            mComposedIconInfo.iconScale = 0;
            mComposedIconInfo.iconRotation = 0;
            mComposedIconInfo.iconTranslationX = 0;
            mComposedIconInfo.iconTranslationY = 0;
            mComposedIconInfo.colorFilter = null;
            mComposedIconInfo.iconPaletteBack = 0;
            mComposedIconInfo.swatchType = ComposedIconInfo.SwatchType.None;
@@ -544,7 +598,8 @@ public class IconPackHelper {
                back = iconInfo.iconBacks[sRandom.nextInt(iconInfo.iconBacks.length)];
            }
            Bitmap bmp = createIconBitmap(icon, res, back, iconInfo.iconMask, iconInfo.iconUpon,
                    iconInfo.iconScale, iconInfo.iconSize, iconInfo.colorFilter,
                    iconInfo.iconScale, iconInfo.iconRotation, iconInfo.iconTranslationX,
                    iconInfo.iconTranslationY, iconInfo.iconSize, iconInfo.colorFilter,
                    iconInfo.swatchType, defaultSwatchColor);
            return bmp != null ? new BitmapDrawable(res, bmp): null;
        }
@@ -577,7 +632,8 @@ public class IconPackHelper {
                    Log.d(TAG, "Composing icon for " + pkgName);
                }
                Bitmap bmp = createIconBitmap(baseIcon, res, back, iconInfo.iconMask,
                        iconInfo.iconUpon, iconInfo.iconScale, iconInfo.iconSize,
                        iconInfo.iconUpon, iconInfo.iconScale, iconInfo.iconRotation,
                        iconInfo.iconTranslationX, iconInfo.iconTranslationY, iconInfo.iconSize,
                        iconInfo.colorFilter, iconInfo.swatchType, defaultSwatchColor);
                if (!cacheComposedIcon(bmp, getCachedIconName(pkgName, resId, outValue.density))) {
                    Log.w(TAG, "Unable to cache icon " + outValue.string);
@@ -588,7 +644,8 @@ public class IconPackHelper {
        }

        private static Bitmap createIconBitmap(Drawable icon, Resources res, int iconBack,
                int iconMask, int iconUpon, float scale, int iconSize, float[] colorFilter,
                int iconMask, int iconUpon, float scale, float angle, float translationX,
                float translationY, int iconSize, float[] colorFilter,
                ComposedIconInfo.SwatchType swatchType, int defaultSwatchColor) {
            if (iconSize <= 0) return null;

@@ -669,7 +726,11 @@ public class IconPackHelper {
            oldBounds.set(icon.getBounds());
            icon.setBounds(0, 0, width, height);
            canvas.save();
            canvas.scale(scale, scale, width / 2, height / 2);
            final float halfWidth = width / 2f;
            final float halfHeight = height / 2f;
            canvas.rotate(angle, halfWidth, halfHeight);
            canvas.scale(scale, scale, halfWidth, halfHeight);
            canvas.translate(translationX, translationY);
            if (colorFilter != null) {
                Paint p = null;
                if (icon instanceof BitmapDrawable) {