FileDocCategorySizeDatePackage
NotificationColorUtil.javaAPI DocAndroid 5.1 API8024Thu Mar 12 22:22:10 GMT 2015com.android.internal.util

NotificationColorUtil

public class NotificationColorUtil extends Object
Helper class to process legacy (Holo) notifications to make them look like material notifications.
hide

Fields Summary
private static final String
TAG
private static final Object
sLock
private static NotificationColorUtil
sInstance
private final ImageUtils
mImageUtils
private final WeakHashMap
mGrayscaleBitmapCache
private final int
mGrayscaleIconMaxSize
Constructors Summary
private NotificationColorUtil(android.content.Context context)

        mGrayscaleIconMaxSize = context.getResources().getDimensionPixelSize(
                com.android.internal.R.dimen.notification_large_icon_width);
    
Methods Summary
public static com.android.internal.util.NotificationColorUtilgetInstance(android.content.Context context)

 // @dimen/notification_large_icon_width (64dp)

         
        synchronized (sLock) {
            if (sInstance == null) {
                sInstance = new NotificationColorUtil(context);
            }
            return sInstance;
        }
    
public java.lang.CharSequenceinvertCharSequenceColors(java.lang.CharSequence charSequence)
Inverts all the grayscale colors set by {@link android.text.style.TextAppearanceSpan}s on the text.

param
charSequence The text to process.
return
The color inverted text.

        if (charSequence instanceof Spanned) {
            Spanned ss = (Spanned) charSequence;
            Object[] spans = ss.getSpans(0, ss.length(), Object.class);
            SpannableStringBuilder builder = new SpannableStringBuilder(ss.toString());
            for (Object span : spans) {
                Object resultSpan = span;
                if (span instanceof TextAppearanceSpan) {
                    resultSpan = processTextAppearanceSpan((TextAppearanceSpan) span);
                }
                builder.setSpan(resultSpan, ss.getSpanStart(span), ss.getSpanEnd(span),
                        ss.getSpanFlags(span));
            }
            return builder;
        }
        return charSequence;
    
public booleanisGrayscaleIcon(android.graphics.Bitmap bitmap)
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
True if the bitmap is grayscale; false if it is color or too large to examine.

        // 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) {
                if (cached.second == bitmap.getGenerationId()) {
                    return cached.first;
                }
            }
        }
        boolean result;
        int generationId;
        synchronized (mImageUtils) {
            result = mImageUtils.isGrayscale(bitmap);

            // generationId and the check whether the Bitmap is grayscale can't be read atomically
            // here. However, since the thread is in the process of posting the notification, we can
            // assume that it doesn't modify the bitmap while we are checking the pixels.
            generationId = bitmap.getGenerationId();
        }
        synchronized (sLock) {
            mGrayscaleBitmapCache.put(bitmap, Pair.create(result, generationId));
        }
        return result;
    
public booleanisGrayscaleIcon(android.graphics.drawable.Drawable d)
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
True if the bitmap is grayscale; false if it is color or too large to examine.

        if (d == null) {
            return false;
        } else if (d instanceof BitmapDrawable) {
            BitmapDrawable bd = (BitmapDrawable) d;
            return bd.getBitmap() != null && isGrayscaleIcon(bd.getBitmap());
        } else if (d instanceof AnimationDrawable) {
            AnimationDrawable ad = (AnimationDrawable) d;
            int count = ad.getNumberOfFrames();
            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;
        } else {
            return false;
        }
    
public booleanisGrayscaleIcon(android.content.Context context, int drawableResId)
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
True if the bitmap is grayscale; false if it is color or too large to examine.

        if (drawableResId != 0) {
            try {
                return isGrayscaleIcon(context.getDrawable(drawableResId));
            } catch (Resources.NotFoundException ex) {
                Log.e(TAG, "Drawable not found: " + drawableResId);
                return false;
            }
        } else {
            return false;
        }
    
private intprocessColor(int color)

        return Color.argb(Color.alpha(color),
                255 - Color.red(color),
                255 - Color.green(color),
                255 - Color.blue(color));
    
private android.text.style.TextAppearanceSpanprocessTextAppearanceSpan(android.text.style.TextAppearanceSpan span)

        ColorStateList colorStateList = span.getTextColor();
        if (colorStateList != null) {
            int[] colors = colorStateList.getColors();
            boolean changed = false;
            for (int i = 0; i < colors.length; i++) {
                if (ImageUtils.isGrayscale(colors[i])) {

                    // Allocate a new array so we don't change the colors in the old color state
                    // list.
                    if (!changed) {
                        colors = Arrays.copyOf(colors, colors.length);
                    }
                    colors[i] = processColor(colors[i]);
                    changed = true;
                }
            }
            if (changed) {
                return new TextAppearanceSpan(
                        span.getFamily(), span.getTextStyle(), span.getTextSize(),
                        new ColorStateList(colorStateList.getStates(), colors),
                        span.getLinkTextColor());
            }
        }
        return span;