Loading core/java/android/app/Notification.java +5 −5 Original line number Diff line number Diff line Loading @@ -1917,7 +1917,7 @@ public class Notification implements Parcelable mPeople = new ArrayList<String>(); mColorUtil = context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.L ? NotificationColorUtil.getInstance() : null; NotificationColorUtil.getInstance(mContext) : null; } /** Loading Loading @@ -2890,7 +2890,7 @@ public class Notification implements Parcelable } private void processLegacyAction(Action action, RemoteViews button) { if (!isLegacy() || mColorUtil.isGrayscale(mContext, action.icon)) { if (!isLegacy() || mColorUtil.isGrayscaleIcon(mContext, action.icon)) { button.setTextViewCompoundDrawablesRelativeColorFilter(R.id.action0, 0, mContext.getResources().getColor(R.color.notification_action_color_filter), PorterDuff.Mode.MULTIPLY); Loading @@ -2909,7 +2909,7 @@ public class Notification implements Parcelable * Apply any necessary background to smallIcons being used in the largeIcon spot. */ private void processSmallIconAsLarge(int largeIconId, RemoteViews contentView) { if (!isLegacy() || mColorUtil.isGrayscale(mContext, largeIconId)) { if (!isLegacy() || mColorUtil.isGrayscaleIcon(mContext, largeIconId)) { applyLargeIconBackground(contentView); } } Loading @@ -2920,7 +2920,7 @@ public class Notification implements Parcelable */ // TODO: also check bounds, transparency, that sort of thing. private void processLargeLegacyIcon(Bitmap largeIcon, RemoteViews contentView) { if (isLegacy() && mColorUtil.isGrayscale(largeIcon)) { if (isLegacy() && mColorUtil.isGrayscaleIcon(largeIcon)) { applyLargeIconBackground(contentView); } else { removeLargeIconBackground(contentView); Loading Loading @@ -2956,7 +2956,7 @@ public class Notification implements Parcelable */ private void processSmallRightIcon(int smallIconDrawableId, RemoteViews contentView) { if (!isLegacy() || mColorUtil.isGrayscale(mContext, smallIconDrawableId)) { if (!isLegacy() || mColorUtil.isGrayscaleIcon(mContext, smallIconDrawableId)) { contentView.setDrawableParameters(R.id.right_icon, false, -1, 0xFFFFFFFF, PorterDuff.Mode.SRC_ATOP, -1); Loading core/java/com/android/internal/util/ImageUtils.java +39 −3 Original line number Diff line number Diff line Loading @@ -17,6 +17,10 @@ package com.android.internal.util; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PorterDuff; /** * Utility class for image analysis and processing. Loading @@ -31,17 +35,49 @@ public class ImageUtils { // Alpha amount for which values below are considered transparent. private static final int ALPHA_TOLERANCE = 50; // Size of the smaller bitmap we're actually going to scan. private static final int COMPACT_BITMAP_SIZE = 64; // pixels private int[] mTempBuffer; private Bitmap mTempCompactBitmap; private Canvas mTempCompactBitmapCanvas; private Paint mTempCompactBitmapPaint; private final Matrix mTempMatrix = new Matrix(); /** * Checks whether a bitmap is grayscale. Grayscale here means "very close to a perfect * gray". * * Instead of scanning every pixel in the bitmap, we first resize the bitmap to no more than * COMPACT_BITMAP_SIZE^2 pixels using filtering. The hope is that any non-gray color elements * will survive the squeezing process, contaminating the result with color. */ public boolean isGrayscale(Bitmap bitmap) { final int height = bitmap.getHeight(); final int width = bitmap.getWidth(); int size = height*width; int height = bitmap.getHeight(); int width = bitmap.getWidth(); // shrink to a more manageable (yet hopefully no more or less colorful) size if (height > COMPACT_BITMAP_SIZE || width > COMPACT_BITMAP_SIZE) { if (mTempCompactBitmap == null) { mTempCompactBitmap = Bitmap.createBitmap( COMPACT_BITMAP_SIZE, COMPACT_BITMAP_SIZE, Bitmap.Config.ARGB_8888 ); mTempCompactBitmapCanvas = new Canvas(mTempCompactBitmap); mTempCompactBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mTempCompactBitmapPaint.setFilterBitmap(true); } mTempMatrix.reset(); mTempMatrix.setScale( (float) COMPACT_BITMAP_SIZE / width, (float) COMPACT_BITMAP_SIZE / height, 0, 0); mTempCompactBitmapCanvas.drawColor(0, PorterDuff.Mode.SRC); // select all, erase mTempCompactBitmapCanvas.drawBitmap(bitmap, mTempMatrix, mTempCompactBitmapPaint); bitmap = mTempCompactBitmap; width = height = COMPACT_BITMAP_SIZE; } final int size = height*width; ensureBufferSize(size); bitmap.getPixels(mTempBuffer, 0, width, 0, 0, width, height); for (int i = 0; i < size; i++) { Loading core/java/com/android/internal/util/NotificationColorUtil.java +30 −17 Original line number Diff line number Diff line Loading @@ -50,23 +50,36 @@ public class NotificationColorUtil { private final WeakHashMap<Bitmap, Pair<Boolean, Integer>> mGrayscaleBitmapCache = new WeakHashMap<Bitmap, Pair<Boolean, Integer>>(); public static NotificationColorUtil getInstance() { private final int mGrayscaleIconMaxSize; // @dimen/notification_large_icon_width (64dp) public static NotificationColorUtil getInstance(Context context) { synchronized (sLock) { if (sInstance == null) { sInstance = new NotificationColorUtil(); sInstance = new NotificationColorUtil(context); } return sInstance; } } private NotificationColorUtil(Context context) { mGrayscaleIconMaxSize = context.getResources().getDimensionPixelSize( com.android.internal.R.dimen.notification_large_icon_width); } /** * Checks whether a bitmap is grayscale. Grayscale here means "very close to a perfect * gray". * Checks whether a Bitmap is a small grayscale icon. * Grayscale here means "very close to a perfect gray"; icon means "no larger than 64dp". * * @param bitmap The bitmap to test. * @return Whether the bitmap is grayscale. * @return True if the bitmap is grayscale; false if it is color or too large to examine. */ public boolean isGrayscale(Bitmap bitmap) { public boolean isGrayscaleIcon(Bitmap bitmap) { // quick test: reject large bitmaps if (bitmap.getWidth() > mGrayscaleIconMaxSize || bitmap.getHeight() > mGrayscaleIconMaxSize) { return false; } synchronized (sLock) { Pair<Boolean, Integer> cached = mGrayscaleBitmapCache.get(bitmap); if (cached != null) { Loading @@ -92,22 +105,22 @@ public class NotificationColorUtil { } /** * Checks whether a drawable is grayscale. Grayscale here means "very close to a perfect * gray". * Checks whether a Drawable is a small grayscale icon. * Grayscale here means "very close to a perfect gray"; icon means "no larger than 64dp". * * @param d The drawable to test. * @return Whether the drawable is grayscale. * @return True if the bitmap is grayscale; false if it is color or too large to examine. */ public boolean isGrayscale(Drawable d) { public boolean isGrayscaleIcon(Drawable d) { if (d == null) { return false; } else if (d instanceof BitmapDrawable) { BitmapDrawable bd = (BitmapDrawable) d; return bd.getBitmap() != null && isGrayscale(bd.getBitmap()); return bd.getBitmap() != null && isGrayscaleIcon(bd.getBitmap()); } else if (d instanceof AnimationDrawable) { AnimationDrawable ad = (AnimationDrawable) d; int count = ad.getNumberOfFrames(); return count > 0 && isGrayscale(ad.getFrame(0)); return count > 0 && isGrayscaleIcon(ad.getFrame(0)); } else if (d instanceof VectorDrawable) { // We just assume you're doing the right thing if using vectors return true; Loading @@ -117,16 +130,16 @@ public class NotificationColorUtil { } /** * Checks whether a drawable with a resoure id is grayscale. Grayscale here means "very close * to a perfect gray". * Checks whether a drawable with a resoure id is a small grayscale icon. * Grayscale here means "very close to a perfect gray"; icon means "no larger than 64dp". * * @param context The context to load the drawable from. * @return Whether the drawable is grayscale. * @return True if the bitmap is grayscale; false if it is color or too large to examine. */ public boolean isGrayscale(Context context, int drawableResId) { public boolean isGrayscaleIcon(Context context, int drawableResId) { if (drawableResId != 0) { try { return isGrayscale(context.getDrawable(drawableResId)); return isGrayscaleIcon(context.getDrawable(drawableResId)); } catch (Resources.NotFoundException ex) { Log.e(TAG, "Drawable not found: " + drawableResId); return false; Loading packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +4 −5 Original line number Diff line number Diff line Loading @@ -39,9 +39,6 @@ import android.content.pm.UserInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.os.Build; Loading Loading @@ -179,7 +176,7 @@ public abstract class BaseStatusBar extends SystemUI implements // public mode, private notifications, etc private boolean mLockscreenPublicMode = false; private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray(); private NotificationColorUtil mNotificationColorUtil = NotificationColorUtil.getInstance(); private NotificationColorUtil mNotificationColorUtil; private UserManager mUserManager; Loading Loading @@ -437,6 +434,8 @@ public abstract class BaseStatusBar extends SystemUI implements mDevicePolicyManager = (DevicePolicyManager)mContext.getSystemService( Context.DEVICE_POLICY_SERVICE); mNotificationColorUtil = NotificationColorUtil.getInstance(mContext); mNotificationData = new NotificationData(this); mDreamManager = IDreamManager.Stub.asInterface( Loading Loading @@ -1348,7 +1347,7 @@ public abstract class BaseStatusBar extends SystemUI implements Drawable iconDrawable = StatusBarIconView.getIcon(mContext, ic); icon.setImageDrawable(iconDrawable); if (mNotificationColorUtil.isGrayscale(iconDrawable)) { if (mNotificationColorUtil.isGrayscaleIcon(iconDrawable)) { icon.setBackgroundResource( com.android.internal.R.drawable.notification_icon_legacy_bg); int padding = mContext.getResources().getDimensionPixelSize( Loading packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java +2 −1 Original line number Diff line number Diff line Loading @@ -36,7 +36,7 @@ public class NotificationOverflowIconsView extends IconMerger { private TextView mMoreText; private int mTintColor; private int mIconSize; private NotificationColorUtil mNotificationColorUtil = new NotificationColorUtil(); private NotificationColorUtil mNotificationColorUtil; public NotificationOverflowIconsView(Context context, AttributeSet attrs) { super(context, attrs); Loading @@ -45,6 +45,7 @@ public class NotificationOverflowIconsView extends IconMerger { @Override protected void onFinishInflate() { super.onFinishInflate(); mNotificationColorUtil = NotificationColorUtil.getInstance(getContext()); mTintColor = getResources().getColor(R.color.keyguard_overflow_content_color); mIconSize = getResources().getDimensionPixelSize( com.android.internal.R.dimen.status_bar_icon_size); Loading Loading
core/java/android/app/Notification.java +5 −5 Original line number Diff line number Diff line Loading @@ -1917,7 +1917,7 @@ public class Notification implements Parcelable mPeople = new ArrayList<String>(); mColorUtil = context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.L ? NotificationColorUtil.getInstance() : null; NotificationColorUtil.getInstance(mContext) : null; } /** Loading Loading @@ -2890,7 +2890,7 @@ public class Notification implements Parcelable } private void processLegacyAction(Action action, RemoteViews button) { if (!isLegacy() || mColorUtil.isGrayscale(mContext, action.icon)) { if (!isLegacy() || mColorUtil.isGrayscaleIcon(mContext, action.icon)) { button.setTextViewCompoundDrawablesRelativeColorFilter(R.id.action0, 0, mContext.getResources().getColor(R.color.notification_action_color_filter), PorterDuff.Mode.MULTIPLY); Loading @@ -2909,7 +2909,7 @@ public class Notification implements Parcelable * Apply any necessary background to smallIcons being used in the largeIcon spot. */ private void processSmallIconAsLarge(int largeIconId, RemoteViews contentView) { if (!isLegacy() || mColorUtil.isGrayscale(mContext, largeIconId)) { if (!isLegacy() || mColorUtil.isGrayscaleIcon(mContext, largeIconId)) { applyLargeIconBackground(contentView); } } Loading @@ -2920,7 +2920,7 @@ public class Notification implements Parcelable */ // TODO: also check bounds, transparency, that sort of thing. private void processLargeLegacyIcon(Bitmap largeIcon, RemoteViews contentView) { if (isLegacy() && mColorUtil.isGrayscale(largeIcon)) { if (isLegacy() && mColorUtil.isGrayscaleIcon(largeIcon)) { applyLargeIconBackground(contentView); } else { removeLargeIconBackground(contentView); Loading Loading @@ -2956,7 +2956,7 @@ public class Notification implements Parcelable */ private void processSmallRightIcon(int smallIconDrawableId, RemoteViews contentView) { if (!isLegacy() || mColorUtil.isGrayscale(mContext, smallIconDrawableId)) { if (!isLegacy() || mColorUtil.isGrayscaleIcon(mContext, smallIconDrawableId)) { contentView.setDrawableParameters(R.id.right_icon, false, -1, 0xFFFFFFFF, PorterDuff.Mode.SRC_ATOP, -1); Loading
core/java/com/android/internal/util/ImageUtils.java +39 −3 Original line number Diff line number Diff line Loading @@ -17,6 +17,10 @@ package com.android.internal.util; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PorterDuff; /** * Utility class for image analysis and processing. Loading @@ -31,17 +35,49 @@ public class ImageUtils { // Alpha amount for which values below are considered transparent. private static final int ALPHA_TOLERANCE = 50; // Size of the smaller bitmap we're actually going to scan. private static final int COMPACT_BITMAP_SIZE = 64; // pixels private int[] mTempBuffer; private Bitmap mTempCompactBitmap; private Canvas mTempCompactBitmapCanvas; private Paint mTempCompactBitmapPaint; private final Matrix mTempMatrix = new Matrix(); /** * Checks whether a bitmap is grayscale. Grayscale here means "very close to a perfect * gray". * * Instead of scanning every pixel in the bitmap, we first resize the bitmap to no more than * COMPACT_BITMAP_SIZE^2 pixels using filtering. The hope is that any non-gray color elements * will survive the squeezing process, contaminating the result with color. */ public boolean isGrayscale(Bitmap bitmap) { final int height = bitmap.getHeight(); final int width = bitmap.getWidth(); int size = height*width; int height = bitmap.getHeight(); int width = bitmap.getWidth(); // shrink to a more manageable (yet hopefully no more or less colorful) size if (height > COMPACT_BITMAP_SIZE || width > COMPACT_BITMAP_SIZE) { if (mTempCompactBitmap == null) { mTempCompactBitmap = Bitmap.createBitmap( COMPACT_BITMAP_SIZE, COMPACT_BITMAP_SIZE, Bitmap.Config.ARGB_8888 ); mTempCompactBitmapCanvas = new Canvas(mTempCompactBitmap); mTempCompactBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mTempCompactBitmapPaint.setFilterBitmap(true); } mTempMatrix.reset(); mTempMatrix.setScale( (float) COMPACT_BITMAP_SIZE / width, (float) COMPACT_BITMAP_SIZE / height, 0, 0); mTempCompactBitmapCanvas.drawColor(0, PorterDuff.Mode.SRC); // select all, erase mTempCompactBitmapCanvas.drawBitmap(bitmap, mTempMatrix, mTempCompactBitmapPaint); bitmap = mTempCompactBitmap; width = height = COMPACT_BITMAP_SIZE; } final int size = height*width; ensureBufferSize(size); bitmap.getPixels(mTempBuffer, 0, width, 0, 0, width, height); for (int i = 0; i < size; i++) { Loading
core/java/com/android/internal/util/NotificationColorUtil.java +30 −17 Original line number Diff line number Diff line Loading @@ -50,23 +50,36 @@ public class NotificationColorUtil { private final WeakHashMap<Bitmap, Pair<Boolean, Integer>> mGrayscaleBitmapCache = new WeakHashMap<Bitmap, Pair<Boolean, Integer>>(); public static NotificationColorUtil getInstance() { private final int mGrayscaleIconMaxSize; // @dimen/notification_large_icon_width (64dp) public static NotificationColorUtil getInstance(Context context) { synchronized (sLock) { if (sInstance == null) { sInstance = new NotificationColorUtil(); sInstance = new NotificationColorUtil(context); } return sInstance; } } private NotificationColorUtil(Context context) { mGrayscaleIconMaxSize = context.getResources().getDimensionPixelSize( com.android.internal.R.dimen.notification_large_icon_width); } /** * Checks whether a bitmap is grayscale. Grayscale here means "very close to a perfect * gray". * Checks whether a Bitmap is a small grayscale icon. * Grayscale here means "very close to a perfect gray"; icon means "no larger than 64dp". * * @param bitmap The bitmap to test. * @return Whether the bitmap is grayscale. * @return True if the bitmap is grayscale; false if it is color or too large to examine. */ public boolean isGrayscale(Bitmap bitmap) { public boolean isGrayscaleIcon(Bitmap bitmap) { // quick test: reject large bitmaps if (bitmap.getWidth() > mGrayscaleIconMaxSize || bitmap.getHeight() > mGrayscaleIconMaxSize) { return false; } synchronized (sLock) { Pair<Boolean, Integer> cached = mGrayscaleBitmapCache.get(bitmap); if (cached != null) { Loading @@ -92,22 +105,22 @@ public class NotificationColorUtil { } /** * Checks whether a drawable is grayscale. Grayscale here means "very close to a perfect * gray". * Checks whether a Drawable is a small grayscale icon. * Grayscale here means "very close to a perfect gray"; icon means "no larger than 64dp". * * @param d The drawable to test. * @return Whether the drawable is grayscale. * @return True if the bitmap is grayscale; false if it is color or too large to examine. */ public boolean isGrayscale(Drawable d) { public boolean isGrayscaleIcon(Drawable d) { if (d == null) { return false; } else if (d instanceof BitmapDrawable) { BitmapDrawable bd = (BitmapDrawable) d; return bd.getBitmap() != null && isGrayscale(bd.getBitmap()); return bd.getBitmap() != null && isGrayscaleIcon(bd.getBitmap()); } else if (d instanceof AnimationDrawable) { AnimationDrawable ad = (AnimationDrawable) d; int count = ad.getNumberOfFrames(); return count > 0 && isGrayscale(ad.getFrame(0)); return count > 0 && isGrayscaleIcon(ad.getFrame(0)); } else if (d instanceof VectorDrawable) { // We just assume you're doing the right thing if using vectors return true; Loading @@ -117,16 +130,16 @@ public class NotificationColorUtil { } /** * Checks whether a drawable with a resoure id is grayscale. Grayscale here means "very close * to a perfect gray". * Checks whether a drawable with a resoure id is a small grayscale icon. * Grayscale here means "very close to a perfect gray"; icon means "no larger than 64dp". * * @param context The context to load the drawable from. * @return Whether the drawable is grayscale. * @return True if the bitmap is grayscale; false if it is color or too large to examine. */ public boolean isGrayscale(Context context, int drawableResId) { public boolean isGrayscaleIcon(Context context, int drawableResId) { if (drawableResId != 0) { try { return isGrayscale(context.getDrawable(drawableResId)); return isGrayscaleIcon(context.getDrawable(drawableResId)); } catch (Resources.NotFoundException ex) { Log.e(TAG, "Drawable not found: " + drawableResId); return false; Loading
packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +4 −5 Original line number Diff line number Diff line Loading @@ -39,9 +39,6 @@ import android.content.pm.UserInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.os.Build; Loading Loading @@ -179,7 +176,7 @@ public abstract class BaseStatusBar extends SystemUI implements // public mode, private notifications, etc private boolean mLockscreenPublicMode = false; private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray(); private NotificationColorUtil mNotificationColorUtil = NotificationColorUtil.getInstance(); private NotificationColorUtil mNotificationColorUtil; private UserManager mUserManager; Loading Loading @@ -437,6 +434,8 @@ public abstract class BaseStatusBar extends SystemUI implements mDevicePolicyManager = (DevicePolicyManager)mContext.getSystemService( Context.DEVICE_POLICY_SERVICE); mNotificationColorUtil = NotificationColorUtil.getInstance(mContext); mNotificationData = new NotificationData(this); mDreamManager = IDreamManager.Stub.asInterface( Loading Loading @@ -1348,7 +1347,7 @@ public abstract class BaseStatusBar extends SystemUI implements Drawable iconDrawable = StatusBarIconView.getIcon(mContext, ic); icon.setImageDrawable(iconDrawable); if (mNotificationColorUtil.isGrayscale(iconDrawable)) { if (mNotificationColorUtil.isGrayscaleIcon(iconDrawable)) { icon.setBackgroundResource( com.android.internal.R.drawable.notification_icon_legacy_bg); int padding = mContext.getResources().getDimensionPixelSize( Loading
packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java +2 −1 Original line number Diff line number Diff line Loading @@ -36,7 +36,7 @@ public class NotificationOverflowIconsView extends IconMerger { private TextView mMoreText; private int mTintColor; private int mIconSize; private NotificationColorUtil mNotificationColorUtil = new NotificationColorUtil(); private NotificationColorUtil mNotificationColorUtil; public NotificationOverflowIconsView(Context context, AttributeSet attrs) { super(context, attrs); Loading @@ -45,6 +45,7 @@ public class NotificationOverflowIconsView extends IconMerger { @Override protected void onFinishInflate() { super.onFinishInflate(); mNotificationColorUtil = NotificationColorUtil.getInstance(getContext()); mTintColor = getResources().getColor(R.color.keyguard_overflow_content_color); mIconSize = getResources().getDimensionPixelSize( com.android.internal.R.dimen.status_bar_icon_size); Loading