From 547010ff863e634186fddf75890b6894f1cfa6be Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Mon, 13 Mar 2017 01:23:15 -0700 Subject: [PATCH] Add LauncherIcons.AdaptiveIconDrawableWithShadow class to support shadow b/36088922 Test: Settings app This utility class can be used to bake shadow in drawable level in system ui surfaces such as Settings, Overview and ShareSheet. Change-Id: Iaec867d9ce5b949380c1e5004b68269d1bbeacd4 --- core/java/android/util/LauncherIcons.java | 113 ++++++++++++++++++ .../drawable/AdaptiveIconDrawable.java | 2 + .../recents/misc/SystemServicesProxy.java | 7 +- 3 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 core/java/android/util/LauncherIcons.java diff --git a/core/java/android/util/LauncherIcons.java b/core/java/android/util/LauncherIcons.java new file mode 100644 index 0000000000000..e5aa2b5b4ce7a --- /dev/null +++ b/core/java/android/util/LauncherIcons.java @@ -0,0 +1,113 @@ +/* + * 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.content.Context; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.PaintFlagsDrawFilter; +import android.graphics.Path; +import android.graphics.RectF; +import android.graphics.drawable.AdaptiveIconDrawable; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; + +/** + * Utility class to handle icon treatments (e.g., shadow generation) for the Launcher icons. + * @hide + */ +public final class LauncherIcons { + + private final Paint mPaint = new Paint(); + private final Canvas mCanvas = new Canvas(); + + 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; + + public LauncherIcons(Context context) { + mRes = context.getResources(); + DisplayMetrics metrics = mRes.getDisplayMetrics(); + mShadowInset = (int) metrics.density / DisplayMetrics.DENSITY_DEFAULT; + 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; + } + + 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); + } + + private Bitmap getShadowBitmap(AdaptiveIconDrawable d) { + if (mShadowBitmap != null) { + return mShadowBitmap; + } + + int shadowSize = mIconSize - mShadowInset; + mShadowBitmap = Bitmap.createBitmap(mIconSize, mIconSize, Bitmap.Config.ALPHA_8); + mCanvas.setBitmap(mShadowBitmap); + + // 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); + + // 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(); + + return mShadowBitmap; + } +} diff --git a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java index 0722c18563727..c6c92714d1cca 100644 --- a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java +++ b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java @@ -218,6 +218,8 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback } /** + * Only call this method after bound is set on this drawable. + * * @return the mask path object used to clip the drawable */ public Path getIconMask() { diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index 47468aeaeb973..ac24e2e715df0 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -67,6 +67,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.util.ArraySet; +import android.util.LauncherIcons; import android.util.Log; import android.util.MutableBoolean; import android.view.Display; @@ -142,6 +143,7 @@ public class SystemServicesProxy { int mDummyThumbnailHeight; Paint mBgProtectionPaint; Canvas mBgProtectionCanvas; + LauncherIcons mLauncherIcons; private final Handler mHandler = new H(); @@ -299,6 +301,7 @@ public class SystemServicesProxy { Collections.addAll(sRecentsBlacklist, res.getStringArray(R.array.recents_blacklist_array)); } + mLauncherIcons = new LauncherIcons(context); } /** @@ -834,7 +837,7 @@ public class SystemServicesProxy { return new ColorDrawable(0xFF666666); } - Drawable icon = info.loadIcon(mPm); + Drawable icon = mLauncherIcons.wrapIconDrawableWithShadow(info.loadIcon(mPm)); return getBadgedIcon(icon, userId); } @@ -850,7 +853,7 @@ public class SystemServicesProxy { return new ColorDrawable(0xFF666666); } - Drawable icon = appInfo.loadIcon(mPm); + Drawable icon = mLauncherIcons.wrapIconDrawableWithShadow(appInfo.loadIcon(mPm)); return getBadgedIcon(icon, userId); }