package androidx.appcompat.widget; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; import android.os.Build; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; import android.util.Xml; import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import androidx.annotation.RestrictTo; import androidx.appcompat.graphics.drawable.AnimatedStateListDrawableCompat; import androidx.appcompat.resources.R; import androidx.collection.LongSparseArray; import androidx.collection.LruCache; import androidx.collection.SimpleArrayMap; import androidx.collection.SparseArrayCompat; import androidx.core.content.ContextCompat; import androidx.core.graphics.drawable.DrawableCompat; import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat; import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat; import java.lang.ref.WeakReference; import java.util.WeakHashMap; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @RestrictTo({RestrictTo.Scope.LIBRARY_GROUP_PREFIX}) public final class ResourceManagerInternal { private static final ColorFilterLruCache COLOR_FILTER_CACHE = new ColorFilterLruCache(6); private static final boolean DEBUG = false; private static final PorterDuff.Mode DEFAULT_MODE = PorterDuff.Mode.SRC_IN; private static ResourceManagerInternal INSTANCE = null; private static final String PLATFORM_VD_CLAZZ = "android.graphics.drawable.VectorDrawable"; private static final String SKIP_DRAWABLE_TAG = "appcompat_skip_skip"; private static final String TAG = "ResourceManagerInternal"; private SimpleArrayMap mDelegates; private final WeakHashMap>> mDrawableCaches = new WeakHashMap<>(0); private boolean mHasCheckedVectorDrawableSetup; private ResourceManagerHooks mHooks; private SparseArrayCompat mKnownDrawableIdTags; private WeakHashMap> mTintLists; private TypedValue mTypedValue; @RequiresApi(11) public static class AsldcInflateDelegate implements InflateDelegate { @Override // androidx.appcompat.widget.ResourceManagerInternal.InflateDelegate public Drawable createFromXmlInner(@NonNull Context context, @NonNull XmlPullParser xmlPullParser, @NonNull AttributeSet attributeSet, @Nullable Resources.Theme theme) { try { return AnimatedStateListDrawableCompat.createFromXmlInner(context, context.getResources(), xmlPullParser, attributeSet, theme); } catch (Exception e) { Log.e("AsldcInflateDelegate", "Exception while inflating ", e); return null; } } } public static class AvdcInflateDelegate implements InflateDelegate { @Override // androidx.appcompat.widget.ResourceManagerInternal.InflateDelegate public Drawable createFromXmlInner(@NonNull Context context, @NonNull XmlPullParser xmlPullParser, @NonNull AttributeSet attributeSet, @Nullable Resources.Theme theme) { try { return AnimatedVectorDrawableCompat.createFromXmlInner(context, context.getResources(), xmlPullParser, attributeSet, theme); } catch (Exception e) { Log.e("AvdcInflateDelegate", "Exception while inflating ", e); return null; } } } public static class ColorFilterLruCache extends LruCache { public ColorFilterLruCache(int i) { super(i); } private static int generateCacheKey(int i, PorterDuff.Mode mode) { return mode.hashCode() + ((i + 31) * 31); } public PorterDuffColorFilter get(int i, PorterDuff.Mode mode) { return get(Integer.valueOf(generateCacheKey(i, mode))); } public PorterDuffColorFilter put(int i, PorterDuff.Mode mode, PorterDuffColorFilter porterDuffColorFilter) { return put(Integer.valueOf(generateCacheKey(i, mode)), porterDuffColorFilter); } } public interface InflateDelegate { Drawable createFromXmlInner(@NonNull Context context, @NonNull XmlPullParser xmlPullParser, @NonNull AttributeSet attributeSet, @Nullable Resources.Theme theme); } @RestrictTo({RestrictTo.Scope.LIBRARY_GROUP_PREFIX}) public interface ResourceManagerHooks { Drawable createDrawableFor(@NonNull ResourceManagerInternal resourceManagerInternal, @NonNull Context context, @DrawableRes int i); ColorStateList getTintListForDrawableRes(@NonNull Context context, @DrawableRes int i); PorterDuff.Mode getTintModeForDrawableRes(int i); boolean tintDrawable(@NonNull Context context, @DrawableRes int i, @NonNull Drawable drawable); boolean tintDrawableUsingColorFilter(@NonNull Context context, @DrawableRes int i, @NonNull Drawable drawable); } public static class VdcInflateDelegate implements InflateDelegate { @Override // androidx.appcompat.widget.ResourceManagerInternal.InflateDelegate public Drawable createFromXmlInner(@NonNull Context context, @NonNull XmlPullParser xmlPullParser, @NonNull AttributeSet attributeSet, @Nullable Resources.Theme theme) { try { return VectorDrawableCompat.createFromXmlInner(context.getResources(), xmlPullParser, attributeSet, theme); } catch (Exception e) { Log.e("VdcInflateDelegate", "Exception while inflating ", e); return null; } } } private void addDelegate(@NonNull String str, @NonNull InflateDelegate inflateDelegate) { if (this.mDelegates == null) { this.mDelegates = new SimpleArrayMap<>(); } this.mDelegates.put(str, inflateDelegate); } private synchronized boolean addDrawableToCache(@NonNull Context context, long j, @NonNull Drawable drawable) { Drawable.ConstantState constantState = drawable.getConstantState(); if (constantState == null) { return false; } LongSparseArray> longSparseArray = this.mDrawableCaches.get(context); if (longSparseArray == null) { longSparseArray = new LongSparseArray<>(); this.mDrawableCaches.put(context, longSparseArray); } longSparseArray.put(j, new WeakReference<>(constantState)); return true; } private void addTintListToCache(@NonNull Context context, @DrawableRes int i, @NonNull ColorStateList colorStateList) { if (this.mTintLists == null) { this.mTintLists = new WeakHashMap<>(); } SparseArrayCompat sparseArrayCompat = this.mTintLists.get(context); if (sparseArrayCompat == null) { sparseArrayCompat = new SparseArrayCompat<>(); this.mTintLists.put(context, sparseArrayCompat); } sparseArrayCompat.append(i, colorStateList); } private void checkVectorDrawableSetup(@NonNull Context context) { if (!this.mHasCheckedVectorDrawableSetup) { this.mHasCheckedVectorDrawableSetup = true; Drawable drawable = getDrawable(context, R.drawable.abc_vector_test); if (drawable == null || !isVectorDrawable(drawable)) { this.mHasCheckedVectorDrawableSetup = false; throw new IllegalStateException("This app has been built with an incorrect configuration. Please configure your build for VectorDrawableCompat."); } } } private static long createCacheKey(TypedValue typedValue) { return (((long) typedValue.assetCookie) << 32) | ((long) typedValue.data); } private Drawable createDrawableIfNeeded(@NonNull Context context, @DrawableRes int i) { if (this.mTypedValue == null) { this.mTypedValue = new TypedValue(); } TypedValue typedValue = this.mTypedValue; context.getResources().getValue(i, typedValue, true); long createCacheKey = createCacheKey(typedValue); Drawable cachedDrawable = getCachedDrawable(context, createCacheKey); if (cachedDrawable != null) { return cachedDrawable; } ResourceManagerHooks resourceManagerHooks = this.mHooks; Drawable createDrawableFor = resourceManagerHooks == null ? null : resourceManagerHooks.createDrawableFor(this, context, i); if (createDrawableFor != null) { createDrawableFor.setChangingConfigurations(typedValue.changingConfigurations); addDrawableToCache(context, createCacheKey, createDrawableFor); } return createDrawableFor; } private static PorterDuffColorFilter createTintFilter(ColorStateList colorStateList, PorterDuff.Mode mode, int[] iArr) { if (colorStateList == null || mode == null) { return null; } return getPorterDuffColorFilter(colorStateList.getColorForState(iArr, 0), mode); } public static synchronized ResourceManagerInternal get() { ResourceManagerInternal resourceManagerInternal; synchronized (ResourceManagerInternal.class) { if (INSTANCE == null) { ResourceManagerInternal resourceManagerInternal2 = new ResourceManagerInternal(); INSTANCE = resourceManagerInternal2; installDefaultInflateDelegates(resourceManagerInternal2); } resourceManagerInternal = INSTANCE; } return resourceManagerInternal; } private synchronized Drawable getCachedDrawable(@NonNull Context context, long j) { LongSparseArray> longSparseArray = this.mDrawableCaches.get(context); if (longSparseArray == null) { return null; } WeakReference weakReference = longSparseArray.get(j); if (weakReference != null) { Drawable.ConstantState constantState = weakReference.get(); if (constantState != null) { return constantState.newDrawable(context.getResources()); } longSparseArray.remove(j); } return null; } public static synchronized PorterDuffColorFilter getPorterDuffColorFilter(int i, PorterDuff.Mode mode) { PorterDuffColorFilter porterDuffColorFilter; synchronized (ResourceManagerInternal.class) { ColorFilterLruCache colorFilterLruCache = COLOR_FILTER_CACHE; porterDuffColorFilter = colorFilterLruCache.get(i, mode); if (porterDuffColorFilter == null) { porterDuffColorFilter = new PorterDuffColorFilter(i, mode); colorFilterLruCache.put(i, mode, porterDuffColorFilter); } } return porterDuffColorFilter; } private ColorStateList getTintListFromCache(@NonNull Context context, @DrawableRes int i) { SparseArrayCompat sparseArrayCompat; WeakHashMap> weakHashMap = this.mTintLists; if (weakHashMap == null || (sparseArrayCompat = weakHashMap.get(context)) == null) { return null; } return sparseArrayCompat.get(i); } private static void installDefaultInflateDelegates(@NonNull ResourceManagerInternal resourceManagerInternal) { if (Build.VERSION.SDK_INT < 24) { resourceManagerInternal.addDelegate("vector", new VdcInflateDelegate()); resourceManagerInternal.addDelegate("animated-vector", new AvdcInflateDelegate()); resourceManagerInternal.addDelegate("animated-selector", new AsldcInflateDelegate()); } } private static boolean isVectorDrawable(@NonNull Drawable drawable) { return (drawable instanceof VectorDrawableCompat) || PLATFORM_VD_CLAZZ.equals(drawable.getClass().getName()); } private Drawable loadDrawableFromDelegates(@NonNull Context context, @DrawableRes int i) { XmlResourceParser xml; int next; SimpleArrayMap simpleArrayMap = this.mDelegates; if (simpleArrayMap == null || simpleArrayMap.isEmpty()) { return null; } SparseArrayCompat sparseArrayCompat = this.mKnownDrawableIdTags; if (sparseArrayCompat != null) { String str = sparseArrayCompat.get(i); if (SKIP_DRAWABLE_TAG.equals(str) || (str != null && this.mDelegates.get(str) == null)) { return null; } } else { this.mKnownDrawableIdTags = new SparseArrayCompat<>(); } if (this.mTypedValue == null) { this.mTypedValue = new TypedValue(); } TypedValue typedValue = this.mTypedValue; Resources resources = context.getResources(); resources.getValue(i, typedValue, true); long createCacheKey = createCacheKey(typedValue); Drawable cachedDrawable = getCachedDrawable(context, createCacheKey); if (cachedDrawable != null) { return cachedDrawable; } CharSequence charSequence = typedValue.string; if (charSequence != null && charSequence.toString().endsWith(".xml")) { try { xml = resources.getXml(i); AttributeSet asAttributeSet = Xml.asAttributeSet(xml); if (next == 2) { String name = xml.getName(); this.mKnownDrawableIdTags.append(i, name); InflateDelegate inflateDelegate = this.mDelegates.get(name); if (inflateDelegate != null) { cachedDrawable = inflateDelegate.createFromXmlInner(context, xml, asAttributeSet, context.getTheme()); } if (cachedDrawable != null) { cachedDrawable.setChangingConfigurations(typedValue.changingConfigurations); addDrawableToCache(context, createCacheKey, cachedDrawable); } } else { throw new XmlPullParserException("No start tag found"); } } catch (Exception e) { Log.e(TAG, "Exception while inflating drawable", e); } while (true) { next = xml.next(); if (next == 2 || next == 1) { break; } } } if (cachedDrawable == null) { this.mKnownDrawableIdTags.append(i, SKIP_DRAWABLE_TAG); } return cachedDrawable; } private Drawable tintDrawable(@NonNull Context context, @DrawableRes int i, boolean z2, @NonNull Drawable drawable) { ColorStateList tintList = getTintList(context, i); if (tintList != null) { if (DrawableUtils.canSafelyMutateDrawable(drawable)) { drawable = drawable.mutate(); } Drawable wrap = DrawableCompat.wrap(drawable); DrawableCompat.setTintList(wrap, tintList); PorterDuff.Mode tintMode = getTintMode(i); if (tintMode == null) { return wrap; } DrawableCompat.setTintMode(wrap, tintMode); return wrap; } ResourceManagerHooks resourceManagerHooks = this.mHooks; if ((resourceManagerHooks == null || !resourceManagerHooks.tintDrawable(context, i, drawable)) && !tintDrawableUsingColorFilter(context, i, drawable) && z2) { return null; } return drawable; } public static void tintDrawable(Drawable drawable, TintInfo tintInfo, int[] iArr) { if (!DrawableUtils.canSafelyMutateDrawable(drawable) || drawable.mutate() == drawable) { boolean z2 = tintInfo.mHasTintList; if (z2 || tintInfo.mHasTintMode) { drawable.setColorFilter(createTintFilter(z2 ? tintInfo.mTintList : null, tintInfo.mHasTintMode ? tintInfo.mTintMode : DEFAULT_MODE, iArr)); } else { drawable.clearColorFilter(); } if (Build.VERSION.SDK_INT <= 23) { drawable.invalidateSelf(); return; } return; } Log.d(TAG, "Mutated drawable is not the same instance as the input."); } public synchronized Drawable getDrawable(@NonNull Context context, @DrawableRes int i) { return getDrawable(context, i, false); } public synchronized Drawable getDrawable(@NonNull Context context, @DrawableRes int i, boolean z2) { Drawable loadDrawableFromDelegates; checkVectorDrawableSetup(context); loadDrawableFromDelegates = loadDrawableFromDelegates(context, i); if (loadDrawableFromDelegates == null) { loadDrawableFromDelegates = createDrawableIfNeeded(context, i); } if (loadDrawableFromDelegates == null) { loadDrawableFromDelegates = ContextCompat.getDrawable(context, i); } if (loadDrawableFromDelegates != null) { loadDrawableFromDelegates = tintDrawable(context, i, z2, loadDrawableFromDelegates); } if (loadDrawableFromDelegates != null) { DrawableUtils.fixDrawable(loadDrawableFromDelegates); } return loadDrawableFromDelegates; } public synchronized ColorStateList getTintList(@NonNull Context context, @DrawableRes int i) { ColorStateList tintListFromCache; tintListFromCache = getTintListFromCache(context, i); if (tintListFromCache == null) { ResourceManagerHooks resourceManagerHooks = this.mHooks; tintListFromCache = resourceManagerHooks == null ? null : resourceManagerHooks.getTintListForDrawableRes(context, i); if (tintListFromCache != null) { addTintListToCache(context, i, tintListFromCache); } } return tintListFromCache; } public PorterDuff.Mode getTintMode(int i) { ResourceManagerHooks resourceManagerHooks = this.mHooks; if (resourceManagerHooks == null) { return null; } return resourceManagerHooks.getTintModeForDrawableRes(i); } public synchronized void onConfigurationChanged(@NonNull Context context) { LongSparseArray> longSparseArray = this.mDrawableCaches.get(context); if (longSparseArray != null) { longSparseArray.clear(); } } public synchronized Drawable onDrawableLoadedFromResources(@NonNull Context context, @NonNull VectorEnabledTintResources vectorEnabledTintResources, @DrawableRes int i) { Drawable loadDrawableFromDelegates = loadDrawableFromDelegates(context, i); if (loadDrawableFromDelegates == null) { loadDrawableFromDelegates = vectorEnabledTintResources.superGetDrawable(i); } if (loadDrawableFromDelegates == null) { return null; } return tintDrawable(context, i, false, loadDrawableFromDelegates); } public synchronized void setHooks(ResourceManagerHooks resourceManagerHooks) { this.mHooks = resourceManagerHooks; } public boolean tintDrawableUsingColorFilter(@NonNull Context context, @DrawableRes int i, @NonNull Drawable drawable) { ResourceManagerHooks resourceManagerHooks = this.mHooks; return resourceManagerHooks != null && resourceManagerHooks.tintDrawableUsingColorFilter(context, i, drawable); } }