19a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham/* 29a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham * Copyright (C) 2017 The Android Open Source Project 39a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham * 49a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham * Licensed under the Apache License, Version 2.0 (the "License"); 59a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham * you may not use this file except in compliance with the License. 69a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham * You may obtain a copy of the License at 79a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham * 89a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham * http://www.apache.org/licenses/LICENSE-2.0 99a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham * 109a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham * Unless required by applicable law or agreed to in writing, software 119a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham * distributed under the License is distributed on an "AS IS" BASIS, 129a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham * See the License for the specific language governing permissions and 149a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham * limitations under the License. 159a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham */ 169a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham 179a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickhampackage com.android.launcher3.graphics; 189a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham 19f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickhamimport android.app.Notification; 20f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickhamimport android.content.Context; 217092db02410562026da17a7b38f48025cc847de2Tony Wickhamimport android.content.res.Resources; 229a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickhamimport android.graphics.Color; 236c82867a7ea3a95a19d6cec7d1fe164d234d2cb6Tony Wickhamimport android.graphics.ColorMatrix; 246c82867a7ea3a95a19d6cec7d1fe164d234d2cb6Tony Wickhamimport android.graphics.ColorMatrixColorFilter; 257092db02410562026da17a7b38f48025cc847de2Tony Wickhamimport android.support.annotation.NonNull; 267092db02410562026da17a7b38f48025cc847de2Tony Wickhamimport android.support.annotation.Nullable; 279a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickhamimport android.support.v4.graphics.ColorUtils; 28f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickhamimport android.util.Log; 29f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham 30f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickhamimport com.android.launcher3.R; 311f3f07d47c29cba3b70bcd15ebb65a077f55a558Sunny Goyalimport com.android.launcher3.util.Themes; 329a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham 339a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham/** 349a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham * Contains colors based on the dominant color of an icon. 359a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham */ 369a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickhampublic class IconPalette { 379a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham 38f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham private static final boolean DEBUG = false; 39f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham private static final String TAG = "IconPalette"; 40f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham 4196ac68a481ce5b794b5227e09ace7c30d6dd5e7bSunny Goyal private static final float MIN_PRELOAD_COLOR_SATURATION = 0.2f; 4296ac68a481ce5b794b5227e09ace7c30d6dd5e7bSunny Goyal private static final float MIN_PRELOAD_COLOR_LIGHTNESS = 0.6f; 4396ac68a481ce5b794b5227e09ace7c30d6dd5e7bSunny Goyal 447092db02410562026da17a7b38f48025cc847de2Tony Wickham private static IconPalette sBadgePalette; 457092db02410562026da17a7b38f48025cc847de2Tony Wickham private static IconPalette sFolderBadgePalette; 467092db02410562026da17a7b38f48025cc847de2Tony Wickham 4796ac68a481ce5b794b5227e09ace7c30d6dd5e7bSunny Goyal public final int dominantColor; 4896ac68a481ce5b794b5227e09ace7c30d6dd5e7bSunny Goyal public final int backgroundColor; 496c82867a7ea3a95a19d6cec7d1fe164d234d2cb6Tony Wickham public final ColorMatrixColorFilter backgroundColorMatrixFilter; 500530e8c60809afa92b1aa907376f0553ad94d58fTony Wickham public final ColorMatrixColorFilter saturatedBackgroundColorMatrixFilter; 5196ac68a481ce5b794b5227e09ace7c30d6dd5e7bSunny Goyal public final int textColor; 5296ac68a481ce5b794b5227e09ace7c30d6dd5e7bSunny Goyal public final int secondaryColor; 5396ac68a481ce5b794b5227e09ace7c30d6dd5e7bSunny Goyal 547092db02410562026da17a7b38f48025cc847de2Tony Wickham private IconPalette(int color, boolean desaturateBackground) { 5596ac68a481ce5b794b5227e09ace7c30d6dd5e7bSunny Goyal dominantColor = color; 567092db02410562026da17a7b38f48025cc847de2Tony Wickham backgroundColor = desaturateBackground ? getMutedColor(dominantColor, 0.87f) : dominantColor; 576c82867a7ea3a95a19d6cec7d1fe164d234d2cb6Tony Wickham ColorMatrix backgroundColorMatrix = new ColorMatrix(); 586c82867a7ea3a95a19d6cec7d1fe164d234d2cb6Tony Wickham Themes.setColorScaleOnMatrix(backgroundColor, backgroundColorMatrix); 596c82867a7ea3a95a19d6cec7d1fe164d234d2cb6Tony Wickham backgroundColorMatrixFilter = new ColorMatrixColorFilter(backgroundColorMatrix); 607092db02410562026da17a7b38f48025cc847de2Tony Wickham if (!desaturateBackground) { 617092db02410562026da17a7b38f48025cc847de2Tony Wickham saturatedBackgroundColorMatrixFilter = backgroundColorMatrixFilter; 627092db02410562026da17a7b38f48025cc847de2Tony Wickham } else { 637092db02410562026da17a7b38f48025cc847de2Tony Wickham // Get slightly more saturated background color. 647092db02410562026da17a7b38f48025cc847de2Tony Wickham Themes.setColorScaleOnMatrix(getMutedColor(dominantColor, 0.54f), backgroundColorMatrix); 657092db02410562026da17a7b38f48025cc847de2Tony Wickham saturatedBackgroundColorMatrixFilter = new ColorMatrixColorFilter(backgroundColorMatrix); 667092db02410562026da17a7b38f48025cc847de2Tony Wickham } 6796ac68a481ce5b794b5227e09ace7c30d6dd5e7bSunny Goyal textColor = getTextColorForBackground(backgroundColor); 6896ac68a481ce5b794b5227e09ace7c30d6dd5e7bSunny Goyal secondaryColor = getLowContrastColor(backgroundColor); 6996ac68a481ce5b794b5227e09ace7c30d6dd5e7bSunny Goyal } 7096ac68a481ce5b794b5227e09ace7c30d6dd5e7bSunny Goyal 7196ac68a481ce5b794b5227e09ace7c30d6dd5e7bSunny Goyal /** 7296ac68a481ce5b794b5227e09ace7c30d6dd5e7bSunny Goyal * Returns a color suitable for the progress bar color of preload icon. 7396ac68a481ce5b794b5227e09ace7c30d6dd5e7bSunny Goyal */ 741f3f07d47c29cba3b70bcd15ebb65a077f55a558Sunny Goyal public int getPreloadProgressColor(Context context) { 7596ac68a481ce5b794b5227e09ace7c30d6dd5e7bSunny Goyal int result = dominantColor; 7696ac68a481ce5b794b5227e09ace7c30d6dd5e7bSunny Goyal 7796ac68a481ce5b794b5227e09ace7c30d6dd5e7bSunny Goyal // Make sure that the dominant color has enough saturation to be visible properly. 7896ac68a481ce5b794b5227e09ace7c30d6dd5e7bSunny Goyal float[] hsv = new float[3]; 7996ac68a481ce5b794b5227e09ace7c30d6dd5e7bSunny Goyal Color.colorToHSV(result, hsv); 8096ac68a481ce5b794b5227e09ace7c30d6dd5e7bSunny Goyal if (hsv[1] < MIN_PRELOAD_COLOR_SATURATION) { 811f3f07d47c29cba3b70bcd15ebb65a077f55a558Sunny Goyal result = Themes.getColorAccent(context); 8296ac68a481ce5b794b5227e09ace7c30d6dd5e7bSunny Goyal } else { 8396ac68a481ce5b794b5227e09ace7c30d6dd5e7bSunny Goyal hsv[2] = Math.max(MIN_PRELOAD_COLOR_LIGHTNESS, hsv[2]); 8496ac68a481ce5b794b5227e09ace7c30d6dd5e7bSunny Goyal result = Color.HSVToColor(hsv); 8596ac68a481ce5b794b5227e09ace7c30d6dd5e7bSunny Goyal } 8696ac68a481ce5b794b5227e09ace7c30d6dd5e7bSunny Goyal return result; 8796ac68a481ce5b794b5227e09ace7c30d6dd5e7bSunny Goyal } 889a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham 897092db02410562026da17a7b38f48025cc847de2Tony Wickham public static IconPalette fromDominantColor(int dominantColor, boolean desaturateBackground) { 907092db02410562026da17a7b38f48025cc847de2Tony Wickham return new IconPalette(dominantColor, desaturateBackground); 917092db02410562026da17a7b38f48025cc847de2Tony Wickham } 927092db02410562026da17a7b38f48025cc847de2Tony Wickham 937092db02410562026da17a7b38f48025cc847de2Tony Wickham /** 947092db02410562026da17a7b38f48025cc847de2Tony Wickham * Returns an IconPalette based on the badge_color in colors.xml. 957092db02410562026da17a7b38f48025cc847de2Tony Wickham * If that color is Color.TRANSPARENT, then returns null instead. 967092db02410562026da17a7b38f48025cc847de2Tony Wickham */ 977092db02410562026da17a7b38f48025cc847de2Tony Wickham public static @Nullable IconPalette getBadgePalette(Resources resources) { 987092db02410562026da17a7b38f48025cc847de2Tony Wickham int badgeColor = resources.getColor(R.color.badge_color); 997092db02410562026da17a7b38f48025cc847de2Tony Wickham if (badgeColor == Color.TRANSPARENT) { 1007092db02410562026da17a7b38f48025cc847de2Tony Wickham // Colors will be extracted per app icon, so a static palette won't work. 1017092db02410562026da17a7b38f48025cc847de2Tony Wickham return null; 1027092db02410562026da17a7b38f48025cc847de2Tony Wickham } 1037092db02410562026da17a7b38f48025cc847de2Tony Wickham if (sBadgePalette == null) { 1047092db02410562026da17a7b38f48025cc847de2Tony Wickham sBadgePalette = fromDominantColor(badgeColor, false); 1057092db02410562026da17a7b38f48025cc847de2Tony Wickham } 1067092db02410562026da17a7b38f48025cc847de2Tony Wickham return sBadgePalette; 1077092db02410562026da17a7b38f48025cc847de2Tony Wickham } 1087092db02410562026da17a7b38f48025cc847de2Tony Wickham 1097092db02410562026da17a7b38f48025cc847de2Tony Wickham /** 1107092db02410562026da17a7b38f48025cc847de2Tony Wickham * Returns an IconPalette based on the folder_badge_color in colors.xml. 1117092db02410562026da17a7b38f48025cc847de2Tony Wickham */ 1127092db02410562026da17a7b38f48025cc847de2Tony Wickham public static @NonNull IconPalette getFolderBadgePalette(Resources resources) { 1137092db02410562026da17a7b38f48025cc847de2Tony Wickham if (sFolderBadgePalette == null) { 1147092db02410562026da17a7b38f48025cc847de2Tony Wickham int badgeColor = resources.getColor(R.color.folder_badge_color); 1157092db02410562026da17a7b38f48025cc847de2Tony Wickham sFolderBadgePalette = fromDominantColor(badgeColor, false); 1167092db02410562026da17a7b38f48025cc847de2Tony Wickham } 1177092db02410562026da17a7b38f48025cc847de2Tony Wickham return sFolderBadgePalette; 1189a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham } 1199a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham 120f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham /** 121f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham * Resolves a color such that it has enough contrast to be used as the 122f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham * color of an icon or text on the given background color. 123f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham * 124f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham * @return a color of the same hue with enough contrast against the background. 125f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham * 126f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham * This was copied from com.android.internal.util.NotificationColorUtil. 127f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham */ 128f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham public static int resolveContrastColor(Context context, int color, int background) { 129f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham final int resolvedColor = resolveColor(context, color); 130f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham 131f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham int contrastingColor = ensureTextContrast(resolvedColor, background); 132f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham 133f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham if (contrastingColor != resolvedColor) { 134f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham if (DEBUG){ 135f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham Log.w(TAG, String.format( 136f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham "Enhanced contrast of notification for %s " + 137f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham "%s (over background) by changing #%s to %s", 138f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham context.getPackageName(), 139f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham contrastChange(resolvedColor, contrastingColor, background), 140f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham Integer.toHexString(resolvedColor), Integer.toHexString(contrastingColor))); 141f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham } 142f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham } 143f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham return contrastingColor; 144f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham } 145f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham 146f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham /** 147f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham * Resolves {@param color} to an actual color if it is {@link Notification#COLOR_DEFAULT} 148f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham * 149f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham * This was copied from com.android.internal.util.NotificationColorUtil. 150f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham */ 151f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham private static int resolveColor(Context context, int color) { 152f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham if (color == Notification.COLOR_DEFAULT) { 153f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham return context.getColor(R.color.notification_icon_default_color); 154f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham } 155f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham return color; 156f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham } 157f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham 158f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham /** For debugging. This was copied from com.android.internal.util.NotificationColorUtil. */ 159f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham private static String contrastChange(int colorOld, int colorNew, int bg) { 160f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham return String.format("from %.2f:1 to %.2f:1", 161f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham ColorUtils.calculateContrast(colorOld, bg), 162f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham ColorUtils.calculateContrast(colorNew, bg)); 163f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham } 164f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham 165f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham /** 166f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham * Finds a text color with sufficient contrast over bg that has the same hue as the original 167f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham * color. 168f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham * 169f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham * This was copied from com.android.internal.util.NotificationColorUtil. 170f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham */ 171f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham private static int ensureTextContrast(int color, int bg) { 17247ab9b1fc5a8625bc714a1def91374d762927877Tony Wickham return findContrastColor(color, bg, 4.5); 173f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham } 174f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham /** 175f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham * Finds a suitable color such that there's enough contrast. 176f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham * 17747ab9b1fc5a8625bc714a1def91374d762927877Tony Wickham * @param fg the color to start searching from. 17847ab9b1fc5a8625bc714a1def91374d762927877Tony Wickham * @param bg the color to ensure contrast against. 179f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham * @param minRatio the minimum contrast ratio required. 180f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham * @return a color with the same hue as {@param color}, potentially darkened to meet the 181f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham * contrast ratio. 182f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham * 183f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham * This was copied from com.android.internal.util.NotificationColorUtil. 184f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham */ 18547ab9b1fc5a8625bc714a1def91374d762927877Tony Wickham private static int findContrastColor(int fg, int bg, double minRatio) { 186f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham if (ColorUtils.calculateContrast(fg, bg) >= minRatio) { 18747ab9b1fc5a8625bc714a1def91374d762927877Tony Wickham return fg; 188f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham } 189f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham 190f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham double[] lab = new double[3]; 19147ab9b1fc5a8625bc714a1def91374d762927877Tony Wickham ColorUtils.colorToLAB(bg, lab); 19247ab9b1fc5a8625bc714a1def91374d762927877Tony Wickham double bgL = lab[0]; 19347ab9b1fc5a8625bc714a1def91374d762927877Tony Wickham ColorUtils.colorToLAB(fg, lab); 19447ab9b1fc5a8625bc714a1def91374d762927877Tony Wickham double fgL = lab[0]; 19547ab9b1fc5a8625bc714a1def91374d762927877Tony Wickham boolean isBgDark = bgL < 50; 196f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham 19747ab9b1fc5a8625bc714a1def91374d762927877Tony Wickham double low = isBgDark ? fgL : 0, high = isBgDark ? 100 : fgL; 198f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham final double a = lab[1], b = lab[2]; 199f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham for (int i = 0; i < 15 && high - low > 0.00001; i++) { 200f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham final double l = (low + high) / 2; 20147ab9b1fc5a8625bc714a1def91374d762927877Tony Wickham fg = ColorUtils.LABToColor(l, a, b); 202f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham if (ColorUtils.calculateContrast(fg, bg) > minRatio) { 20347ab9b1fc5a8625bc714a1def91374d762927877Tony Wickham if (isBgDark) high = l; else low = l; 204f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham } else { 20547ab9b1fc5a8625bc714a1def91374d762927877Tony Wickham if (isBgDark) low = l; else high = l; 206f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham } 207f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham } 208f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham return ColorUtils.LABToColor(low, a, b); 209f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham } 210f79877c04c071b7ae1618395f0a1dce134fec36eTony Wickham 2110530e8c60809afa92b1aa907376f0553ad94d58fTony Wickham private static int getMutedColor(int color, float whiteScrimAlpha) { 2120530e8c60809afa92b1aa907376f0553ad94d58fTony Wickham int whiteScrim = ColorUtils.setAlphaComponent(Color.WHITE, (int) (255 * whiteScrimAlpha)); 2131237df0a7cb89570b90b30fa30a3c76417ce3b64Tony Wickham return ColorUtils.compositeColors(whiteScrim, color); 2149a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham } 2159a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham 2169a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham private static int getTextColorForBackground(int backgroundColor) { 2171237df0a7cb89570b90b30fa30a3c76417ce3b64Tony Wickham return getLighterOrDarkerVersionOfColor(backgroundColor, 4.5f); 2189a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham } 2199a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham 2209a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham private static int getLowContrastColor(int color) { 2219a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham return getLighterOrDarkerVersionOfColor(color, 1.5f); 2229a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham } 2239a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham 2249a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham private static int getLighterOrDarkerVersionOfColor(int color, float contrastRatio) { 2259a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham int whiteMinAlpha = ColorUtils.calculateMinimumAlpha(Color.WHITE, color, contrastRatio); 2269a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham int blackMinAlpha = ColorUtils.calculateMinimumAlpha(Color.BLACK, color, contrastRatio); 2279a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham int translucentWhiteOrBlack; 2289a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham if (whiteMinAlpha >= 0) { 2299a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham translucentWhiteOrBlack = ColorUtils.setAlphaComponent(Color.WHITE, whiteMinAlpha); 2309a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham } else if (blackMinAlpha >= 0) { 2319a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham translucentWhiteOrBlack = ColorUtils.setAlphaComponent(Color.BLACK, blackMinAlpha); 2329a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham } else { 2339a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham translucentWhiteOrBlack = Color.WHITE; 2349a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham } 2359a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham return ColorUtils.compositeColors(translucentWhiteOrBlack, color); 2369a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham } 2379a8d11f930ced4c2706db150b7bbbb21330bd68dTony Wickham} 238