Loading core/java/android/app/Notification.java +45 −26 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static com.android.internal.util.ContrastColorUtil.satisfiesTextContrast; import android.annotation.ColorInt; import android.annotation.DrawableRes; import android.annotation.IdRes; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; Loading @@ -37,6 +38,7 @@ import android.content.pm.ShortcutInfo; import android.content.res.ColorStateList; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; Loading Loading @@ -7759,8 +7761,17 @@ public class Notification implements Parcelable * @see Notification.Builder#setColorized(boolean) */ public static class MediaStyle extends Style { // Changing max media buttons requires also changing templates // (notification_template_material_media and notification_template_material_big_media). static final int MAX_MEDIA_BUTTONS_IN_COMPACT = 3; static final int MAX_MEDIA_BUTTONS = 5; @IdRes private static final int[] MEDIA_BUTTON_IDS = { R.id.action0, R.id.action1, R.id.action2, R.id.action3, R.id.action4, }; private int[] mActionsToShowInCompact = null; private MediaSession.Token mToken; Loading Loading @@ -7874,15 +7885,16 @@ public class Notification implements Parcelable return false; } private RemoteViews generateMediaActionButton(Action action, int color) { private void bindMediaActionButton(RemoteViews container, @IdRes int buttonId, Action action, int color) { final boolean tombstone = (action.actionIntent == null); RemoteViews button = new BuilderRemoteViews(mBuilder.mContext.getApplicationInfo(), R.layout.notification_material_media_action); button.setImageViewIcon(R.id.action0, action.getIcon()); container.setViewVisibility(buttonId, View.VISIBLE); container.setImageViewIcon(buttonId, action.getIcon()); // If the action buttons should not be tinted, then just use the default // notification color. Otherwise, just use the passed-in color. Configuration currentConfig = mBuilder.mContext.getResources().getConfiguration(); Resources resources = mBuilder.mContext.getResources(); Configuration currentConfig = resources.getConfiguration(); boolean inNightMode = (currentConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES; int tintColor = mBuilder.shouldTintActionButtons() || mBuilder.isColorized() Loading @@ -7890,13 +7902,21 @@ public class Notification implements Parcelable : ContrastColorUtil.resolveColor(mBuilder.mContext, Notification.COLOR_DEFAULT, inNightMode); button.setDrawableTint(R.id.action0, false, tintColor, container.setDrawableTint(buttonId, false, tintColor, PorterDuff.Mode.SRC_ATOP); final TypedArray typedArray = mBuilder.mContext.obtainStyledAttributes( new int[]{ android.R.attr.colorControlHighlight }); int rippleAlpha = Color.alpha(typedArray.getColor(0, 0)); typedArray.recycle(); int rippleColor = Color.argb(rippleAlpha, Color.red(tintColor), Color.green(tintColor), Color.blue(tintColor)); container.setRippleDrawableColor(buttonId, ColorStateList.valueOf(rippleColor)); if (!tombstone) { button.setOnClickPendingIntent(R.id.action0, action.actionIntent); container.setOnClickPendingIntent(buttonId, action.actionIntent); } button.setContentDescription(R.id.action0, action.title); return button; container.setContentDescription(buttonId, action.title); } private RemoteViews makeMediaContentView() { Loading @@ -7905,21 +7925,20 @@ public class Notification implements Parcelable null /* result */); final int numActions = mBuilder.mActions.size(); final int N = mActionsToShowInCompact == null final int numActionsToShow = mActionsToShowInCompact == null ? 0 : Math.min(mActionsToShowInCompact.length, MAX_MEDIA_BUTTONS_IN_COMPACT); view.removeAllViews(com.android.internal.R.id.media_actions); if (N > 0) { for (int i = 0; i < N; i++) { if (i >= numActions) { if (numActionsToShow > numActions) { throw new IllegalArgumentException(String.format( "setShowActionsInCompactView: action %d out of bounds (max %d)", i, numActions - 1)); numActions, numActions - 1)); } for (int i = 0; i < MAX_MEDIA_BUTTONS_IN_COMPACT; i++) { if (i < numActionsToShow) { final Action action = mBuilder.mActions.get(mActionsToShowInCompact[i]); final RemoteViews button = generateMediaActionButton(action, getActionColor()); view.addView(com.android.internal.R.id.media_actions, button); bindMediaActionButton(view, MEDIA_BUTTON_IDS[i], action, getActionColor()); } else { view.setViewVisibility(MEDIA_BUTTON_IDS[i], View.GONE); } } handleImage(view); Loading Loading @@ -7949,12 +7968,12 @@ public class Notification implements Parcelable RemoteViews big = mBuilder.applyStandardTemplate( R.layout.notification_template_material_big_media, false, null /* result */); if (actionCount > 0) { big.removeAllViews(com.android.internal.R.id.media_actions); for (int i = 0; i < actionCount; i++) { final RemoteViews button = generateMediaActionButton(mBuilder.mActions.get(i), for (int i = 0; i < MAX_MEDIA_BUTTONS; i++) { if (i < actionCount) { bindMediaActionButton(big, MEDIA_BUTTON_IDS[i], mBuilder.mActions.get(i), getActionColor()); big.addView(com.android.internal.R.id.media_actions, button); } else { big.setViewVisibility(MEDIA_BUTTON_IDS[i], View.GONE); } } handleImage(big); Loading core/java/android/widget/RemoteViews.java +67 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.graphics.drawable.RippleDrawable; import android.net.Uri; import android.os.AsyncTask; import android.os.Binder; Loading Loading @@ -152,6 +153,7 @@ public class RemoteViews implements Parcelable, Filter { private static final int SET_REMOTE_INPUTS_ACTION_TAG = 18; private static final int LAYOUT_PARAM_ACTION_TAG = 19; private static final int OVERRIDE_TEXT_COLORS_TAG = 20; private static final int SET_RIPPLE_DRAWABLE_COLOR_TAG = 21; /** * Application that hosts the remote views. Loading Loading @@ -1122,6 +1124,53 @@ public class RemoteViews implements Parcelable, Filter { PorterDuff.Mode filterMode; } /** * Equivalent to calling * {@link RippleDrawable#setColor(ColorStateList)}, * on the {@link Drawable} of a given view. * <p> * The operation will be performed on the {@link Drawable} returned by the * target {@link View#getBackground()}. * <p> */ private class SetRippleDrawableColor extends Action { ColorStateList mColorStateList; SetRippleDrawableColor(int id, ColorStateList colorStateList) { this.viewId = id; this.mColorStateList = colorStateList; } SetRippleDrawableColor(Parcel parcel) { viewId = parcel.readInt(); mColorStateList = parcel.readParcelable(null); } public void writeToParcel(Parcel dest, int flags) { dest.writeInt(viewId); dest.writeParcelable(mColorStateList, 0); } @Override public void apply(View root, ViewGroup rootParent, OnClickHandler handler) { final View target = root.findViewById(viewId); if (target == null) return; // Pick the correct drawable to modify for this view Drawable targetDrawable = target.getBackground(); if (targetDrawable instanceof RippleDrawable) { ((RippleDrawable) targetDrawable.mutate()).setColor(mColorStateList); } } @Override public int getActionTag() { return SET_RIPPLE_DRAWABLE_COLOR_TAG; } } private final class ViewContentNavigation extends Action { final boolean mNext; Loading Loading @@ -2394,6 +2443,8 @@ public class RemoteViews implements Parcelable, Filter { return new LayoutParamAction(parcel); case OVERRIDE_TEXT_COLORS_TAG: return new OverrideTextColorsAction(parcel); case SET_RIPPLE_DRAWABLE_COLOR_TAG: return new SetRippleDrawableColor(parcel); default: throw new ActionException("Tag " + tag + " not found"); } Loading Loading @@ -2853,6 +2904,22 @@ public class RemoteViews implements Parcelable, Filter { addAction(new SetDrawableTint(viewId, targetBackground, colorFilter, mode)); } /** * @hide * Equivalent to calling * {@link RippleDrawable#setColor(ColorStateList)} on the {@link Drawable} of a given view, * assuming it's a {@link RippleDrawable}. * <p> * * @param viewId The id of the view that contains the target * {@link RippleDrawable} * @param colorStateList Specify a color for a * {@link ColorStateList} for this drawable. */ public void setRippleDrawableColor(int viewId, ColorStateList colorStateList) { addAction(new SetRippleDrawableColor(viewId, colorStateList)); } /** * @hide * Equivalent to calling {@link android.widget.ProgressBar#setProgressTintList}. Loading core/res/res/layout/notification_material_media_action.xml +1 −1 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ <ImageButton xmlns:android="http://schemas.android.com/apk/res/android" style="@android:style/Widget.Material.Button.Borderless.Small" android:id="@+id/action0" android:layout_width="@dimen/media_notification_action_button_size" android:layout_height="@dimen/media_notification_action_button_size" android:paddingBottom="8dp" Loading @@ -28,4 +27,5 @@ android:layout_marginEnd="2dp" android:gravity="center" android:background="@drawable/notification_material_media_action_background" android:visibility="gone" /> core/res/res/layout/notification_template_material_big_media.xml +20 −1 Original line number Diff line number Diff line Loading @@ -59,7 +59,26 @@ android:orientation="horizontal" android:layoutDirection="ltr" style="@style/NotificationMediaActionContainer" > <!-- media buttons will be added here --> <include layout="@layout/notification_material_media_action" android:id="@+id/action0" /> <include layout="@layout/notification_material_media_action" android:id="@+id/action1" /> <include layout="@layout/notification_material_media_action" android:id="@+id/action2" /> <include layout="@layout/notification_material_media_action" android:id="@+id/action3" /> <include layout="@layout/notification_material_media_action" android:id="@+id/action4" /> </LinearLayout> </LinearLayout> </com.android.internal.widget.MediaNotificationView> core/res/res/layout/notification_template_material_media.xml +12 −1 Original line number Diff line number Diff line Loading @@ -65,7 +65,18 @@ android:layoutDirection="ltr" android:orientation="horizontal" > <!-- media buttons will be added here --> <include layout="@layout/notification_material_media_action" android:id="@+id/action0" /> <include layout="@layout/notification_material_media_action" android:id="@+id/action1" /> <include layout="@layout/notification_material_media_action" android:id="@+id/action2" /> </LinearLayout> </LinearLayout> </FrameLayout> Loading
core/java/android/app/Notification.java +45 −26 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static com.android.internal.util.ContrastColorUtil.satisfiesTextContrast; import android.annotation.ColorInt; import android.annotation.DrawableRes; import android.annotation.IdRes; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; Loading @@ -37,6 +38,7 @@ import android.content.pm.ShortcutInfo; import android.content.res.ColorStateList; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; Loading Loading @@ -7759,8 +7761,17 @@ public class Notification implements Parcelable * @see Notification.Builder#setColorized(boolean) */ public static class MediaStyle extends Style { // Changing max media buttons requires also changing templates // (notification_template_material_media and notification_template_material_big_media). static final int MAX_MEDIA_BUTTONS_IN_COMPACT = 3; static final int MAX_MEDIA_BUTTONS = 5; @IdRes private static final int[] MEDIA_BUTTON_IDS = { R.id.action0, R.id.action1, R.id.action2, R.id.action3, R.id.action4, }; private int[] mActionsToShowInCompact = null; private MediaSession.Token mToken; Loading Loading @@ -7874,15 +7885,16 @@ public class Notification implements Parcelable return false; } private RemoteViews generateMediaActionButton(Action action, int color) { private void bindMediaActionButton(RemoteViews container, @IdRes int buttonId, Action action, int color) { final boolean tombstone = (action.actionIntent == null); RemoteViews button = new BuilderRemoteViews(mBuilder.mContext.getApplicationInfo(), R.layout.notification_material_media_action); button.setImageViewIcon(R.id.action0, action.getIcon()); container.setViewVisibility(buttonId, View.VISIBLE); container.setImageViewIcon(buttonId, action.getIcon()); // If the action buttons should not be tinted, then just use the default // notification color. Otherwise, just use the passed-in color. Configuration currentConfig = mBuilder.mContext.getResources().getConfiguration(); Resources resources = mBuilder.mContext.getResources(); Configuration currentConfig = resources.getConfiguration(); boolean inNightMode = (currentConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES; int tintColor = mBuilder.shouldTintActionButtons() || mBuilder.isColorized() Loading @@ -7890,13 +7902,21 @@ public class Notification implements Parcelable : ContrastColorUtil.resolveColor(mBuilder.mContext, Notification.COLOR_DEFAULT, inNightMode); button.setDrawableTint(R.id.action0, false, tintColor, container.setDrawableTint(buttonId, false, tintColor, PorterDuff.Mode.SRC_ATOP); final TypedArray typedArray = mBuilder.mContext.obtainStyledAttributes( new int[]{ android.R.attr.colorControlHighlight }); int rippleAlpha = Color.alpha(typedArray.getColor(0, 0)); typedArray.recycle(); int rippleColor = Color.argb(rippleAlpha, Color.red(tintColor), Color.green(tintColor), Color.blue(tintColor)); container.setRippleDrawableColor(buttonId, ColorStateList.valueOf(rippleColor)); if (!tombstone) { button.setOnClickPendingIntent(R.id.action0, action.actionIntent); container.setOnClickPendingIntent(buttonId, action.actionIntent); } button.setContentDescription(R.id.action0, action.title); return button; container.setContentDescription(buttonId, action.title); } private RemoteViews makeMediaContentView() { Loading @@ -7905,21 +7925,20 @@ public class Notification implements Parcelable null /* result */); final int numActions = mBuilder.mActions.size(); final int N = mActionsToShowInCompact == null final int numActionsToShow = mActionsToShowInCompact == null ? 0 : Math.min(mActionsToShowInCompact.length, MAX_MEDIA_BUTTONS_IN_COMPACT); view.removeAllViews(com.android.internal.R.id.media_actions); if (N > 0) { for (int i = 0; i < N; i++) { if (i >= numActions) { if (numActionsToShow > numActions) { throw new IllegalArgumentException(String.format( "setShowActionsInCompactView: action %d out of bounds (max %d)", i, numActions - 1)); numActions, numActions - 1)); } for (int i = 0; i < MAX_MEDIA_BUTTONS_IN_COMPACT; i++) { if (i < numActionsToShow) { final Action action = mBuilder.mActions.get(mActionsToShowInCompact[i]); final RemoteViews button = generateMediaActionButton(action, getActionColor()); view.addView(com.android.internal.R.id.media_actions, button); bindMediaActionButton(view, MEDIA_BUTTON_IDS[i], action, getActionColor()); } else { view.setViewVisibility(MEDIA_BUTTON_IDS[i], View.GONE); } } handleImage(view); Loading Loading @@ -7949,12 +7968,12 @@ public class Notification implements Parcelable RemoteViews big = mBuilder.applyStandardTemplate( R.layout.notification_template_material_big_media, false, null /* result */); if (actionCount > 0) { big.removeAllViews(com.android.internal.R.id.media_actions); for (int i = 0; i < actionCount; i++) { final RemoteViews button = generateMediaActionButton(mBuilder.mActions.get(i), for (int i = 0; i < MAX_MEDIA_BUTTONS; i++) { if (i < actionCount) { bindMediaActionButton(big, MEDIA_BUTTON_IDS[i], mBuilder.mActions.get(i), getActionColor()); big.addView(com.android.internal.R.id.media_actions, button); } else { big.setViewVisibility(MEDIA_BUTTON_IDS[i], View.GONE); } } handleImage(big); Loading
core/java/android/widget/RemoteViews.java +67 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.graphics.drawable.RippleDrawable; import android.net.Uri; import android.os.AsyncTask; import android.os.Binder; Loading Loading @@ -152,6 +153,7 @@ public class RemoteViews implements Parcelable, Filter { private static final int SET_REMOTE_INPUTS_ACTION_TAG = 18; private static final int LAYOUT_PARAM_ACTION_TAG = 19; private static final int OVERRIDE_TEXT_COLORS_TAG = 20; private static final int SET_RIPPLE_DRAWABLE_COLOR_TAG = 21; /** * Application that hosts the remote views. Loading Loading @@ -1122,6 +1124,53 @@ public class RemoteViews implements Parcelable, Filter { PorterDuff.Mode filterMode; } /** * Equivalent to calling * {@link RippleDrawable#setColor(ColorStateList)}, * on the {@link Drawable} of a given view. * <p> * The operation will be performed on the {@link Drawable} returned by the * target {@link View#getBackground()}. * <p> */ private class SetRippleDrawableColor extends Action { ColorStateList mColorStateList; SetRippleDrawableColor(int id, ColorStateList colorStateList) { this.viewId = id; this.mColorStateList = colorStateList; } SetRippleDrawableColor(Parcel parcel) { viewId = parcel.readInt(); mColorStateList = parcel.readParcelable(null); } public void writeToParcel(Parcel dest, int flags) { dest.writeInt(viewId); dest.writeParcelable(mColorStateList, 0); } @Override public void apply(View root, ViewGroup rootParent, OnClickHandler handler) { final View target = root.findViewById(viewId); if (target == null) return; // Pick the correct drawable to modify for this view Drawable targetDrawable = target.getBackground(); if (targetDrawable instanceof RippleDrawable) { ((RippleDrawable) targetDrawable.mutate()).setColor(mColorStateList); } } @Override public int getActionTag() { return SET_RIPPLE_DRAWABLE_COLOR_TAG; } } private final class ViewContentNavigation extends Action { final boolean mNext; Loading Loading @@ -2394,6 +2443,8 @@ public class RemoteViews implements Parcelable, Filter { return new LayoutParamAction(parcel); case OVERRIDE_TEXT_COLORS_TAG: return new OverrideTextColorsAction(parcel); case SET_RIPPLE_DRAWABLE_COLOR_TAG: return new SetRippleDrawableColor(parcel); default: throw new ActionException("Tag " + tag + " not found"); } Loading Loading @@ -2853,6 +2904,22 @@ public class RemoteViews implements Parcelable, Filter { addAction(new SetDrawableTint(viewId, targetBackground, colorFilter, mode)); } /** * @hide * Equivalent to calling * {@link RippleDrawable#setColor(ColorStateList)} on the {@link Drawable} of a given view, * assuming it's a {@link RippleDrawable}. * <p> * * @param viewId The id of the view that contains the target * {@link RippleDrawable} * @param colorStateList Specify a color for a * {@link ColorStateList} for this drawable. */ public void setRippleDrawableColor(int viewId, ColorStateList colorStateList) { addAction(new SetRippleDrawableColor(viewId, colorStateList)); } /** * @hide * Equivalent to calling {@link android.widget.ProgressBar#setProgressTintList}. Loading
core/res/res/layout/notification_material_media_action.xml +1 −1 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ <ImageButton xmlns:android="http://schemas.android.com/apk/res/android" style="@android:style/Widget.Material.Button.Borderless.Small" android:id="@+id/action0" android:layout_width="@dimen/media_notification_action_button_size" android:layout_height="@dimen/media_notification_action_button_size" android:paddingBottom="8dp" Loading @@ -28,4 +27,5 @@ android:layout_marginEnd="2dp" android:gravity="center" android:background="@drawable/notification_material_media_action_background" android:visibility="gone" />
core/res/res/layout/notification_template_material_big_media.xml +20 −1 Original line number Diff line number Diff line Loading @@ -59,7 +59,26 @@ android:orientation="horizontal" android:layoutDirection="ltr" style="@style/NotificationMediaActionContainer" > <!-- media buttons will be added here --> <include layout="@layout/notification_material_media_action" android:id="@+id/action0" /> <include layout="@layout/notification_material_media_action" android:id="@+id/action1" /> <include layout="@layout/notification_material_media_action" android:id="@+id/action2" /> <include layout="@layout/notification_material_media_action" android:id="@+id/action3" /> <include layout="@layout/notification_material_media_action" android:id="@+id/action4" /> </LinearLayout> </LinearLayout> </com.android.internal.widget.MediaNotificationView>
core/res/res/layout/notification_template_material_media.xml +12 −1 Original line number Diff line number Diff line Loading @@ -65,7 +65,18 @@ android:layoutDirection="ltr" android:orientation="horizontal" > <!-- media buttons will be added here --> <include layout="@layout/notification_material_media_action" android:id="@+id/action0" /> <include layout="@layout/notification_material_media_action" android:id="@+id/action1" /> <include layout="@layout/notification_material_media_action" android:id="@+id/action2" /> </LinearLayout> </LinearLayout> </FrameLayout>