OSDN Git Service

Merge "Updating the PreloadIconDrawable" into ub-launcher3-master
[android-x86/packages-apps-Launcher3.git] / src / com / android / launcher3 / graphics / IconPalette.java
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.android.launcher3.graphics;
18
19 import android.app.Notification;
20 import android.content.Context;
21 import android.graphics.Color;
22 import android.support.v4.graphics.ColorUtils;
23 import android.util.Log;
24
25 import com.android.launcher3.R;
26
27 /**
28  * Contains colors based on the dominant color of an icon.
29  */
30 public class IconPalette {
31
32     private static final boolean DEBUG = false;
33     private static final String TAG = "IconPalette";
34
35     private static final float MIN_PRELOAD_COLOR_SATURATION = 0.2f;
36     private static final float MIN_PRELOAD_COLOR_LIGHTNESS = 0.6f;
37     private static final int DEFAULT_PRELOAD_COLOR = 0xFF009688;
38
39     public final int dominantColor;
40     public final int backgroundColor;
41     public final int textColor;
42     public final int secondaryColor;
43
44     private IconPalette(int color) {
45         dominantColor = color;
46         backgroundColor = getMutedColor(dominantColor);
47         textColor = getTextColorForBackground(backgroundColor);
48         secondaryColor = getLowContrastColor(backgroundColor);
49     }
50
51     /**
52      * Returns a color suitable for the progress bar color of preload icon.
53      */
54     public int getPreloadProgressColor() {
55         int result = dominantColor;
56
57         // Make sure that the dominant color has enough saturation to be visible properly.
58         float[] hsv = new float[3];
59         Color.colorToHSV(result, hsv);
60         if (hsv[1] < MIN_PRELOAD_COLOR_SATURATION) {
61             result = DEFAULT_PRELOAD_COLOR;
62         } else {
63             hsv[2] = Math.max(MIN_PRELOAD_COLOR_LIGHTNESS, hsv[2]);
64             result = Color.HSVToColor(hsv);
65         }
66         return result;
67     }
68
69     public static IconPalette fromDominantColor(int dominantColor) {
70         return new IconPalette(dominantColor);
71     }
72
73     /**
74      * Resolves a color such that it has enough contrast to be used as the
75      * color of an icon or text on the given background color.
76      *
77      * @return a color of the same hue with enough contrast against the background.
78      *
79      * This was copied from com.android.internal.util.NotificationColorUtil.
80      */
81     public static int resolveContrastColor(Context context, int color, int background) {
82         final int resolvedColor = resolveColor(context, color);
83
84         int contrastingColor = ensureTextContrast(resolvedColor, background);
85
86         if (contrastingColor != resolvedColor) {
87             if (DEBUG){
88                 Log.w(TAG, String.format(
89                         "Enhanced contrast of notification for %s " +
90                                 "%s (over background) by changing #%s to %s",
91                         context.getPackageName(),
92                         contrastChange(resolvedColor, contrastingColor, background),
93                         Integer.toHexString(resolvedColor), Integer.toHexString(contrastingColor)));
94             }
95         }
96         return contrastingColor;
97     }
98
99     /**
100      * Resolves {@param color} to an actual color if it is {@link Notification#COLOR_DEFAULT}
101      *
102      * This was copied from com.android.internal.util.NotificationColorUtil.
103      */
104     private static int resolveColor(Context context, int color) {
105         if (color == Notification.COLOR_DEFAULT) {
106             return context.getColor(R.color.notification_icon_default_color);
107         }
108         return color;
109     }
110
111     /** For debugging. This was copied from com.android.internal.util.NotificationColorUtil. */
112     private static String contrastChange(int colorOld, int colorNew, int bg) {
113         return String.format("from %.2f:1 to %.2f:1",
114                 ColorUtils.calculateContrast(colorOld, bg),
115                 ColorUtils.calculateContrast(colorNew, bg));
116     }
117
118     /**
119      * Finds a text color with sufficient contrast over bg that has the same hue as the original
120      * color.
121      *
122      * This was copied from com.android.internal.util.NotificationColorUtil.
123      */
124     private static int ensureTextContrast(int color, int bg) {
125         return findContrastColor(color, bg, true, 4.5);
126     }
127     /**
128      * Finds a suitable color such that there's enough contrast.
129      *
130      * @param color the color to start searching from.
131      * @param other the color to ensure contrast against. Assumed to be lighter than {@param color}
132      * @param findFg if true, we assume {@param color} is a foreground, otherwise a background.
133      * @param minRatio the minimum contrast ratio required.
134      * @return a color with the same hue as {@param color}, potentially darkened to meet the
135      *          contrast ratio.
136      *
137      * This was copied from com.android.internal.util.NotificationColorUtil.
138      */
139     private static int findContrastColor(int color, int other, boolean findFg, double minRatio) {
140         int fg = findFg ? color : other;
141         int bg = findFg ? other : color;
142         if (ColorUtils.calculateContrast(fg, bg) >= minRatio) {
143             return color;
144         }
145
146         double[] lab = new double[3];
147         ColorUtils.colorToLAB(findFg ? fg : bg, lab);
148
149         double low = 0, high = lab[0];
150         final double a = lab[1], b = lab[2];
151         for (int i = 0; i < 15 && high - low > 0.00001; i++) {
152             final double l = (low + high) / 2;
153             if (findFg) {
154                 fg = ColorUtils.LABToColor(l, a, b);
155             } else {
156                 bg = ColorUtils.LABToColor(l, a, b);
157             }
158             if (ColorUtils.calculateContrast(fg, bg) > minRatio) {
159                 low = l;
160             } else {
161                 high = l;
162             }
163         }
164         return ColorUtils.LABToColor(low, a, b);
165     }
166
167     private static int getMutedColor(int color) {
168         int alpha = (int) (255 * 0.15f);
169         return ColorUtils.compositeColors(ColorUtils.setAlphaComponent(color, alpha), Color.WHITE);
170     }
171
172     private static int getTextColorForBackground(int backgroundColor) {
173         return getLighterOrDarkerVersionOfColor(backgroundColor, 3f);
174     }
175
176     private static int getLowContrastColor(int color) {
177         return getLighterOrDarkerVersionOfColor(color, 1.5f);
178     }
179
180     private static int getLighterOrDarkerVersionOfColor(int color, float contrastRatio) {
181         int whiteMinAlpha = ColorUtils.calculateMinimumAlpha(Color.WHITE, color, contrastRatio);
182         int blackMinAlpha = ColorUtils.calculateMinimumAlpha(Color.BLACK, color, contrastRatio);
183         int translucentWhiteOrBlack;
184         if (whiteMinAlpha >= 0) {
185             translucentWhiteOrBlack = ColorUtils.setAlphaComponent(Color.WHITE, whiteMinAlpha);
186         } else if (blackMinAlpha >= 0) {
187             translucentWhiteOrBlack = ColorUtils.setAlphaComponent(Color.BLACK, blackMinAlpha);
188         } else {
189             translucentWhiteOrBlack = Color.WHITE;
190         }
191         return ColorUtils.compositeColors(translucentWhiteOrBlack, color);
192     }
193 }