diff options
| author | TreeHugger Robot <treehugger-gerrit@google.com> | 2017-04-19 02:43:40 +0000 |
|---|---|---|
| committer | Android (Google) Code Review <android-gerrit@google.com> | 2017-04-19 02:43:47 +0000 |
| commit | 15b48ff4de81c60263db6f70b226a4dfe3607b05 (patch) | |
| tree | ab3272d192cbf769c1a28e31edd10d2688f52384 /core/java/android | |
| parent | 42775f2a8990c0e599fbfe5b187467f1764c6b75 (diff) | |
| parent | bab3075e2ee85de8b0ac6c3961eae5156a95c699 (diff) | |
Merge "Creating a common class for loading drawables and handling various badging" into oc-dev
Diffstat (limited to 'core/java/android')
| -rw-r--r-- | core/java/android/app/ApplicationPackageManager.java | 30 | ||||
| -rw-r--r-- | core/java/android/util/IconDrawableFactory.java | 112 | ||||
| -rw-r--r-- | core/java/android/util/LauncherIcons.java | 183 |
3 files changed, 247 insertions, 78 deletions
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index e07b7e4a03a1..027ddf51a069 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -79,6 +79,8 @@ import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; import android.provider.Settings; import android.util.ArrayMap; +import android.util.IconDrawableFactory; +import android.util.LauncherIcons; import android.util.Log; import android.view.Display; @@ -1245,16 +1247,9 @@ public class ApplicationPackageManager extends PackageManager { if (!isManagedProfile(user.getIdentifier())) { return icon; } - Drawable badgeShadow = getDrawable("system", - com.android.internal.R.drawable.ic_corp_icon_badge_shadow, null); - Drawable badgeColor = getDrawable("system", - com.android.internal.R.drawable.ic_corp_icon_badge_color, null); - badgeColor.setTint(getUserBadgeColor(user)); - Drawable badgeForeground = getDrawable("system", - com.android.internal.R.drawable.ic_corp_icon_badge_case, null); - - Drawable badge = new LayerDrawable( - new Drawable[] {badgeShadow, badgeColor, badgeForeground }); + Drawable badge = new LauncherIcons(mContext).getBadgeDrawable( + com.android.internal.R.drawable.ic_corp_icon_badge_case, + getUserBadgeColor(user)); return getBadgedDrawable(icon, badge, null, true); } @@ -1268,14 +1263,6 @@ public class ApplicationPackageManager extends PackageManager { return getBadgedDrawable(drawable, badgeDrawable, badgeLocation, true); } - // Should have enough colors to cope with UserManagerService.getMaxManagedProfiles() - @VisibleForTesting - public static final int[] CORP_BADGE_COLORS = new int[] { - com.android.internal.R.color.profile_badge_1, - com.android.internal.R.color.profile_badge_2, - com.android.internal.R.color.profile_badge_3 - }; - @VisibleForTesting public static final int[] CORP_BADGE_LABEL_RES_ID = new int[] { com.android.internal.R.string.managed_profile_label_badge, @@ -1284,12 +1271,7 @@ public class ApplicationPackageManager extends PackageManager { }; private int getUserBadgeColor(UserHandle user) { - int badge = getUserManager().getManagedProfileBadge(user.getIdentifier()); - if (badge < 0) { - badge = 0; - } - int resourceId = CORP_BADGE_COLORS[badge % CORP_BADGE_COLORS.length]; - return Resources.getSystem().getColor(resourceId, null); + return IconDrawableFactory.getUserBadgeColor(getUserManager(), user.getIdentifier()); } @Override diff --git a/core/java/android/util/IconDrawableFactory.java b/core/java/android/util/IconDrawableFactory.java new file mode 100644 index 000000000000..b07942ff7f9d --- /dev/null +++ b/core/java/android/util/IconDrawableFactory.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.util; + +import android.annotation.UserIdInt; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageItemInfo; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.os.UserHandle; +import android.os.UserManager; + +import com.android.internal.annotations.VisibleForTesting; + +/** + * Utility class to load app drawables with appropriate badging. + * + * @hide + */ +public class IconDrawableFactory { + + protected final Context mContext; + protected final PackageManager mPm; + protected final UserManager mUm; + protected final LauncherIcons mLauncherIcons; + protected final boolean mEmbedShadow; + + private IconDrawableFactory(Context context, boolean embedShadow) { + mContext = context; + mPm = context.getPackageManager(); + mUm = context.getSystemService(UserManager.class); + mLauncherIcons = new LauncherIcons(context); + mEmbedShadow = embedShadow; + } + + protected boolean needsBadging(ApplicationInfo appInfo, @UserIdInt int userId) { + return appInfo.isInstantApp() || mUm.isManagedProfile(userId); + } + + public Drawable getBadgedIcon(ApplicationInfo appInfo) { + return getBadgedIcon(appInfo, UserHandle.getUserId(appInfo.uid)); + } + + public Drawable getBadgedIcon(ApplicationInfo appInfo, @UserIdInt int userId) { + return getBadgedIcon(appInfo, appInfo, userId); + } + + public Drawable getBadgedIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo, + @UserIdInt int userId) { + Drawable icon = mPm.loadUnbadgedItemIcon(itemInfo, appInfo); + if (!mEmbedShadow && !needsBadging(appInfo, userId)) { + return icon; + } + + // Before badging, add shadow to adaptive icon if needed. + icon = mLauncherIcons.wrapIconDrawableWithShadow(icon); + if (appInfo.isInstantApp()) { + int badgeColor = Resources.getSystem().getColor( + com.android.internal.R.color.instant_app_badge, null); + icon = mLauncherIcons.getBadgedDrawable(icon, + com.android.internal.R.drawable.ic_instant_icon_badge_bolt, + badgeColor); + } + if (mUm.isManagedProfile(userId)) { + icon = mLauncherIcons.getBadgedDrawable(icon, + com.android.internal.R.drawable.ic_corp_icon_badge_case, + getUserBadgeColor(mUm, userId)); + } + return icon; + } + + // Should have enough colors to cope with UserManagerService.getMaxManagedProfiles() + @VisibleForTesting + public static final int[] CORP_BADGE_COLORS = new int[] { + com.android.internal.R.color.profile_badge_1, + com.android.internal.R.color.profile_badge_2, + com.android.internal.R.color.profile_badge_3 + }; + + public static int getUserBadgeColor(UserManager um, @UserIdInt int userId) { + int badge = um.getManagedProfileBadge(userId); + if (badge < 0) { + badge = 0; + } + int resourceId = CORP_BADGE_COLORS[badge % CORP_BADGE_COLORS.length]; + return Resources.getSystem().getColor(resourceId, null); + } + + public static IconDrawableFactory newInstance(Context context) { + return new IconDrawableFactory(context, true); + } + + public static IconDrawableFactory newInstance(Context context, boolean embedShadow) { + return new IconDrawableFactory(context, embedShadow); + } +} diff --git a/core/java/android/util/LauncherIcons.java b/core/java/android/util/LauncherIcons.java index 89b9646e54b3..402bef914421 100644 --- a/core/java/android/util/LauncherIcons.java +++ b/core/java/android/util/LauncherIcons.java @@ -21,10 +21,11 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; -import android.graphics.PaintFlagsDrawFilter; +import android.graphics.Rect; import android.graphics.drawable.AdaptiveIconDrawable; -import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.graphics.drawable.DrawableWrapper; +import android.graphics.drawable.LayerDrawable; /** * Utility class to handle icon treatments (e.g., shadow generation) for the Launcher icons. @@ -32,78 +33,152 @@ import android.graphics.drawable.Drawable; */ public final class LauncherIcons { - private final Paint mPaint = new Paint(); - private final Canvas mCanvas = new Canvas(); + // Percent of actual icon size + private static final float ICON_SIZE_BLUR_FACTOR = 0.5f/48; + // Percent of actual icon size + private static final float ICON_SIZE_KEY_SHADOW_DELTA_FACTOR = 1f/48; private static final int KEY_SHADOW_ALPHA = 61; private static final int AMBIENT_SHADOW_ALPHA = 30; - private static final float BLUR_FACTOR = 0.5f / 48; - private int mShadowInset; - private Bitmap mShadowBitmap; - private int mIconSize; - private Resources mRes; + + private final SparseArray<Bitmap> mShadowCache = new SparseArray<>(); + private final int mIconSize; + private final Resources mRes; public LauncherIcons(Context context) { mRes = context.getResources(); - DisplayMetrics metrics = mRes.getDisplayMetrics(); - mShadowInset = (int)(2 * metrics.density); - mCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG, - Paint.FILTER_BITMAP_FLAG)); - mIconSize = (int) mRes.getDimensionPixelSize(android.R.dimen.app_icon_size); - } - - /** - * Draw the drawable into a bitmap. - */ - public Bitmap createIconBitmap(Drawable icon) { - final Bitmap bitmap = Bitmap.createBitmap(mIconSize, mIconSize, Bitmap.Config.ARGB_8888); - mPaint.setAlpha(255); - mCanvas.setBitmap(bitmap); - int iconInset = 0; - if (mShadowBitmap != null) { - mCanvas.drawBitmap(mShadowBitmap, 0, 0, mPaint); - iconInset = mShadowInset; - } - - icon.setBounds(iconInset, iconInset, mIconSize - iconInset, - mIconSize - iconInset); - icon.draw(mCanvas); - mCanvas.setBitmap(null); - return bitmap; + mIconSize = mRes.getDimensionPixelSize(android.R.dimen.app_icon_size); } public Drawable wrapIconDrawableWithShadow(Drawable drawable) { if (!(drawable instanceof AdaptiveIconDrawable)) { return drawable; } - AdaptiveIconDrawable d = - (AdaptiveIconDrawable) drawable.getConstantState().newDrawable().mutate(); - getShadowBitmap(d); - Bitmap iconbitmap = createIconBitmap(d); - return new BitmapDrawable(mRes, iconbitmap); + Bitmap shadow = getShadowBitmap((AdaptiveIconDrawable) drawable); + return new ShadowDrawable(shadow, drawable); } private Bitmap getShadowBitmap(AdaptiveIconDrawable d) { - if (mShadowBitmap != null) { - return mShadowBitmap; + int shadowSize = Math.max(mIconSize, d.getIntrinsicHeight()); + synchronized (mShadowCache) { + Bitmap shadow = mShadowCache.get(shadowSize); + if (shadow != null) { + return shadow; + } } - mShadowBitmap = Bitmap.createBitmap(mIconSize, mIconSize, Bitmap.Config.ALPHA_8); - mCanvas.setBitmap(mShadowBitmap); + d.setBounds(0, 0, shadowSize, shadowSize); - // Draw key shadow - mPaint.setColor(Color.TRANSPARENT); - float blur = BLUR_FACTOR * mIconSize; - mPaint.setShadowLayer(blur, 0, mShadowInset, KEY_SHADOW_ALPHA << 24); - d.setBounds(mShadowInset, mShadowInset, mIconSize - mShadowInset, mIconSize - mShadowInset); - mCanvas.drawPath(d.getIconMask(), mPaint); + float blur = ICON_SIZE_BLUR_FACTOR * shadowSize; + float keyShadowDistance = ICON_SIZE_KEY_SHADOW_DELTA_FACTOR * shadowSize; + + int bitmapSize = (int) (shadowSize + 2 * blur + keyShadowDistance); + Bitmap shadow = Bitmap.createBitmap(bitmapSize, bitmapSize, Bitmap.Config.ARGB_8888); + + Canvas canvas = new Canvas(shadow); + canvas.translate(blur + keyShadowDistance / 2, blur); + + Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + paint.setColor(Color.TRANSPARENT); // Draw ambient shadow - mPaint.setShadowLayer(blur, 0, 0, AMBIENT_SHADOW_ALPHA << 24); - d.setBounds(mShadowInset, 2 * mShadowInset, mIconSize - mShadowInset, mIconSize); - mCanvas.drawPath(d.getIconMask(), mPaint); - mPaint.clearShadowLayer(); + paint.setShadowLayer(blur, 0, 0, AMBIENT_SHADOW_ALPHA << 24); + canvas.drawPath(d.getIconMask(), paint); + + // Draw key shadow + canvas.translate(0, keyShadowDistance); + paint.setShadowLayer(blur, 0, 0, KEY_SHADOW_ALPHA << 24); + canvas.drawPath(d.getIconMask(), paint); + + canvas.setBitmap(null); + synchronized (mShadowCache) { + mShadowCache.put(shadowSize, shadow); + } + return shadow; + } + + public Drawable getBadgeDrawable(int foregroundRes, int backgroundColor) { + return getBadgedDrawable(null, foregroundRes, backgroundColor); + } + + public Drawable getBadgedDrawable(Drawable base, int foregroundRes, int backgroundColor) { + Resources sysRes = Resources.getSystem(); + + Drawable badgeShadow = sysRes.getDrawable( + com.android.internal.R.drawable.ic_corp_icon_badge_shadow); + + Drawable badgeColor = sysRes.getDrawable( + com.android.internal.R.drawable.ic_corp_icon_badge_color) + .getConstantState().newDrawable().mutate(); + badgeColor.setTint(backgroundColor); - return mShadowBitmap; + Drawable badgeForeground = sysRes.getDrawable(foregroundRes); + + Drawable[] drawables = base == null + ? new Drawable[] {badgeShadow, badgeColor, badgeForeground } + : new Drawable[] {base, badgeShadow, badgeColor, badgeForeground }; + return new LayerDrawable(drawables); + } + + /** + * A drawable which draws a shadow bitmap behind a drawable + */ + private static class ShadowDrawable extends DrawableWrapper { + + final MyConstantState mState; + + public ShadowDrawable(Bitmap shadow, Drawable dr) { + super(dr); + mState = new MyConstantState(shadow, dr.getConstantState()); + } + + ShadowDrawable(MyConstantState state) { + super(state.mChildState.newDrawable()); + mState = state; + } + + @Override + public ConstantState getConstantState() { + return mState; + } + + @Override + public void draw(Canvas canvas) { + Rect bounds = getBounds(); + canvas.drawBitmap(mState.mShadow, null, bounds, mState.mPaint); + canvas.save(); + // Ratio of child drawable size to shadow bitmap size + float factor = 1 / (1 + 2 * ICON_SIZE_BLUR_FACTOR + ICON_SIZE_KEY_SHADOW_DELTA_FACTOR); + + canvas.translate( + bounds.width() * factor * + (ICON_SIZE_BLUR_FACTOR + ICON_SIZE_KEY_SHADOW_DELTA_FACTOR / 2), + bounds.height() * factor * ICON_SIZE_BLUR_FACTOR); + canvas.scale(factor, factor); + super.draw(canvas); + canvas.restore(); + } + + private static class MyConstantState extends ConstantState { + + final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG); + final Bitmap mShadow; + final ConstantState mChildState; + + MyConstantState(Bitmap shadow, ConstantState childState) { + mShadow = shadow; + mChildState = childState; + } + + @Override + public Drawable newDrawable() { + return new ShadowDrawable(this); + } + + @Override + public int getChangingConfigurations() { + return mChildState.getChangingConfigurations(); + } + } } } |
