Added song track info

This commit is contained in:
h4h13 2020-01-06 08:42:32 +05:30
parent 9b89259178
commit 813fb86073
55 changed files with 2267 additions and 1528 deletions

View file

@ -17,7 +17,6 @@ import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RadioButton;
import androidx.annotation.CheckResult;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
@ -36,55 +35,266 @@ import androidx.appcompat.widget.AppCompatImageView;
import androidx.appcompat.widget.Toolbar;
import androidx.appcompat.widget.ToolbarWidgetWrapper;
import androidx.core.graphics.drawable.DrawableCompat;
import code.name.monkey.appthemehelper.R;
import code.name.monkey.appthemehelper.ThemeStore;
import java.lang.reflect.Field;
import java.util.ArrayList;
import code.name.monkey.appthemehelper.R;
import code.name.monkey.appthemehelper.ThemeStore;
public final class ToolbarContentTintHelper {
private ToolbarContentTintHelper() {
}
public static class InternalToolbarContentTintUtil {
public static void tintAllIcons(Menu menu, final int color) {
for (int i = 0; i < menu.size(); ++i) {
final MenuItem item = menu.getItem(i);
tintMenuItemIcon(color, item);
tintShareIconIfPresent(color, item);
}
}
public static final class SearchViewTintUtil {
private static void tintMenuItemIcon(int color, MenuItem item) {
final Drawable drawable = item.getIcon();
if (drawable != null) {
final Drawable wrapped = DrawableCompat.wrap(drawable);
drawable.mutate();
DrawableCompat.setTint(wrapped, color);
item.setIcon(drawable);
}
}
public static void setSearchViewContentColor(View searchView, final @ColorInt int color) {
if (searchView == null) {
return;
}
final Class<?> cls = searchView.getClass();
try {
final Field mSearchSrcTextViewField = cls.getDeclaredField("mSearchSrcTextView");
mSearchSrcTextViewField.setAccessible(true);
final EditText mSearchSrcTextView = (EditText) mSearchSrcTextViewField.get(searchView);
mSearchSrcTextView.setTextColor(color);
mSearchSrcTextView.setHintTextColor(ColorUtil.INSTANCE.adjustAlpha(color, 0.5f));
TintHelper.setCursorTint(mSearchSrcTextView, color);
private static void tintShareIconIfPresent(int color, MenuItem item) {
if (item.getActionView() != null) {
final View actionView = item.getActionView();
final View expandActivitiesButton = actionView.findViewById(R.id.expand_activities_button);
if (expandActivitiesButton != null) {
final ImageView image = (ImageView) expandActivitiesButton.findViewById(R.id.image);
if (image != null) {
final Drawable drawable = image.getDrawable();
final Drawable wrapped = DrawableCompat.wrap(drawable);
drawable.mutate();
DrawableCompat.setTint(wrapped, color);
image.setImageDrawable(drawable);
Field field = cls.getDeclaredField("mSearchButton");
tintImageView(searchView, field, color);
field = cls.getDeclaredField("mGoButton");
tintImageView(searchView, field, color);
field = cls.getDeclaredField("mCloseButton");
tintImageView(searchView, field, color);
field = cls.getDeclaredField("mVoiceButton");
tintImageView(searchView, field, color);
} catch (Exception e) {
e.printStackTrace();
}
}
private SearchViewTintUtil() {
}
private static void tintImageView(Object target, Field field, final @ColorInt int color)
throws Exception {
field.setAccessible(true);
final ImageView imageView = (ImageView) field.get(target);
if (imageView.getDrawable() != null) {
imageView
.setImageDrawable(
TintHelper.createTintedDrawable(imageView.getDrawable(), color));
}
}
}
public static void applyOverflowMenuTint(final @NonNull Context context, final Toolbar toolbar,
final @ColorInt int color) {
if (toolbar == null) {
return;
}
toolbar.post(new Runnable() {
@Override
public void run() {
try {
Field f1 = Toolbar.class.getDeclaredField("mMenuView");
f1.setAccessible(true);
ActionMenuView actionMenuView = (ActionMenuView) f1.get(toolbar);
Field f2 = ActionMenuView.class.getDeclaredField("mPresenter");
f2.setAccessible(true);
// Actually ActionMenuPresenter
BaseMenuPresenter presenter = (BaseMenuPresenter) f2.get(actionMenuView);
Field f3 = presenter.getClass().getDeclaredField("mOverflowPopup");
f3.setAccessible(true);
MenuPopupHelper overflowMenuPopupHelper = (MenuPopupHelper) f3.get(presenter);
setTintForMenuPopupHelper(context, overflowMenuPopupHelper, color);
Field f4 = presenter.getClass().getDeclaredField("mActionButtonPopup");
f4.setAccessible(true);
MenuPopupHelper subMenuPopupHelper = (MenuPopupHelper) f4.get(presenter);
setTintForMenuPopupHelper(context, subMenuPopupHelper, color);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public static void setOverflowButtonColor(@NonNull Activity activity,
final @ColorInt int color) {
final String overflowDescription = activity
.getString(R.string.abc_action_menu_overflow_description);
final ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
final ViewTreeObserver viewTreeObserver = decorView.getViewTreeObserver();
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
final ArrayList<View> outViews = new ArrayList<>();
decorView.findViewsWithText(outViews, overflowDescription,
View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION);
if (outViews.isEmpty()) {
return;
}
final AppCompatImageView overflow = (AppCompatImageView) outViews.get(0);
overflow.setImageDrawable(TintHelper.createTintedDrawable(overflow.getDrawable(), color));
ViewUtil.INSTANCE.removeOnGlobalLayoutListener(decorView, this);
}
});
}
public static void setTintForMenuPopupHelper(final @NonNull Context context,
@Nullable MenuPopupHelper menuPopupHelper, final @ColorInt int color) {
try {
if (menuPopupHelper != null) {
final ListView listView = ((ShowableListMenu) menuPopupHelper.getPopup()).getListView();
listView.getViewTreeObserver()
.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
try {
Field checkboxField = ListMenuItemView.class.getDeclaredField("mCheckBox");
checkboxField.setAccessible(true);
Field radioButtonField = ListMenuItemView.class
.getDeclaredField("mRadioButton");
radioButtonField.setAccessible(true);
final boolean isDark = !ColorUtil.INSTANCE.isColorLight(
ATHUtil.INSTANCE
.resolveColor(context, android.R.attr.windowBackground));
for (int i = 0; i < listView.getChildCount(); i++) {
View v = listView.getChildAt(i);
if (!(v instanceof ListMenuItemView)) {
continue;
}
ListMenuItemView iv = (ListMenuItemView) v;
CheckBox check = (CheckBox) checkboxField.get(iv);
if (check != null) {
TintHelper.setTint(check, color, isDark);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
check.setBackground(null);
}
}
RadioButton radioButton = (RadioButton) radioButtonField.get(iv);
if (radioButton != null) {
TintHelper.setTint(radioButton, color, isDark);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
radioButton.setBackground(null);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
listView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
//noinspection deprecation
listView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
}
});
}
} catch (Exception e) {
e.printStackTrace();
}
}
@SuppressWarnings("unchecked")
public static void tintMenu(@NonNull Toolbar toolbar, @Nullable Menu menu,
final @ColorInt int color) {
try {
final Field field = Toolbar.class.getDeclaredField("mCollapseIcon");
field.setAccessible(true);
Drawable collapseIcon = (Drawable) field.get(toolbar);
if (collapseIcon != null) {
field.set(toolbar, TintHelper.createTintedDrawable(collapseIcon, color));
}
} catch (Exception e) {
e.printStackTrace();
}
if (menu != null && menu.size() > 0) {
for (int i = 0; i < menu.size(); i++) {
final MenuItem item = menu.getItem(i);
if (item.getIcon() != null) {
item.setIcon(TintHelper.createTintedDrawable(item.getIcon(), color));
}
// Search view theming
if (item.getActionView() != null && (
item.getActionView() instanceof android.widget.SearchView || item
.getActionView() instanceof androidx.appcompat.widget.SearchView)) {
SearchViewTintUtil.setSearchViewContentColor(item.getActionView(), color);
}
}
}
}
private InternalToolbarContentTintUtil() {
}
}
private static class ATHMenuPresenterCallback implements MenuPresenter.Callback {
private int mColor;
private Context mContext;
private MenuPresenter.Callback mParentCb;
private Toolbar mToolbar;
public ATHMenuPresenterCallback(Context context, final @ColorInt int color,
MenuPresenter.Callback parentCb, Toolbar toolbar) {
mContext = context;
mColor = color;
mParentCb = parentCb;
mToolbar = toolbar;
}
@Override
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
if (mParentCb != null) {
mParentCb.onCloseMenu(menu, allMenusAreClosing);
}
}
@Override
public boolean onOpenSubMenu(MenuBuilder subMenu) {
InternalToolbarContentTintUtil.applyOverflowMenuTint(mContext, mToolbar, mColor);
return mParentCb != null && mParentCb.onOpenSubMenu(subMenu);
}
}
private static class ATHOnMenuItemClickListener implements Toolbar.OnMenuItemClickListener {
private int mColor;
private Context mContext;
private Toolbar.OnMenuItemClickListener mParentListener;
private Toolbar mToolbar;
public ATHOnMenuItemClickListener(Context context, final @ColorInt int color,
Toolbar.OnMenuItemClickListener parentCb, Toolbar toolbar) {
mContext = context;
mColor = color;
mParentListener = parentCb;
mToolbar = toolbar;
}
@Override
public boolean onMenuItemClick(MenuItem item) {
InternalToolbarContentTintUtil.applyOverflowMenuTint(mContext, mToolbar, mColor);
return mParentListener != null && mParentListener.onMenuItemClick(item);
}
}
public static void colorBackButton(@NonNull Toolbar toolbar) {
int color = ATHUtil.INSTANCE.resolveColor(toolbar.getContext(), R.attr.colorControlNormal);
int color = ATHUtil.INSTANCE.resolveColor(toolbar.getContext(), R.attr.colorControlNormal);
final PorterDuffColorFilter colorFilter = new PorterDuffColorFilter(color, PorterDuff.Mode.MULTIPLY);
for (int i = 0; i < toolbar.getChildCount(); i++) {
final View backButton = toolbar.getChildAt(i);
@ -102,7 +312,7 @@ public final class ToolbarContentTintHelper {
* @param activity reference to activity needed to register observers
*/
public static void colorizeToolbar(Toolbar toolbarView, int toolbarIconsColor,
Activity activity) {
Activity activity) {
final PorterDuffColorFilter colorFilter = new PorterDuffColorFilter(toolbarIconsColor,
PorterDuff.Mode.MULTIPLY);
@ -150,93 +360,64 @@ public final class ToolbarContentTintHelper {
}
}
/**
* It's important to set overflowDescription atribute in styles, so we can grab the reference to
* the overflow icon. Check: res/values/styles.xml
*/
private static void setOverflowButtonColor(final Activity activity,
final PorterDuffColorFilter colorFilter) {
final String overflowDescription = activity
.getString(R.string.abc_action_menu_overflow_description);
final ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
final ViewTreeObserver viewTreeObserver = decorView.getViewTreeObserver();
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
final ArrayList<View> outViews = new ArrayList<View>();
decorView.findViewsWithText(outViews, overflowDescription,
View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION);
if (outViews.isEmpty()) {
return;
}
final ActionMenuView overflowViewParent = (ActionMenuView) outViews.get(0).getParent();
overflowViewParent.getOverflowIcon().setColorFilter(colorFilter);
removeOnGlobalLayoutListener(decorView, this);
}
});
@Nullable
public static Toolbar getSupportActionBarView(@Nullable ActionBar ab) {
if (ab == null || !(ab instanceof WindowDecorActionBar)) {
return null;
}
try {
WindowDecorActionBar decorAb = (WindowDecorActionBar) ab;
Field field = WindowDecorActionBar.class.getDeclaredField("mDecorToolbar");
field.setAccessible(true);
ToolbarWidgetWrapper wrapper = (ToolbarWidgetWrapper) field.get(decorAb);
field = ToolbarWidgetWrapper.class.getDeclaredField("mToolbar");
field.setAccessible(true);
return (Toolbar) field.get(wrapper);
} catch (Throwable t) {
throw new RuntimeException(
"Failed to retrieve Toolbar from AppCompat support ActionBar: " + t.getMessage(), t);
}
}
private static void setOverflowButtonColor(final Activity activity, final Toolbar toolbar,
final int toolbarIconsColor) {
final ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
final ViewTreeObserver viewTreeObserver = decorView.getViewTreeObserver();
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (toolbar != null && toolbar.getOverflowIcon() != null) {
Drawable bg = DrawableCompat.wrap(toolbar.getOverflowIcon());
DrawableCompat.setTint(bg, toolbarIconsColor);
}
removeOnGlobalLayoutListener(decorView, this);
}
});
public static void handleOnCreateOptionsMenu(
@NonNull Context context,
@NonNull Toolbar toolbar,
@NonNull Menu menu,
int toolbarColor) {
setToolbarContentColorBasedOnToolbarColor(context, toolbar, menu, toolbarColor);
}
private static void removeOnGlobalLayoutListener(View v,
ViewTreeObserver.OnGlobalLayoutListener listener) {
v.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
public static void handleOnCreateOptionsMenu(Context context, Toolbar toolbar, Menu menu,
@ColorInt int toolbarContentColor, @ColorInt int titleTextColor,
@ColorInt int subtitleTextColor, @ColorInt int menuWidgetColor) {
setToolbarContentColor(context, toolbar, menu, toolbarContentColor, titleTextColor,
subtitleTextColor, menuWidgetColor);
}
public static void setToolbarContentColorBasedOnToolbarColor(@NonNull Context context,
Toolbar toolbar,
int toolbarColor) {
setToolbarContentColorBasedOnToolbarColor(context, toolbar, null, toolbarColor);
public static void handleOnPrepareOptionsMenu(Activity activity, Toolbar toolbar) {
handleOnPrepareOptionsMenu(activity, toolbar, ThemeStore.Companion.accentColor(activity));
}
public static void setToolbarContentColorBasedOnToolbarColor(@NonNull Context context,
Toolbar toolbar,
@Nullable Menu menu,
int toolbarColor) {
setToolbarContentColorBasedOnToolbarColor(context, toolbar, menu, toolbarColor,
ThemeStore.Companion.accentColor(context));
}
public static void setToolbarContentColorBasedOnToolbarColor(@NonNull Context context,
Toolbar toolbar,
@Nullable Menu menu,
int toolbarColor,
final @ColorInt int menuWidgetColor) {
setToolbarContentColor(context, toolbar, menu, toolbarContentColor(context, toolbarColor),
toolbarTitleColor(context, toolbarColor), toolbarSubtitleColor(context, toolbarColor),
menuWidgetColor);
public static void handleOnPrepareOptionsMenu(Activity activity, Toolbar toolbar,
int widgetColor) {
InternalToolbarContentTintUtil.applyOverflowMenuTint(activity, toolbar, widgetColor);
}
public static void setToolbarContentColor(@NonNull Context context, Toolbar toolbar,
final @ColorInt int toolbarContentColor, final @ColorInt int primaryTextColor,
final @ColorInt int secondaryTextColor, final @ColorInt int menuWidgetColor) {
final @ColorInt int toolbarContentColor, final @ColorInt int primaryTextColor,
final @ColorInt int secondaryTextColor, final @ColorInt int menuWidgetColor) {
setToolbarContentColor(context, toolbar, null, toolbarContentColor, primaryTextColor,
secondaryTextColor, menuWidgetColor);
}
@SuppressWarnings("unchecked")
public static void setToolbarContentColor(@NonNull Context context,
Toolbar toolbar,
@Nullable Menu menu,
final @ColorInt int toolbarContentColor,
final @ColorInt int titleTextColor,
final @ColorInt int subtitleTextColor,
final @ColorInt int menuWidgetColor) {
Toolbar toolbar,
@Nullable Menu menu,
final @ColorInt int toolbarContentColor,
final @ColorInt int titleTextColor,
final @ColorInt int subtitleTextColor,
final @ColorInt int menuWidgetColor) {
if (toolbar == null) {
return;
}
@ -258,8 +439,7 @@ public final class ToolbarContentTintHelper {
InternalToolbarContentTintUtil.applyOverflowMenuTint(context, toolbar, menuWidgetColor);
if (context instanceof Activity) {
InternalToolbarContentTintUtil
.setOverflowButtonColor((Activity) context, toolbarContentColor);
InternalToolbarContentTintUtil.setOverflowButtonColor((Activity) context, toolbarContentColor);
}
try {
@ -288,7 +468,8 @@ public final class ToolbarContentTintHelper {
final Field menuItemClickListener = Toolbar.class
.getDeclaredField("mOnMenuItemClickListener");
menuItemClickListener.setAccessible(true);
Toolbar.OnMenuItemClickListener currentClickListener = (Toolbar.OnMenuItemClickListener) menuItemClickListener
Toolbar.OnMenuItemClickListener currentClickListener
= (Toolbar.OnMenuItemClickListener) menuItemClickListener
.get(toolbar);
if (!(currentClickListener instanceof ATHOnMenuItemClickListener)) {
final ATHOnMenuItemClickListener newClickListener = new ATHOnMenuItemClickListener(context,
@ -300,44 +481,38 @@ public final class ToolbarContentTintHelper {
}
}
@Nullable
public static Toolbar getSupportActionBarView(@Nullable ActionBar ab) {
if (ab == null || !(ab instanceof WindowDecorActionBar)) {
return null;
public static void setToolbarContentColorBasedOnToolbarColor(@NonNull Context context,
Toolbar toolbar,
int toolbarColor) {
setToolbarContentColorBasedOnToolbarColor(context, toolbar, null, toolbarColor);
}
public static void setToolbarContentColorBasedOnToolbarColor(
@NonNull Context context,
@NonNull Toolbar toolbar,
@Nullable Menu menu,
int toolbarColor) {
setToolbarContentColorBasedOnToolbarColor(context, toolbar, menu, toolbarColor,
ThemeStore.Companion.accentColor(context));
}
public static void setToolbarContentColorBasedOnToolbarColor(
@NonNull Context context,
@NonNull Toolbar toolbar,
@Nullable Menu menu,
int toolbarColor,
final @ColorInt int menuWidgetColor) {
setToolbarContentColor(context, toolbar, menu, toolbarContentColor(context, toolbarColor),
toolbarTitleColor(context, toolbarColor), toolbarSubtitleColor(context, toolbarColor),
menuWidgetColor);
}
public static void tintAllIcons(Menu menu, final int color) {
for (int i = 0; i < menu.size(); ++i) {
final MenuItem item = menu.getItem(i);
tintMenuItemIcon(color, item);
tintShareIconIfPresent(color, item);
}
try {
WindowDecorActionBar decorAb = (WindowDecorActionBar) ab;
Field field = WindowDecorActionBar.class.getDeclaredField("mDecorToolbar");
field.setAccessible(true);
ToolbarWidgetWrapper wrapper = (ToolbarWidgetWrapper) field.get(decorAb);
field = ToolbarWidgetWrapper.class.getDeclaredField("mToolbar");
field.setAccessible(true);
return (Toolbar) field.get(wrapper);
} catch (Throwable t) {
throw new RuntimeException(
"Failed to retrieve Toolbar from AppCompat support ActionBar: " + t.getMessage(), t);
}
}
public static void handleOnPrepareOptionsMenu(Activity activity, Toolbar toolbar) {
handleOnPrepareOptionsMenu(activity, toolbar, ThemeStore.Companion.accentColor(activity));
}
public static void handleOnPrepareOptionsMenu(Activity activity, Toolbar toolbar,
int widgetColor) {
InternalToolbarContentTintUtil.applyOverflowMenuTint(activity, toolbar, widgetColor);
}
public static void handleOnCreateOptionsMenu(Context context, Toolbar toolbar, Menu menu,
int toolbarColor) {
setToolbarContentColorBasedOnToolbarColor(context, toolbar, menu, toolbarColor);
}
public static void handleOnCreateOptionsMenu(Context context, Toolbar toolbar, Menu menu,
@ColorInt int toolbarContentColor, @ColorInt int titleTextColor,
@ColorInt int subtitleTextColor, @ColorInt int menuWidgetColor) {
setToolbarContentColor(context, toolbar, menu, toolbarContentColor, titleTextColor,
subtitleTextColor, menuWidgetColor);
}
@CheckResult
@ -352,254 +527,90 @@ public final class ToolbarContentTintHelper {
@CheckResult
@ColorInt
public static int toolbarSubtitleColor(@NonNull Context context, @ColorInt int toolbarColor) {
return MaterialValueHelper.INSTANCE.getSecondaryTextColor(context, ColorUtil.INSTANCE.isColorLight(toolbarColor));
return MaterialValueHelper.INSTANCE
.getSecondaryTextColor(context, ColorUtil.INSTANCE.isColorLight(toolbarColor));
}
@CheckResult
@ColorInt
public static int toolbarTitleColor(@NonNull Context context, @ColorInt int toolbarColor) {
return MaterialValueHelper.INSTANCE.getPrimaryTextColor(context, ColorUtil.INSTANCE.isColorLight(toolbarColor));
return MaterialValueHelper.INSTANCE
.getPrimaryTextColor(context, ColorUtil.INSTANCE.isColorLight(toolbarColor));
}
private static class ATHMenuPresenterCallback implements MenuPresenter.Callback {
private Context mContext;
private int mColor;
private MenuPresenter.Callback mParentCb;
private Toolbar mToolbar;
public ATHMenuPresenterCallback(Context context, final @ColorInt int color,
MenuPresenter.Callback parentCb, Toolbar toolbar) {
mContext = context;
mColor = color;
mParentCb = parentCb;
mToolbar = toolbar;
}
@Override
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
if (mParentCb != null) {
mParentCb.onCloseMenu(menu, allMenusAreClosing);
}
}
@Override
public boolean onOpenSubMenu(MenuBuilder subMenu) {
InternalToolbarContentTintUtil.applyOverflowMenuTint(mContext, mToolbar, mColor);
return mParentCb != null && mParentCb.onOpenSubMenu(subMenu);
}
private ToolbarContentTintHelper() {
}
private static class ATHOnMenuItemClickListener implements Toolbar.OnMenuItemClickListener {
private Context mContext;
private int mColor;
private Toolbar.OnMenuItemClickListener mParentListener;
private Toolbar mToolbar;
public ATHOnMenuItemClickListener(Context context, final @ColorInt int color,
Toolbar.OnMenuItemClickListener parentCb, Toolbar toolbar) {
mContext = context;
mColor = color;
mParentListener = parentCb;
mToolbar = toolbar;
}
@Override
public boolean onMenuItemClick(MenuItem item) {
InternalToolbarContentTintUtil.applyOverflowMenuTint(mContext, mToolbar, mColor);
return mParentListener != null && mParentListener.onMenuItemClick(item);
}
private static void removeOnGlobalLayoutListener(View v,
ViewTreeObserver.OnGlobalLayoutListener listener) {
v.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
}
public static class InternalToolbarContentTintUtil {
private static void setOverflowButtonColor(final Activity activity, final Toolbar toolbar,
final int toolbarIconsColor) {
final ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
final ViewTreeObserver viewTreeObserver = decorView.getViewTreeObserver();
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
private InternalToolbarContentTintUtil() {
}
@SuppressWarnings("unchecked")
public static void tintMenu(@NonNull Toolbar toolbar, @Nullable Menu menu,
final @ColorInt int color) {
try {
final Field field = Toolbar.class.getDeclaredField("mCollapseIcon");
field.setAccessible(true);
Drawable collapseIcon = (Drawable) field.get(toolbar);
if (collapseIcon != null) {
field.set(toolbar, TintHelper.createTintedDrawable(collapseIcon, color));
if (toolbar != null && toolbar.getOverflowIcon() != null) {
Drawable bg = DrawableCompat.wrap(toolbar.getOverflowIcon());
DrawableCompat.setTint(bg, toolbarIconsColor);
}
} catch (Exception e) {
e.printStackTrace();
removeOnGlobalLayoutListener(decorView, this);
}
});
}
if (menu != null && menu.size() > 0) {
for (int i = 0; i < menu.size(); i++) {
final MenuItem item = menu.getItem(i);
if (item.getIcon() != null) {
item.setIcon(TintHelper.createTintedDrawable(item.getIcon(), color));
}
// Search view theming
if (item.getActionView() != null && (
item.getActionView() instanceof android.widget.SearchView || item
.getActionView() instanceof androidx.appcompat.widget.SearchView)) {
SearchViewTintUtil.setSearchViewContentColor(item.getActionView(), color);
}
}
}
}
public static void applyOverflowMenuTint(final @NonNull Context context, final Toolbar toolbar,
final @ColorInt int color) {
if (toolbar == null) {
return;
}
toolbar.post(new Runnable() {
@Override
public void run() {
try {
Field f1 = Toolbar.class.getDeclaredField("mMenuView");
f1.setAccessible(true);
ActionMenuView actionMenuView = (ActionMenuView) f1.get(toolbar);
Field f2 = ActionMenuView.class.getDeclaredField("mPresenter");
f2.setAccessible(true);
// Actually ActionMenuPresenter
BaseMenuPresenter presenter = (BaseMenuPresenter) f2.get(actionMenuView);
Field f3 = presenter.getClass().getDeclaredField("mOverflowPopup");
f3.setAccessible(true);
MenuPopupHelper overflowMenuPopupHelper = (MenuPopupHelper) f3.get(presenter);
setTintForMenuPopupHelper(context, overflowMenuPopupHelper, color);
Field f4 = presenter.getClass().getDeclaredField("mActionButtonPopup");
f4.setAccessible(true);
MenuPopupHelper subMenuPopupHelper = (MenuPopupHelper) f4.get(presenter);
setTintForMenuPopupHelper(context, subMenuPopupHelper, color);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public static void setTintForMenuPopupHelper(final @NonNull Context context,
@Nullable MenuPopupHelper menuPopupHelper, final @ColorInt int color) {
try {
if (menuPopupHelper != null) {
final ListView listView = ((ShowableListMenu) menuPopupHelper.getPopup()).getListView();
listView.getViewTreeObserver()
.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
try {
Field checkboxField = ListMenuItemView.class.getDeclaredField("mCheckBox");
checkboxField.setAccessible(true);
Field radioButtonField = ListMenuItemView.class
.getDeclaredField("mRadioButton");
radioButtonField.setAccessible(true);
final boolean isDark = !ColorUtil.INSTANCE.isColorLight(
ATHUtil.INSTANCE.resolveColor(context, android.R.attr.windowBackground));
for (int i = 0; i < listView.getChildCount(); i++) {
View v = listView.getChildAt(i);
if (!(v instanceof ListMenuItemView)) {
continue;
}
ListMenuItemView iv = (ListMenuItemView) v;
CheckBox check = (CheckBox) checkboxField.get(iv);
if (check != null) {
TintHelper.setTint(check, color, isDark);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
check.setBackground(null);
}
}
RadioButton radioButton = (RadioButton) radioButtonField.get(iv);
if (radioButton != null) {
TintHelper.setTint(radioButton, color, isDark);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
radioButton.setBackground(null);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
listView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
//noinspection deprecation
listView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
}
});
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void setOverflowButtonColor(@NonNull Activity activity,
final @ColorInt int color) {
final String overflowDescription = activity
.getString(R.string.abc_action_menu_overflow_description);
final ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
final ViewTreeObserver viewTreeObserver = decorView.getViewTreeObserver();
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
final ArrayList<View> outViews = new ArrayList<>();
decorView.findViewsWithText(outViews, overflowDescription,
View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION);
if (outViews.isEmpty()) {
return;
}
final AppCompatImageView overflow = (AppCompatImageView) outViews.get(0);
overflow.setImageDrawable(TintHelper.createTintedDrawable(overflow.getDrawable(), color));
ViewUtil.INSTANCE.removeOnGlobalLayoutListener(decorView, this);
}
});
}
public static final class SearchViewTintUtil {
private SearchViewTintUtil() {
}
private static void tintImageView(Object target, Field field, final @ColorInt int color)
throws Exception {
field.setAccessible(true);
final ImageView imageView = (ImageView) field.get(target);
if (imageView.getDrawable() != null) {
imageView
.setImageDrawable(
TintHelper.createTintedDrawable(imageView.getDrawable(), color));
}
}
public static void setSearchViewContentColor(View searchView, final @ColorInt int color) {
if (searchView == null) {
/**
* It's important to set overflowDescription atribute in styles, so we can grab the reference to
* the overflow icon. Check: res/values/styles.xml
*/
private static void setOverflowButtonColor(final Activity activity,
final PorterDuffColorFilter colorFilter) {
final String overflowDescription = activity
.getString(R.string.abc_action_menu_overflow_description);
final ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
final ViewTreeObserver viewTreeObserver = decorView.getViewTreeObserver();
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
final ArrayList<View> outViews = new ArrayList<View>();
decorView.findViewsWithText(outViews, overflowDescription,
View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION);
if (outViews.isEmpty()) {
return;
}
final Class<?> cls = searchView.getClass();
try {
final Field mSearchSrcTextViewField = cls.getDeclaredField("mSearchSrcTextView");
mSearchSrcTextViewField.setAccessible(true);
final EditText mSearchSrcTextView = (EditText) mSearchSrcTextViewField.get(searchView);
mSearchSrcTextView.setTextColor(color);
mSearchSrcTextView.setHintTextColor(ColorUtil.INSTANCE.adjustAlpha(color, 0.5f));
TintHelper.setCursorTint(mSearchSrcTextView, color);
final ActionMenuView overflowViewParent = (ActionMenuView) outViews.get(0).getParent();
overflowViewParent.getOverflowIcon().setColorFilter(colorFilter);
removeOnGlobalLayoutListener(decorView, this);
}
});
}
Field field = cls.getDeclaredField("mSearchButton");
tintImageView(searchView, field, color);
field = cls.getDeclaredField("mGoButton");
tintImageView(searchView, field, color);
field = cls.getDeclaredField("mCloseButton");
tintImageView(searchView, field, color);
field = cls.getDeclaredField("mVoiceButton");
tintImageView(searchView, field, color);
} catch (Exception e) {
e.printStackTrace();
private static void tintMenuItemIcon(int color, MenuItem item) {
final Drawable drawable = item.getIcon();
if (drawable != null) {
final Drawable wrapped = DrawableCompat.wrap(drawable);
drawable.mutate();
DrawableCompat.setTint(wrapped, color);
item.setIcon(drawable);
}
}
private static void tintShareIconIfPresent(int color, MenuItem item) {
if (item.getActionView() != null) {
final View actionView = item.getActionView();
final View expandActivitiesButton = actionView.findViewById(R.id.expand_activities_button);
if (expandActivitiesButton != null) {
final ImageView image = (ImageView) expandActivitiesButton.findViewById(R.id.image);
if (image != null) {
final Drawable drawable = image.getDrawable();
final Drawable wrapped = DrawableCompat.wrap(drawable);
drawable.mutate();
DrawableCompat.setTint(wrapped, color);
image.setImageDrawable(drawable);
}
}
}