1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.launcher3.icons; 17 18 import android.content.Context; 19 import android.content.res.Resources; 20 import android.content.res.TypedArray; 21 import android.graphics.Bitmap; 22 import android.graphics.Color; 23 import android.graphics.Matrix; 24 import android.graphics.Path; 25 import android.graphics.Rect; 26 import android.graphics.Region; 27 import android.graphics.RegionIterator; 28 import android.graphics.drawable.AdaptiveIconDrawable; 29 import android.graphics.drawable.ColorDrawable; 30 import android.util.Log; 31 32 import androidx.annotation.ColorInt; 33 import androidx.annotation.NonNull; 34 import androidx.core.graphics.PathParser; 35 36 import java.io.ByteArrayOutputStream; 37 import java.io.IOException; 38 39 public class GraphicsUtils { 40 41 private static final String TAG = "GraphicsUtils"; 42 private static final float MASK_SIZE = 100f; 43 44 public static Runnable sOnNewBitmapRunnable = () -> { }; 45 46 /** 47 * Set the alpha component of {@code color} to be {@code alpha}. Unlike the support lib version, 48 * it bounds the alpha in valid range instead of throwing an exception to allow for safer 49 * interpolation of color animations 50 */ 51 @ColorInt setColorAlphaBound(int color, int alpha)52 public static int setColorAlphaBound(int color, int alpha) { 53 if (alpha < 0) { 54 alpha = 0; 55 } else if (alpha > 255) { 56 alpha = 255; 57 } 58 return (color & 0x00ffffff) | (alpha << 24); 59 } 60 61 /** 62 * Compresses the bitmap to a byte array for serialization. 63 */ flattenBitmap(Bitmap bitmap)64 public static byte[] flattenBitmap(Bitmap bitmap) { 65 ByteArrayOutputStream out = new ByteArrayOutputStream(getExpectedBitmapSize(bitmap)); 66 try { 67 bitmap.compress(Bitmap.CompressFormat.PNG, 100, out); 68 out.flush(); 69 out.close(); 70 return out.toByteArray(); 71 } catch (IOException e) { 72 Log.w(TAG, "Could not write bitmap"); 73 return null; 74 } 75 } 76 77 /** 78 * Try go guesstimate how much space the icon will take when serialized to avoid unnecessary 79 * allocations/copies during the write (4 bytes per pixel). 80 */ getExpectedBitmapSize(Bitmap bitmap)81 static int getExpectedBitmapSize(Bitmap bitmap) { 82 return bitmap.getWidth() * bitmap.getHeight() * 4; 83 } 84 getArea(Region r)85 public static int getArea(Region r) { 86 RegionIterator itr = new RegionIterator(r); 87 int area = 0; 88 Rect tempRect = new Rect(); 89 while (itr.next(tempRect)) { 90 area += tempRect.width() * tempRect.height(); 91 } 92 return area; 93 } 94 95 /** 96 * Utility method to track new bitmap creation 97 */ noteNewBitmapCreated()98 public static void noteNewBitmapCreated() { 99 sOnNewBitmapRunnable.run(); 100 } 101 102 103 /** 104 * Returns the default path to be used by an icon 105 */ getShapePath(@onNull Context context, int size)106 public static Path getShapePath(@NonNull Context context, int size) { 107 if (IconProvider.CONFIG_ICON_MASK_RES_ID != Resources.ID_NULL) { 108 Path path = PathParser.createPathFromPathData( 109 context.getString(IconProvider.CONFIG_ICON_MASK_RES_ID)); 110 if (path != null) { 111 if (size != MASK_SIZE) { 112 Matrix m = new Matrix(); 113 float scale = ((float) size) / MASK_SIZE; 114 m.setScale(scale, scale); 115 path.transform(m); 116 } 117 return path; 118 } 119 } 120 AdaptiveIconDrawable drawable = new AdaptiveIconDrawable( 121 new ColorDrawable(Color.BLACK), new ColorDrawable(Color.BLACK)); 122 drawable.setBounds(0, 0, size, size); 123 return new Path(drawable.getIconMask()); 124 } 125 126 /** 127 * Returns the color associated with the attribute 128 */ getAttrColor(Context context, int attr)129 public static int getAttrColor(Context context, int attr) { 130 TypedArray ta = context.obtainStyledAttributes(new int[]{attr}); 131 int colorAccent = ta.getColor(0, 0); 132 ta.recycle(); 133 return colorAccent; 134 } 135 136 /** 137 * Returns the alpha corresponding to the theme attribute {@param attr} 138 */ getFloat(Context context, int attr, float defValue)139 public static float getFloat(Context context, int attr, float defValue) { 140 TypedArray ta = context.obtainStyledAttributes(new int[]{attr}); 141 float value = ta.getFloat(0, defValue); 142 ta.recycle(); 143 return value; 144 } 145 } 146