Merge "Fixes touch ripples on media buttons."

This commit is contained in:
TreeHugger Robot
2018-10-15 17:21:17 +00:00
committed by Android (Google) Code Review
7 changed files with 153 additions and 31 deletions

View File

@@ -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;
@@ -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;
@@ -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;
@@ -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()
@@ -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() {
@@ -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) {
throw new IllegalArgumentException(String.format(
"setShowActionsInCompactView: action %d out of bounds (max %d)",
i, numActions - 1));
}
if (numActionsToShow > numActions) {
throw new IllegalArgumentException(String.format(
"setShowActionsInCompactView: action %d out of bounds (max %d)",
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);
@@ -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);

View File

@@ -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;
@@ -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.
@@ -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;
@@ -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");
}
@@ -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}.