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 android.content.Context; 19 import android.graphics.Bitmap; 20 import android.graphics.Bitmap.Config; 21 import android.graphics.Canvas; 22 import android.graphics.drawable.Drawable; 23 24 import androidx.annotation.IntDef; 25 import androidx.annotation.NonNull; 26 import androidx.annotation.Nullable; 27 28 import com.android.launcher3.util.FlagOp; 29 30 public class BitmapInfo { 31 32 public static final int FLAG_WORK = 1 << 0; 33 public static final int FLAG_INSTANT = 1 << 1; 34 public static final int FLAG_CLONE = 1 << 2; 35 public static final int FLAG_PRIVATE = 1 << 3; 36 @IntDef(flag = true, value = { 37 FLAG_WORK, 38 FLAG_INSTANT, 39 FLAG_CLONE, 40 FLAG_PRIVATE 41 }) 42 @interface BitmapInfoFlags {} 43 44 public static final int FLAG_THEMED = 1 << 0; 45 public static final int FLAG_NO_BADGE = 1 << 1; 46 public static final int FLAG_SKIP_USER_BADGE = 1 << 2; 47 @IntDef(flag = true, value = { 48 FLAG_THEMED, 49 FLAG_NO_BADGE, 50 FLAG_SKIP_USER_BADGE, 51 }) 52 public @interface DrawableCreationFlags {} 53 54 public static final Bitmap LOW_RES_ICON = Bitmap.createBitmap(1, 1, Config.ALPHA_8); 55 public static final BitmapInfo LOW_RES_INFO = fromBitmap(LOW_RES_ICON); 56 57 public static final String TAG = "BitmapInfo"; 58 59 public final Bitmap icon; 60 public final int color; 61 62 @Nullable 63 protected Bitmap mMono; 64 protected Bitmap mWhiteShadowLayer; 65 66 public @BitmapInfoFlags int flags; 67 private BitmapInfo badgeInfo; 68 BitmapInfo(Bitmap icon, int color)69 public BitmapInfo(Bitmap icon, int color) { 70 this.icon = icon; 71 this.color = color; 72 } 73 withBadgeInfo(BitmapInfo badgeInfo)74 public BitmapInfo withBadgeInfo(BitmapInfo badgeInfo) { 75 BitmapInfo result = clone(); 76 result.badgeInfo = badgeInfo; 77 return result; 78 } 79 80 /** 81 * Returns a bitmapInfo with the flagOP applied 82 */ withFlags(@onNull FlagOp op)83 public BitmapInfo withFlags(@NonNull FlagOp op) { 84 if (op == FlagOp.NO_OP) { 85 return this; 86 } 87 BitmapInfo result = clone(); 88 result.flags = op.apply(result.flags); 89 return result; 90 } 91 copyInternalsTo(BitmapInfo target)92 protected BitmapInfo copyInternalsTo(BitmapInfo target) { 93 target.mMono = mMono; 94 target.mWhiteShadowLayer = mWhiteShadowLayer; 95 target.flags = flags; 96 target.badgeInfo = badgeInfo; 97 return target; 98 } 99 100 @Override clone()101 public BitmapInfo clone() { 102 return copyInternalsTo(new BitmapInfo(icon, color)); 103 } 104 setMonoIcon(Bitmap mono, BaseIconFactory iconFactory)105 public void setMonoIcon(Bitmap mono, BaseIconFactory iconFactory) { 106 mMono = mono; 107 mWhiteShadowLayer = iconFactory.getWhiteShadowLayer(); 108 } 109 110 /** 111 * Ideally icon should not be null, except in cases when generating hardware bitmap failed 112 */ isNullOrLowRes()113 public final boolean isNullOrLowRes() { 114 return icon == null || icon == LOW_RES_ICON; 115 } 116 isLowRes()117 public final boolean isLowRes() { 118 return LOW_RES_ICON == icon; 119 } 120 121 /** 122 * BitmapInfo can be stored on disk or other persistent storage 123 */ canPersist()124 public boolean canPersist() { 125 return !isNullOrLowRes(); 126 } 127 getMono()128 public Bitmap getMono() { 129 return mMono; 130 } 131 132 /** 133 * Creates a drawable for the provided BitmapInfo 134 */ newIcon(Context context)135 public FastBitmapDrawable newIcon(Context context) { 136 return newIcon(context, 0); 137 } 138 139 /** 140 * Creates a drawable for the provided BitmapInfo 141 */ newIcon(Context context, @DrawableCreationFlags int creationFlags)142 public FastBitmapDrawable newIcon(Context context, @DrawableCreationFlags int creationFlags) { 143 FastBitmapDrawable drawable; 144 if (isLowRes()) { 145 drawable = new PlaceHolderIconDrawable(this, context); 146 } else if ((creationFlags & FLAG_THEMED) != 0 && mMono != null) { 147 drawable = ThemedIconDrawable.newDrawable(this, context); 148 } else { 149 drawable = new FastBitmapDrawable(this); 150 } 151 applyFlags(context, drawable, creationFlags); 152 return drawable; 153 } 154 applyFlags(Context context, FastBitmapDrawable drawable, @DrawableCreationFlags int creationFlags)155 protected void applyFlags(Context context, FastBitmapDrawable drawable, 156 @DrawableCreationFlags int creationFlags) { 157 drawable.mDisabledAlpha = GraphicsUtils.getFloat(context, R.attr.disabledIconAlpha, 1f); 158 drawable.mCreationFlags = creationFlags; 159 if ((creationFlags & FLAG_NO_BADGE) == 0) { 160 Drawable badge = getBadgeDrawable(context, (creationFlags & FLAG_THEMED) != 0, 161 (creationFlags & FLAG_SKIP_USER_BADGE) != 0); 162 if (badge != null) { 163 drawable.setBadge(badge); 164 } 165 } 166 } 167 getBadgeDrawable(Context context, boolean isThemed)168 public Drawable getBadgeDrawable(Context context, boolean isThemed) { 169 return getBadgeDrawable(context, isThemed, false); 170 } 171 172 /** 173 * Returns a drawable representing the badge for this info 174 */ 175 @Nullable getBadgeDrawable(Context context, boolean isThemed, boolean skipUserBadge)176 private Drawable getBadgeDrawable(Context context, boolean isThemed, boolean skipUserBadge) { 177 if (badgeInfo != null) { 178 int creationFlag = isThemed ? FLAG_THEMED : 0; 179 if (skipUserBadge) { 180 creationFlag |= FLAG_SKIP_USER_BADGE; 181 } 182 return badgeInfo.newIcon(context, creationFlag); 183 } 184 if (skipUserBadge) { 185 return null; 186 } else if ((flags & FLAG_INSTANT) != 0) { 187 return new UserBadgeDrawable(context, R.drawable.ic_instant_app_badge, 188 R.color.badge_tint_instant, isThemed); 189 } else if ((flags & FLAG_WORK) != 0) { 190 return new UserBadgeDrawable(context, R.drawable.ic_work_app_badge, 191 R.color.badge_tint_work, isThemed); 192 } else if ((flags & FLAG_CLONE) != 0) { 193 return new UserBadgeDrawable(context, R.drawable.ic_clone_app_badge, 194 R.color.badge_tint_clone, isThemed); 195 } else if ((flags & FLAG_PRIVATE) != 0) { 196 return new UserBadgeDrawable(context, R.drawable.ic_private_profile_app_badge, 197 R.color.badge_tint_private, isThemed); 198 } 199 return null; 200 } 201 fromBitmap(@onNull Bitmap bitmap)202 public static BitmapInfo fromBitmap(@NonNull Bitmap bitmap) { 203 return of(bitmap, 0); 204 } 205 of(@onNull Bitmap bitmap, int color)206 public static BitmapInfo of(@NonNull Bitmap bitmap, int color) { 207 return new BitmapInfo(bitmap, color); 208 } 209 210 /** 211 * Interface to be implemented by drawables to provide a custom BitmapInfo 212 */ 213 public interface Extender { 214 215 /** 216 * Called for creating a custom BitmapInfo 217 */ getExtendedInfo(Bitmap bitmap, int color, BaseIconFactory iconFactory, float normalizationScale)218 BitmapInfo getExtendedInfo(Bitmap bitmap, int color, 219 BaseIconFactory iconFactory, float normalizationScale); 220 221 /** 222 * Called to draw the UI independent of any runtime configurations like time or theme 223 */ drawForPersistence(Canvas canvas)224 void drawForPersistence(Canvas canvas); 225 } 226 } 227