public final class

CarIcon

extends java.lang.Object

 java.lang.Object

↳androidx.car.app.model.CarIcon

Gradle dependencies

compile group: 'androidx.car.app', name: 'app', version: '1.2.0-rc01'

  • groupId: androidx.car.app
  • artifactId: app
  • version: 1.2.0-rc01

Artifact androidx.car.app:app:1.2.0-rc01 it located at Google repository (https://maven.google.com/)

Overview

Represents an icon to be used in a car app.

Car icons wrap a backing IconCompat, and add additional attributes optimized for the car such as a CarColor tint.

Car Screen Pixel Densities

Similar to Android devices, car screens cover a wide range of sizes and densities. To ensure that icons and images render well across all car screens, use vector assets whenever possible to avoid scaling issues. If your app relies on bitmaps or other non-vector assets, you should ensure that you have resources that address multiple pixel density buckets using configuration qualifiers in your resource folders (e.g. "mdpi", "hdpi", etc). See CarContext for more details.

Themed Drawables

Vector drawables can contain references to attributes declared in a theme. For example:
 
 
 
The theme must be defined in the app's manifest metadata, by declaring them in a theme and referencing it from the androidx.car.app.theme metadata.

In AndroidManifest.xml, under the application element corresponding to the car app:

 
 
The CarAppTheme style is defined as any other themes in a resource file:
 
   
 
 

Summary

Fields
public static final CarIconALERT

An icon representing an alert.

public static final CarIconAPP_ICON

Represents the app's icon, as defined in the app's manifest by the android:icon attribute of the application element.

public static final CarIconBACK

An icon representing a "back" action.

public static final CarIconERROR

An icon representing an error.

public static final CarIconPAN

An icon representing a pan action (for example, in a map surface).

public static final intTYPE_ALERT

An alert icon.

public static final intTYPE_APP_ICON

The app's icon.

public static final intTYPE_BACK

An icon representing a "back" action.

public static final intTYPE_CUSTOM

A custom, non-standard, app-defined icon.

public static final intTYPE_ERROR

An error icon.

public static final intTYPE_PAN

A pan icon.

Methods
public booleanequals(java.lang.Object other)

public IconCompatgetIcon()

Returns the IconCompat instance backing by this car icon or null if one isn't set.

public CarColorgetTint()

Returns the tint of the icon or null if not set.

public intgetType()

Returns the type of car icon for this instance.

public inthashCode()

public java.lang.StringtoString()

from java.lang.Objectclone, finalize, getClass, notify, notifyAll, wait, wait, wait

Fields

public static final int TYPE_CUSTOM

A custom, non-standard, app-defined icon.

public static final int TYPE_BACK

An icon representing a "back" action.

See also: CarIcon.BACK

public static final int TYPE_ALERT

An alert icon.

See also: CarIcon.ALERT

public static final int TYPE_APP_ICON

The app's icon.

See also: CarIcon.APP_ICON

public static final int TYPE_ERROR

An error icon.

See also: CarIcon.ERROR

public static final int TYPE_PAN

A pan icon.

See also: CarIcon.PAN

public static final CarIcon APP_ICON

Represents the app's icon, as defined in the app's manifest by the android:icon attribute of the application element.

public static final CarIcon BACK

An icon representing a "back" action.

public static final CarIcon ALERT

An icon representing an alert.

public static final CarIcon ERROR

An icon representing an error.

public static final CarIcon PAN

An icon representing a pan action (for example, in a map surface).

Methods

public IconCompat getIcon()

Returns the IconCompat instance backing by this car icon or null if one isn't set.

See also: CarIcon.Builder

public CarColor getTint()

Returns the tint of the icon or null if not set.

See also: CarIcon.Builder.setTint(CarColor)

public int getType()

Returns the type of car icon for this instance.

public java.lang.String toString()

public int hashCode()

public boolean equals(java.lang.Object other)

Source

/*
 * 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 static androidx.car.app.model.CarColor.DEFAULT;

import static java.util.Objects.requireNonNull;

import android.annotation.SuppressLint;
import android.content.ContentResolver;
import android.graphics.PorterDuff.Mode;

import androidx.annotation.IntDef;
import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.car.app.annotations.CarProtocol;
import androidx.car.app.annotations.RequiresCarApi;
import androidx.car.app.model.constraints.CarColorConstraints;
import androidx.car.app.model.constraints.CarIconConstraints;
import androidx.core.graphics.drawable.IconCompat;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;

/**
 * Represents an icon to be used in a car app.
 *
 * <p>Car icons wrap a backing {@link IconCompat}, and add additional attributes optimized for the
 * car such as a {@link CarColor} tint.
 *
 * <h4>Car Screen Pixel Densities</h4>
 *
 * <p>Similar to Android devices, car screens cover a wide range of sizes and densities. To
 * ensure that icons and images render well across all car screens, use vector assets whenever
 * possible to avoid scaling issues. If your app relies on bitmaps or other non-vector
 * assets, you should ensure that you have resources that address multiple pixel density
 * buckets using configuration qualifiers in your resource folders (e.g. "mdpi", "hdpi", etc).
 * See {@link androidx.car.app.CarContext} for more details.
 *
 * <h4>Themed Drawables</h4>
 *
 * Vector drawables can contain references to attributes declared in a theme. For example:
 *
 * <pre>{@code
 * <vector ...
 *   <path
 *     android:pathData="..."
 *     android:fillColor="?myIconColor"/>
 * </vector>
 * }</pre>
 *
 * The theme must be defined in the app's manifest metadata, by declaring them in a theme and
 * referencing it from the <code>androidx.car.app.theme</code> metadata.
 *
 * <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="myIconColor">@color/my_icon_color</item>
 *     ...
 *   </style>
 * </resources>
 * }</pre>
 */
@CarProtocol
public final class CarIcon {
    /** Matches with {@link android.graphics.drawable.Icon#TYPE_RESOURCE} */
    private static final int TYPE_RESOURCE = 2;

    /** Matches with {@link android.graphics.drawable.Icon#TYPE_URI} */
    private static final int TYPE_URI = 4;

    /**
     * The type of car icon represented by the {@link CarIcon} instance.
     *
     * @hide
     */
    @RestrictTo(LIBRARY)
    @SuppressLint("UniqueConstants") // TYPE_APP will be removed in a follow-up change.
    @IntDef(
            value = {
                    TYPE_CUSTOM,
                    TYPE_BACK,
                    TYPE_ALERT,
                    TYPE_APP_ICON,
                    TYPE_ERROR,
                    TYPE_PAN,
            })
    @Retention(RetentionPolicy.SOURCE)
    public @interface CarIconType {
    }

    /**
     * A custom, non-standard, app-defined icon.
     */
    public static final int TYPE_CUSTOM = 1;

    /**
     * An icon representing a "back" action.
     *
     * @see #BACK
     */
    public static final int TYPE_BACK = 3;

    /**
     * An alert icon.
     *
     * @see #ALERT
     */
    public static final int TYPE_ALERT = 4;

    /**
     * The app's icon.
     *
     * @see #APP_ICON
     */
    public static final int TYPE_APP_ICON = 5;

    /**
     * An error icon.
     *
     * @see #ERROR
     */
    public static final int TYPE_ERROR = 6;

    /**
     * A pan icon.
     *
     * @see #PAN
     */
    public static final int TYPE_PAN = 7;

    /**
     * Represents the app's icon, as defined in the app's manifest by the {@code android:icon}
     * attribute of the {@code application} element.
     */
    @NonNull
    public static final CarIcon APP_ICON = CarIcon.forStandardType(TYPE_APP_ICON);

    /**
     * An icon representing a "back" action.
     */
    @NonNull
    public static final CarIcon BACK = CarIcon.forStandardType(TYPE_BACK);

    /**
     * An icon representing an alert.
     */
    @NonNull
    public static final CarIcon ALERT = CarIcon.forStandardType(TYPE_ALERT);

    /**
     * An icon representing an error.
     */
    @NonNull
    public static final CarIcon ERROR = CarIcon.forStandardType(TYPE_ERROR);

    /**
     * An icon representing a pan action (for example, in a map surface).
     */
    @RequiresCarApi(2)
    @NonNull
    public static final CarIcon PAN = CarIcon.forStandardType(TYPE_PAN);

    @Keep
    @CarIconType
    private final int mType;
    @Keep
    @Nullable
    private final IconCompat mIcon;
    @Keep
    @Nullable
    private final CarColor mTint;

    /**
     * Returns the {@link IconCompat} instance backing by this car icon or {@code null} if one
     * isn't set.
     *
     * @see Builder#Builder(IconCompat)
     */
    @Nullable
    public IconCompat getIcon() {
        return mIcon;
    }

    /**
     * Returns the tint of the icon or {@code null} if not set.
     *
     * @see Builder#setTint(CarColor)
     */
    @Nullable
    public CarColor getTint() {
        return mTint;
    }

    /**
     * Returns the type of car icon for this instance.
     */
    @CarIconType
    public int getType() {
        return mType;
    }

    @Override
    public String toString() {
        return "[type: " + typeToString(mType) + ", tint: " + mTint + "]";
    }

    @Override
    public int hashCode() {
        return Objects.hash(mType, mTint, iconCompatHash());
    }

    @Override
    public boolean equals(@Nullable Object other) {
        if (this == other) {
            return true;
        }
        if (!(other instanceof CarIcon)) {
            return false;
        }
        CarIcon otherIcon = (CarIcon) other;

        return mType == otherIcon.mType
                && Objects.equals(mTint, otherIcon.mTint)
                && iconCompatEquals(otherIcon.mIcon);
    }

    @Nullable
    private Object iconCompatHash() {
        // Use the same things being compared in iconCompatEquals for hashing.
        if (mIcon == null) {
            return null;
        }

        int type = mIcon.getType();
        if (type == TYPE_RESOURCE) {
            return mIcon.getResPackage() + mIcon.getResId();
        } else if (type == TYPE_URI) {
            return mIcon.getUri();
        }

        return type;
    }

    private boolean iconCompatEquals(@Nullable IconCompat other) {
        if (mIcon == null) {
            return other == null;
        } else if (other == null) {
            return false;
        }

        int type = mIcon.getType();
        int otherType = other.getType();

        if (type != otherType) {
            return false;
        }

        // TODO(b/146175636): Decide how/if we will diff bitmap type IconCompat
        if (type == TYPE_RESOURCE) {
            return Objects.equals(mIcon.getResPackage(), other.getResPackage())
                    && mIcon.getResId() == other.getResId();
        } else if (type == TYPE_URI) {
            return Objects.equals(mIcon.getUri(), other.getUri());
        }

        // Since we support any icon types, we only check for type equality if the type is
        // neither a resource or uri.
        return true;
    }

    private static CarIcon forStandardType(@CarIconType int type) {
        return forStandardType(type, DEFAULT);
    }

    private static CarIcon forStandardType(@CarIconType int type, @Nullable CarColor tint) {
        return new CarIcon(null, tint, type);
    }

    private static String typeToString(@CarIconType int type) {
        switch (type) {
            case TYPE_ALERT:
                return "ALERT";
            case TYPE_APP_ICON:
                return "APP";
            case TYPE_ERROR:
                return "ERROR";
            case TYPE_BACK:
                return "BACK";
            case TYPE_PAN:
                return "PAN";
            case TYPE_CUSTOM:
                return "CUSTOM";
            default:
                return "<unknown>";
        }
    }

    CarIcon(@Nullable IconCompat icon, @Nullable CarColor tint, @CarIconType int type) {
        mType = type;
        mIcon = icon;
        mTint = tint;
    }

    /** Constructs an empty instance, used by serialization code. */
    private CarIcon() {
        mType = TYPE_CUSTOM;
        mIcon = null;
        mTint = null;
    }

    /** A builder of {@link CarIcon}. */
    public static final class Builder {
        @Nullable
        private IconCompat mIcon;
        @Nullable
        private CarColor mTint;
        @CarIconType
        private int mType;

        /**
         * Sets the tint of the icon to the given {@link CarColor}.
         *
         * <p>This tint overrides the tint set through {@link IconCompat#setTint(int)} in the
         * backing {@link IconCompat} with a {@link CarColor} tint. The tint set through {@link
         * IconCompat#setTint(int)} is not guaranteed to be applied if the {@link CarIcon} tint
         * is not set.
         *
         * <p>The tint mode used to blend this color is {@link Mode#SRC_IN}.
         *
         * <p>Depending on contrast requirements, capabilities of the vehicle screens, or other
         *  factors, the color may be ignored by the host or overridden by the vehicle system.
         *
         * @throws NullPointerException if {@code tin} is {@code null}
         * @see CarColor
         * @see android.graphics.drawable.Drawable#setTintMode(Mode)
         */
        @NonNull
        public Builder setTint(@NonNull CarColor tint) {
            CarColorConstraints.UNCONSTRAINED.validateOrThrow(requireNonNull(tint));
            mTint = tint;
            return this;
        }

        /** Constructs the {@link CarIcon} defined by this builder. */
        @NonNull
        public CarIcon build() {
            return new CarIcon(mIcon, mTint, mType);
        }

        /**
         * Creates a {@link Builder} instance using the given {@link IconCompat}.
         *
         * <p>The following types are supported:
         *
         * <ul>
         *   <li>{@link IconCompat#TYPE_BITMAP}
         *   <li>{@link IconCompat#TYPE_RESOURCE}
         *   <li>{@link IconCompat#TYPE_URI}
         * </ul>
         *
         * <p>{@link IconCompat#TYPE_URI} is only supported in templates that explicitly allow it.
         * In those cases, the appropriate APIs will be documented to indicate this.
         *
         * <p>For {@link IconCompat#TYPE_URI}, the URI's scheme must be {@link
         * ContentResolver#SCHEME_CONTENT}.
         *
         * <p>If the icon image is loaded from URI, it may be cached on the host side. Changing the
         * contents of the URI will result in the host showing a stale image.
         *
         * @throws IllegalArgumentException if {@code icon}'s URI scheme is not supported
         * @throws NullPointerException     if {@code icon} is {@code null}
         */
        public Builder(@NonNull IconCompat icon) {
            CarIconConstraints.UNCONSTRAINED.checkSupportedIcon(requireNonNull(icon));
            mType = TYPE_CUSTOM;
            mIcon = icon;
            mTint = null;
        }

        /**
         * Returns a {@link Builder} instance configured with the same data as the given
         * {@link CarIcon} instance.
         *
         * @throws NullPointerException if {@code icon} is {@code null}
         */
        public Builder(@NonNull CarIcon carIcon) {
            requireNonNull(carIcon);
            mType = carIcon.getType();
            mIcon = carIcon.getIcon();
            mTint = carIcon.getTint();
        }
    }
}