summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Kirill Grouchnikov <kirillg@google.com> 2017-03-21 13:52:09 -0400
committer Kirill Grouchnikov <kirillg@google.com> 2017-03-22 11:05:49 -0400
commit6eea0d2a4ce20c9709d2cc9c24c823f7ef795c0a (patch)
treea963705b0abbc665de31e07c3f71c9ebf022f810
parent9a4b2ab18cc54d954f6d6a3981af10ec13acbb0b (diff)
Add support for tinting icon menus
Test: CTS tests in separate CL (same topic) Bug: 31545315 Change-Id: I8877c77dab9b7b229b4246012b9380beadeb4790
-rw-r--r--api/current.txt6
-rw-r--r--api/system-current.txt6
-rw-r--r--api/test-current.txt6
-rw-r--r--core/java/android/view/MenuInflater.java29
-rw-r--r--core/java/android/view/MenuItem.java56
-rw-r--r--core/java/com/android/internal/view/menu/ActionMenuItem.java57
-rw-r--r--core/java/com/android/internal/view/menu/MenuItemImpl.java183
-rw-r--r--core/res/res/values/attrs.xml24
-rw-r--r--core/res/res/values/public.xml2
9 files changed, 308 insertions, 61 deletions
diff --git a/api/current.txt b/api/current.txt
index 6ecf213450ac..06d8d562e19d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -696,6 +696,8 @@ package android {
field public static final int hyphenationFrequency = 16843998; // 0x10104de
field public static final int icon = 16842754; // 0x1010002
field public static final int iconPreview = 16843337; // 0x1010249
+ field public static final int iconTint = 16844129; // 0x1010561
+ field public static final int iconTintMode = 16844130; // 0x1010562
field public static final int iconifiedByDefault = 16843514; // 0x10102fa
field public static final int id = 16842960; // 0x10100d0
field public static final int ignoreGravity = 16843263; // 0x10101ff
@@ -44595,6 +44597,8 @@ package android.view {
method public default java.lang.CharSequence getContentDescription();
method public abstract int getGroupId();
method public abstract android.graphics.drawable.Drawable getIcon();
+ method public default android.content.res.ColorStateList getIconTintList();
+ method public default android.graphics.PorterDuff.Mode getIconTintMode();
method public abstract android.content.Intent getIntent();
method public abstract int getItemId();
method public abstract android.view.ContextMenu.ContextMenuInfo getMenuInfo();
@@ -44622,6 +44626,8 @@ package android.view {
method public abstract android.view.MenuItem setEnabled(boolean);
method public abstract android.view.MenuItem setIcon(android.graphics.drawable.Drawable);
method public abstract android.view.MenuItem setIcon(int);
+ method public default android.view.MenuItem setIconTintList(android.content.res.ColorStateList);
+ method public default android.view.MenuItem setIconTintMode(android.graphics.PorterDuff.Mode);
method public abstract android.view.MenuItem setIntent(android.content.Intent);
method public abstract android.view.MenuItem setNumericShortcut(char);
method public default android.view.MenuItem setNumericShortcut(char, int);
diff --git a/api/system-current.txt b/api/system-current.txt
index 230343329e6e..d39d43364180 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -809,6 +809,8 @@ package android {
field public static final int hyphenationFrequency = 16843998; // 0x10104de
field public static final int icon = 16842754; // 0x1010002
field public static final int iconPreview = 16843337; // 0x1010249
+ field public static final int iconTint = 16844129; // 0x1010561
+ field public static final int iconTintMode = 16844130; // 0x1010562
field public static final int iconifiedByDefault = 16843514; // 0x10102fa
field public static final int id = 16842960; // 0x10100d0
field public static final int ignoreGravity = 16843263; // 0x10101ff
@@ -48048,6 +48050,8 @@ package android.view {
method public default java.lang.CharSequence getContentDescription();
method public abstract int getGroupId();
method public abstract android.graphics.drawable.Drawable getIcon();
+ method public default android.content.res.ColorStateList getIconTintList();
+ method public default android.graphics.PorterDuff.Mode getIconTintMode();
method public abstract android.content.Intent getIntent();
method public abstract int getItemId();
method public abstract android.view.ContextMenu.ContextMenuInfo getMenuInfo();
@@ -48075,6 +48079,8 @@ package android.view {
method public abstract android.view.MenuItem setEnabled(boolean);
method public abstract android.view.MenuItem setIcon(android.graphics.drawable.Drawable);
method public abstract android.view.MenuItem setIcon(int);
+ method public default android.view.MenuItem setIconTintList(android.content.res.ColorStateList);
+ method public default android.view.MenuItem setIconTintMode(android.graphics.PorterDuff.Mode);
method public abstract android.view.MenuItem setIntent(android.content.Intent);
method public abstract android.view.MenuItem setNumericShortcut(char);
method public default android.view.MenuItem setNumericShortcut(char, int);
diff --git a/api/test-current.txt b/api/test-current.txt
index 80e100277d8f..53de23fdedce 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -696,6 +696,8 @@ package android {
field public static final int hyphenationFrequency = 16843998; // 0x10104de
field public static final int icon = 16842754; // 0x1010002
field public static final int iconPreview = 16843337; // 0x1010249
+ field public static final int iconTint = 16844129; // 0x1010561
+ field public static final int iconTintMode = 16844130; // 0x1010562
field public static final int iconifiedByDefault = 16843514; // 0x10102fa
field public static final int id = 16842960; // 0x10100d0
field public static final int ignoreGravity = 16843263; // 0x10101ff
@@ -44955,6 +44957,8 @@ package android.view {
method public default java.lang.CharSequence getContentDescription();
method public abstract int getGroupId();
method public abstract android.graphics.drawable.Drawable getIcon();
+ method public default android.content.res.ColorStateList getIconTintList();
+ method public default android.graphics.PorterDuff.Mode getIconTintMode();
method public abstract android.content.Intent getIntent();
method public abstract int getItemId();
method public abstract android.view.ContextMenu.ContextMenuInfo getMenuInfo();
@@ -44982,6 +44986,8 @@ package android.view {
method public abstract android.view.MenuItem setEnabled(boolean);
method public abstract android.view.MenuItem setIcon(android.graphics.drawable.Drawable);
method public abstract android.view.MenuItem setIcon(int);
+ method public default android.view.MenuItem setIconTintList(android.content.res.ColorStateList);
+ method public default android.view.MenuItem setIconTintMode(android.graphics.PorterDuff.Mode);
method public abstract android.view.MenuItem setIntent(android.content.Intent);
method public abstract android.view.MenuItem setNumericShortcut(char);
method public default android.view.MenuItem setNumericShortcut(char, int);
diff --git a/core/java/android/view/MenuInflater.java b/core/java/android/view/MenuInflater.java
index 6574bc0a1db8..a3cd0ba4b823 100644
--- a/core/java/android/view/MenuInflater.java
+++ b/core/java/android/view/MenuInflater.java
@@ -20,8 +20,11 @@ import android.annotation.MenuRes;
import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
+import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
@@ -304,6 +307,8 @@ public class MenuInflater {
private CharSequence itemTitle;
private CharSequence itemTitleCondensed;
private int itemIconResId;
+ private ColorStateList itemIconTintList = null;
+ private PorterDuff.Mode itemIconTintMode = null;
private char itemAlphabeticShortcut;
private int itemAlphabeticModifiers;
private char itemNumericShortcut;
@@ -395,6 +400,22 @@ public class MenuInflater {
itemTitle = a.getText(com.android.internal.R.styleable.MenuItem_title);
itemTitleCondensed = a.getText(com.android.internal.R.styleable.MenuItem_titleCondensed);
itemIconResId = a.getResourceId(com.android.internal.R.styleable.MenuItem_icon, 0);
+ if (a.hasValue(com.android.internal.R.styleable.MenuItem_iconTintMode)) {
+ itemIconTintMode = Drawable.parseTintMode(a.getInt(
+ com.android.internal.R.styleable.MenuItem_iconTintMode, -1),
+ itemIconTintMode);
+ } else {
+ // Reset to null so that it's not carried over to the next item
+ itemIconTintMode = null;
+ }
+ if (a.hasValue(com.android.internal.R.styleable.MenuItem_iconTint)) {
+ itemIconTintList = a.getColorStateList(
+ com.android.internal.R.styleable.MenuItem_iconTint);
+ } else {
+ // Reset to null so that it's not carried over to the next item
+ itemIconTintList = null;
+ }
+
itemAlphabeticShortcut =
getShortcut(a.getString(com.android.internal.R.styleable.MenuItem_alphabeticShortcut));
itemAlphabeticModifiers =
@@ -466,6 +487,14 @@ public class MenuInflater {
item.setShowAsAction(itemShowAsAction);
}
+ if (itemIconTintMode != null) {
+ item.setIconTintMode(itemIconTintMode);
+ }
+
+ if (itemIconTintList != null) {
+ item.setIconTintList(itemIconTintList);
+ }
+
if (itemListenerMethodName != null) {
if (mContext.isRestricted()) {
throw new IllegalStateException("The android:onClick attribute cannot "
diff --git a/core/java/android/view/MenuItem.java b/core/java/android/view/MenuItem.java
index 6aaaedbeb1af..b171ad0cf52f 100644
--- a/core/java/android/view/MenuItem.java
+++ b/core/java/android/view/MenuItem.java
@@ -18,9 +18,12 @@ package android.view;
import android.annotation.DrawableRes;
import android.annotation.LayoutRes;
+import android.annotation.Nullable;
import android.annotation.StringRes;
import android.app.Activity;
import android.content.Intent;
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View.OnCreateContextMenuListener;
@@ -221,11 +224,62 @@ public interface MenuItem {
/**
* Returns the icon for this item as a Drawable (getting it from resources if it hasn't been
- * loaded before).
+ * loaded before). Note that if you call {@link #setIconTintList(ColorStateList)} or
+ * {@link #setIconTintMode(PorterDuff.Mode)} on this item, and you use a custom menu presenter
+ * in your application, you have to apply the tinting explicitly on the {@link Drawable}
+ * returned by this method.
*
* @return The icon as a Drawable.
*/
public Drawable getIcon();
+
+ /**
+ * Applies a tint to this item's icon. Does not modify the
+ * current tint mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
+ * <p>
+ * Subsequent calls to {@link #setIcon(Drawable)} or {@link #setIcon(int)} will
+ * automatically mutate the icon and apply the specified tint and
+ * tint mode using
+ * {@link Drawable#setTintList(ColorStateList)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#MenuItem_iconTint
+ * @see #getIconTintList()
+ * @see Drawable#setTintList(ColorStateList)
+ */
+ public default MenuItem setIconTintList(@Nullable ColorStateList tint) { return this; }
+
+ /**
+ * @return the tint applied to this item's icon
+ * @attr ref android.R.styleable#MenuItem_iconTint
+ * @see #setIconTintList(ColorStateList)
+ */
+ @Nullable
+ public default ColorStateList getIconTintList() { return null; }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setIconTintList(ColorStateList)} to this item's icon. The default mode is
+ * {@link PorterDuff.Mode#SRC_IN}.
+ *
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#MenuItem_iconTintMode
+ * @see #setIconTintList(ColorStateList)
+ * @see Drawable#setTintMode(PorterDuff.Mode)
+ */
+ public default MenuItem setIconTintMode(@Nullable PorterDuff.Mode tintMode) { return this; }
+
+ /**
+ * Returns the blending mode used to apply the tint to this item's icon, if specified.
+ *
+ * @return the blending mode used to apply the tint to this item's icon
+ * @attr ref android.R.styleable#MenuItem_iconTintMode
+ * @see #setIconTintMode(PorterDuff.Mode)
+ */
+ @Nullable
+ public default PorterDuff.Mode getIconTintMode() { return null; }
/**
* Change the Intent associated with this item. By default there is no
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItem.java b/core/java/com/android/internal/view/menu/ActionMenuItem.java
index ac226ddb8ea9..b807a42e922e 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuItem.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuItem.java
@@ -16,8 +16,11 @@
package com.android.internal.view.menu;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.view.ActionProvider;
import android.view.ContextMenu.ContextMenuInfo;
@@ -45,6 +48,10 @@ public class ActionMenuItem implements MenuItem {
private Drawable mIconDrawable;
private int mIconResId = NO_ICON;
+ private ColorStateList mIconTintList = null;
+ private PorterDuff.Mode mIconTintMode = null;
+ private boolean mHasIconTint = false;
+ private boolean mHasIconTintMode = false;
private Context mContext;
@@ -178,15 +185,65 @@ public class ActionMenuItem implements MenuItem {
public MenuItem setIcon(Drawable icon) {
mIconDrawable = icon;
mIconResId = NO_ICON;
+
+ applyIconTint();
return this;
}
public MenuItem setIcon(int iconRes) {
mIconResId = iconRes;
mIconDrawable = mContext.getDrawable(iconRes);
+
+ applyIconTint();
return this;
}
+ @Override
+ public MenuItem setIconTintList(@Nullable ColorStateList iconTintList) {
+ mIconTintList = iconTintList;
+ mHasIconTint = true;
+
+ applyIconTint();
+
+ return this;
+ }
+
+ @Nullable
+ @Override
+ public ColorStateList getIconTintList() {
+ return mIconTintList;
+ }
+
+ @Override
+ public MenuItem setIconTintMode(PorterDuff.Mode iconTintMode) {
+ mIconTintMode = iconTintMode;
+ mHasIconTintMode = true;
+
+ applyIconTint();
+
+ return this;
+ }
+
+ @Nullable
+ @Override
+ public PorterDuff.Mode getIconTintMode() {
+ return mIconTintMode;
+ }
+
+ private void applyIconTint() {
+ if (mIconDrawable != null && (mHasIconTint || mHasIconTintMode)) {
+ mIconDrawable = mIconDrawable.mutate();
+
+ if (mHasIconTint) {
+ mIconDrawable.setTintList(mIconTintList);
+ }
+
+ if (mHasIconTintMode) {
+ mIconDrawable.setTintMode(mIconTintMode);
+ }
+ }
+ }
+
public MenuItem setIntent(Intent intent) {
mIntent = intent;
return this;
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index 9310d14ab667..101623c6b7e3 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -18,9 +18,12 @@ package com.android.internal.view.menu;
import com.android.internal.view.menu.MenuView.ItemView;
+import android.annotation.Nullable;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.ActionProvider;
@@ -38,7 +41,7 @@ import android.widget.LinearLayout;
*/
public final class MenuItemImpl implements MenuItem {
private static final String TAG = "MenuItemImpl";
-
+
private static final int SHOW_AS_ACTION_MASK = SHOW_AS_ACTION_NEVER |
SHOW_AS_ACTION_IF_ROOM |
SHOW_AS_ACTION_ALWAYS;
@@ -61,14 +64,20 @@ public final class MenuItemImpl implements MenuItem {
* The icon's resource ID which is used to get the Drawable when it is
* needed (if the Drawable isn't already obtained--only one of the two is
* needed).
- */
+ */
private int mIconResId = NO_ICON;
-
+
+ private ColorStateList mIconTintList = null;
+ private PorterDuff.Mode mIconTintMode = null;
+ private boolean mHasIconTint = false;
+ private boolean mHasIconTintMode = false;
+ private boolean mNeedToApplyIconTint = false;
+
/** The menu to which this item belongs */
private MenuBuilder mMenu;
/** If this item should launch a sub menu, this is the sub menu to launch */
private SubMenuBuilder mSubMenu;
-
+
private Runnable mItemCallback;
private MenuItem.OnMenuItemClickListener mClickListener;
@@ -124,7 +133,7 @@ public final class MenuItemImpl implements MenuItem {
String lang = menu.getContext().getResources().getConfiguration().locale.toString();
if (sPrependShortcutLabel == null || !lang.equals(sLanguage)) {
sLanguage = lang;
- // This is instantiated from the UI thread, so no chance of sync issues
+ // This is instantiated from the UI thread, so no chance of sync issues
sPrependShortcutLabel = menu.getContext().getResources().getString(
com.android.internal.R.string.prepend_shortcut_label);
sEnterShortcutLabel = menu.getContext().getResources().getString(
@@ -134,7 +143,7 @@ public final class MenuItemImpl implements MenuItem {
sSpaceShortcutLabel = menu.getContext().getResources().getString(
com.android.internal.R.string.menu_space_shortcut_label);
}
-
+
mMenu = menu;
mId = id;
mGroup = group;
@@ -143,10 +152,10 @@ public final class MenuItemImpl implements MenuItem {
mTitle = title;
mShowAsAction = showAsAction;
}
-
+
/**
* Invokes the item by calling various listeners or callbacks.
- *
+ *
* @return true if the invocation was handled, false otherwise
*/
public boolean invoke() {
@@ -179,7 +188,7 @@ public final class MenuItemImpl implements MenuItem {
return false;
}
-
+
public boolean isEnabled() {
return (mFlags & ENABLED) != 0;
}
@@ -192,10 +201,10 @@ public final class MenuItemImpl implements MenuItem {
}
mMenu.onItemsChanged(false);
-
+
return this;
}
-
+
public int getGroupId() {
return mGroup;
}
@@ -208,11 +217,11 @@ public final class MenuItemImpl implements MenuItem {
public int getOrder() {
return mCategoryOrder;
}
-
+
public int getOrdering() {
- return mOrdering;
+ return mOrdering;
}
-
+
public Intent getIntent() {
return mIntent;
}
@@ -225,7 +234,7 @@ public final class MenuItemImpl implements MenuItem {
Runnable getCallback() {
return mItemCallback;
}
-
+
public MenuItem setCallback(Runnable callback) {
mItemCallback = callback;
return this;
@@ -273,11 +282,11 @@ public final class MenuItemImpl implements MenuItem {
public MenuItem setNumericShortcut(char numericChar) {
if (mShortcutNumericChar == numericChar) return this;
-
+
mShortcutNumericChar = numericChar;
-
+
mMenu.onItemsChanged(false);
-
+
return this;
}
@@ -297,9 +306,9 @@ public final class MenuItemImpl implements MenuItem {
public MenuItem setShortcut(char numericChar, char alphaChar) {
mShortcutNumericChar = numericChar;
mShortcutAlphabeticChar = Character.toLowerCase(alphaChar);
-
+
mMenu.onItemsChanged(false);
-
+
return this;
}
@@ -321,7 +330,7 @@ public final class MenuItemImpl implements MenuItem {
char getShortcut() {
return (mMenu.isQwertyMode() ? mShortcutAlphabeticChar : mShortcutNumericChar);
}
-
+
/**
* @return The label to show for the shortcut. This includes the chording
* key (for example 'Menu+a'). Also, any non-human readable
@@ -333,30 +342,30 @@ public final class MenuItemImpl implements MenuItem {
if (shortcut == 0) {
return "";
}
-
+
StringBuilder sb = new StringBuilder(sPrependShortcutLabel);
switch (shortcut) {
-
+
case '\n':
sb.append(sEnterShortcutLabel);
break;
-
+
case '\b':
sb.append(sDeleteShortcutLabel);
break;
-
+
case ' ':
sb.append(sSpaceShortcutLabel);
break;
-
+
default:
sb.append(shortcut);
break;
}
-
+
return sb.toString();
}
-
+
/**
* @return Whether this menu item should be showing shortcuts (depends on
* whether the menu should show shortcuts and whether this item has
@@ -366,7 +375,7 @@ public final class MenuItemImpl implements MenuItem {
// Show shortcuts if the menu is supposed to show shortcuts AND this item has a shortcut
return mMenu.isShortcutsVisible() && (getShortcut() != 0);
}
-
+
public SubMenu getSubMenu() {
return mSubMenu;
}
@@ -377,10 +386,10 @@ public final class MenuItemImpl implements MenuItem {
void setSubMenu(SubMenuBuilder subMenu) {
mSubMenu = subMenu;
-
+
subMenu.setHeaderTitle(getTitle());
}
-
+
@ViewDebug.CapturedViewProperty
public CharSequence getTitle() {
return mTitle;
@@ -388,7 +397,7 @@ public final class MenuItemImpl implements MenuItem {
/**
* Gets the title for a particular {@link ItemView}
- *
+ *
* @param itemView The ItemView that is receiving the title
* @return Either the title or condensed title based on what the ItemView
* prefers
@@ -403,68 +412,122 @@ public final class MenuItemImpl implements MenuItem {
mTitle = title;
mMenu.onItemsChanged(false);
-
+
if (mSubMenu != null) {
mSubMenu.setHeaderTitle(title);
}
-
+
return this;
}
-
+
public MenuItem setTitle(int title) {
return setTitle(mMenu.getContext().getString(title));
}
-
+
public CharSequence getTitleCondensed() {
return mTitleCondensed != null ? mTitleCondensed : mTitle;
}
-
+
public MenuItem setTitleCondensed(CharSequence title) {
mTitleCondensed = title;
- // Could use getTitle() in the loop below, but just cache what it would do here
+ // Could use getTitle() in the loop below, but just cache what it would do here
if (title == null) {
title = mTitle;
}
-
+
mMenu.onItemsChanged(false);
-
+
return this;
}
public Drawable getIcon() {
if (mIconDrawable != null) {
- return mIconDrawable;
+ return applyIconTintIfNecessary(mIconDrawable);
}
if (mIconResId != NO_ICON) {
Drawable icon = mMenu.getContext().getDrawable(mIconResId);
mIconResId = NO_ICON;
mIconDrawable = icon;
- return icon;
+ return applyIconTintIfNecessary(icon);
}
-
+
return null;
}
-
+
public MenuItem setIcon(Drawable icon) {
mIconResId = NO_ICON;
mIconDrawable = icon;
+ mNeedToApplyIconTint = true;
mMenu.onItemsChanged(false);
-
+
return this;
}
-
+
public MenuItem setIcon(int iconResId) {
mIconDrawable = null;
mIconResId = iconResId;
+ mNeedToApplyIconTint = true;
// If we have a view, we need to push the Drawable to them
mMenu.onItemsChanged(false);
-
+
return this;
}
-
+
+ @Override
+ public MenuItem setIconTintList(@Nullable ColorStateList iconTintList) {
+ mIconTintList = iconTintList;
+ mHasIconTint = true;
+ mNeedToApplyIconTint = true;
+
+ mMenu.onItemsChanged(false);
+
+ return this;
+ }
+
+ @Nullable
+ @Override
+ public ColorStateList getIconTintList() {
+ return mIconTintList;
+ }
+
+ @Override
+ public MenuItem setIconTintMode(PorterDuff.Mode iconTintMode) {
+ mIconTintMode = iconTintMode;
+ mHasIconTintMode = true;
+ mNeedToApplyIconTint = true;
+
+ mMenu.onItemsChanged(false);
+
+ return this;
+ }
+
+ @Nullable
+ @Override
+ public PorterDuff.Mode getIconTintMode() {
+ return mIconTintMode;
+ }
+
+ private Drawable applyIconTintIfNecessary(Drawable icon) {
+ if (icon != null && mNeedToApplyIconTint && (mHasIconTint || mHasIconTintMode)) {
+ icon = icon.mutate();
+
+ if (mHasIconTint) {
+ icon.setTintList(mIconTintList);
+ }
+
+ if (mHasIconTintMode) {
+ icon.setTintMode(mIconTintMode);
+ }
+
+ mNeedToApplyIconTint = false;
+ }
+
+ return icon;
+ }
+
public boolean isCheckable() {
return (mFlags & CHECKABLE) == CHECKABLE;
}
@@ -475,7 +538,7 @@ public final class MenuItemImpl implements MenuItem {
if (oldFlags != mFlags) {
mMenu.onItemsChanged(false);
}
-
+
return this;
}
@@ -486,7 +549,7 @@ public final class MenuItemImpl implements MenuItem {
public boolean isExclusiveCheckable() {
return (mFlags & EXCLUSIVE) != 0;
}
-
+
public boolean isChecked() {
return (mFlags & CHECKED) == CHECKED;
}
@@ -499,7 +562,7 @@ public final class MenuItemImpl implements MenuItem {
} else {
setCheckedInt(checked);
}
-
+
return this;
}
@@ -510,7 +573,7 @@ public final class MenuItemImpl implements MenuItem {
mMenu.onItemsChanged(false);
}
}
-
+
public boolean isVisible() {
if (mActionProvider != null && mActionProvider.overridesItemVisibility()) {
return (mFlags & HIDDEN) == 0 && mActionProvider.isVisible();
@@ -523,7 +586,7 @@ public final class MenuItemImpl implements MenuItem {
* parent menu of a change in this item, so this should only be called from
* methods that will eventually trigger this change. If unsure, use {@link #setVisible(boolean)}
* instead.
- *
+ *
* @param shown Whether to show (true) or hide (false).
* @return Whether the item's shown state was changed
*/
@@ -532,13 +595,13 @@ public final class MenuItemImpl implements MenuItem {
mFlags = (mFlags & ~HIDDEN) | (shown ? 0 : HIDDEN);
return oldFlags != mFlags;
}
-
+
public MenuItem setVisible(boolean shown) {
// Try to set the shown state to the given state. If the shown state was changed
// (i.e. the previous state isn't the same as given state), notify the parent menu that
// the shown state has changed for this item
if (setVisibleInt(shown)) mMenu.onItemVisibleChanged(this);
-
+
return this;
}
@@ -546,7 +609,7 @@ public final class MenuItemImpl implements MenuItem {
mClickListener = clickListener;
return this;
}
-
+
@Override
public String toString() {
return mTitle != null ? mTitle.toString() : null;
@@ -555,7 +618,7 @@ public final class MenuItemImpl implements MenuItem {
void setMenuInfo(ContextMenuInfo menuInfo) {
mMenuInfo = menuInfo;
}
-
+
public ContextMenuInfo getMenuInfo() {
return mMenuInfo;
}
@@ -570,15 +633,15 @@ public final class MenuItemImpl implements MenuItem {
public boolean shouldShowIcon() {
return mMenu.getOptionalIconsVisible();
}
-
+
public boolean isActionButton() {
return (mFlags & IS_ACTION) == IS_ACTION;
}
-
+
public boolean requestsActionButton() {
return (mShowAsAction & SHOW_AS_ACTION_IF_ROOM) == SHOW_AS_ACTION_IF_ROOM;
}
-
+
public boolean requiresActionButton() {
return (mShowAsAction & SHOW_AS_ACTION_ALWAYS) == SHOW_AS_ACTION_ALWAYS;
}
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index e1068ead93a9..3a1cf77edc12 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -7010,6 +7010,30 @@
the title should be sufficient in describing this item. -->
<attr name="icon" />
+ <!-- Tint to apply to the icon. -->
+ <attr name="iconTint" format="color" />
+
+ <!-- Blending mode used to apply the icon tint. -->
+ <attr name="iconTintMode">
+ <!-- The tint is drawn on top of the icon.
+ [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+ <enum name="src_over" value="3" />
+ <!-- The tint is masked by the alpha channel of the icon. The icon’s
+ color channels are thrown out. [Sa * Da, Sc * Da] -->
+ <enum name="src_in" value="5" />
+ <!-- The tint is drawn above the icon, but with the icon’s alpha
+ channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+ <enum name="src_atop" value="9" />
+ <!-- Multiplies the color and alpha channels of the icon with those of
+ the tint. [Sa * Da, Sc * Dc] -->
+ <enum name="multiply" value="14" />
+ <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+ <enum name="screen" value="15" />
+ <!-- Combines the tint and icon color and alpha channels, clamping the
+ result to valid color values. Saturate(S + D) -->
+ <enum name="add" value="16" />
+ </attr>
+
<!-- The alphabetic shortcut key. This is the shortcut when using a keyboard
with alphabetic keys. -->
<attr name="alphabeticShortcut" format="string" />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index baad14812be3..d6b5527bb590 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2810,6 +2810,8 @@
<public name="isFeatureSplit" />
<public name="singleLineTitle" />
<public name="fontProviderCerts" />
+ <public name="iconTint" />
+ <public name="iconTintMode" />
</public-group>
<public-group type="style" first-id="0x010302e0">