| /* |
| * Copyright 2015 The Android Open Source Project |
| * |
| * 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 android.support.v7.graphics; |
| |
| import android.support.annotation.FloatRange; |
| |
| /** |
| * A class which allows custom selection of colors in a {@link Palette}'s generation. Instances |
| * can be created via the {@link Builder} class. |
| * |
| * <p>To use the target, use the {@link Palette.Builder#addTarget(Target)} API when building a |
| * Palette.</p> |
| */ |
| public final class Target { |
| |
| private static final float TARGET_DARK_LUMA = 0.26f; |
| private static final float MAX_DARK_LUMA = 0.45f; |
| |
| private static final float MIN_LIGHT_LUMA = 0.55f; |
| private static final float TARGET_LIGHT_LUMA = 0.74f; |
| |
| private static final float MIN_NORMAL_LUMA = 0.3f; |
| private static final float TARGET_NORMAL_LUMA = 0.5f; |
| private static final float MAX_NORMAL_LUMA = 0.7f; |
| |
| private static final float TARGET_MUTED_SATURATION = 0.3f; |
| private static final float MAX_MUTED_SATURATION = 0.4f; |
| |
| private static final float TARGET_VIBRANT_SATURATION = 1f; |
| private static final float MIN_VIBRANT_SATURATION = 0.35f; |
| |
| private static final float WEIGHT_SATURATION = 0.24f; |
| private static final float WEIGHT_LUMA = 0.52f; |
| private static final float WEIGHT_POPULATION = 0.24f; |
| |
| private static final int INDEX_MIN = 0; |
| private static final int INDEX_TARGET = 1; |
| private static final int INDEX_MAX = 2; |
| |
| private static final int INDEX_WEIGHT_SAT = 0; |
| private static final int INDEX_WEIGHT_LUMA = 1; |
| private static final int INDEX_WEIGHT_POP = 2; |
| |
| /** |
| * A target which has the characteristics of a vibrant color which is light in luminance. |
| */ |
| public static final Target LIGHT_VIBRANT; |
| |
| /** |
| * A target which has the characteristics of a vibrant color which is neither light or dark. |
| */ |
| public static final Target VIBRANT; |
| |
| /** |
| * A target which has the characteristics of a vibrant color which is dark in luminance. |
| */ |
| public static final Target DARK_VIBRANT; |
| |
| /** |
| * A target which has the characteristics of a muted color which is light in luminance. |
| */ |
| public static final Target LIGHT_MUTED; |
| |
| /** |
| * A target which has the characteristics of a muted color which is neither light or dark. |
| */ |
| public static final Target MUTED; |
| |
| /** |
| * A target which has the characteristics of a muted color which is dark in luminance. |
| */ |
| public static final Target DARK_MUTED; |
| |
| static { |
| LIGHT_VIBRANT = new Target(); |
| setDefaultLightLightnessValues(LIGHT_VIBRANT); |
| setDefaultVibrantSaturationValues(LIGHT_VIBRANT); |
| |
| VIBRANT = new Target(); |
| setDefaultNormalLightnessValues(VIBRANT); |
| setDefaultVibrantSaturationValues(VIBRANT); |
| |
| DARK_VIBRANT = new Target(); |
| setDefaultDarkLightnessValues(DARK_VIBRANT); |
| setDefaultVibrantSaturationValues(DARK_VIBRANT); |
| |
| LIGHT_MUTED = new Target(); |
| setDefaultLightLightnessValues(LIGHT_MUTED); |
| setDefaultMutedSaturationValues(LIGHT_MUTED); |
| |
| MUTED = new Target(); |
| setDefaultNormalLightnessValues(MUTED); |
| setDefaultMutedSaturationValues(MUTED); |
| |
| DARK_MUTED = new Target(); |
| setDefaultDarkLightnessValues(DARK_MUTED); |
| setDefaultMutedSaturationValues(DARK_MUTED); |
| } |
| |
| private final float[] mSaturationTargets = new float[3]; |
| private final float[] mLightnessTargets = new float[3]; |
| private final float[] mWeights = new float[3]; |
| private boolean mIsExclusive = true; // default to true |
| |
| private Target() { |
| setTargetDefaultValues(mSaturationTargets); |
| setTargetDefaultValues(mLightnessTargets); |
| setDefaultWeights(); |
| } |
| |
| private Target(Target from) { |
| System.arraycopy(from.mSaturationTargets, 0, mSaturationTargets, 0, |
| mSaturationTargets.length); |
| System.arraycopy(from.mLightnessTargets, 0, mLightnessTargets, 0, |
| mLightnessTargets.length); |
| System.arraycopy(from.mWeights, 0, mWeights, 0, mWeights.length); |
| } |
| |
| /** |
| * The minimum saturation value for this target. |
| */ |
| @FloatRange(from = 0, to = 1) |
| public float getMinimumSaturation() { |
| return mSaturationTargets[INDEX_MIN]; |
| } |
| |
| /** |
| * The target saturation value for this target. |
| */ |
| @FloatRange(from = 0, to = 1) |
| public float getTargetSaturation() { |
| return mSaturationTargets[INDEX_TARGET]; |
| } |
| |
| /** |
| * The maximum saturation value for this target. |
| */ |
| @FloatRange(from = 0, to = 1) |
| public float getMaximumSaturation() { |
| return mSaturationTargets[INDEX_MAX]; |
| } |
| |
| /** |
| * The minimum lightness value for this target. |
| */ |
| @FloatRange(from = 0, to = 1) |
| public float getMinimumLightness() { |
| return mLightnessTargets[INDEX_MIN]; |
| } |
| |
| /** |
| * The target lightness value for this target. |
| */ |
| @FloatRange(from = 0, to = 1) |
| public float getTargetLightness() { |
| return mLightnessTargets[INDEX_TARGET]; |
| } |
| |
| /** |
| * The maximum lightness value for this target. |
| */ |
| @FloatRange(from = 0, to = 1) |
| public float getMaximumLightness() { |
| return mLightnessTargets[INDEX_MAX]; |
| } |
| |
| /** |
| * The weight of important that a color's saturation value has on selection. |
| */ |
| public float getSaturationWeight() { |
| return mWeights[INDEX_WEIGHT_SAT]; |
| } |
| |
| /** |
| * The weight of important that a color's lightness value has on selection. |
| */ |
| public float getLightnessWeight() { |
| return mWeights[INDEX_WEIGHT_LUMA]; |
| } |
| |
| /** |
| * The weight of important that a color's population value has on selection. |
| */ |
| public float getPopulationWeight() { |
| return mWeights[INDEX_WEIGHT_POP]; |
| } |
| |
| /** |
| * Returns whether any color selected for this target is exclusive for this target only. |
| * |
| * <p>If false, then the color can be selected for other targets.</p> |
| */ |
| public boolean isExclusive() { |
| return mIsExclusive; |
| } |
| |
| private static void setTargetDefaultValues(final float[] values) { |
| values[INDEX_MIN] = 0f; |
| values[INDEX_TARGET] = 0.5f; |
| values[INDEX_MAX] = 1f; |
| } |
| |
| private void setDefaultWeights() { |
| mWeights[INDEX_WEIGHT_SAT] = WEIGHT_SATURATION; |
| mWeights[INDEX_WEIGHT_LUMA] = WEIGHT_LUMA; |
| mWeights[INDEX_WEIGHT_POP] = WEIGHT_POPULATION; |
| } |
| |
| void normalizeWeights() { |
| float sum = 0; |
| for (int i = 0, z = mWeights.length; i < z; i++) { |
| float weight = mWeights[i]; |
| if (weight > 0) { |
| sum += weight; |
| } |
| } |
| if (sum != 0) { |
| for (int i = 0, z = mWeights.length; i < z; i++) { |
| if (mWeights[i] > 0) { |
| mWeights[i] /= sum; |
| } |
| } |
| } |
| } |
| |
| private static void setDefaultDarkLightnessValues(Target target) { |
| target.mLightnessTargets[INDEX_TARGET] = TARGET_DARK_LUMA; |
| target.mLightnessTargets[INDEX_MAX] = MAX_DARK_LUMA; |
| } |
| |
| private static void setDefaultNormalLightnessValues(Target target) { |
| target.mLightnessTargets[INDEX_MIN] = MIN_NORMAL_LUMA; |
| target.mLightnessTargets[INDEX_TARGET] = TARGET_NORMAL_LUMA; |
| target.mLightnessTargets[INDEX_MAX] = MAX_NORMAL_LUMA; |
| } |
| |
| private static void setDefaultLightLightnessValues(Target target) { |
| target.mLightnessTargets[INDEX_MIN] = MIN_LIGHT_LUMA; |
| target.mLightnessTargets[INDEX_TARGET] = TARGET_LIGHT_LUMA; |
| } |
| |
| private static void setDefaultVibrantSaturationValues(Target target) { |
| target.mSaturationTargets[INDEX_MIN] = MIN_VIBRANT_SATURATION; |
| target.mSaturationTargets[INDEX_TARGET] = TARGET_VIBRANT_SATURATION; |
| } |
| |
| private static void setDefaultMutedSaturationValues(Target target) { |
| target.mSaturationTargets[INDEX_TARGET] = TARGET_MUTED_SATURATION; |
| target.mSaturationTargets[INDEX_MAX] = MAX_MUTED_SATURATION; |
| } |
| |
| /** |
| * Builder class for generating custom {@link Target} instances. |
| */ |
| public final static class Builder { |
| private final Target mTarget; |
| |
| /** |
| * Create a new {@link Target} builder from scratch. |
| */ |
| public Builder() { |
| mTarget = new Target(); |
| } |
| |
| /** |
| * Create a new builder based on an existing {@link Target}. |
| */ |
| public Builder(Target target) { |
| mTarget = new Target(target); |
| } |
| |
| /** |
| * Set the minimum saturation value for this target. |
| */ |
| public Builder setMinimumSaturation(@FloatRange(from = 0, to = 1) float value) { |
| mTarget.mSaturationTargets[INDEX_MIN] = value; |
| return this; |
| } |
| |
| /** |
| * Set the target/ideal saturation value for this target. |
| */ |
| public Builder setTargetSaturation(@FloatRange(from = 0, to = 1) float value) { |
| mTarget.mSaturationTargets[INDEX_TARGET] = value; |
| return this; |
| } |
| |
| /** |
| * Set the maximum saturation value for this target. |
| */ |
| public Builder setMaximumSaturation(@FloatRange(from = 0, to = 1) float value) { |
| mTarget.mSaturationTargets[INDEX_MAX] = value; |
| return this; |
| } |
| |
| /** |
| * Set the minimum lightness value for this target. |
| */ |
| public Builder setMinimumLightness(@FloatRange(from = 0, to = 1) float value) { |
| mTarget.mLightnessTargets[INDEX_MIN] = value; |
| return this; |
| } |
| |
| /** |
| * Set the target/ideal lightness value for this target. |
| */ |
| public Builder setTargetLightness(@FloatRange(from = 0, to = 1) float value) { |
| mTarget.mLightnessTargets[INDEX_TARGET] = value; |
| return this; |
| } |
| |
| /** |
| * Set the maximum lightness value for this target. |
| */ |
| public Builder setMaximumLightness(@FloatRange(from = 0, to = 1) float value) { |
| mTarget.mLightnessTargets[INDEX_MAX] = value; |
| return this; |
| } |
| |
| /** |
| * Set the weight of important that a color's saturation value has on selection. A weight |
| * of <= 0 means that it has no weight and is ignored. |
| */ |
| public Builder setSaturationWeight(@FloatRange(from = 0) float weight) { |
| mTarget.mWeights[INDEX_WEIGHT_SAT] = weight; |
| return this; |
| } |
| |
| /** |
| * Set the weight of important that a color's lightness value has on selection. A weight |
| * of <= 0 means that it has no weight and is ignored. |
| */ |
| public Builder setLightnessWeight(@FloatRange(from = 0) float weight) { |
| mTarget.mWeights[INDEX_WEIGHT_LUMA] = weight; |
| return this; |
| } |
| |
| /** |
| * Set the weight of important that a color's population value has on selection. A weight |
| * of <= 0 means that it has no weight and is ignored. |
| */ |
| public Builder setPopulationWeight(@FloatRange(from = 0) float weight) { |
| mTarget.mWeights[INDEX_WEIGHT_POP] = weight; |
| return this; |
| } |
| |
| /** |
| * Set whether any color selected for this target is exclusive to this target only. |
| * Defaults to true. |
| * |
| * @param exclusive true if any the color is exclusive to this target, or false is the |
| * color can be selected for other targets. |
| */ |
| public Builder setExclusive(boolean exclusive) { |
| mTarget.mIsExclusive = exclusive; |
| return this; |
| } |
| |
| /** |
| * Builds and returns the resulting {@link Target}. |
| */ |
| public Target build() { |
| return mTarget; |
| } |
| } |
| |
| } |