1 /* 2 * Copyright (C) 2017 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 static com.android.launcher3.icons.GraphicsUtils.getExpectedBitmapSize; 19 20 import android.content.Context; 21 import android.graphics.Bitmap; 22 import android.graphics.Bitmap.Config; 23 import android.graphics.BitmapFactory; 24 import android.graphics.Canvas; 25 import android.graphics.drawable.Drawable; 26 import android.os.Build; 27 import android.os.UserHandle; 28 import android.util.Log; 29 30 import androidx.annotation.NonNull; 31 import androidx.annotation.Nullable; 32 33 import com.android.launcher3.icons.ThemedIconDrawable.ThemedBitmapInfo; 34 import com.android.launcher3.icons.cache.BaseIconCache; 35 36 import java.io.ByteArrayOutputStream; 37 import java.io.IOException; 38 39 public class BitmapInfo { 40 41 public static final Bitmap LOW_RES_ICON = Bitmap.createBitmap(1, 1, Config.ALPHA_8); 42 public static final BitmapInfo LOW_RES_INFO = fromBitmap(LOW_RES_ICON); 43 44 public static final String TAG = "BitmapInfo"; 45 46 protected static final byte TYPE_DEFAULT = 1; 47 protected static final byte TYPE_THEMED = 2; 48 49 public final Bitmap icon; 50 public final int color; 51 BitmapInfo(Bitmap icon, int color)52 public BitmapInfo(Bitmap icon, int color) { 53 this.icon = icon; 54 this.color = color; 55 } 56 57 /** 58 * Ideally icon should not be null, except in cases when generating hardware bitmap failed 59 */ isNullOrLowRes()60 public final boolean isNullOrLowRes() { 61 return icon == null || icon == LOW_RES_ICON; 62 } 63 isLowRes()64 public final boolean isLowRes() { 65 return LOW_RES_ICON == icon; 66 } 67 68 /** 69 * Returns a serialized version of BitmapInfo 70 */ 71 @Nullable toByteArray()72 public byte[] toByteArray() { 73 if (isNullOrLowRes()) { 74 return null; 75 } 76 ByteArrayOutputStream out = new ByteArrayOutputStream(getExpectedBitmapSize(icon) + 1); 77 try { 78 out.write(TYPE_DEFAULT); 79 icon.compress(Bitmap.CompressFormat.PNG, 100, out); 80 out.flush(); 81 out.close(); 82 return out.toByteArray(); 83 } catch (IOException e) { 84 Log.w(TAG, "Could not write bitmap"); 85 return null; 86 } 87 } 88 89 /** 90 * Returns a new icon based on the theme of the context 91 */ newThemedIcon(Context context)92 public FastBitmapDrawable newThemedIcon(Context context) { 93 return newIcon(context); 94 } 95 96 /** 97 * Creates a drawable for the provided BitmapInfo 98 */ newIcon(Context context)99 public FastBitmapDrawable newIcon(Context context) { 100 FastBitmapDrawable drawable = isLowRes() 101 ? new PlaceHolderIconDrawable(this, context) 102 : new FastBitmapDrawable(this); 103 drawable.mDisabledAlpha = GraphicsUtils.getFloat(context, R.attr.disabledIconAlpha, 1f); 104 return drawable; 105 } 106 107 /** 108 * Returns a BitmapInfo previously serialized using {@link #toByteArray()}; 109 */ 110 @NonNull fromByteArray(byte[] data, int color, UserHandle user, BaseIconCache iconCache, Context context)111 public static BitmapInfo fromByteArray(byte[] data, int color, UserHandle user, 112 BaseIconCache iconCache, Context context) { 113 if (data == null) { 114 return null; 115 } 116 BitmapFactory.Options decodeOptions; 117 if (BitmapRenderer.USE_HARDWARE_BITMAP && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 118 decodeOptions = new BitmapFactory.Options(); 119 decodeOptions.inPreferredConfig = Bitmap.Config.HARDWARE; 120 } else { 121 decodeOptions = null; 122 } 123 if (data[0] == TYPE_DEFAULT) { 124 return BitmapInfo.of( 125 BitmapFactory.decodeByteArray(data, 1, data.length - 1, decodeOptions), 126 color); 127 } else if (data[0] == TYPE_THEMED) { 128 return ThemedBitmapInfo.decode(data, color, decodeOptions, user, iconCache, context); 129 } else { 130 return null; 131 } 132 } 133 fromBitmap(@onNull Bitmap bitmap)134 public static BitmapInfo fromBitmap(@NonNull Bitmap bitmap) { 135 return of(bitmap, 0); 136 } 137 of(@onNull Bitmap bitmap, int color)138 public static BitmapInfo of(@NonNull Bitmap bitmap, int color) { 139 return new BitmapInfo(bitmap, color); 140 } 141 142 /** 143 * Interface to be implemented by drawables to provide a custom BitmapInfo 144 */ 145 public interface Extender { 146 147 /** 148 * Called for creating a custom BitmapInfo 149 */ getExtendedInfo(Bitmap bitmap, int color, BaseIconFactory iconFactory, float normalizationScale, UserHandle user)150 BitmapInfo getExtendedInfo(Bitmap bitmap, int color, 151 BaseIconFactory iconFactory, float normalizationScale, UserHandle user); 152 153 /** 154 * Called to draw the UI independent of any runtime configurations like time or theme 155 */ drawForPersistence(Canvas canvas)156 void drawForPersistence(Canvas canvas); 157 158 /** 159 * Returns a new icon with theme applied 160 */ getThemedDrawable(Context context)161 Drawable getThemedDrawable(Context context); 162 } 163 } 164