Merge "Reduce RAM requirements of grayscale icon testing" into lmp-dev
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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) {
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
|
||||
@@ -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(
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user