/*
* Copyright 2020 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 androidx.car.app.model;
import static androidx.annotation.RestrictTo.Scope.LIBRARY;
import androidx.annotation.ColorInt;
import androidx.annotation.IntDef;
import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
/**
* Represents a color to be used in a car app.
*
* <p>The host chooses the dark or light variant of the color when displaying the user interface,
* depending where the color is used, to ensure the proper contrast ratio is maintained. For
* example, the dark variant when may be used as the background of a view with brighter text on it,
* and the light variant for text on a dark background.
*
* <p>Colors provided by the app should meet the contrast requirements defined by the host, and
* documented by the app quality guidelines.
*
* <h4>Standard colors</h4>
*
* A set of standard {@link CarColor} instances (for example, {@link #BLUE}) is available in this
* class. It is recommended to use these standard colors whenever possible as they are guaranteed to
* adhere to the contrast requirements.
*
* <h4>Primary and secondary colors</h4>
*
* The app can define two additional {@link CarColor}s in its manifest metadata, through the <code>
* carColorPrimary</code>, <code>carColorPrimaryDark</code>, <code>
* carColorSecondary</code>, and <code>carColorSecondaryDark</code> theme attributes, by declaring
* them in a theme and referencing the theme from the <code>
* androidx.car.app.theme</code> metadata. Both the light and dark variants must
* be declared for the primary and secondary colors, otherwise default variants will be used.
* Wherever primary and secondary colors are used by the app, the host may use a default color
* instead if the colors do not pass the contrast requirements.
*
* <p>In <code>AndroidManifest.xml</code>, under the <code>application</code> element corresponding
* to the car app:
*
* <pre>{@code
* <meta-data
* android:name="androidx.car.app.theme"
* android:resource="@style/CarAppTheme"/>
* }</pre>
*
* The <code>CarAppTheme</code> style is defined as any other themes in a resource file:
*
* <pre>{@code
* <resources>
* <style name="CarAppTheme">
* <item name="carColorPrimary">@color/my_primary_car_color</item>
* <item name="carColorPrimaryDark">@color/my_primary_dark_car_color</item>
* <item name="carColorSecondary">@color/my_secondary_car_color</item>
* <item name="carColorSecondaryDark">@color/my_secondary_cark_car_color</item>
* </style>
* </resources>
* }</pre>
*
* <h4>Custom Colors</h4>
*
* Besides the primary and secondary colors, custom colors can be created at runtime with {@link
* #createCustom}. Wherever custom colors are used by the app, the host may use a default color
* instead if the custom color does not pass the contrast requirements.
*/
public final class CarColor {
/**
* The type of color represented by the {@link CarColor} instance.
*
* @hide
*/
@IntDef(
value = {
TYPE_CUSTOM,
TYPE_DEFAULT,
TYPE_PRIMARY,
TYPE_SECONDARY,
TYPE_RED,
TYPE_GREEN,
TYPE_BLUE,
TYPE_YELLOW
})
@Retention(RetentionPolicy.SOURCE)
@RestrictTo(LIBRARY)
public @interface CarColorType {
}
/**
* A custom, non-standard, app-defined color.
*/
@CarColorType
public static final int TYPE_CUSTOM = 0;
/**
* A default color, chosen by the host.
*
* @see #DEFAULT
*/
@CarColorType
public static final int TYPE_DEFAULT = 1;
/**
* The primary app color.
*
* @see #PRIMARY
*/
@CarColorType
public static final int TYPE_PRIMARY = 2;
/**
* The secondary app color.
*
* @see #SECONDARY
*/
@CarColorType
public static final int TYPE_SECONDARY = 3;
/**
* The standard red color.
*
* @see #RED
*/
@CarColorType
public static final int TYPE_RED = 4;
/**
* The standard green color.
*
* @see #GREEN
*/
@CarColorType
public static final int TYPE_GREEN = 5;
/**
* The standard blue color.
*
* @see #BLUE
*/
@CarColorType
public static final int TYPE_BLUE = 6;
/**
* The standard yellow color.
*
* @see #YELLOW
*/
@CarColorType
public static final int TYPE_YELLOW = 7;
/**
* Indicates that a default color should be used.
*
* <p>This can be used for example to tell the host that the app has no preference for the
* tint of an icon, and it should use whatever default it finds appropriate.
*/
@NonNull
public static final CarColor DEFAULT = create(TYPE_DEFAULT);
/**
* Indicates that the app primary color and its dark version should be used, as declared in the
* app manifest through the {@code carColorPrimary} and {@code carColorPrimaryDark}
* theme attributes.
*/
@NonNull
public static final CarColor PRIMARY = create(TYPE_PRIMARY);
/**
* Indicates that the app secondary color and its dark version should be used, as declared in
* the app manifest through the <code>carColorSecondary</code> and {@code
* carColorSecondaryDark} theme attributes.
*/
@NonNull
public static final CarColor SECONDARY = create(TYPE_SECONDARY);
/** A standard red color. */
@NonNull
public static final CarColor RED = create(TYPE_RED);
/** A standard green color. */
@NonNull
public static final CarColor GREEN = create(TYPE_GREEN);
/** A standard blue color. */
@NonNull
public static final CarColor BLUE = create(TYPE_BLUE);
/** A standard yellow color. */
@NonNull
public static final CarColor YELLOW = create(TYPE_YELLOW);
@Keep
@CarColorType
private final int mType;
/** A light-variant custom color-int, used when the type is {@link #TYPE_CUSTOM}. */
@Keep
@ColorInt
private final int mColor;
/** A dark-variant custom color-int, used when the type is {@link #TYPE_CUSTOM}. */
@Keep
@ColorInt
private final int mColorDark;
/**
* Returns an instance of {@link CarColor} containing a non-standard color.
*
* <p>See the top-level documentation of {@link CarColor} for details about how the host
* determines which variant is used.
*/
@NonNull
public static CarColor createCustom(@ColorInt int color, @ColorInt int colorDark) {
return new CarColor(TYPE_CUSTOM, color, colorDark);
}
/** Returns the type of color for this instance. */
@CarColorType
public int getType() {
return mType;
}
/**
* Returns a packed color int for the light variant of the color, used when the type
* is {@link #TYPE_CUSTOM}.
*/
@ColorInt
public int getColor() {
return mColor;
}
/**
* Returns a packed color int for the dark variant of the color, used when the type
* is {@link #TYPE_CUSTOM}.
*/
@ColorInt
public int getColorDark() {
return mColorDark;
}
@Override
public String toString() {
return "[type: " + typeToString(mType) + ", color: " + mColor + ", dark: " + mColorDark
+ "]";
}
@Override
public int hashCode() {
return Objects.hash(mType, mColor, mColorDark);
}
@Override
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
}
if (!(other instanceof CarColor)) {
return false;
}
CarColor otherColor = (CarColor) other;
return mColor == otherColor.mColor
&& mColorDark == otherColor.mColorDark
&& mType == otherColor.mType;
}
private static CarColor create(@CarColorType int type) {
return new CarColor(type, 0, 0);
}
private static String typeToString(@CarColorType int type) {
switch (type) {
case TYPE_BLUE:
return "BLUE";
case TYPE_DEFAULT:
return "DEFAULT";
case TYPE_PRIMARY:
return "PRIMARY";
case TYPE_SECONDARY:
return "SECONDARY";
case TYPE_CUSTOM:
return "CUSTOM";
case TYPE_GREEN:
return "GREEN";
case TYPE_RED:
return "RED";
case TYPE_YELLOW:
return "YELLOW";
default:
return "<unknown>";
}
}
private CarColor() {
mType = TYPE_DEFAULT;
mColor = 0;
mColorDark = 0;
}
private CarColor(@CarColorType int type, @ColorInt int color, @ColorInt int colorDark) {
mType = type;
mColor = color;
mColorDark = colorDark;
}
}