Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 304ea5aa authored by Alan Viverette's avatar Alan Viverette Committed by Android (Google) Code Review
Browse files

Merge "Allow use of theme attributes in color state lists"

parents 2b2ad7ce 45c4bbbb
Loading
Loading
Loading
Loading
+11 −3
Original line number Diff line number Diff line
@@ -2407,6 +2407,7 @@ package android {
    field public static final int Widget_Material_Button_Borderless = 16974425; // 0x1030259
    field public static final int Widget_Material_Button_Borderless_Colored = 16974426; // 0x103025a
    field public static final int Widget_Material_Button_Borderless_Small = 16974427; // 0x103025b
    field public static final int Widget_Material_Button_Colored = 16974547; // 0x10302d3
    field public static final int Widget_Material_Button_Inset = 16974428; // 0x103025c
    field public static final int Widget_Material_Button_Small = 16974429; // 0x103025d
    field public static final int Widget_Material_Button_Toggle = 16974430; // 0x103025e
@@ -7148,6 +7149,8 @@ package android.content {
    method public abstract java.io.File getCacheDir();
    method public abstract java.lang.ClassLoader getClassLoader();
    method public abstract java.io.File getCodeCacheDir();
    method public final int getColor(int);
    method public final android.content.res.ColorStateList getColorStateList(int);
    method public abstract android.content.ContentResolver getContentResolver();
    method public abstract java.io.File getDatabasePath(java.lang.String);
    method public abstract java.io.File getDir(java.lang.String, int);
@@ -9076,7 +9079,10 @@ package android.content.res {
  public class ColorStateList implements android.os.Parcelable {
    ctor public ColorStateList(int[][], int[]);
    method public static android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
    method public void applyTheme(android.content.res.Resources.Theme);
    method public boolean canApplyTheme();
    method public static deprecated android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
    method public static android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
    method public int describeContents();
    method public int getColorForState(int[], int);
    method public int getDefaultColor();
@@ -9206,8 +9212,10 @@ package android.content.res {
    method public android.content.res.XmlResourceParser getAnimation(int) throws android.content.res.Resources.NotFoundException;
    method public final android.content.res.AssetManager getAssets();
    method public boolean getBoolean(int) throws android.content.res.Resources.NotFoundException;
    method public int getColor(int) throws android.content.res.Resources.NotFoundException;
    method public android.content.res.ColorStateList getColorStateList(int) throws android.content.res.Resources.NotFoundException;
    method public deprecated int getColor(int) throws android.content.res.Resources.NotFoundException;
    method public int getColor(int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
    method public deprecated android.content.res.ColorStateList getColorStateList(int) throws android.content.res.Resources.NotFoundException;
    method public android.content.res.ColorStateList getColorStateList(int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
    method public android.content.res.Configuration getConfiguration();
    method public float getDimension(int) throws android.content.res.Resources.NotFoundException;
    method public int getDimensionPixelOffset(int) throws android.content.res.Resources.NotFoundException;
+40 −2
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.annotation.SystemApi;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -392,18 +393,55 @@ public abstract class Context {
    }

    /**
     * Return a drawable object associated with a particular resource ID and
     * Returns a color associated with a particular resource ID and styled for
     * the current theme.
     *
     * @param id The desired resource identifier, as generated by the aapt
     *           tool. This integer encodes the package, type, and resource
     *           entry. The value 0 is an invalid identifier.
     * @return A single color value in the form 0xAARRGGBB.
     * @throws android.content.res.Resources.NotFoundException if the given ID
     *         does not exist.
     */
    @Nullable
    public final int getColor(int id) {
        return getResources().getColor(id, getTheme());
    }

    /**
     * Returns a drawable object associated with a particular resource ID and
     * styled for the current theme.
     *
     * @param id The desired resource identifier, as generated by the aapt
     *           tool. This integer encodes the package, type, and resource
     *           entry. The value 0 is an invalid identifier.
     * @return Drawable An object that can be used to draw this resource.
     * @return An object that can be used to draw this resource, or
     *         {@code null} if the resource could not be resolved.
     * @throws android.content.res.Resources.NotFoundException if the given ID
     *         does not exist.
     */
    @Nullable
    public final Drawable getDrawable(int id) {
        return getResources().getDrawable(id, getTheme());
    }

    /**
     * Returns a color state list associated with a particular resource ID and
     * styled for the current theme.
     *
     * @param id The desired resource identifier, as generated by the aapt
     *           tool. This integer encodes the package, type, and resource
     *           entry. The value 0 is an invalid identifier.
     * @return A color state list, or {@code null} if the resource could not be
     *         resolved.
     * @throws android.content.res.Resources.NotFoundException if the given ID
     *         does not exist.
     */
    @Nullable
    public final ColorStateList getColorStateList(int id) {
        return getResources().getColorStateList(id, getTheme());
    }

     /**
     * Set the base theme for this context.  Note that this should be called
     * before any views are instantiated in the Context (for example before
+302 −98

File changed.

Preview size limit exceeded, changes collapsed.

+172 −89
Original line number Diff line number Diff line
@@ -16,21 +16,20 @@

package android.content.res;

import android.animation.Animator;
import android.animation.StateListAnimator;
import android.annotation.NonNull;
import android.util.Pools.SynchronizedPool;
import android.view.ViewDebug;
import com.android.internal.util.XmlUtils;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.animation.Animator;
import android.animation.StateListAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.ActivityInfo;
import android.content.res.ColorStateList.ColorStateListFactory;
import android.graphics.Movie;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable.ConstantState;
import android.os.Build;
import android.os.Bundle;
@@ -40,9 +39,11 @@ import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.LongSparseArray;
import android.util.Pools.SynchronizedPool;
import android.util.Slog;
import android.util.TypedValue;
import android.util.LongSparseArray;
import android.view.ViewDebug;

import java.io.IOException;
import java.io.InputStream;
@@ -97,8 +98,8 @@ public class Resources {
    private static final LongSparseArray<ConstantState>[] sPreloadedDrawables;
    private static final LongSparseArray<ConstantState> sPreloadedColorDrawables
            = new LongSparseArray<ConstantState>();
    private static final LongSparseArray<ColorStateList> sPreloadedColorStateLists
            = new LongSparseArray<ColorStateList>();
    private static final LongSparseArray<ColorStateListFactory> sPreloadedColorStateLists
            = new LongSparseArray<ColorStateListFactory>();

    // Pool of TypedArrays targeted to this Resources object.
    final SynchronizedPool<TypedArray> mTypedArrayPool = new SynchronizedPool<TypedArray>(5);
@@ -116,8 +117,8 @@ public class Resources {
            new ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>>();
    private final ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> mColorDrawableCache =
            new ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>>();
    private final LongSparseArray<WeakReference<ColorStateList>> mColorStateListCache =
            new LongSparseArray<WeakReference<ColorStateList>>();
    private final ConfigurationBoundResourceCache<ColorStateList> mColorStateListCache =
            new ConfigurationBoundResourceCache<ColorStateList>(this);
    private final ConfigurationBoundResourceCache<Animator> mAnimatorCache =
            new ConfigurationBoundResourceCache<Animator>(this);
    private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache =
@@ -897,20 +898,41 @@ public class Resources {
    }

    /**
     * Return a color integer associated with a particular resource ID.
     * If the resource holds a complex
     * {@link android.content.res.ColorStateList}, then the default color from
     * the set is returned.
     * Returns a color integer associated with a particular resource ID. If the
     * resource holds a complex {@link ColorStateList}, then the default color
     * from the set is returned.
     *
     * @param id The desired resource identifier, as generated by the aapt
     *           tool. This integer encodes the package, type, and resource
     *           entry. The value 0 is an invalid identifier.
     *
     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
     * @throws NotFoundException Throws NotFoundException if the given ID does
     *         not exist.
     *
     * @return Returns a single color value in the form 0xAARRGGBB.
     * @return A single color value in the form 0xAARRGGBB.
     * @deprecated Use {@link #getColor(int, Theme)} instead.
     */
    public int getColor(int id) throws NotFoundException {
        return getColor(id, null);
    }

    /**
     * Returns a themed color integer associated with a particular resource ID.
     * If the resource holds a complex {@link ColorStateList}, then the default
     * color from the set is returned.
     *
     * @param id The desired resource identifier, as generated by the aapt
     *           tool. This integer encodes the package, type, and resource
     *           entry. The value 0 is an invalid identifier.
     * @param theme The theme used to style the color attributes, may be
     *              {@code null}.
     *
     * @throws NotFoundException Throws NotFoundException if the given ID does
     *         not exist.
     *
     * @return A single color value in the form 0xAARRGGBB.
     */
    public int getColor(int id, @Nullable Theme theme) throws NotFoundException {
        TypedValue value;
        synchronized (mAccessLock) {
            value = mTmpValue;
@@ -929,30 +951,67 @@ public class Resources {
            }
            mTmpValue = null;
        }
        ColorStateList csl = loadColorStateList(value, id);

        final ColorStateList csl = loadColorStateList(value, id, theme);
        synchronized (mAccessLock) {
            if (mTmpValue == null) {
                mTmpValue = value;
            }
        }

        return csl.getDefaultColor();
    }

    /**
     * Return a color state list associated with a particular resource ID.  The
     * resource may contain either a single raw color value, or a complex
     * {@link android.content.res.ColorStateList} holding multiple possible colors.
     * Returns a color state list associated with a particular resource ID. The
     * resource may contain either a single raw color value or a complex
     * {@link ColorStateList} holding multiple possible colors.
     *
     * @param id The desired resource identifier of a {@link ColorStateList},
     *        as generated by the aapt tool. This integer encodes the package, type, and resource
     *        entry. The value 0 is an invalid identifier.
     *           as generated by the aapt tool. This integer encodes the
     *           package, type, and resource entry. The value 0 is an invalid
     *           identifier.
     *
     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
     * @throws NotFoundException Throws NotFoundException if the given ID does
     *         not exist.
     *
     * @return Returns a ColorStateList object containing either a single
     * solid color or multiple colors that can be selected based on a state.
     * @return A ColorStateList object containing either a single solid color
     *         or multiple colors that can be selected based on a state.
     * @deprecated Use {@link #getColorStateList(int, Theme)} instead.
     */
    @Nullable
    public ColorStateList getColorStateList(int id) throws NotFoundException {
        final ColorStateList csl = getColorStateList(id, null);
        if (csl != null && csl.canApplyTheme()) {
            Log.w(TAG, "ColorStateList " + getResourceName(id) + " has "
                    + "unresolved theme attributes! Consider using "
                    + "Resources.getColorStateList(int, Theme) or "
                    + "Context.getColorStateList(int).", new RuntimeException());
        }
        return csl;
    }

    /**
     * Returns a themed color state list associated with a particular resource
     * ID. The resource may contain either a single raw color value or a
     * complex {@link ColorStateList} holding multiple possible colors.
     *
     * @param id The desired resource identifier of a {@link ColorStateList},
     *           as generated by the aapt tool. This integer encodes the
     *           package, type, and resource entry. The value 0 is an invalid
     *           identifier.
     * @param theme The theme used to style the color attributes, may be
     *              {@code null}.
     *
     * @throws NotFoundException Throws NotFoundException if the given ID does
     *         not exist.
     *
     * @return A themed ColorStateList object containing either a single solid
     *         color or multiple colors that can be selected based on a state.
     */
    @Nullable
    public ColorStateList getColorStateList(int id, @Nullable Theme theme)
            throws NotFoundException {
        TypedValue value;
        synchronized (mAccessLock) {
            value = mTmpValue;
@@ -963,15 +1022,19 @@ public class Resources {
            }
            getValue(id, value, true);
        }
        ColorStateList res = loadColorStateList(value, id);

        final ColorStateList res = loadColorStateList(value, id, theme);
        synchronized (mAccessLock) {
            if (mTmpValue == null) {
                mTmpValue = value;
            }
        }

        return res;
    }



    /**
     * Return a boolean associated with a particular resource ID.  This can be
     * used with any integral resource value, and will return true if it is
@@ -1843,11 +1906,10 @@ public class Resources {

            clearDrawableCachesLocked(mDrawableCache, configChanges);
            clearDrawableCachesLocked(mColorDrawableCache, configChanges);
            mColorStateListCache.onConfigurationChange(configChanges);
            mAnimatorCache.onConfigurationChange(configChanges);
            mStateListAnimatorCache.onConfigurationChange(configChanges);

            mColorStateListCache.clear();

            flushLayoutCache();
        }
        synchronized (sSync) {
@@ -2567,7 +2629,8 @@ public class Resources {
        return null;
    }

    /*package*/ ColorStateList loadColorStateList(TypedValue value, int id)
    @Nullable
    ColorStateList loadColorStateList(TypedValue value, int id, Theme theme)
            throws NotFoundException {
        if (TRACE_FOR_PRELOAD) {
            // Log only framework resources
@@ -2581,101 +2644,107 @@ public class Resources {

        ColorStateList csl;

        if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT &&
                value.type <= TypedValue.TYPE_LAST_COLOR_INT) {

            csl = sPreloadedColorStateLists.get(key);
            if (csl != null) {
                return csl;
        // Handle inline color definitions.
        if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
                && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
            final ColorStateListFactory factory = sPreloadedColorStateLists.get(key);
            if (factory != null) {
                return factory.newInstance();
            }

            csl = ColorStateList.valueOf(value.data);

            if (mPreloading) {
                if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
                        "color")) {
                    sPreloadedColorStateLists.put(key, csl);
                    sPreloadedColorStateLists.put(key, csl.getFactory());
                }
            }

            return csl;
        }

        csl = getCachedColorStateList(key);
        final ConfigurationBoundResourceCache<ColorStateList> cache = mColorStateListCache;

        csl = cache.get(key, theme);
        if (csl != null) {
            return csl;
        }

        csl = sPreloadedColorStateLists.get(key);
        final ColorStateListFactory factory = sPreloadedColorStateLists.get(key);
        if (factory != null) {
            csl = factory.newInstance(this, theme);
        }

        if (csl == null) {
            csl = loadColorStateListForCookie(value, id, theme);
        }

        if (csl != null) {
            if (mPreloading) {
                if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
                        "color")) {
                    sPreloadedColorStateLists.put(key, csl.getFactory());
                }
            } else {
                cache.put(key, theme, csl.getFactory());
            }
        }

        return csl;
    }

    private ColorStateList loadColorStateListForCookie(TypedValue value, int id, Theme theme) {
        if (value.string == null) {
            throw new NotFoundException(
                    "Resource is not a ColorStateList (color or path): " + value);
            throw new NotFoundException("Resource \"" + getResourceName(id) + "\" ("
                    + Integer.toHexString(id) + ") is not a ColorStateList: " + value);
        }

        final String file = value.string.toString();

        if (file.endsWith(".xml")) {
        if (TRACE_FOR_MISS_PRELOAD) {
            // Log only framework resources
            if ((id >>> 24) == 0x1) {
                final String name = getResourceName(id);
                if (name != null) {
                    Log.d(TAG, "Loading framework color state list #" + Integer.toHexString(id)
                            + ": " + name + " at " + file);
                }
            }
        }

        if (DEBUG_LOAD) {
            Log.v(TAG, "Loading color state list for cookie " + value.assetCookie + ": " + file);
        }

        final ColorStateList csl;

        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
        if (file.endsWith(".xml")) {
            try {
                final XmlResourceParser rp = loadXmlResourceParser(
                        file, id, value.assetCookie, "colorstatelist");
                csl = ColorStateList.createFromXml(this, rp);
                csl = ColorStateList.createFromXml(this, rp, theme);
                rp.close();
            } catch (Exception e) {
                Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
                NotFoundException rnf = new NotFoundException(
                final NotFoundException rnf = new NotFoundException(
                        "File " + file + " from color state list resource ID #0x"
                                + Integer.toHexString(id));
                rnf.initCause(e);
                throw rnf;
            }
            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
        } else {
            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
            throw new NotFoundException(
                    "File " + file + " from drawable resource ID #0x"
                            + Integer.toHexString(id) + ": .xml extension required");
        }

        if (csl != null) {
            if (mPreloading) {
                if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
                        "color")) {
                    sPreloadedColorStateLists.put(key, csl);
                }
            } else {
                synchronized (mAccessLock) {
                    //Log.i(TAG, "Saving cached color state list @ #" +
                    //        Integer.toHexString(key.intValue())
                    //        + " in " + this + ": " + csl);
                    mColorStateListCache.put(key, new WeakReference<ColorStateList>(csl));
                }
            }
        }
        Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);

        return csl;
    }

    private ColorStateList getCachedColorStateList(long key) {
        synchronized (mAccessLock) {
            WeakReference<ColorStateList> wr = mColorStateListCache.get(key);
            if (wr != null) {   // we have the key
                ColorStateList entry = wr.get();
                if (entry != null) {
                    //Log.i(TAG, "Returning cached color state list @ #" +
                    //        Integer.toHexString(((Integer)key).intValue())
                    //        + " in " + this + ": " + entry);
                    return entry;
                } else {  // our entry has been purged
                    mColorStateListCache.delete(key);
                }
            }
        }
        return null;
    }

    /*package*/ XmlResourceParser loadXmlResourceParser(int id, String type)
            throws NotFoundException {
        synchronized (mAccessLock) {
@@ -2752,6 +2821,20 @@ public class Resources {
        }
    }

    /**
     * Obtains styled attributes from the theme, if available, or unstyled
     * resources if the theme is null.
     *
     * @hide
     */
    public static TypedArray obtainAttributes(
            Resources res, Theme theme, AttributeSet set, int[] attrs) {
        if (theme == null) {
            return res.obtainAttributes(set, attrs);
        }
        return theme.obtainStyledAttributes(set, attrs, 0, 0);
    }

    private Resources() {
        mAssets = AssetManager.getSystem();
        // NOTE: Intentionally leaving this uninitialized (all values set
+25 −8
Original line number Diff line number Diff line
@@ -392,8 +392,8 @@ public class TypedArray {
        } else if (type == TypedValue.TYPE_STRING) {
            final TypedValue value = mValue;
            if (getValueAt(index, value)) {
                ColorStateList csl = mResources.loadColorStateList(
                        value, value.resourceId);
                final ColorStateList csl = mResources.loadColorStateList(
                        value, value.resourceId, mTheme);
                return csl.getDefaultColor();
            }
            return defValue;
@@ -424,7 +424,7 @@ public class TypedArray {
            if (value.type == TypedValue.TYPE_ATTRIBUTE) {
                throw new RuntimeException("Failed to resolve attribute at index " + index);
            }
            return mResources.loadColorStateList(value, value.resourceId);
            return mResources.loadColorStateList(value, value.resourceId, mTheme);
        }
        return null;
    }
@@ -905,12 +905,21 @@ public class TypedArray {
     * Removes the entries from the typed array so that subsequent calls to typed
     * getters will return the default value without crashing.
     *
     * @return an array of length {@link #getIndexCount()} populated with theme
     *         attributes, or null if there are no theme attributes in the typed
     *         array
     * @return An array of length {@link #getIndexCount()} populated with theme
     *         attributes, or {@code null} if there are no theme attributes in
     *         the typed array.
     * @hide
     */
    @Nullable
    public int[] extractThemeAttrs() {
        return extractThemeAttrs(null);
    }

    /**
     * @hide
     */
    @Nullable
    public int[] extractThemeAttrs(@Nullable int[] scrap) {
        if (mRecycled) {
            throw new RuntimeException("Cannot make calls to a recycled instance!");
        }
@@ -922,6 +931,7 @@ public class TypedArray {
        for (int i = 0; i < N; i++) {
            final int index = i * AssetManager.STYLE_NUM_ENTRIES;
            if (data[index + AssetManager.STYLE_TYPE] != TypedValue.TYPE_ATTRIBUTE) {
                // Not an attribute, ignore.
                continue;
            }

@@ -930,13 +940,20 @@ public class TypedArray {

            final int attr = data[index + AssetManager.STYLE_DATA];
            if (attr == 0) {
                // This attribute is useless!
                // Useless data, ignore.
                continue;
            }

            // Ensure we have a usable attribute array.
            if (attrs == null) {
                if (scrap != null && scrap.length == N) {
                    attrs = scrap;
                    Arrays.fill(attrs, 0);
                } else {
                    attrs = new int[N];
                }
            }

            attrs[i] = attr;
        }

Loading