Gradle dependencies
compile group: 'androidx.core', name: 'core', version: '1.15.0-alpha02'
- groupId: androidx.core
 - artifactId: core
 - version: 1.15.0-alpha02
 
Artifact androidx.core:core:1.15.0-alpha02 it located at Google repository (https://maven.google.com/)
Androidx artifact mapping:
androidx.core:core com.android.support:support-compat
Androidx class mapping:
androidx.core.graphics.drawable.IconCompat android.support.v4.graphics.drawable.IconCompat
Overview
Helper for accessing features in android.graphics.drawable.Icon.
Summary
| Constructors | 
|---|
| public | IconCompat()
 Used for VersionedParcelable.  | 
| Methods | 
|---|
| public void | addToShortcutIntent(Intent outIntent, Drawable badge, Context c)
  | 
| public void | checkResource(Context context)
  | 
| public static IconCompat | createFromBundle(Bundle bundle)
 Extracts an icon from a bundle that was added using IconCompat.toBundle().  | 
| public static IconCompat | createFromIcon(Context context, Icon icon)
 Creates an IconCompat from an Icon.  | 
| public static IconCompat | createFromIcon(Icon icon)
 Creates an IconCompat from an Icon.  | 
| public static IconCompat | createFromIconOrNullIfZeroResId(Icon icon)
 Creates an IconCompat from an Icon, or returns null if the given Icon is created from
 resource 0.  | 
| public static IconCompat | createWithAdaptiveBitmap(Bitmap bits)
 Create an Icon pointing to a bitmap in memory that follows the icon design guideline defined
 by .  | 
| public static IconCompat | createWithAdaptiveBitmapContentUri(java.lang.String uri)
 Create an Icon pointing to an image file specified by URI.  | 
| public static IconCompat | createWithAdaptiveBitmapContentUri(Uri uri)
 Create an Icon pointing to an image file specified by URI.  | 
| public static IconCompat | createWithBitmap(Bitmap bits)
 Create an Icon pointing to a bitmap in memory.  | 
| public static IconCompat | createWithContentUri(java.lang.String uri)
 Create an Icon pointing to an image file specified by URI.  | 
| public static IconCompat | createWithContentUri(Uri uri)
 Create an Icon pointing to an image file specified by URI.  | 
| public static IconCompat | createWithData(byte[] data[], int offset, int length)
 Create an Icon pointing to a compressed bitmap stored in a byte array.  | 
| public static IconCompat | createWithResource(Context context, int resId)
 Create an Icon pointing to a drawable resource.  | 
| public static IconCompat | createWithResource(Resources r, java.lang.String pkg, int resId)
  | 
| public Bitmap | getBitmap()
 Gets the bitmap used to create this icon.  | 
| public int | getResId()
 Gets the drawable resource id used to create this icon.  | 
| public java.lang.String | getResPackage()
 Gets the package used to create this icon.  | 
| public int | getType()
 Gets the type of the icon provided.  | 
| public Uri | getUri()
 Gets the uri used to create this icon.  | 
| public java.io.InputStream | getUriInputStream(Context context)
 Create an input stream for bitmap by resolving corresponding content uri.  | 
| public Drawable | loadDrawable(Context context)
 Returns a Drawable that can be used to draw the image inside this Icon, constructing it
 if necessary.  | 
| public void | onPostParceling()
 Called immediately after this object has been deserialized, can be used
 to handle any custom fields that cannot be easily annotated.  | 
| public void | onPreParceling(boolean isStream)
 Called immediately before this object is going to be serialized, can be used
 to handle any custom fields that cannot be easily annotated.  | 
| public IconCompat | setTint(int tint)
 Store a color to use whenever this Icon is drawn.  | 
| public IconCompat | setTintList(ColorStateList tintList)
 Store a color to use whenever this Icon is drawn.  | 
| public IconCompat | setTintMode(PorterDuff.Mode mode)
 Store a blending mode to use whenever this Icon is drawn.  | 
| public Bundle | toBundle()
 Adds this Icon to a Bundle that can be read back with the same parameters
 to IconCompat.createFromBundle(Bundle).  | 
| public Icon | toIcon()
  | 
| public Icon | toIcon(Context context)
 Convert this compat object to  object.  | 
| public java.lang.String | toString()
  | 
| from java.lang.Object | clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait | 
Fields
public static final int 
TYPE_UNKNOWNValue returned when the type of an  cannot be determined.
public static final int 
TYPE_BITMAPAn icon that was created using IconCompat.createWithBitmap(Bitmap).
public static final int 
TYPE_RESOURCEAn icon that was created using IconCompat.createWithResource(Context, int).
public static final int 
TYPE_DATAAn icon that was created using IconCompat.createWithData(byte[], int, int).
public static final int 
TYPE_URIAn icon that was created using IconCompat.createWithContentUri(String).
public static final int 
TYPE_ADAPTIVE_BITMAPAn icon that was created using IconCompat.createWithAdaptiveBitmap(Bitmap).
public static final int 
TYPE_URI_ADAPTIVE_BITMAPAn icon that was created using IconCompat.createWithAdaptiveBitmapContentUri(String).
public Parcelable 
mParcelablepublic ColorStateList 
mTintListpublic java.lang.String 
mTintModeStrpublic java.lang.String 
mString1Constructors
Used for VersionedParcelable.
Methods
public static 
IconCompat createWithResource(Context context, int resId)
Create an Icon pointing to a drawable resource.
Parameters:
context: The context for the application whose resources should be used to resolve the
                given resource ID.
resId: ID of the drawable resource
See also: android.graphics.drawable.Icon
public static 
IconCompat createWithResource(Resources r, java.lang.String pkg, int resId)
public static 
IconCompat createWithBitmap(Bitmap bits)
Create an Icon pointing to a bitmap in memory.
Parameters:
bits: A valid android.graphics.Bitmap object
See also: android.graphics.drawable.Icon
public static 
IconCompat createWithAdaptiveBitmap(Bitmap bits)
Create an Icon pointing to a bitmap in memory that follows the icon design guideline defined
 by .
Parameters:
bits: A valid android.graphics.Bitmap object
See also: android.graphics.drawable.Icon
public static 
IconCompat createWithData(byte[] data[], int offset, int length)
Create an Icon pointing to a compressed bitmap stored in a byte array.
Parameters:
data: Byte array storing compressed bitmap data of a type that
             
             can decode (see ).
offset: Offset into data at which the bitmap data starts
length: Length of the bitmap data
See also: android.graphics.drawable.Icon
public static 
IconCompat createWithContentUri(java.lang.String uri)
Create an Icon pointing to an image file specified by URI.
Parameters:
uri: A uri referring to local content:// or file:// image data.
See also: android.graphics.drawable.Icon
public static 
IconCompat createWithContentUri(Uri uri)
Create an Icon pointing to an image file specified by URI.
Parameters:
uri: A uri referring to local content:// or file:// image data.
See also: android.graphics.drawable.Icon
public static 
IconCompat createWithAdaptiveBitmapContentUri(java.lang.String uri)
Create an Icon pointing to an image file specified by URI. Image file should follow the icon
 design guideline defined by .
Parameters:
uri: A uri referring to local content:// or file:// image data.
See also: android.graphics.drawable.Icon
public static 
IconCompat createWithAdaptiveBitmapContentUri(Uri uri)
Create an Icon pointing to an image file specified by URI. Image file should follow the icon
 design guideline defined by .
Parameters:
uri: A uri referring to local content:// or file:// image data.
See also: android.graphics.drawable.Icon
Gets the type of the icon provided.
 
 Note that new types may be added later, so callers should guard against other
 types being returned.
public java.lang.String 
getResPackage()
Gets the package used to create this icon.
 
 Only valid for icons of type TYPE_RESOURCE.
 Note: This package may not be available if referenced in the future, and it is
 up to the caller to ensure safety if this package is re-used and/or persisted.
Gets the drawable resource id used to create this icon.
 
 Only valid for icons of type TYPE_RESOURCE.
 Note: This resource may not be available if the application changes at all, and it is
 up to the caller to ensure safety if this resource is re-used and/or persisted.
public Bitmap 
getBitmap()
Gets the bitmap used to create this icon.
 
 Only valid for icons of type TYPE_BITMAP.
 Note: This bitmap may not be available in the future, and it is
 up to the caller to ensure safety if this bitmap is re-used and/or persisted.
Gets the uri used to create this icon.
 
 Only valid for icons of type TYPE_URI.
 Note: This uri may not be available in the future, and it is
 up to the caller to ensure safety if this uri is re-used and/or persisted.
Store a color to use whenever this Icon is drawn.
Parameters:
tint: a color, as in Drawable
Returns:
this same object, for use in chained construction
public 
IconCompat setTintList(ColorStateList tintList)
Store a color to use whenever this Icon is drawn.
Parameters:
tintList: as in Drawable, null to remove tint
Returns:
this same object, for use in chained construction
public 
IconCompat setTintMode(PorterDuff.Mode mode)
Store a blending mode to use whenever this Icon is drawn.
Parameters:
mode: a blending mode, as in Drawable, may be null
Returns:
this same object, for use in chained construction
Deprecated: Use IconCompat.toIcon(Context) to generate the  object.
public Icon 
toIcon(Context context)
Convert this compat object to  object.
Returns:
 object
public void 
checkResource(Context context)
public Drawable 
loadDrawable(Context context)
Returns a Drawable that can be used to draw the image inside this Icon, constructing it
 if necessary.
Parameters:
context:  in which to load the drawable; used
                to access Resources, for example.
Returns:
A fresh instance of a drawable for this image, yours to keep.
public java.io.InputStream 
getUriInputStream(Context context)
Create an input stream for bitmap by resolving corresponding content uri.
public void 
addToShortcutIntent(Intent outIntent, Drawable badge, Context c)
Adds this Icon to a Bundle that can be read back with the same parameters
 to IconCompat.createFromBundle(Bundle).
public java.lang.String 
toString()
public void 
onPreParceling(boolean isStream)
Called immediately before this object is going to be serialized, can be used
 to handle any custom fields that cannot be easily annotated.
public void 
onPostParceling()
Called immediately after this object has been deserialized, can be used
 to handle any custom fields that cannot be easily annotated.
public static 
IconCompat createFromBundle(Bundle bundle)
Extracts an icon from a bundle that was added using IconCompat.toBundle().
public static 
IconCompat createFromIcon(Context context, Icon icon)
Creates an IconCompat from an Icon.
public static 
IconCompat createFromIcon(Icon icon)
Creates an IconCompat from an Icon.
public static 
IconCompat createFromIconOrNullIfZeroResId(Icon icon)
Creates an IconCompat from an Icon, or returns null if the given Icon is created from
 resource 0.
Source
/*
 * Copyright (C) 2017 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.core.graphics.drawable;
import static androidx.annotation.RestrictTo.Scope.LIBRARY;
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX;
import android.app.ActivityManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.Shader;
import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.ColorInt;
import androidx.annotation.DrawableRes;
import androidx.annotation.IdRes;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import androidx.annotation.VisibleForTesting;
import androidx.core.content.ContextCompat;
import androidx.core.content.res.ResourcesCompat;
import androidx.core.util.ObjectsCompat;
import androidx.core.util.Preconditions;
import androidx.versionedparcelable.CustomVersionedParcelable;
import androidx.versionedparcelable.NonParcelField;
import androidx.versionedparcelable.ParcelField;
import androidx.versionedparcelable.VersionedParcelize;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.Charset;
/**
 * Helper for accessing features in {@link android.graphics.drawable.Icon}.
 */
@VersionedParcelize(allowSerialization = true, ignoreParcelables = true, isCustom = true,
        jetifyAs = "android.support.v4.graphics.drawable.IconCompat")
public class IconCompat extends CustomVersionedParcelable {
    private static final String TAG = "IconCompat";
    /**
     * Value returned when the type of an {@link Icon} cannot be determined.
     */
    public static final int TYPE_UNKNOWN  = -1;
    /**
     * An icon that was created using {@link #createWithBitmap(Bitmap)}.
     */
    public static final int TYPE_BITMAP   = Icon.TYPE_BITMAP;
    /**
     * An icon that was created using {@link #createWithResource}.
     */
    public static final int TYPE_RESOURCE = Icon.TYPE_RESOURCE;
    /**
     * An icon that was created using {@link #createWithData(byte[], int, int)}.
     */
    public static final int TYPE_DATA     = Icon.TYPE_DATA;
    /**
     * An icon that was created using {@link #createWithContentUri}.
     */
    public static final int TYPE_URI      = Icon.TYPE_URI;
    /**
     * An icon that was created using {@link #createWithAdaptiveBitmap}.
     */
    public static final int TYPE_ADAPTIVE_BITMAP = Icon.TYPE_ADAPTIVE_BITMAP;
    /**
     * An icon that was created using {@link #createWithAdaptiveBitmapContentUri}.
     */
    public static final int TYPE_URI_ADAPTIVE_BITMAP = Icon.TYPE_URI_ADAPTIVE_BITMAP;
    /**
     */
    @RestrictTo(LIBRARY)
    @IntDef({TYPE_UNKNOWN, TYPE_BITMAP, TYPE_RESOURCE, TYPE_DATA, TYPE_URI, TYPE_ADAPTIVE_BITMAP,
            TYPE_URI_ADAPTIVE_BITMAP})
    @Retention(RetentionPolicy.SOURCE)
    public @interface IconType {
    }
    // Ratio of expected size to actual icon size
    private static final float ADAPTIVE_ICON_INSET_FACTOR = 1 / 4f;
    private static final float DEFAULT_VIEW_PORT_SCALE = 1 / (1 + 2 * ADAPTIVE_ICON_INSET_FACTOR);
    private static final float ICON_DIAMETER_FACTOR = 176f / 192;
    private static final float BLUR_FACTOR = 0.5f / 48;
    private static final float KEY_SHADOW_OFFSET_FACTOR = 1f / 48;
    private static final int KEY_SHADOW_ALPHA = 61;
    private static final int AMBIENT_SHADOW_ALPHA = 30;
    @VisibleForTesting
    static final String EXTRA_TYPE = "type";
    @VisibleForTesting
    static final String EXTRA_OBJ = "obj";
    @VisibleForTesting
    static final String EXTRA_INT1 = "int1";
    @VisibleForTesting
    static final String EXTRA_INT2 = "int2";
    @VisibleForTesting
    static final String EXTRA_TINT_LIST = "tint_list";
    @VisibleForTesting
    static final String EXTRA_TINT_MODE = "tint_mode";
    @VisibleForTesting
    static final String EXTRA_STRING1 = "string1";
    /**
     */
    @RestrictTo(LIBRARY_GROUP_PREFIX)
    @ParcelField(value = 1,
            defaultValue = "androidx.core.graphics.drawable.IconCompat.TYPE_UNKNOWN")
    public int mType = TYPE_UNKNOWN;
    // To avoid adding unnecessary overhead, we have a few basic objects that get repurposed
    // based on the value of mType.
    // TYPE_BITMAP: Bitmap
    // TYPE_ADAPTIVE_BITMAP: Bitmap
    // TYPE_RESOURCE: String
    // TYPE_URI: String
    // TYPE_DATA: DataBytes
    @NonParcelField
    Object          mObj1;
    /**
     */
    @Nullable
    @RestrictTo(LIBRARY)
    @ParcelField(value = 2, defaultValue = "null")
    public byte[]          mData = null;
    /**
     */
    @Nullable
    @RestrictTo(LIBRARY)
    @ParcelField(value = 3, defaultValue = "null")
    public Parcelable      mParcelable = null;
    // TYPE_RESOURCE: resId
    // TYPE_DATA: data offset
    /**
     */
    @RestrictTo(LIBRARY)
    @ParcelField(value = 4, defaultValue = "0")
    public int             mInt1 = 0;
    // TYPE_DATA: data length
    /**
     */
    @RestrictTo(LIBRARY)
    @ParcelField(value = 5, defaultValue = "0")
    public int             mInt2 = 0;
    /**
     */
    @Nullable
    @RestrictTo(LIBRARY)
    @ParcelField(value = 6, defaultValue = "null")
    public ColorStateList  mTintList = null;
    static final PorterDuff.Mode DEFAULT_TINT_MODE = PorterDuff.Mode.SRC_IN; // SRC_IN
    @NonParcelField
    PorterDuff.Mode mTintMode = DEFAULT_TINT_MODE;
    /**
     */
    @Nullable
    @RestrictTo(LIBRARY)
    @ParcelField(value = 7, defaultValue = "null")
    public String mTintModeStr = null;
    /**
     */
    @Nullable
    @RestrictTo(LIBRARY)
    @ParcelField(value = 8, defaultValue = "null")
    public String mString1;
    /**
     * Create an Icon pointing to a drawable resource.
     * @param context The context for the application whose resources should be used to resolve the
     *                given resource ID.
     * @param resId ID of the drawable resource
     * @see android.graphics.drawable.Icon#createWithResource(Context, int)
     */
    @NonNull
    public static IconCompat createWithResource(@NonNull Context context, @DrawableRes int resId) {
        ObjectsCompat.requireNonNull(context);
        return createWithResource(context.getResources(), context.getPackageName(), resId);
    }
    /**
     */
    @NonNull
    @RestrictTo(LIBRARY_GROUP_PREFIX)
    public static IconCompat createWithResource(@Nullable Resources r, @NonNull String pkg,
            @DrawableRes int resId) {
        ObjectsCompat.requireNonNull(pkg);
        if (resId == 0) {
            throw new IllegalArgumentException("Drawable resource ID must not be 0");
        }
        final IconCompat rep = new IconCompat(TYPE_RESOURCE);
        rep.mInt1 = resId;
        if (r != null) {
            try {
                rep.mObj1 = r.getResourceName(resId);
            } catch (Resources.NotFoundException e) {
                throw new IllegalArgumentException("Icon resource cannot be found");
            }
        } else {
            rep.mObj1 = pkg;
        }
        rep.mString1 = pkg;
        return rep;
    }
    /**
     * Create an Icon pointing to a bitmap in memory.
     * @param bits A valid {@link android.graphics.Bitmap} object
     * @see android.graphics.drawable.Icon#createWithBitmap(Bitmap)
     */
    @NonNull
    public static IconCompat createWithBitmap(@NonNull Bitmap bits) {
        ObjectsCompat.requireNonNull(bits);
        final IconCompat rep = new IconCompat(TYPE_BITMAP);
        rep.mObj1 = bits;
        return rep;
    }
    /**
     * Create an Icon pointing to a bitmap in memory that follows the icon design guideline defined
     * by {@link android.graphics.drawable.AdaptiveIconDrawable}.
     * @param bits A valid {@link android.graphics.Bitmap} object
     * @see android.graphics.drawable.Icon#createWithAdaptiveBitmap(Bitmap)
     */
    @NonNull
    public static IconCompat createWithAdaptiveBitmap(@NonNull Bitmap bits) {
        ObjectsCompat.requireNonNull(bits);
        final IconCompat rep = new IconCompat(TYPE_ADAPTIVE_BITMAP);
        rep.mObj1 = bits;
        return rep;
    }
    /**
     * Create an Icon pointing to a compressed bitmap stored in a byte array.
     * @param data Byte array storing compressed bitmap data of a type that
     *             {@link android.graphics.BitmapFactory}
     *             can decode (see {@link android.graphics.Bitmap.CompressFormat}).
     * @param offset Offset into <code>data</code> at which the bitmap data starts
     * @param length Length of the bitmap data
     * @see android.graphics.drawable.Icon#createWithData(byte[], int, int)
     */
    @NonNull
    public static IconCompat createWithData(@NonNull byte[] data, int offset, int length) {
        ObjectsCompat.requireNonNull(data);
        final IconCompat rep = new IconCompat(TYPE_DATA);
        rep.mObj1 = data;
        rep.mInt1 = offset;
        rep.mInt2 = length;
        return rep;
    }
    /**
     * Create an Icon pointing to an image file specified by URI.
     *
     * @param uri A uri referring to local content:// or file:// image data.
     * @see android.graphics.drawable.Icon#createWithContentUri(String)
     */
    @NonNull
    public static IconCompat createWithContentUri(@NonNull String uri) {
        ObjectsCompat.requireNonNull(uri);
        final IconCompat rep = new IconCompat(TYPE_URI);
        rep.mObj1 = uri;
        return rep;
    }
    /**
     * Create an Icon pointing to an image file specified by URI.
     *
     * @param uri A uri referring to local content:// or file:// image data.
     * @see android.graphics.drawable.Icon#createWithContentUri(String)
     */
    @NonNull
    public static IconCompat createWithContentUri(@NonNull Uri uri) {
        ObjectsCompat.requireNonNull(uri);
        return createWithContentUri(uri.toString());
    }
    /**
     * Create an Icon pointing to an image file specified by URI. Image file should follow the icon
     * design guideline defined by {@link AdaptiveIconDrawable}.
     *
     * @param uri A uri referring to local content:// or file:// image data.
     * @see android.graphics.drawable.Icon#createWithAdaptiveBitmapContentUri(String)
     */
    @NonNull
    public static IconCompat createWithAdaptiveBitmapContentUri(@NonNull String uri) {
        ObjectsCompat.requireNonNull(uri);
        final IconCompat rep = new IconCompat(TYPE_URI_ADAPTIVE_BITMAP);
        rep.mObj1 = uri;
        return rep;
    }
    /**
     * Create an Icon pointing to an image file specified by URI. Image file should follow the icon
     * design guideline defined by {@link AdaptiveIconDrawable}.
     *
     * @param uri A uri referring to local content:// or file:// image data.
     * @see android.graphics.drawable.Icon#createWithAdaptiveBitmapContentUri(String)
     */
    @NonNull
    public static IconCompat createWithAdaptiveBitmapContentUri(@NonNull Uri uri) {
        ObjectsCompat.requireNonNull(uri);
        return createWithAdaptiveBitmapContentUri(uri.toString());
    }
    /**
     * Used for VersionedParcelable.
     */
    @RestrictTo(LIBRARY)
    public IconCompat() {
    }
    IconCompat(int mType) {
        this.mType = mType;
    }
    /**
     * Gets the type of the icon provided.
     * <p>
     * Note that new types may be added later, so callers should guard against other
     * types being returned.
     */
    @IconType
    public int getType() {
        if (mType == TYPE_UNKNOWN && Build.VERSION.SDK_INT >= 23) {
            return Api23Impl.getType(mObj1);
        }
        return mType;
    }
    /**
     * Gets the package used to create this icon.
     * <p>
     * Only valid for icons of type TYPE_RESOURCE.
     * Note: This package may not be available if referenced in the future, and it is
     * up to the caller to ensure safety if this package is re-used and/or persisted.
     */
    @NonNull
    public String getResPackage() {
        if (mType == TYPE_UNKNOWN && Build.VERSION.SDK_INT >= 23) {
            return Api23Impl.getResPackage(mObj1);
        }
        if (mType != TYPE_RESOURCE) {
            throw new IllegalStateException("called getResPackage() on " + this);
        }
        // Before aosp/1307777, we don't put the package name to mString1. Try to get the
        // package name from the full resource name string. Note that this is not always the same
        // as "the package used to create this icon" and this was what aosp/1307777 tried to fix.
        if (mString1 == null || TextUtils.isEmpty(mString1)) {
            return ((String) mObj1).split(":", -1)[0];
        } else {
            // The name of the getResPackage() API is a bit confusing. It actually returns
            // the app package name rather than the package name in the resource table.
            return mString1;
        }
    }
    /**
     * Gets the drawable resource id used to create this icon.
     * <p>
     * Only valid for icons of type TYPE_RESOURCE.
     * Note: This resource may not be available if the application changes at all, and it is
     * up to the caller to ensure safety if this resource is re-used and/or persisted.
     */
    @DrawableRes
    public int getResId() {
        if (mType == TYPE_UNKNOWN && Build.VERSION.SDK_INT >= 23) {
            return Api23Impl.getResId(mObj1);
        }
        if (mType != TYPE_RESOURCE) {
            throw new IllegalStateException("called getResId() on " + this);
        }
        return mInt1;
    }
    /**
     * Gets the bitmap used to create this icon.
     * <p>
     * Only valid for icons of type TYPE_BITMAP.
     * Note: This bitmap may not be available in the future, and it is
     * up to the caller to ensure safety if this bitmap is re-used and/or persisted.
     *
     */
    @RestrictTo(LIBRARY_GROUP_PREFIX)
    @Nullable
    public Bitmap getBitmap() {
        if (mType == TYPE_UNKNOWN && Build.VERSION.SDK_INT >= 23) {
            if (mObj1 instanceof Bitmap) {
                return (Bitmap) mObj1;
            }
            return null;
        }
        if (mType == TYPE_BITMAP) {
            return (Bitmap) mObj1;
        } else if (mType == TYPE_ADAPTIVE_BITMAP) {
            return createLegacyIconFromAdaptiveIcon((Bitmap) mObj1, true);
        } else {
            throw new IllegalStateException("called getBitmap() on " + this);
        }
    }
    /**
     * Gets the uri used to create this icon.
     * <p>
     * Only valid for icons of type TYPE_URI.
     * Note: This uri may not be available in the future, and it is
     * up to the caller to ensure safety if this uri is re-used and/or persisted.
     */
    @NonNull
    public Uri getUri() {
        if (mType == TYPE_UNKNOWN && Build.VERSION.SDK_INT >= 23) {
            return Api23Impl.getUri(mObj1);
        }
        if (mType != TYPE_URI && mType != TYPE_URI_ADAPTIVE_BITMAP) {
            throw new IllegalStateException("called getUri() on " + this);
        }
        return Uri.parse((String) mObj1);
    }
    /**
     * Store a color to use whenever this Icon is drawn.
     *
     * @param tint a color, as in {@link Drawable#setTint(int)}
     * @return this same object, for use in chained construction
     */
    @NonNull
    public IconCompat setTint(@ColorInt int tint) {
        return setTintList(ColorStateList.valueOf(tint));
    }
    /**
     * Store a color to use whenever this Icon is drawn.
     *
     * @param tintList as in {@link Drawable#setTintList(ColorStateList)}, null to remove tint
     * @return this same object, for use in chained construction
     */
    @NonNull
    public IconCompat setTintList(@Nullable ColorStateList tintList) {
        mTintList = tintList;
        return this;
    }
    /**
     * Store a blending mode to use whenever this Icon is drawn.
     *
     * @param mode a blending mode, as in {@link Drawable#setTintMode(PorterDuff.Mode)}, may be null
     * @return this same object, for use in chained construction
     */
    @NonNull
    public IconCompat setTintMode(@Nullable PorterDuff.Mode mode) {
        mTintMode = mode;
        return this;
    }
    /**
     * @deprecated Use {@link #toIcon(Context)} to generate the {@link Icon} object.
     */
    @RequiresApi(23)
    @Deprecated
    @NonNull
    public Icon toIcon() {
        return toIcon(null);
    }
    /**
     * Convert this compat object to {@link Icon} object.
     *
     * @return {@link Icon} object
     */
    @RequiresApi(23)
    @NonNull
    public Icon toIcon(@Nullable Context context) {
        if (Build.VERSION.SDK_INT >= 23) {
            return Api23Impl.toIcon(this, context);
        } else {
            throw new UnsupportedOperationException(
                    "This method is only supported on API level 23+");
        }
    }
    /**
     */
    @RestrictTo(LIBRARY_GROUP_PREFIX)
    public void checkResource(@NonNull Context context) {
        if (mType == TYPE_RESOURCE && mObj1 != null) {
            String fullResName = (String) mObj1;
            if (!fullResName.contains(":")) {
                return;
            }
            // Do some splitting to parse out each of the components.
            String resName = fullResName.split(":", -1)[1];
            String resType = resName.split("/", -1)[0];
            resName = resName.split("/", -1)[1];
            String resPackage = fullResName.split(":", -1)[0];
            if ("0_resource_name_obfuscated".equals(resName)) {
                // All obfuscated resources have the same name, so not going to look up the
                // resource identifier from the resource name.
                Log.i(TAG, "Found obfuscated resource, not trying to update resource id for it");
                return;
            }
            String appPackage = getResPackage();
            Resources res = getResources(context, appPackage);
            int id = res.getIdentifier(resName, resType, resPackage);
            if (mInt1 != id) {
                Log.i(TAG, "Id has changed for " + appPackage + " " + fullResName);
                mInt1 = id;
            }
        }
    }
    /**
     * Returns a Drawable that can be used to draw the image inside this Icon, constructing it
     * if necessary.
     *
     * @param context {@link android.content.Context Context} in which to load the drawable; used
     *                to access {@link android.content.res.Resources Resources}, for example.
     * @return A fresh instance of a drawable for this image, yours to keep.
     */
    @Nullable
    public Drawable loadDrawable(@NonNull Context context) {
        checkResource(context);
        if (Build.VERSION.SDK_INT >= 23) {
            return Api23Impl.loadDrawable(toIcon(context), context);
        }
        final Drawable result = loadDrawableInner(context);
        if (result != null && (mTintList != null || mTintMode != DEFAULT_TINT_MODE)) {
            result.mutate();
            DrawableCompat.setTintList(result, mTintList);
            DrawableCompat.setTintMode(result, mTintMode);
        }
        return result;
    }
    /**
     * Do the heavy lifting of loading the drawable, but stop short of applying any tint.
     */
    private Drawable loadDrawableInner(Context context) {
        switch (mType) {
            case TYPE_BITMAP:
                return new BitmapDrawable(context.getResources(), (Bitmap) mObj1);
            case TYPE_ADAPTIVE_BITMAP:
                return new BitmapDrawable(context.getResources(),
                        createLegacyIconFromAdaptiveIcon((Bitmap) mObj1, false));
            case TYPE_RESOURCE:
                // figure out where to load resources from
                String resPackage = getResPackage();
                if (TextUtils.isEmpty(resPackage)) {
                    // if none is specified, try the given context
                    resPackage = context.getPackageName();
                }
                Resources res = getResources(context, resPackage);
                try {
                    return ResourcesCompat.getDrawable(res, mInt1, context.getTheme());
                } catch (RuntimeException e) {
                    Log.e(TAG, String.format("Unable to load resource 0x%08x from pkg=%s",
                            mInt1,
                            mObj1),
                            e);
                }
                break;
            case TYPE_DATA:
                return new BitmapDrawable(context.getResources(),
                        BitmapFactory.decodeByteArray((byte[]) mObj1, mInt1, mInt2)
                );
            case TYPE_URI:
                InputStream is = getUriInputStream(context);
                if (is != null) {
                    return new BitmapDrawable(context.getResources(),
                            BitmapFactory.decodeStream(is));
                }
                break;
            case TYPE_URI_ADAPTIVE_BITMAP:
                is = getUriInputStream(context);
                if (is != null) {
                    if (Build.VERSION.SDK_INT >= 26) {
                        return Api26Impl.createAdaptiveIconDrawable(null,
                                new BitmapDrawable(context.getResources(),
                                        BitmapFactory.decodeStream(is)));
                    } else {
                        return new BitmapDrawable(context.getResources(),
                                createLegacyIconFromAdaptiveIcon(
                                        BitmapFactory.decodeStream(is), false));
                    }
                }
                break;
        }
        return null;
    }
    /**
     * Create an input stream for bitmap by resolving corresponding content uri.
     *
     */
    @Nullable
    @RestrictTo(LIBRARY_GROUP)
    public InputStream getUriInputStream(@NonNull Context context) {
        final Uri uri = getUri();
        final String scheme = uri.getScheme();
        if (ContentResolver.SCHEME_CONTENT.equals(scheme)
                || ContentResolver.SCHEME_FILE.equals(scheme)) {
            try {
                return context.getContentResolver().openInputStream(uri);
            } catch (Exception e) {
                Log.w(TAG, "Unable to load image from URI: " + uri, e);
            }
        } else {
            try {
                return new FileInputStream(new File((String) mObj1));
            } catch (FileNotFoundException e) {
                Log.w(TAG, "Unable to load image from path: " + uri, e);
            }
        }
        return null;
    }
    @SuppressWarnings("deprecation")
    static Resources getResources(Context context, String resPackage) {
        if ("android".equals(resPackage)) {
            return Resources.getSystem();
        } else {
            final PackageManager pm = context.getPackageManager();
            try {
                ApplicationInfo ai = pm.getApplicationInfo(
                        resPackage, PackageManager.MATCH_UNINSTALLED_PACKAGES);
                if (ai != null) {
                    return pm.getResourcesForApplication(ai);
                } else {
                    return null;
                }
            } catch (PackageManager.NameNotFoundException e) {
                Log.e(TAG, String.format("Unable to find pkg=%s for icon",
                        resPackage), e);
                return null;
            }
        }
    }
    /**
     */
    @RestrictTo(LIBRARY_GROUP_PREFIX)
    @SuppressWarnings("deprecation")
    public void addToShortcutIntent(@NonNull Intent outIntent, @Nullable Drawable badge,
            @NonNull Context c) {
        checkResource(c);
        Bitmap icon;
        switch (mType) {
            case TYPE_BITMAP:
                icon = (Bitmap) mObj1;
                if (badge != null) {
                    // Do not modify the original icon when applying a badge
                    icon = icon.copy(icon.getConfig(), true);
                }
                break;
            case TYPE_ADAPTIVE_BITMAP:
                icon = createLegacyIconFromAdaptiveIcon((Bitmap) mObj1, true);
                break;
            case TYPE_RESOURCE:
                try {
                    Context context = c.createPackageContext(getResPackage(), 0);
                    if (badge == null) {
                        outIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
                                Intent.ShortcutIconResource.fromContext(context, mInt1));
                        return;
                    } else {
                        Drawable dr = ContextCompat.getDrawable(context, mInt1);
                        if (dr.getIntrinsicWidth() <= 0 || dr.getIntrinsicHeight() <= 0) {
                            int size = ((ActivityManager) context.getSystemService(
                                    Context.ACTIVITY_SERVICE)).getLauncherLargeIconSize();
                            icon = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
                        } else {
                            icon = Bitmap.createBitmap(dr.getIntrinsicWidth(),
                                    dr.getIntrinsicHeight(),
                                    Bitmap.Config.ARGB_8888);
                        }
                        dr.setBounds(0, 0, icon.getWidth(), icon.getHeight());
                        dr.draw(new Canvas(icon));
                    }
                } catch (PackageManager.NameNotFoundException e) {
                    throw new IllegalArgumentException("Can't find package " + mObj1, e);
                }
                break;
            default:
                throw new IllegalArgumentException("Icon type not supported for intent shortcuts");
        }
        if (badge != null) {
            // Badge the icon
            int w = icon.getWidth();
            int h = icon.getHeight();
            badge.setBounds(w / 2, h / 2, w, h);
            badge.draw(new Canvas(icon));
        }
        outIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON, icon);
    }
    /**
     * Adds this Icon to a Bundle that can be read back with the same parameters
     * to {@link #createFromBundle(Bundle)}.
     */
    @NonNull
    public Bundle toBundle() {
        Bundle bundle = new Bundle();
        switch (mType) {
            case TYPE_BITMAP:
            case TYPE_ADAPTIVE_BITMAP:
                bundle.putParcelable(EXTRA_OBJ, (Bitmap) mObj1);
                break;
            case TYPE_UNKNOWN:
                // When unknown just wrapping an Icon.
                bundle.putParcelable(EXTRA_OBJ, (Parcelable) mObj1);
                break;
            case TYPE_RESOURCE:
            case TYPE_URI:
            case TYPE_URI_ADAPTIVE_BITMAP:
                bundle.putString(EXTRA_OBJ, (String) mObj1);
                break;
            case TYPE_DATA:
                bundle.putByteArray(EXTRA_OBJ, (byte[]) mObj1);
                break;
            default:
                throw new IllegalArgumentException("Invalid icon");
        }
        bundle.putInt(EXTRA_TYPE, mType);
        bundle.putInt(EXTRA_INT1, mInt1);
        bundle.putInt(EXTRA_INT2, mInt2);
        bundle.putString(EXTRA_STRING1, mString1);
        if (mTintList != null) {
            bundle.putParcelable(EXTRA_TINT_LIST, mTintList);
        }
        if (mTintMode != DEFAULT_TINT_MODE) {
            bundle.putString(EXTRA_TINT_MODE, mTintMode.name());
        }
        return bundle;
    }
    @NonNull
    @Override
    public String toString() {
        if (mType == TYPE_UNKNOWN) {
            return String.valueOf(mObj1);
        }
        final StringBuilder sb = new StringBuilder("Icon(typ=").append(typeToString(mType));
        switch (mType) {
            case TYPE_BITMAP:
            case TYPE_ADAPTIVE_BITMAP:
                sb.append(" size=")
                        .append(((Bitmap) mObj1).getWidth())
                        .append("x")
                        .append(((Bitmap) mObj1).getHeight());
                break;
            case TYPE_RESOURCE:
                sb.append(" pkg=")
                        .append(mString1)
                        .append(" id=")
                        .append(String.format("0x%08x", getResId()));
                break;
            case TYPE_DATA:
                sb.append(" len=").append(mInt1);
                if (mInt2 != 0) {
                    sb.append(" off=").append(mInt2);
                }
                break;
            case TYPE_URI:
            case TYPE_URI_ADAPTIVE_BITMAP:
                sb.append(" uri=").append(mObj1);
                break;
        }
        if (mTintList != null) {
            sb.append(" tint=");
            sb.append(mTintList);
        }
        if (mTintMode != DEFAULT_TINT_MODE) {
            sb.append(" mode=").append(mTintMode);
        }
        sb.append(")");
        return sb.toString();
    }
    @Override
    public void onPreParceling(boolean isStream) {
        mTintModeStr = mTintMode.name();
        switch (mType) {
            case TYPE_UNKNOWN:
                if (isStream) {
                    // We can't determine how to serialize this icon, so throw so the caller knows.
                    throw new IllegalArgumentException("Can't serialize Icon created with "
                            + "IconCompat#createFromIcon");
                } else {
                    mParcelable = (Parcelable) mObj1;
                }
                break;
            case TYPE_ADAPTIVE_BITMAP:
            case TYPE_BITMAP:
                if (isStream) {
                    Bitmap bitmap = (Bitmap) mObj1;
                    ByteArrayOutputStream data = new ByteArrayOutputStream();
                    bitmap.compress(Bitmap.CompressFormat.PNG, 90, data);
                    mData = data.toByteArray();
                } else {
                    mParcelable = (Parcelable) mObj1;
                }
                break;
            case TYPE_URI:
            case TYPE_URI_ADAPTIVE_BITMAP:
                mData = mObj1.toString().getBytes(Charset.forName("UTF-16"));
                break;
            case TYPE_RESOURCE:
                mData = ((String) mObj1).getBytes(Charset.forName("UTF-16"));
                break;
            case TYPE_DATA:
                mData = (byte[]) mObj1;
                break;
        }
    }
    @Override
    public void onPostParceling() {
        mTintMode = PorterDuff.Mode.valueOf(mTintModeStr);
        switch (mType) {
            case TYPE_UNKNOWN:
                if (mParcelable != null) {
                    mObj1 = mParcelable;
                } else {
                    throw new IllegalArgumentException("Invalid icon");
                }
                break;
            case TYPE_ADAPTIVE_BITMAP:
            case TYPE_BITMAP:
                if (mParcelable != null) {
                    mObj1 = mParcelable;
                } else {
                    // This is data now.
                    mObj1 = mData;
                    mType = TYPE_DATA;
                    mInt1 = 0;
                    mInt2 = mData.length;
                }
                break;
            case TYPE_URI:
            case TYPE_URI_ADAPTIVE_BITMAP:
            case TYPE_RESOURCE:
                mObj1 = new String(mData, Charset.forName("UTF-16"));
                // Slice, which may contain a IconCompat object, supports serialization to file.
                // In the old format, we don't store the app package name separately. To keep
                // the backward-compatibility, we have no choice but read the package name from the
                // full resource name string.
                if (mType == TYPE_RESOURCE) {
                    if (mString1 == null) {
                        mString1 = ((String) mObj1).split(":", -1)[0];
                    }
                }
                break;
            case TYPE_DATA:
                mObj1 = mData;
                break;
        }
    }
    private static String typeToString(int x) {
        switch (x) {
            case TYPE_BITMAP: return "BITMAP";
            case TYPE_ADAPTIVE_BITMAP: return "BITMAP_MASKABLE";
            case TYPE_DATA: return "DATA";
            case TYPE_RESOURCE: return "RESOURCE";
            case TYPE_URI: return "URI";
            case TYPE_URI_ADAPTIVE_BITMAP: return "URI_MASKABLE";
            default: return "UNKNOWN";
        }
    }
    /**
     * Extracts an icon from a bundle that was added using {@link #toBundle()}.
     */
    @SuppressWarnings("deprecation")
    public static @Nullable IconCompat createFromBundle(@NonNull Bundle bundle) {
        int type = bundle.getInt(EXTRA_TYPE);
        IconCompat icon = new IconCompat(type);
        icon.mInt1 = bundle.getInt(EXTRA_INT1);
        icon.mInt2 = bundle.getInt(EXTRA_INT2);
        icon.mString1 = bundle.getString(EXTRA_STRING1);
        if (bundle.containsKey(EXTRA_TINT_LIST)) {
            icon.mTintList = bundle.getParcelable(EXTRA_TINT_LIST);
        }
        if (bundle.containsKey(EXTRA_TINT_MODE)) {
            icon.mTintMode = PorterDuff.Mode.valueOf(
                    bundle.getString(EXTRA_TINT_MODE));
        }
        switch (type) {
            case TYPE_BITMAP:
            case TYPE_ADAPTIVE_BITMAP:
            case TYPE_UNKNOWN:
                icon.mObj1 = bundle.getParcelable(EXTRA_OBJ);
                break;
            case TYPE_RESOURCE:
            case TYPE_URI:
            case TYPE_URI_ADAPTIVE_BITMAP:
                icon.mObj1 = bundle.getString(EXTRA_OBJ);
                break;
            case TYPE_DATA:
                icon.mObj1 = bundle.getByteArray(EXTRA_OBJ);
                break;
            default:
                Log.w(TAG, "Unknown type " + type);
                return null;
        }
        return icon;
    }
    /**
     * Creates an IconCompat from an Icon.
     */
    @RequiresApi(23)
    @Nullable
    public static IconCompat createFromIcon(@NonNull Context context, @NonNull Icon icon) {
        Preconditions.checkNotNull(icon);
        return Api23Impl.createFromIcon(context, icon);
    }
    /**
     * Creates an IconCompat from an Icon.
     */
    @RestrictTo(LIBRARY_GROUP_PREFIX)
    @RequiresApi(23)
    @Nullable
    public static IconCompat createFromIcon(@NonNull Icon icon) {
        return Api23Impl.createFromIconInner(icon);
    }
    /**
     * Creates an IconCompat from an Icon, or returns null if the given Icon is created from
     * resource 0.
     */
    @RestrictTo(LIBRARY_GROUP_PREFIX)
    @RequiresApi(23)
    @Nullable
    public static IconCompat createFromIconOrNullIfZeroResId(@NonNull Icon icon) {
        if (Api23Impl.getType(icon) == TYPE_RESOURCE && Api23Impl.getResId(icon) == 0) {
            return null;
        }
        return Api23Impl.createFromIconInner(icon);
    }
    /**
     * Converts a bitmap following the adaptive icon guide lines, into a bitmap following the
     * shortcut icon guide lines.
     * The returned bitmap will always have same width and height and clipped to a circle.
     *
     * @param addShadow set to {@code true} only for legacy shortcuts and {@code false} otherwise
     */
    @VisibleForTesting
    static Bitmap createLegacyIconFromAdaptiveIcon(Bitmap adaptiveIconBitmap, boolean addShadow) {
        int size = (int) (DEFAULT_VIEW_PORT_SCALE * Math.min(adaptiveIconBitmap.getWidth(),
                adaptiveIconBitmap.getHeight()));
        Bitmap icon = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(icon);
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
        float center = size * 0.5f;
        float radius = center * ICON_DIAMETER_FACTOR;
        if (addShadow) {
            // Draw key shadow
            float blur = BLUR_FACTOR * size;
            paint.setColor(Color.TRANSPARENT);
            paint.setShadowLayer(blur, 0, KEY_SHADOW_OFFSET_FACTOR * size, KEY_SHADOW_ALPHA << 24);
            canvas.drawCircle(center, center, radius, paint);
            // Draw ambient shadow
            paint.setShadowLayer(blur, 0, 0, AMBIENT_SHADOW_ALPHA << 24);
            canvas.drawCircle(center, center, radius, paint);
            paint.clearShadowLayer();
        }
        // Draw the clipped icon
        paint.setColor(Color.BLACK);
        BitmapShader shader = new BitmapShader(adaptiveIconBitmap, Shader.TileMode.CLAMP,
                Shader.TileMode.CLAMP);
        Matrix shift = new Matrix();
        shift.setTranslate(-(adaptiveIconBitmap.getWidth() - size) / 2.0f,
                -(adaptiveIconBitmap.getHeight() - size) / 2.0f);
        shader.setLocalMatrix(shift);
        paint.setShader(shader);
        canvas.drawCircle(center, center, radius, paint);
        canvas.setBitmap(null);
        return icon;
    }
    @RequiresApi(28)
    static class Api28Impl {
        private Api28Impl() {
            // This class is not instantiable.
        }
        static String getResPackage(Object icon) {
            return ((Icon) icon).getResPackage();
        }
        static int getType(Object icon) {
            return ((Icon) icon).getType();
        }
        static int getResId(Object icon) {
            return ((Icon) icon).getResId();
        }
        static Uri getUri(Object icon) {
            return ((Icon) icon).getUri();
        }
    }
    @RequiresApi(26)
    static class Api26Impl {
        private Api26Impl() {
            // This class is not instantiable.
        }
        static Drawable createAdaptiveIconDrawable(Drawable backgroundDrawable,
                Drawable foregroundDrawable) {
            return new AdaptiveIconDrawable(backgroundDrawable, foregroundDrawable);
        }
        static Icon createWithAdaptiveBitmap(Bitmap bits) {
            return Icon.createWithAdaptiveBitmap(bits);
        }
    }
    @RequiresApi(30)
    static class Api30Impl {
        private Api30Impl() {
            // This class is not instantiable.
        }
        static Icon createWithAdaptiveBitmapContentUri(Uri uri) {
            return Icon.createWithAdaptiveBitmapContentUri(uri);
        }
    }
    @RequiresApi(23)
    static class Api23Impl {
        private Api23Impl() {
            // This class is not instantiable.
        }
        @Nullable
        static IconCompat createFromIcon(@NonNull Context context, @NonNull Icon icon) {
            switch (getType(icon)) {
                case TYPE_RESOURCE:
                    String resPackage = getResPackage(icon);
                    try {
                        return createWithResource(getResources(context, resPackage), resPackage,
                                getResId(icon));
                    } catch (Resources.NotFoundException e) {
                        throw new IllegalArgumentException("Icon resource cannot be found");
                    }
                case TYPE_URI:
                    return createWithContentUri(getUri(icon));
                case TYPE_URI_ADAPTIVE_BITMAP:
                    return createWithAdaptiveBitmapContentUri(getUri(icon));
            }
            IconCompat iconCompat = new IconCompat(TYPE_UNKNOWN);
            iconCompat.mObj1 = icon;
            return iconCompat;
        }
        /**
         * Gets the type of the icon provided.
         * <p>
         * Note that new types may be added later, so callers should guard against other
         * types being returned. Returns {@link #TYPE_UNKNOWN} when the type cannot be
         * determined.
         */
        @IconType
        static int getType(@NonNull Object icon) {
            if (Build.VERSION.SDK_INT >= 28) {
                return Api28Impl.getType(icon);
            } else {
                try {
                    return (int) icon.getClass().getMethod("getType").invoke(icon);
                } catch (IllegalAccessException e) {
                    Log.e(TAG, "Unable to get icon type " + icon, e);
                    return TYPE_UNKNOWN;
                } catch (InvocationTargetException e) {
                    Log.e(TAG, "Unable to get icon type " + icon, e);
                    return TYPE_UNKNOWN;
                } catch (NoSuchMethodException e) {
                    Log.e(TAG, "Unable to get icon type " + icon, e);
                    return TYPE_UNKNOWN;
                }
            }
        }
        /**
         * Gets the package used to create this icon.
         * <p>
         * Only valid for icons of type TYPE_RESOURCE.
         * Note: This package may not be available if referenced in the future, and it is
         * up to the caller to ensure safety if this package is re-used and/or persisted.
         * Returns {@code null} when the value cannot be gotten.
         */
        @Nullable
        static String getResPackage(@NonNull Object icon) {
            if (Build.VERSION.SDK_INT >= 28) {
                return Api28Impl.getResPackage(icon);
            } else {
                try {
                    return (String) icon.getClass().getMethod("getResPackage").invoke(icon);
                } catch (IllegalAccessException e) {
                    Log.e(TAG, "Unable to get icon package", e);
                    return null;
                } catch (InvocationTargetException e) {
                    Log.e(TAG, "Unable to get icon package", e);
                    return null;
                } catch (NoSuchMethodException e) {
                    Log.e(TAG, "Unable to get icon package", e);
                    return null;
                }
            }
        }
        /**
         * Used internally to avoid casting to Icon class in code accessible to SDK < 23.
         */
        static IconCompat createFromIconInner(@NonNull Object icon) {
            Preconditions.checkNotNull(icon);
            switch (getType(icon)) {
                case TYPE_RESOURCE:
                    return createWithResource(null, getResPackage(icon), getResId(icon));
                case TYPE_URI:
                    return createWithContentUri(getUri(icon));
                case TYPE_URI_ADAPTIVE_BITMAP:
                    return createWithAdaptiveBitmapContentUri(getUri(icon));
            }
            IconCompat iconCompat = new IconCompat(TYPE_UNKNOWN);
            iconCompat.mObj1 = icon;
            return iconCompat;
        }
        /**
         * Gets the resource used to create this icon.
         * <p>
         * Only valid for icons of type TYPE_RESOURCE.
         * Note: This resource may not be available if the application changes at all, and it is
         * up to the caller to ensure safety if this resource is re-used and/or persisted.
         * Returns {@code 0} if the id cannot be gotten.
         */
        @IdRes
        @DrawableRes
        static int getResId(@NonNull Object icon) {
            if (Build.VERSION.SDK_INT >= 28) {
                return Api28Impl.getResId(icon);
            } else {
                try {
                    return (int) icon.getClass().getMethod("getResId").invoke(icon);
                } catch (IllegalAccessException e) {
                    Log.e(TAG, "Unable to get icon resource", e);
                    return 0;
                } catch (InvocationTargetException e) {
                    Log.e(TAG, "Unable to get icon resource", e);
                    return 0;
                } catch (NoSuchMethodException e) {
                    Log.e(TAG, "Unable to get icon resource", e);
                    return 0;
                }
            }
        }
        /**
         * Gets the uri used to create this icon.
         * <p>
         * Only valid for icons of type TYPE_URI.
         * Note: This uri may not be available in the future, and it is
         * up to the caller to ensure safety if this uri is re-used and/or persisted.
         * Returns {@code null} if the uri cannot be gotten.
         */
        @Nullable
        static Uri getUri(@NonNull Object icon) {
            if (Build.VERSION.SDK_INT >= 28) {
                return Api28Impl.getUri(icon);
            } else {
                try {
                    return (Uri) icon.getClass().getMethod("getUri").invoke(icon);
                } catch (IllegalAccessException e) {
                    Log.e(TAG, "Unable to get icon uri", e);
                    return null;
                } catch (InvocationTargetException e) {
                    Log.e(TAG, "Unable to get icon uri", e);
                    return null;
                } catch (NoSuchMethodException e) {
                    Log.e(TAG, "Unable to get icon uri", e);
                    return null;
                }
            }
        }
        static Icon toIcon(IconCompat iconCompat, Context context) {
            Icon icon;
            switch (iconCompat.mType) {
                case TYPE_UNKNOWN:
                    // When type is unknown we are just wrapping an icon.
                    return (Icon) iconCompat.mObj1;
                case TYPE_BITMAP:
                    icon = Icon.createWithBitmap((Bitmap) iconCompat.mObj1);
                    break;
                case TYPE_ADAPTIVE_BITMAP:
                    if (Build.VERSION.SDK_INT >= 26) {
                        icon = Api26Impl.createWithAdaptiveBitmap((Bitmap) iconCompat.mObj1);
                    } else {
                        icon = Icon.createWithBitmap(
                                createLegacyIconFromAdaptiveIcon((Bitmap) iconCompat.mObj1, false));
                    }
                    break;
                case TYPE_RESOURCE:
                    icon = Icon.createWithResource(iconCompat.getResPackage(), iconCompat.mInt1);
                    break;
                case TYPE_DATA:
                    icon = Icon.createWithData((byte[]) iconCompat.mObj1, iconCompat.mInt1,
                            iconCompat.mInt2);
                    break;
                case TYPE_URI:
                    icon = Icon.createWithContentUri((String) iconCompat.mObj1);
                    break;
                case TYPE_URI_ADAPTIVE_BITMAP:
                    if (Build.VERSION.SDK_INT >= 30) {
                        icon = Api30Impl.createWithAdaptiveBitmapContentUri(iconCompat.getUri());
                        break;
                    }
                    if (context == null) {
                        throw new IllegalArgumentException(
                                "Context is required to resolve the file uri of the icon: "
                                        + iconCompat.getUri());
                    }
                    InputStream is = iconCompat.getUriInputStream(context);
                    if (is == null) {
                        throw new IllegalStateException(
                                "Cannot load adaptive icon from uri: " + iconCompat.getUri());
                    }
                    if (Build.VERSION.SDK_INT >= 26) {
                        icon = Api26Impl.createWithAdaptiveBitmap(BitmapFactory.decodeStream(is));
                    } else {
                        icon = Icon.createWithBitmap(createLegacyIconFromAdaptiveIcon(
                                BitmapFactory.decodeStream(is), false));
                    }
                    break;
                default:
                    throw new IllegalArgumentException("Unknown type");
            }
            if (iconCompat.mTintList != null) {
                icon.setTintList(iconCompat.mTintList);
            }
            if (iconCompat.mTintMode != DEFAULT_TINT_MODE) {
                icon.setTintMode(iconCompat.mTintMode);
            }
            return icon;
        }
        static Drawable loadDrawable(Icon icon, Context context) {
            return icon.loadDrawable(context);
        }
    }
}