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.TypedArray; 20 import android.graphics.Bitmap; 21 import android.graphics.Color; 22 import android.graphics.Path; 23 import android.graphics.Rect; 24 import android.graphics.Region; 25 import android.graphics.RegionIterator; 26 import android.graphics.drawable.AdaptiveIconDrawable; 27 import android.graphics.drawable.ColorDrawable; 28 import android.util.Log; 29 30 import androidx.annotation.ColorInt; 31 32 import java.io.ByteArrayOutputStream; 33 import java.io.IOException; 34 35 public class GraphicsUtils { 36 37 private static final String TAG = "GraphicsUtils"; 38 39 public static Runnable sOnNewBitmapRunnable = () -> { }; 40 41 /** 42 * Set the alpha component of {@code color} to be {@code alpha}. Unlike the support lib version, 43 * it bounds the alpha in valid range instead of throwing an exception to allow for safer 44 * interpolation of color animations 45 */ 46 @ColorInt setColorAlphaBound(int color, int alpha)47 public static int setColorAlphaBound(int color, int alpha) { 48 if (alpha < 0) { 49 alpha = 0; 50 } else if (alpha > 255) { 51 alpha = 255; 52 } 53 return (color & 0x00ffffff) | (alpha << 24); 54 } 55 56 /** 57 * Compresses the bitmap to a byte array for serialization. 58 */ flattenBitmap(Bitmap bitmap)59 public static byte[] flattenBitmap(Bitmap bitmap) { 60 ByteArrayOutputStream out = new ByteArrayOutputStream(getExpectedBitmapSize(bitmap)); 61 try { 62 bitmap.compress(Bitmap.CompressFormat.PNG, 100, out); 63 out.flush(); 64 out.close(); 65 return out.toByteArray(); 66 } catch (IOException e) { 67 Log.w(TAG, "Could not write bitmap"); 68 return null; 69 } 70 } 71 72 /** 73 * Try go guesstimate how much space the icon will take when serialized to avoid unnecessary 74 * allocations/copies during the write (4 bytes per pixel). 75 */ getExpectedBitmapSize(Bitmap bitmap)76 static int getExpectedBitmapSize(Bitmap bitmap) { 77 return bitmap.getWidth() * bitmap.getHeight() * 4; 78 } 79 getArea(Region r)80 public static int getArea(Region r) { 81 RegionIterator itr = new RegionIterator(r); 82 int area = 0; 83 Rect tempRect = new Rect(); 84 while (itr.next(tempRect)) { 85 area += tempRect.width() * tempRect.height(); 86 } 87 return area; 88 } 89 90 /** 91 * Utility method to track new bitmap creation 92 */ noteNewBitmapCreated()93 public static void noteNewBitmapCreated() { 94 sOnNewBitmapRunnable.run(); 95 } 96 97 98 /** 99 * Returns the default path to be used by an icon 100 */ getShapePath(int size)101 public static Path getShapePath(int size) { 102 AdaptiveIconDrawable drawable = new AdaptiveIconDrawable( 103 new ColorDrawable(Color.BLACK), new ColorDrawable(Color.BLACK)); 104 drawable.setBounds(0, 0, size, size); 105 return new Path(drawable.getIconMask()); 106 } 107 108 /** 109 * Returns the color associated with the attribute 110 */ getAttrColor(Context context, int attr)111 public static int getAttrColor(Context context, int attr) { 112 TypedArray ta = context.obtainStyledAttributes(new int[]{attr}); 113 int colorAccent = ta.getColor(0, 0); 114 ta.recycle(); 115 return colorAccent; 116 } 117 118 /** 119 * Returns the alpha corresponding to the theme attribute {@param attr} 120 */ getFloat(Context context, int attr, float defValue)121 public static float getFloat(Context context, int attr, float defValue) { 122 TypedArray ta = context.obtainStyledAttributes(new int[]{attr}); 123 float value = ta.getFloat(0, defValue); 124 ta.recycle(); 125 return value; 126 } 127 } 128