Java tutorial
/* * Copyright 2015 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jahirfiquitiva.iconshowcase.utilities.color; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; import android.graphics.drawable.VectorDrawable; import android.os.Build; import android.support.annotation.CheckResult; import android.support.annotation.ColorInt; import android.support.annotation.DrawableRes; import android.support.annotation.FloatRange; import android.support.annotation.IntDef; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.graphics.drawable.VectorDrawableCompat; import android.support.v4.content.ContextCompat; import android.support.v4.graphics.drawable.DrawableCompat; import android.support.v7.graphics.Palette; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import jahirfiquitiva.iconshowcase.R; /** * Utility methods for working with colors. */ public class ColorUtils { private ColorUtils() { } public static final int IS_LIGHT = 0; public static final int IS_DARK = 1; public static final int LIGHTNESS_UNKNOWN = 2; public static float S = 0.0f; /** * Blend {@code color1} and {@code color2} using the given ratio. * * @param ratio of which to blend. 0.0 will return {@code color1}, 0.5 will give an even blend, * 1.0 will return {@code color2}. */ public static @CheckResult @ColorInt int blendColors(@ColorInt int color1, @ColorInt int color2, @FloatRange(from = 0f, to = 1f) 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); } /** * Changes opacity of {@code color} to the specified {@code factor} * * @param factor which will change the opacity of the color */ public static int adjustAlpha(@ColorInt int color, @FloatRange(from = 0.0, to = 1.0) float factor) { float a = Color.alpha(color) * factor; float r = Color.red(color); float g = Color.green(color); float b = Color.blue(color); return Color.argb((int) a, (int) r, (int) g, (int) b); } /** * Checks if the most populous color in the given palette is dark * <p/> * Annoyingly we have to return this Lightness 'enum' rather than a boolean as palette isn't * guaranteed to find the most populous color. */ public static @Lightness int isDark(Palette palette) { Palette.Swatch mostPopulous = ColorExtractor.getProminentSwatch(palette, false); if (mostPopulous == null) return LIGHTNESS_UNKNOWN; return isDark(mostPopulous.getHsl()) ? IS_DARK : IS_LIGHT; } /** * Determines if a given bitmap is dark. This extracts a palette inline so should not be called * with a large image!! * <p/> * Note: If palette fails then check the color of the central pixel */ public static boolean isDark(@NonNull Bitmap bitmap) { return isDark(bitmap, bitmap.getWidth() / 2, bitmap.getHeight() / 2); } /** * Determines if a given bitmap is dark. This extracts a palette inline so should not be called * with a large image!! If palette fails then check the color of the specified pixel */ public static boolean isDark(@NonNull Bitmap bitmap, int backupPixelX, int backupPixelY) { // first try palette with a small color quant size Palette palette = Palette.from(bitmap).generate(); if (palette.getSwatches().size() > 0) { return isDark(palette) == IS_DARK; } else { // if palette failed, then check the color of the specified pixel return isDark(bitmap.getPixel(backupPixelX, backupPixelY)); } } /** * Check that the lightness value (01) */ public static boolean isDark(float[] hsl) { // @Size(3) ColorUtils.S = hsl[2]; return hsl[2] < 0.51f; } /** * Convert to HSL & check that the lightness value */ public static boolean isDark(@ColorInt int color) { float[] hsl = new float[3]; android.support.v4.graphics.ColorUtils.colorToHSL(color, hsl); return isDark(hsl); } public static Drawable getTintedIcon(@NonNull Context context, @DrawableRes int drawable, @ColorInt int color) { try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { return getTintedIcon(ContextCompat.getDrawable(context, drawable), color); } else { Drawable icon = VectorDrawableCompat.create(context.getResources(), drawable, null); return getTintedIcon(icon, color); } } catch (Resources.NotFoundException ex) { return getTintedIcon(ContextCompat.getDrawable(context, R.drawable.iconshowcase_logo), color); } } @CheckResult @Nullable public static Drawable getTintedIcon(Drawable drawable, int color) { if (drawable != null) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (drawable instanceof VectorDrawable) { drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN); } drawable = DrawableCompat.wrap(drawable.mutate()); } else { drawable = DrawableCompat.wrap(drawable); } DrawableCompat.setTintMode(drawable, PorterDuff.Mode.SRC_IN); DrawableCompat.setTint(drawable, color); return drawable; } else { return null; } } @Retention(RetentionPolicy.SOURCE) @IntDef({ IS_LIGHT, IS_DARK, LIGHTNESS_UNKNOWN }) public @interface Lightness { } }