Loading core/java/android/app/Notification.java +5 −12 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ package android.app; import static android.annotation.Dimension.DP; import static android.graphics.drawable.Icon.TYPE_BITMAP; import static com.android.internal.util.ContrastColorUtil.satisfiesTextContrast; Loading Loading @@ -8741,26 +8740,20 @@ public class Notification implements Parcelable * If your app produces multiple bubbles, the image should be unique for each of them. * </p> * * <p>The shape of a bubble icon is adaptive and can match the device theme. * <p>The shape of a bubble icon is adaptive and will match the device theme. * * If your icon is bitmap-based, you should create it using * {@link Icon#createWithAdaptiveBitmap(Bitmap)}, otherwise this method will throw. * * If your icon is not bitmap-based, you should expect that the icon will be tinted. * Ideally your icon should be constructed via * {@link Icon#createWithAdaptiveBitmap(Bitmap)}, otherwise, the icon will be shrunk * and placed on an adaptive shape. * </p> * * @throws IllegalArgumentException if icon is null or a non-adaptive bitmap * @throws IllegalArgumentException if icon is null. */ @NonNull public BubbleMetadata.Builder setIcon(@NonNull Icon icon) { if (icon == null) { throw new IllegalArgumentException("Bubbles require non-null icon"); } if (icon.getType() == TYPE_BITMAP) { throw new IllegalArgumentException("When using bitmap based icons, Bubbles " + "require TYPE_ADAPTIVE_BITMAP, please use" + " Icon#createWithAdaptiveBitmap instead"); } mIcon = icon; return this; } Loading packages/SystemUI/res/values/dimens.xml +0 −2 Original line number Diff line number Diff line Loading @@ -1120,8 +1120,6 @@ <dimen name="bubble_touch_padding">12dp</dimen> <!-- Size of the circle around the bubbles when they're in the dismiss target. --> <dimen name="bubble_dismiss_encircle_size">52dp</dimen> <!-- How much to inset the icon in the circle --> <dimen name="bubble_icon_inset">16dp</dimen> <!-- Padding around the view displayed when the bubble is expanded --> <dimen name="bubble_expanded_view_padding">4dp</dimen> <!-- This should be at least the size of bubble_expanded_view_padding; it is used to include Loading packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java +4 −1 Original line number Diff line number Diff line Loading @@ -134,6 +134,10 @@ class Bubble { return mAppName; } public Drawable getUserBadgedAppIcon() { return mUserBadgedAppIcon; } boolean isInflated() { return mInflated; } Loading Loading @@ -165,7 +169,6 @@ class Bubble { mIconView = (BubbleView) inflater.inflate( R.layout.bubble_view, stackView, false /* attachToRoot */); mIconView.setBubble(this); mIconView.setAppIcon(mUserBadgedAppIcon); mExpandedView = (BubbleExpandedView) inflater.inflate( R.layout.bubble_expanded_view, stackView, false /* attachToRoot */); Loading packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +1 −1 Original line number Diff line number Diff line Loading @@ -1459,7 +1459,7 @@ public class BubbleStackView extends FrameLayout { mFlyout.setupFlyoutStartingAsDot( updateMessage, mStackAnimationController.getStackPosition(), getWidth(), mStackAnimationController.isStackOnLeftSide(), bubble.getIconView().getBadgeColor() /* dotColor */, bubble.getIconView().getDotColor() /* dotColor */, expandFlyoutAfterDelay /* onLayoutComplete */, mFlyoutOnHide, bubble.getIconView().getDotCenter()); Loading packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java +50 −79 Original line number Diff line number Diff line Loading @@ -24,17 +24,16 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Path; import android.graphics.drawable.AdaptiveIconDrawable; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.graphics.drawable.InsetDrawable; import android.util.AttributeSet; import android.util.PathParser; import android.widget.FrameLayout; import com.android.internal.graphics.ColorUtils; import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.icons.ColorExtractor; import com.android.launcher3.icons.ShadowGenerator; import com.android.systemui.Interpolators; import com.android.systemui.R; Loading @@ -45,17 +44,13 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; */ public class BubbleView extends FrameLayout { private static final int DARK_ICON_ALPHA = 180; private static final double ICON_MIN_CONTRAST = 4.1; private static final int DEFAULT_BACKGROUND_COLOR = Color.LTGRAY; // Same value as Launcher3 badge code private static final float WHITE_SCRIM_ALPHA = 0.54f; private Context mContext; private BadgedImageView mBadgedImageView; private int mBadgeColor; private int mIconInset; private Drawable mUserBadgedAppIcon; private int mDotColor; private ColorExtractor mColorExtractor; // mBubbleIconFactory cannot be static because it depends on Context. private BubbleIconFactory mBubbleIconFactory; Loading @@ -79,13 +74,13 @@ public class BubbleView extends FrameLayout { public BubbleView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); mContext = context; mIconInset = getResources().getDimensionPixelSize(R.dimen.bubble_icon_inset); } @Override protected void onFinishInflate() { super.onFinishInflate(); mBadgedImageView = findViewById(R.id.bubble_image); mColorExtractor = new ColorExtractor(); } @Override Loading @@ -105,6 +100,13 @@ public class BubbleView extends FrameLayout { mBubble = bubble; } /** * @param factory Factory for creating normalized bubble icons. */ public void setBubbleIconFactory(BubbleIconFactory factory) { mBubbleIconFactory = factory; } /** * The {@link NotificationEntry} associated with this view, if one exists. */ Loading @@ -129,17 +131,6 @@ public class BubbleView extends FrameLayout { updateViews(); } /** * @param factory Factory for creating normalized bubble icons. */ public void setBubbleIconFactory(BubbleIconFactory factory) { mBubbleIconFactory = factory; } public void setAppIcon(Drawable appIcon) { mUserBadgedAppIcon = appIcon; } /** Changes the dot's visibility to match the bubble view's state. */ void updateDotVisibility(boolean animate) { updateDotVisibility(animate, null /* after */); Loading @@ -154,9 +145,17 @@ public class BubbleView extends FrameLayout { updateDotVisibility(animate); } boolean isDotShowing() { return mBubble.showBubbleDot() && !mSuppressDot; } int getDotColor() { return mDotColor; } /** Sets the position of the 'new' dot, animating it out and back in if requested. */ void setDotPosition(boolean onLeft, boolean animate) { if (animate && onLeft != mBadgedImageView.getDotOnLeft() && shouldShowDot()) { if (animate && onLeft != mBadgedImageView.getDotOnLeft() && isDotShowing()) { animateDot(false /* showDot */, () -> { mBadgedImageView.setDotOnLeft(onLeft); animateDot(true /* showDot */, null); Loading @@ -180,7 +179,7 @@ public class BubbleView extends FrameLayout { * after animation if requested. */ private void updateDotVisibility(boolean animate, Runnable after) { final boolean showDot = shouldShowDot(); final boolean showDot = isDotShowing(); if (animate) { animateDot(showDot, after); } else { Loading Loading @@ -218,42 +217,21 @@ public class BubbleView extends FrameLayout { if (mBubble == null || mBubbleIconFactory == null) { return; } // Update icon. Notification.BubbleMetadata metadata = mBubble.getEntry().getBubbleMetadata(); Notification n = mBubble.getEntry().getSbn().getNotification(); Icon ic = metadata.getIcon(); boolean needsTint = ic.getType() != Icon.TYPE_ADAPTIVE_BITMAP; Drawable iconDrawable = ic.loadDrawable(mContext); if (needsTint) { iconDrawable = buildIconWithTint(iconDrawable, n.color); } Bitmap bubbleIcon = mBubbleIconFactory.createBadgedIconBitmap(iconDrawable, null /* user */, true /* shrinkNonAdaptiveIcons */).icon; // Give it a shadow Bitmap userBadgedBitmap = mBubbleIconFactory.createIconBitmap(mUserBadgedAppIcon, 1f, mBubbleIconFactory.getBadgeSize()); Canvas c = new Canvas(); ShadowGenerator shadowGenerator = new ShadowGenerator(mBubbleIconFactory.getBadgeSize()); c.setBitmap(userBadgedBitmap); shadowGenerator.recreateIcon(Bitmap.createBitmap(userBadgedBitmap), c); mBubbleIconFactory.badgeWithDrawable(bubbleIcon, new BitmapDrawable(mContext.getResources(), userBadgedBitmap)); mBadgedImageView.setImageBitmap(bubbleIcon); Drawable bubbleDrawable = getBubbleDrawable(mContext); BitmapInfo badgeBitmapInfo = getBadgedBitmap(); BitmapInfo bubbleBitmapInfo = getBubbleBitmap(bubbleDrawable, badgeBitmapInfo); mBadgedImageView.setImageBitmap(bubbleBitmapInfo.icon); // Update badge. int badgeColor = determineDominateColor(iconDrawable, n.color); mBadgeColor = badgeColor; mBadgedImageView.setDotColor(badgeColor); mDotColor = ColorUtils.blendARGB(badgeBitmapInfo.color, Color.WHITE, WHITE_SCRIM_ALPHA); mBadgedImageView.setDotColor(mDotColor); // Update dot. Path iconPath = PathParser.createPathFromPathData( getResources().getString(com.android.internal.R.string.config_icon_mask)); Matrix matrix = new Matrix(); float scale = mBubbleIconFactory.getNormalizer().getScale(iconDrawable, float scale = mBubbleIconFactory.getNormalizer().getScale(bubbleDrawable, null /* outBounds */, null /* path */, null /* outMaskShape */); float radius = BadgedImageView.DEFAULT_PATH_SIZE / 2f; matrix.setScale(scale /* x scale */, scale /* y scale */, radius /* pivot x */, Loading @@ -261,41 +239,34 @@ public class BubbleView extends FrameLayout { iconPath.transform(matrix); mBadgedImageView.drawDot(iconPath); animateDot(shouldShowDot(), null /* after */); animateDot(isDotShowing(), null /* after */); } boolean shouldShowDot() { return mBubble.showBubbleDot() && !mSuppressDot; Drawable getBubbleDrawable(Context context) { Notification.BubbleMetadata metadata = getEntry().getBubbleMetadata(); Icon ic = metadata.getIcon(); return ic.loadDrawable(context); } int getBadgeColor() { return mBadgeColor; } BitmapInfo getBadgedBitmap() { Bitmap userBadgedBitmap = mBubbleIconFactory.createIconBitmap( mBubble.getUserBadgedAppIcon(), 1f, mBubbleIconFactory.getBadgeSize()); private AdaptiveIconDrawable buildIconWithTint(Drawable iconDrawable, int backgroundColor) { iconDrawable = checkTint(iconDrawable, backgroundColor); InsetDrawable foreground = new InsetDrawable(iconDrawable, mIconInset); ColorDrawable background = new ColorDrawable(backgroundColor); return new AdaptiveIconDrawable(background, foreground); Canvas c = new Canvas(); ShadowGenerator shadowGenerator = new ShadowGenerator(mBubbleIconFactory.getBadgeSize()); c.setBitmap(userBadgedBitmap); shadowGenerator.recreateIcon(Bitmap.createBitmap(userBadgedBitmap), c); BitmapInfo bitmapInfo = mBubbleIconFactory.createIconBitmap(userBadgedBitmap); return bitmapInfo; } private Drawable checkTint(Drawable iconDrawable, int backgroundColor) { backgroundColor = ColorUtils.setAlphaComponent(backgroundColor, 255 /* alpha */); if (backgroundColor == Color.TRANSPARENT) { // ColorUtils throws exception when background is translucent. backgroundColor = DEFAULT_BACKGROUND_COLOR; } iconDrawable.setTint(Color.WHITE); double contrastRatio = ColorUtils.calculateContrast(Color.WHITE, backgroundColor); if (contrastRatio < ICON_MIN_CONTRAST) { int dark = ColorUtils.setAlphaComponent(Color.BLACK, DARK_ICON_ALPHA); iconDrawable.setTint(dark); } return iconDrawable; } BitmapInfo getBubbleBitmap(Drawable bubble, BitmapInfo badge) { BitmapInfo bubbleIconInfo = mBubbleIconFactory.createBadgedIconBitmap(bubble, null /* user */, true /* shrinkNonAdaptiveIcons */); private int determineDominateColor(Drawable d, int defaultTint) { // XXX: should we pull from the drawable, app icon, notif tint? return ColorUtils.blendARGB(defaultTint, Color.WHITE, WHITE_SCRIM_ALPHA); mBubbleIconFactory.badgeWithDrawable(bubbleIconInfo.icon, new BitmapDrawable(mContext.getResources(), badge.icon)); return bubbleIconInfo; } } Loading
core/java/android/app/Notification.java +5 −12 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ package android.app; import static android.annotation.Dimension.DP; import static android.graphics.drawable.Icon.TYPE_BITMAP; import static com.android.internal.util.ContrastColorUtil.satisfiesTextContrast; Loading Loading @@ -8741,26 +8740,20 @@ public class Notification implements Parcelable * If your app produces multiple bubbles, the image should be unique for each of them. * </p> * * <p>The shape of a bubble icon is adaptive and can match the device theme. * <p>The shape of a bubble icon is adaptive and will match the device theme. * * If your icon is bitmap-based, you should create it using * {@link Icon#createWithAdaptiveBitmap(Bitmap)}, otherwise this method will throw. * * If your icon is not bitmap-based, you should expect that the icon will be tinted. * Ideally your icon should be constructed via * {@link Icon#createWithAdaptiveBitmap(Bitmap)}, otherwise, the icon will be shrunk * and placed on an adaptive shape. * </p> * * @throws IllegalArgumentException if icon is null or a non-adaptive bitmap * @throws IllegalArgumentException if icon is null. */ @NonNull public BubbleMetadata.Builder setIcon(@NonNull Icon icon) { if (icon == null) { throw new IllegalArgumentException("Bubbles require non-null icon"); } if (icon.getType() == TYPE_BITMAP) { throw new IllegalArgumentException("When using bitmap based icons, Bubbles " + "require TYPE_ADAPTIVE_BITMAP, please use" + " Icon#createWithAdaptiveBitmap instead"); } mIcon = icon; return this; } Loading
packages/SystemUI/res/values/dimens.xml +0 −2 Original line number Diff line number Diff line Loading @@ -1120,8 +1120,6 @@ <dimen name="bubble_touch_padding">12dp</dimen> <!-- Size of the circle around the bubbles when they're in the dismiss target. --> <dimen name="bubble_dismiss_encircle_size">52dp</dimen> <!-- How much to inset the icon in the circle --> <dimen name="bubble_icon_inset">16dp</dimen> <!-- Padding around the view displayed when the bubble is expanded --> <dimen name="bubble_expanded_view_padding">4dp</dimen> <!-- This should be at least the size of bubble_expanded_view_padding; it is used to include Loading
packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java +4 −1 Original line number Diff line number Diff line Loading @@ -134,6 +134,10 @@ class Bubble { return mAppName; } public Drawable getUserBadgedAppIcon() { return mUserBadgedAppIcon; } boolean isInflated() { return mInflated; } Loading Loading @@ -165,7 +169,6 @@ class Bubble { mIconView = (BubbleView) inflater.inflate( R.layout.bubble_view, stackView, false /* attachToRoot */); mIconView.setBubble(this); mIconView.setAppIcon(mUserBadgedAppIcon); mExpandedView = (BubbleExpandedView) inflater.inflate( R.layout.bubble_expanded_view, stackView, false /* attachToRoot */); Loading
packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +1 −1 Original line number Diff line number Diff line Loading @@ -1459,7 +1459,7 @@ public class BubbleStackView extends FrameLayout { mFlyout.setupFlyoutStartingAsDot( updateMessage, mStackAnimationController.getStackPosition(), getWidth(), mStackAnimationController.isStackOnLeftSide(), bubble.getIconView().getBadgeColor() /* dotColor */, bubble.getIconView().getDotColor() /* dotColor */, expandFlyoutAfterDelay /* onLayoutComplete */, mFlyoutOnHide, bubble.getIconView().getDotCenter()); Loading
packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java +50 −79 Original line number Diff line number Diff line Loading @@ -24,17 +24,16 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Path; import android.graphics.drawable.AdaptiveIconDrawable; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.graphics.drawable.InsetDrawable; import android.util.AttributeSet; import android.util.PathParser; import android.widget.FrameLayout; import com.android.internal.graphics.ColorUtils; import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.icons.ColorExtractor; import com.android.launcher3.icons.ShadowGenerator; import com.android.systemui.Interpolators; import com.android.systemui.R; Loading @@ -45,17 +44,13 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; */ public class BubbleView extends FrameLayout { private static final int DARK_ICON_ALPHA = 180; private static final double ICON_MIN_CONTRAST = 4.1; private static final int DEFAULT_BACKGROUND_COLOR = Color.LTGRAY; // Same value as Launcher3 badge code private static final float WHITE_SCRIM_ALPHA = 0.54f; private Context mContext; private BadgedImageView mBadgedImageView; private int mBadgeColor; private int mIconInset; private Drawable mUserBadgedAppIcon; private int mDotColor; private ColorExtractor mColorExtractor; // mBubbleIconFactory cannot be static because it depends on Context. private BubbleIconFactory mBubbleIconFactory; Loading @@ -79,13 +74,13 @@ public class BubbleView extends FrameLayout { public BubbleView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); mContext = context; mIconInset = getResources().getDimensionPixelSize(R.dimen.bubble_icon_inset); } @Override protected void onFinishInflate() { super.onFinishInflate(); mBadgedImageView = findViewById(R.id.bubble_image); mColorExtractor = new ColorExtractor(); } @Override Loading @@ -105,6 +100,13 @@ public class BubbleView extends FrameLayout { mBubble = bubble; } /** * @param factory Factory for creating normalized bubble icons. */ public void setBubbleIconFactory(BubbleIconFactory factory) { mBubbleIconFactory = factory; } /** * The {@link NotificationEntry} associated with this view, if one exists. */ Loading @@ -129,17 +131,6 @@ public class BubbleView extends FrameLayout { updateViews(); } /** * @param factory Factory for creating normalized bubble icons. */ public void setBubbleIconFactory(BubbleIconFactory factory) { mBubbleIconFactory = factory; } public void setAppIcon(Drawable appIcon) { mUserBadgedAppIcon = appIcon; } /** Changes the dot's visibility to match the bubble view's state. */ void updateDotVisibility(boolean animate) { updateDotVisibility(animate, null /* after */); Loading @@ -154,9 +145,17 @@ public class BubbleView extends FrameLayout { updateDotVisibility(animate); } boolean isDotShowing() { return mBubble.showBubbleDot() && !mSuppressDot; } int getDotColor() { return mDotColor; } /** Sets the position of the 'new' dot, animating it out and back in if requested. */ void setDotPosition(boolean onLeft, boolean animate) { if (animate && onLeft != mBadgedImageView.getDotOnLeft() && shouldShowDot()) { if (animate && onLeft != mBadgedImageView.getDotOnLeft() && isDotShowing()) { animateDot(false /* showDot */, () -> { mBadgedImageView.setDotOnLeft(onLeft); animateDot(true /* showDot */, null); Loading @@ -180,7 +179,7 @@ public class BubbleView extends FrameLayout { * after animation if requested. */ private void updateDotVisibility(boolean animate, Runnable after) { final boolean showDot = shouldShowDot(); final boolean showDot = isDotShowing(); if (animate) { animateDot(showDot, after); } else { Loading Loading @@ -218,42 +217,21 @@ public class BubbleView extends FrameLayout { if (mBubble == null || mBubbleIconFactory == null) { return; } // Update icon. Notification.BubbleMetadata metadata = mBubble.getEntry().getBubbleMetadata(); Notification n = mBubble.getEntry().getSbn().getNotification(); Icon ic = metadata.getIcon(); boolean needsTint = ic.getType() != Icon.TYPE_ADAPTIVE_BITMAP; Drawable iconDrawable = ic.loadDrawable(mContext); if (needsTint) { iconDrawable = buildIconWithTint(iconDrawable, n.color); } Bitmap bubbleIcon = mBubbleIconFactory.createBadgedIconBitmap(iconDrawable, null /* user */, true /* shrinkNonAdaptiveIcons */).icon; // Give it a shadow Bitmap userBadgedBitmap = mBubbleIconFactory.createIconBitmap(mUserBadgedAppIcon, 1f, mBubbleIconFactory.getBadgeSize()); Canvas c = new Canvas(); ShadowGenerator shadowGenerator = new ShadowGenerator(mBubbleIconFactory.getBadgeSize()); c.setBitmap(userBadgedBitmap); shadowGenerator.recreateIcon(Bitmap.createBitmap(userBadgedBitmap), c); mBubbleIconFactory.badgeWithDrawable(bubbleIcon, new BitmapDrawable(mContext.getResources(), userBadgedBitmap)); mBadgedImageView.setImageBitmap(bubbleIcon); Drawable bubbleDrawable = getBubbleDrawable(mContext); BitmapInfo badgeBitmapInfo = getBadgedBitmap(); BitmapInfo bubbleBitmapInfo = getBubbleBitmap(bubbleDrawable, badgeBitmapInfo); mBadgedImageView.setImageBitmap(bubbleBitmapInfo.icon); // Update badge. int badgeColor = determineDominateColor(iconDrawable, n.color); mBadgeColor = badgeColor; mBadgedImageView.setDotColor(badgeColor); mDotColor = ColorUtils.blendARGB(badgeBitmapInfo.color, Color.WHITE, WHITE_SCRIM_ALPHA); mBadgedImageView.setDotColor(mDotColor); // Update dot. Path iconPath = PathParser.createPathFromPathData( getResources().getString(com.android.internal.R.string.config_icon_mask)); Matrix matrix = new Matrix(); float scale = mBubbleIconFactory.getNormalizer().getScale(iconDrawable, float scale = mBubbleIconFactory.getNormalizer().getScale(bubbleDrawable, null /* outBounds */, null /* path */, null /* outMaskShape */); float radius = BadgedImageView.DEFAULT_PATH_SIZE / 2f; matrix.setScale(scale /* x scale */, scale /* y scale */, radius /* pivot x */, Loading @@ -261,41 +239,34 @@ public class BubbleView extends FrameLayout { iconPath.transform(matrix); mBadgedImageView.drawDot(iconPath); animateDot(shouldShowDot(), null /* after */); animateDot(isDotShowing(), null /* after */); } boolean shouldShowDot() { return mBubble.showBubbleDot() && !mSuppressDot; Drawable getBubbleDrawable(Context context) { Notification.BubbleMetadata metadata = getEntry().getBubbleMetadata(); Icon ic = metadata.getIcon(); return ic.loadDrawable(context); } int getBadgeColor() { return mBadgeColor; } BitmapInfo getBadgedBitmap() { Bitmap userBadgedBitmap = mBubbleIconFactory.createIconBitmap( mBubble.getUserBadgedAppIcon(), 1f, mBubbleIconFactory.getBadgeSize()); private AdaptiveIconDrawable buildIconWithTint(Drawable iconDrawable, int backgroundColor) { iconDrawable = checkTint(iconDrawable, backgroundColor); InsetDrawable foreground = new InsetDrawable(iconDrawable, mIconInset); ColorDrawable background = new ColorDrawable(backgroundColor); return new AdaptiveIconDrawable(background, foreground); Canvas c = new Canvas(); ShadowGenerator shadowGenerator = new ShadowGenerator(mBubbleIconFactory.getBadgeSize()); c.setBitmap(userBadgedBitmap); shadowGenerator.recreateIcon(Bitmap.createBitmap(userBadgedBitmap), c); BitmapInfo bitmapInfo = mBubbleIconFactory.createIconBitmap(userBadgedBitmap); return bitmapInfo; } private Drawable checkTint(Drawable iconDrawable, int backgroundColor) { backgroundColor = ColorUtils.setAlphaComponent(backgroundColor, 255 /* alpha */); if (backgroundColor == Color.TRANSPARENT) { // ColorUtils throws exception when background is translucent. backgroundColor = DEFAULT_BACKGROUND_COLOR; } iconDrawable.setTint(Color.WHITE); double contrastRatio = ColorUtils.calculateContrast(Color.WHITE, backgroundColor); if (contrastRatio < ICON_MIN_CONTRAST) { int dark = ColorUtils.setAlphaComponent(Color.BLACK, DARK_ICON_ALPHA); iconDrawable.setTint(dark); } return iconDrawable; } BitmapInfo getBubbleBitmap(Drawable bubble, BitmapInfo badge) { BitmapInfo bubbleIconInfo = mBubbleIconFactory.createBadgedIconBitmap(bubble, null /* user */, true /* shrinkNonAdaptiveIcons */); private int determineDominateColor(Drawable d, int defaultTint) { // XXX: should we pull from the drawable, app icon, notif tint? return ColorUtils.blendARGB(defaultTint, Color.WHITE, WHITE_SCRIM_ALPHA); mBubbleIconFactory.badgeWithDrawable(bubbleIconInfo.icon, new BitmapDrawable(mContext.getResources(), badge.icon)); return bubbleIconInfo; } }