• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 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 android.support.v7.graphics;
18 
19 import android.support.annotation.FloatRange;
20 
21 /**
22  * A class which allows custom selection of colors in a {@link Palette}'s generation. Instances
23  * can be created via the {@link Builder} class.
24  *
25  * <p>To use the target, use the {@link Palette.Builder#addTarget(Target)} API when building a
26  * Palette.</p>
27  */
28 public final class Target {
29 
30     private static final float TARGET_DARK_LUMA = 0.26f;
31     private static final float MAX_DARK_LUMA = 0.45f;
32 
33     private static final float MIN_LIGHT_LUMA = 0.55f;
34     private static final float TARGET_LIGHT_LUMA = 0.74f;
35 
36     private static final float MIN_NORMAL_LUMA = 0.3f;
37     private static final float TARGET_NORMAL_LUMA = 0.5f;
38     private static final float MAX_NORMAL_LUMA = 0.7f;
39 
40     private static final float TARGET_MUTED_SATURATION = 0.3f;
41     private static final float MAX_MUTED_SATURATION = 0.4f;
42 
43     private static final float TARGET_VIBRANT_SATURATION = 1f;
44     private static final float MIN_VIBRANT_SATURATION = 0.35f;
45 
46     private static final float WEIGHT_SATURATION = 0.24f;
47     private static final float WEIGHT_LUMA = 0.52f;
48     private static final float WEIGHT_POPULATION = 0.24f;
49 
50     static final int INDEX_MIN = 0;
51     static final int INDEX_TARGET = 1;
52     static final int INDEX_MAX = 2;
53 
54     static final int INDEX_WEIGHT_SAT = 0;
55     static final int INDEX_WEIGHT_LUMA = 1;
56     static final int INDEX_WEIGHT_POP = 2;
57 
58     /**
59      * A target which has the characteristics of a vibrant color which is light in luminance.
60     */
61     public static final Target LIGHT_VIBRANT;
62 
63     /**
64      * A target which has the characteristics of a vibrant color which is neither light or dark.
65      */
66     public static final Target VIBRANT;
67 
68     /**
69      * A target which has the characteristics of a vibrant color which is dark in luminance.
70      */
71     public static final Target DARK_VIBRANT;
72 
73     /**
74      * A target which has the characteristics of a muted color which is light in luminance.
75      */
76     public static final Target LIGHT_MUTED;
77 
78     /**
79      * A target which has the characteristics of a muted color which is neither light or dark.
80      */
81     public static final Target MUTED;
82 
83     /**
84      * A target which has the characteristics of a muted color which is dark in luminance.
85      */
86     public static final Target DARK_MUTED;
87 
88     static {
89         LIGHT_VIBRANT = new Target();
90         setDefaultLightLightnessValues(LIGHT_VIBRANT);
91         setDefaultVibrantSaturationValues(LIGHT_VIBRANT);
92 
93         VIBRANT = new Target();
94         setDefaultNormalLightnessValues(VIBRANT);
95         setDefaultVibrantSaturationValues(VIBRANT);
96 
97         DARK_VIBRANT = new Target();
98         setDefaultDarkLightnessValues(DARK_VIBRANT);
99         setDefaultVibrantSaturationValues(DARK_VIBRANT);
100 
101         LIGHT_MUTED = new Target();
102         setDefaultLightLightnessValues(LIGHT_MUTED);
103         setDefaultMutedSaturationValues(LIGHT_MUTED);
104 
105         MUTED = new Target();
106         setDefaultNormalLightnessValues(MUTED);
107         setDefaultMutedSaturationValues(MUTED);
108 
109         DARK_MUTED = new Target();
110         setDefaultDarkLightnessValues(DARK_MUTED);
111         setDefaultMutedSaturationValues(DARK_MUTED);
112     }
113 
114     final float[] mSaturationTargets = new float[3];
115     final float[] mLightnessTargets = new float[3];
116     final float[] mWeights = new float[3];
117     boolean mIsExclusive = true; // default to true
118 
Target()119     Target() {
120         setTargetDefaultValues(mSaturationTargets);
121         setTargetDefaultValues(mLightnessTargets);
122         setDefaultWeights();
123     }
124 
Target(Target from)125     Target(Target from) {
126         System.arraycopy(from.mSaturationTargets, 0, mSaturationTargets, 0,
127                 mSaturationTargets.length);
128         System.arraycopy(from.mLightnessTargets, 0, mLightnessTargets, 0,
129                 mLightnessTargets.length);
130         System.arraycopy(from.mWeights, 0, mWeights, 0, mWeights.length);
131     }
132 
133     /**
134      * The minimum saturation value for this target.
135      */
136     @FloatRange(from = 0, to = 1)
getMinimumSaturation()137     public float getMinimumSaturation() {
138         return mSaturationTargets[INDEX_MIN];
139     }
140 
141     /**
142      * The target saturation value for this target.
143      */
144     @FloatRange(from = 0, to = 1)
getTargetSaturation()145     public float getTargetSaturation() {
146         return mSaturationTargets[INDEX_TARGET];
147     }
148 
149     /**
150      * The maximum saturation value for this target.
151      */
152     @FloatRange(from = 0, to = 1)
getMaximumSaturation()153     public float getMaximumSaturation() {
154         return mSaturationTargets[INDEX_MAX];
155     }
156 
157     /**
158      * The minimum lightness value for this target.
159      */
160     @FloatRange(from = 0, to = 1)
getMinimumLightness()161     public float getMinimumLightness() {
162         return mLightnessTargets[INDEX_MIN];
163     }
164 
165     /**
166      * The target lightness value for this target.
167      */
168     @FloatRange(from = 0, to = 1)
getTargetLightness()169     public float getTargetLightness() {
170         return mLightnessTargets[INDEX_TARGET];
171     }
172 
173     /**
174      * The maximum lightness value for this target.
175      */
176     @FloatRange(from = 0, to = 1)
getMaximumLightness()177     public float getMaximumLightness() {
178         return mLightnessTargets[INDEX_MAX];
179     }
180 
181     /**
182      * Returns the weight of importance that this target places on a color's saturation within
183      * the image.
184      *
185      * <p>The larger the weight, relative to the other weights, the more important that a color
186      * being close to the target value has on selection.</p>
187      *
188      * @see #getTargetSaturation()
189      */
getSaturationWeight()190     public float getSaturationWeight() {
191         return mWeights[INDEX_WEIGHT_SAT];
192     }
193 
194     /**
195      * Returns the weight of importance that this target places on a color's lightness within
196      * the image.
197      *
198      * <p>The larger the weight, relative to the other weights, the more important that a color
199      * being close to the target value has on selection.</p>
200      *
201      * @see #getTargetLightness()
202      */
getLightnessWeight()203     public float getLightnessWeight() {
204         return mWeights[INDEX_WEIGHT_LUMA];
205     }
206 
207     /**
208      * Returns the weight of importance that this target places on a color's population within
209      * the image.
210      *
211      * <p>The larger the weight, relative to the other weights, the more important that a
212      * color's population being close to the most populous has on selection.</p>
213      */
getPopulationWeight()214     public float getPopulationWeight() {
215         return mWeights[INDEX_WEIGHT_POP];
216     }
217 
218     /**
219      * Returns whether any color selected for this target is exclusive for this target only.
220      *
221      * <p>If false, then the color can be selected for other targets.</p>
222      */
isExclusive()223     public boolean isExclusive() {
224         return mIsExclusive;
225     }
226 
setTargetDefaultValues(final float[] values)227     private static void setTargetDefaultValues(final float[] values) {
228         values[INDEX_MIN] = 0f;
229         values[INDEX_TARGET] = 0.5f;
230         values[INDEX_MAX] = 1f;
231     }
232 
setDefaultWeights()233     private void setDefaultWeights() {
234         mWeights[INDEX_WEIGHT_SAT] = WEIGHT_SATURATION;
235         mWeights[INDEX_WEIGHT_LUMA] = WEIGHT_LUMA;
236         mWeights[INDEX_WEIGHT_POP] = WEIGHT_POPULATION;
237     }
238 
normalizeWeights()239     void normalizeWeights() {
240         float sum = 0;
241         for (int i = 0, z = mWeights.length; i < z; i++) {
242             float weight = mWeights[i];
243             if (weight > 0) {
244                 sum += weight;
245             }
246         }
247         if (sum != 0) {
248             for (int i = 0, z = mWeights.length; i < z; i++) {
249                 if (mWeights[i] > 0) {
250                     mWeights[i] /= sum;
251                 }
252             }
253         }
254     }
255 
setDefaultDarkLightnessValues(Target target)256     private static void setDefaultDarkLightnessValues(Target target) {
257         target.mLightnessTargets[INDEX_TARGET] = TARGET_DARK_LUMA;
258         target.mLightnessTargets[INDEX_MAX] = MAX_DARK_LUMA;
259     }
260 
setDefaultNormalLightnessValues(Target target)261     private static void setDefaultNormalLightnessValues(Target target) {
262         target.mLightnessTargets[INDEX_MIN] = MIN_NORMAL_LUMA;
263         target.mLightnessTargets[INDEX_TARGET] = TARGET_NORMAL_LUMA;
264         target.mLightnessTargets[INDEX_MAX] = MAX_NORMAL_LUMA;
265     }
266 
setDefaultLightLightnessValues(Target target)267     private static void setDefaultLightLightnessValues(Target target) {
268         target.mLightnessTargets[INDEX_MIN] = MIN_LIGHT_LUMA;
269         target.mLightnessTargets[INDEX_TARGET] = TARGET_LIGHT_LUMA;
270     }
271 
setDefaultVibrantSaturationValues(Target target)272     private static void setDefaultVibrantSaturationValues(Target target) {
273         target.mSaturationTargets[INDEX_MIN] = MIN_VIBRANT_SATURATION;
274         target.mSaturationTargets[INDEX_TARGET] = TARGET_VIBRANT_SATURATION;
275     }
276 
setDefaultMutedSaturationValues(Target target)277     private static void setDefaultMutedSaturationValues(Target target) {
278         target.mSaturationTargets[INDEX_TARGET] = TARGET_MUTED_SATURATION;
279         target.mSaturationTargets[INDEX_MAX] = MAX_MUTED_SATURATION;
280     }
281 
282     /**
283      * Builder class for generating custom {@link Target} instances.
284      */
285     public final static class Builder {
286         private final Target mTarget;
287 
288         /**
289          * Create a new {@link Target} builder from scratch.
290          */
Builder()291         public Builder() {
292             mTarget = new Target();
293         }
294 
295         /**
296          * Create a new builder based on an existing {@link Target}.
297          */
Builder(Target target)298         public Builder(Target target) {
299             mTarget = new Target(target);
300         }
301 
302         /**
303          * Set the minimum saturation value for this target.
304          */
setMinimumSaturation(@loatRangefrom = 0, to = 1) float value)305         public Builder setMinimumSaturation(@FloatRange(from = 0, to = 1) float value) {
306             mTarget.mSaturationTargets[INDEX_MIN] = value;
307             return this;
308         }
309 
310         /**
311          * Set the target/ideal saturation value for this target.
312          */
setTargetSaturation(@loatRangefrom = 0, to = 1) float value)313         public Builder setTargetSaturation(@FloatRange(from = 0, to = 1) float value) {
314             mTarget.mSaturationTargets[INDEX_TARGET] = value;
315             return this;
316         }
317 
318         /**
319          * Set the maximum saturation value for this target.
320          */
setMaximumSaturation(@loatRangefrom = 0, to = 1) float value)321         public Builder setMaximumSaturation(@FloatRange(from = 0, to = 1) float value) {
322             mTarget.mSaturationTargets[INDEX_MAX] = value;
323             return this;
324         }
325 
326         /**
327          * Set the minimum lightness value for this target.
328          */
setMinimumLightness(@loatRangefrom = 0, to = 1) float value)329         public Builder setMinimumLightness(@FloatRange(from = 0, to = 1) float value) {
330             mTarget.mLightnessTargets[INDEX_MIN] = value;
331             return this;
332         }
333 
334         /**
335          * Set the target/ideal lightness value for this target.
336          */
setTargetLightness(@loatRangefrom = 0, to = 1) float value)337         public Builder setTargetLightness(@FloatRange(from = 0, to = 1) float value) {
338             mTarget.mLightnessTargets[INDEX_TARGET] = value;
339             return this;
340         }
341 
342         /**
343          * Set the maximum lightness value for this target.
344          */
setMaximumLightness(@loatRangefrom = 0, to = 1) float value)345         public Builder setMaximumLightness(@FloatRange(from = 0, to = 1) float value) {
346             mTarget.mLightnessTargets[INDEX_MAX] = value;
347             return this;
348         }
349 
350         /**
351          * Set the weight of importance that this target will place on saturation values.
352          *
353          * <p>The larger the weight, relative to the other weights, the more important that a color
354          * being close to the target value has on selection.</p>
355          *
356          * <p>A weight of 0 means that it has no weight, and thus has no
357          * bearing on the selection.</p>
358          *
359          * @see #setTargetSaturation(float)
360          */
setSaturationWeight(@loatRangefrom = 0) float weight)361         public Builder setSaturationWeight(@FloatRange(from = 0) float weight) {
362             mTarget.mWeights[INDEX_WEIGHT_SAT] = weight;
363             return this;
364         }
365 
366         /**
367          * Set the weight of importance that this target will place on lightness values.
368          *
369          * <p>The larger the weight, relative to the other weights, the more important that a color
370          * being close to the target value has on selection.</p>
371          *
372          * <p>A weight of 0 means that it has no weight, and thus has no
373          * bearing on the selection.</p>
374          *
375          * @see #setTargetLightness(float)
376          */
setLightnessWeight(@loatRangefrom = 0) float weight)377         public Builder setLightnessWeight(@FloatRange(from = 0) float weight) {
378             mTarget.mWeights[INDEX_WEIGHT_LUMA] = weight;
379             return this;
380         }
381 
382         /**
383          * Set the weight of importance that this target will place on a color's population within
384          * the image.
385          *
386          * <p>The larger the weight, relative to the other weights, the more important that a
387          * color's population being close to the most populous has on selection.</p>
388          *
389          * <p>A weight of 0 means that it has no weight, and thus has no
390          * bearing on the selection.</p>
391          */
setPopulationWeight(@loatRangefrom = 0) float weight)392         public Builder setPopulationWeight(@FloatRange(from = 0) float weight) {
393             mTarget.mWeights[INDEX_WEIGHT_POP] = weight;
394             return this;
395         }
396 
397         /**
398          * Set whether any color selected for this target is exclusive to this target only.
399          * Defaults to true.
400          *
401          * @param exclusive true if any the color is exclusive to this target, or false is the
402          *                  color can be selected for other targets.
403          */
setExclusive(boolean exclusive)404         public Builder setExclusive(boolean exclusive) {
405             mTarget.mIsExclusive = exclusive;
406             return this;
407         }
408 
409         /**
410          * Builds and returns the resulting {@link Target}.
411          */
build()412         public Target build() {
413             return mTarget;
414         }
415     }
416 
417 }