package com.afollestad.aesthetic;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.AttrRes;
import android.support.annotation.ColorInt;
import android.support.annotation.FloatRange;
import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
import android.support.v4.view.LayoutInflaterCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.AppCompatImageView;
import android.support.v7.widget.Toolbar;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
/** @author Aidan Follestad (afollestad) */
@RestrictTo(LIBRARY_GROUP)
final class Util {
static void setInflaterFactory(@NonNull LayoutInflater li, @NonNull AppCompatActivity activity) {
LayoutInflaterCompat.setFactory(
li, new InflationInterceptor(activity, li, activity.getDelegate()));
}
/** Taken from CollapsingToolbarLayout's CollapsingTextHelper class. */
static int blendColors(int color1, int color2, float ratio) {
final float inverseRatio = 1f - ratio;
float a = (Color.alpha(color1) * inverseRatio) + (Color.alpha(color2) * ratio);
float r = (Color.red(color1) * inverseRatio) + (Color.red(color2) * ratio);
float g = (Color.green(color1) * inverseRatio) + (Color.green(color2) * ratio);
float b = (Color.blue(color1) * inverseRatio) + (Color.blue(color2) * ratio);
return Color.argb((int) a, (int) r, (int) g, (int) b);
}
@SuppressWarnings("deprecation")
static void setBackgroundCompat(@NonNull View view, @Nullable Drawable drawable) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
view.setBackground(drawable);
} else {
view.setBackgroundDrawable(drawable);
}
}
static void setStatusBarColorCompat(@NonNull AppCompatActivity activity, @ColorInt int color) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
activity.getWindow().setStatusBarColor(color);
}
}
static void setNavBarColorCompat(@NonNull AppCompatActivity activity, @ColorInt int color) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
activity.getWindow().setNavigationBarColor(color);
}
}
static int stripAlpha(@ColorInt int color) {
return Color.rgb(Color.red(color), Color.green(color), Color.blue(color));
}
@ColorInt
static int resolveColor(Context context, @AttrRes int attr) {
return resolveColor(context, attr, 0);
}
@ColorInt
static int resolveColor(Context context, @AttrRes int attr, int fallback) {
TypedArray a = context.getTheme().obtainStyledAttributes(new int[] {attr});
try {
return a.getColor(0, fallback);
} catch (Throwable ignored) {
return fallback;
} finally {
a.recycle();
}
}
@IdRes
static int resolveResId(Context context, @AttrRes int attr, int fallback) {
TypedArray a = context.getTheme().obtainStyledAttributes(new int[] {attr});
try {
return a.getResourceId(0, fallback);
} finally {
a.recycle();
}
}
static int resolveResId(Context context, AttributeSet attrs, @AttrRes int attrId) {
TypedArray ta = context.obtainStyledAttributes(attrs, new int[] {attrId});
int result = ta.getResourceId(0, 0);
ta.recycle();
return result;
}
// static ColorStateList resolveActionTextColorStateList(
// Context context, @AttrRes int colorAttr, ColorStateList fallback) {
// TypedArray a = context.getTheme().obtainStyledAttributes(new int[] {colorAttr});
// try {
// final TypedValue value = a.peekValue(0);
// if (value == null) {
// return fallback;
// }
// if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
// && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
// return getActionTextStateList(context, value.data);
// } else {
// final ColorStateList stateList = a.getColorStateList(0);
// if (stateList != null) {
// return stateList;
// } else {
// return fallback;
// }
// }
// } finally {
// a.recycle();
// }
// }
// Get the specified color resource, creating a ColorStateList if the resource
// points to a color value.
// static ColorStateList getActionTextColorStateList(Context context, @ColorRes int colorId) {
// final TypedValue value = new TypedValue();
// context.getResources().getValue(colorId, value, true);
// if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
// && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
// return getActionTextStateList(context, value.data);
// } else {
//
// if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
// //noinspection deprecation
// return context.getResources().getColorStateList(colorId);
// } else {
// return context.getColorStateList(colorId);
// }
// }
// }
// static ColorStateList getActionTextStateList(Context context, int newPrimaryColor) {
// final int fallBackButtonColor = resolveColor(context, android.R.attr.textColorPrimary);
// if (newPrimaryColor == 0) {
// newPrimaryColor = fallBackButtonColor;
// }
// int[][] states =
// new int[][] {
// new int[] {-android.R.attr.state_enabled}, // disabled
// new int[] {} // enabled
// };
// int[] colors = new int[] {adjustAlpha(newPrimaryColor, 0.4f), newPrimaryColor};
// return new ColorStateList(states, colors);
// }
@ColorInt
static int adjustAlpha(
@ColorInt int color, @SuppressWarnings("SameParameterValue") float factor) {
int alpha = Math.round(Color.alpha(color) * factor);
int red = Color.red(color);
int green = Color.green(color);
int blue = Color.blue(color);
return Color.argb(alpha, red, green, blue);
}
static void setOverflowButtonColor(@NonNull final Toolbar toolbar, final @ColorInt int color) {
@SuppressLint("PrivateResource")
final String overflowDescription =
toolbar.getResources().getString(R.string.abc_action_menu_overflow_description);
final ArrayList<View> outViews = new ArrayList<>();
toolbar.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));
}
@ColorInt
static int shiftColor(@ColorInt int color, @FloatRange(from = 0.0f, to = 2.0f) float by) {
if (by == 1f) return color;
float[] hsv = new float[3];
Color.colorToHSV(color, hsv);
hsv[2] *= by; // value component
return Color.HSVToColor(hsv);
}
@ColorInt
static int darkenColor(@ColorInt int color) {
return shiftColor(color, 0.9f);
}
static boolean isColorLight(@ColorInt int color) {
if (color == Color.BLACK) {
return false;
} else if (color == Color.WHITE || color == Color.TRANSPARENT) {
return true;
}
final double darkness =
1
- (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color))
/ 255;
return darkness < 0.4;
}
// optional convenience method, this can be called when we have information about the background color and want to consider it
static boolean isColorLight(@ColorInt int color, @ColorInt int bgColor) {
if (Color.alpha(color)
< 128) { // if the color is less than 50% visible rely on the background color
return isColorLight(
bgColor); // one could use some kind of color mixing here before passing the color
}
return isColorLight(color);
}
// @ColorInt
// static int invertColor(@ColorInt int color) {
// final int r = 255 - Color.red(color);
// final int g = 255 - Color.green(color);
// final int b = 255 - Color.blue(color);
// return Color.argb(Color.alpha(color), r, g, b);
// }
static void setLightStatusBarCompat(@NonNull AppCompatActivity activity, boolean lightMode) {
final View view = activity.getWindow().getDecorView();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int flags = view.getSystemUiVisibility();
if (lightMode) {
flags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
} else {
flags &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
}
view.setSystemUiVisibility(flags);
}
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
static void setTaskDescriptionColor(@NonNull Activity activity, @ColorInt int color) {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP) {
return;
}
// Task description requires fully opaque color
color = stripAlpha(color);
// Default is app's launcher icon
Bitmap icon =
((BitmapDrawable) activity.getApplicationInfo().loadIcon(activity.getPackageManager()))
.getBitmap();
// Sets color of entry in the system recents page
ActivityManager.TaskDescription td =
new ActivityManager.TaskDescription((String) activity.getTitle(), icon, color);
activity.setTaskDescription(td);
}
// @Nullable
// static Toolbar getSupportActionBarView(@Nullable ActionBar ab) {
// if (ab == null) return null;
// try {
// Field field = ab.getClass().getDeclaredField("mDecorToolbar");
// field.setAccessible(true);
// ToolbarWidgetWrapper wrapper = (ToolbarWidgetWrapper) field.get(ab);
// field = ToolbarWidgetWrapper.class.getDeclaredField("mToolbar");
// field.setAccessible(true);
// return (Toolbar) field.get(wrapper);
// } catch (Throwable t) {
// Log.d("Aesthetic", "Unable to get Toolbar from " + ab.getClass().getName());
// return null;
// }
// }
@NonNull
static ViewGroup getRootView(@NonNull Activity activity) {
return (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);
}
}