ResourceHelper.java revision bc9d2a13f0bbeae4ebf04da5a0b0d2f7814b40e4
1282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Copyright (C) 2008 The Android Open Source Project
3282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
4282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License");
5282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * you may not use this file except in compliance with the License.
6282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * You may obtain a copy of the License at
7282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
8282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *      http://www.apache.org/licenses/LICENSE-2.0
9282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
10282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Unless required by applicable law or agreed to in writing, software
11282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS,
12282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * See the License for the specific language governing permissions and
14282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * limitations under the License.
15282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
16282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
17282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskipackage com.android.layoutlib.bridge.impl;
18282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
195f1bf496948fb6383ae17e5467a26a00489d7564Deepanshu Guptaimport com.android.SdkConstants;
20282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ide.common.rendering.api.DensityBasedResourceValue;
21282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ide.common.rendering.api.LayoutLog;
22282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ide.common.rendering.api.RenderResources;
23282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ide.common.rendering.api.ResourceValue;
24fc8f4aad7395eca11f6d9b82eb266b1f4ee5041bDeepanshu Guptaimport com.android.internal.util.XmlUtils;
25282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.layoutlib.bridge.Bridge;
26282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.layoutlib.bridge.android.BridgeContext;
27282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
28cd6e47e4455cec8daa4570ac8073d93bd567d139Deepanshu Guptaimport com.android.layoutlib.bridge.android.RenderParamsFlags;
29282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ninepatch.NinePatch;
30282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ninepatch.NinePatchChunk;
31282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.resources.Density;
32282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
33282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport org.xmlpull.v1.XmlPullParser;
34282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport org.xmlpull.v1.XmlPullParserException;
35282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
36476e582d2ffdf25102d4c55f8c242baa3d21d37fDeepanshu Guptaimport android.annotation.NonNull;
37566b303365078fac9a454f1595add19e02631db3Diego Perezimport android.annotation.Nullable;
38282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.content.res.ColorStateList;
39566b303365078fac9a454f1595add19e02631db3Diego Perezimport android.content.res.ComplexColor;
40566b303365078fac9a454f1595add19e02631db3Diego Perezimport android.content.res.ComplexColor_Accessor;
41789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perezimport android.content.res.FontResourcesParser;
42566b303365078fac9a454f1595add19e02631db3Diego Perezimport android.content.res.GradientColor;
434a605c6fa0027ee116beb29fbc9625721f0441f0Deepanshu Guptaimport android.content.res.Resources.Theme;
44282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.graphics.Bitmap;
45282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.graphics.Bitmap_Delegate;
46282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.graphics.NinePatch_Delegate;
47282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.graphics.Rect;
48789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perezimport android.graphics.Typeface;
49789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perezimport android.graphics.Typeface_Accessor;
50282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.graphics.drawable.BitmapDrawable;
51282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.graphics.drawable.ColorDrawable;
52282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.graphics.drawable.Drawable;
53282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.graphics.drawable.NinePatchDrawable;
54789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perezimport android.text.FontConfig;
55282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.util.TypedValue;
56282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
57282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.io.File;
58282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.io.FileInputStream;
59566b303365078fac9a454f1595add19e02631db3Diego Perezimport java.io.FileNotFoundException;
60282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.io.IOException;
61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.io.InputStream;
62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.net.MalformedURLException;
63282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.util.regex.Matcher;
64282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.util.regex.Pattern;
65282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
66282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/**
67282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Helper class to provide various conversion method used in handling android resources.
68282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
69282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskipublic final class ResourceHelper {
70282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
71282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private final static Pattern sFloatPattern = Pattern.compile("(-?[0-9]+(?:\\.[0-9]+)?)(.*)");
72282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private final static float[] sFloatOut = new float[1];
73282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
74282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private final static TypedValue mValue = new TypedValue();
75282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
76282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
77282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Returns the color value represented by the given string value
78282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @param value the color value
79282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @return the color as an int
801a12b805698c7cba9c2daa78c76c055afbdfa9fcDeepanshu Gupta     * @throws NumberFormatException if the conversion failed.
81282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
82282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public static int getColor(String value) {
83282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value != null) {
84fb175664469f1eb1bc598f54a7f86ff008e88b0eDiego Perez            value = value.trim();
851a12b805698c7cba9c2daa78c76c055afbdfa9fcDeepanshu Gupta            if (!value.startsWith("#")) {
865f1bf496948fb6383ae17e5467a26a00489d7564Deepanshu Gupta                if (value.startsWith(SdkConstants.PREFIX_THEME_REF)) {
875f1bf496948fb6383ae17e5467a26a00489d7564Deepanshu Gupta                    throw new NumberFormatException(String.format(
885f1bf496948fb6383ae17e5467a26a00489d7564Deepanshu Gupta                            "Attribute '%s' not found. Are you using the right theme?", value));
895f1bf496948fb6383ae17e5467a26a00489d7564Deepanshu Gupta                }
90282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                throw new NumberFormatException(
91282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        String.format("Color value '%s' must start with #", value));
92282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
93282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
94282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            value = value.substring(1);
95282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
96282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // make sure it's not longer than 32bit
97282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (value.length() > 8) {
98282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                throw new NumberFormatException(String.format(
99282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "Color value '%s' is too long. Format is either" +
100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        "#AARRGGBB, #RRGGBB, #RGB, or #ARGB",
101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        value));
102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (value.length() == 3) { // RGB format
105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                char[] color = new char[8];
106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                color[0] = color[1] = 'F';
107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                color[2] = color[3] = value.charAt(0);
108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                color[4] = color[5] = value.charAt(1);
109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                color[6] = color[7] = value.charAt(2);
110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                value = new String(color);
111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (value.length() == 4) { // ARGB format
112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                char[] color = new char[8];
113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                color[0] = color[1] = value.charAt(0);
114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                color[2] = color[3] = value.charAt(1);
115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                color[4] = color[5] = value.charAt(2);
116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                color[6] = color[7] = value.charAt(3);
117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                value = new String(color);
118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else if (value.length() == 6) {
119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                value = "FF" + value;
120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // this is a RRGGBB or AARRGGBB value
123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Integer.parseInt will fail to parse strings like "ff191919", so we use
125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // a Long, but cast the result back into an int, since we know that we're only
126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // dealing with 32 bit values.
127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return (int)Long.parseLong(value, 16);
128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        throw new NumberFormatException();
131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
133566b303365078fac9a454f1595add19e02631db3Diego Perez    /**
134566b303365078fac9a454f1595add19e02631db3Diego Perez     * Returns a {@link ComplexColor} from the given {@link ResourceValue}
135566b303365078fac9a454f1595add19e02631db3Diego Perez     *
136566b303365078fac9a454f1595add19e02631db3Diego Perez     * @param resValue the value containing a color value or a file path to a complex color
137566b303365078fac9a454f1595add19e02631db3Diego Perez     * definition
138566b303365078fac9a454f1595add19e02631db3Diego Perez     * @param context the current context
139566b303365078fac9a454f1595add19e02631db3Diego Perez     * @param theme the theme to use when resolving the complex color
140566b303365078fac9a454f1595add19e02631db3Diego Perez     * @param allowGradients when false, only {@link ColorStateList} will be returned. If a {@link
141566b303365078fac9a454f1595add19e02631db3Diego Perez     * GradientColor} is found, null will be returned.
142566b303365078fac9a454f1595add19e02631db3Diego Perez     */
143566b303365078fac9a454f1595add19e02631db3Diego Perez    @Nullable
144566b303365078fac9a454f1595add19e02631db3Diego Perez    private static ComplexColor getInternalComplexColor(@NonNull ResourceValue resValue,
145566b303365078fac9a454f1595add19e02631db3Diego Perez            @NonNull BridgeContext context, @Nullable Theme theme, boolean allowGradients) {
146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        String value = resValue.getValue();
147566b303365078fac9a454f1595add19e02631db3Diego Perez        if (value == null || RenderResources.REFERENCE_NULL.equals(value)) {
148566b303365078fac9a454f1595add19e02631db3Diego Perez            return null;
149566b303365078fac9a454f1595add19e02631db3Diego Perez        }
150566b303365078fac9a454f1595add19e02631db3Diego Perez
151cd6e47e4455cec8daa4570ac8073d93bd567d139Deepanshu Gupta        XmlPullParser parser = null;
152566b303365078fac9a454f1595add19e02631db3Diego Perez        // first check if the value is a file (xml most likely)
153cd6e47e4455cec8daa4570ac8073d93bd567d139Deepanshu Gupta        Boolean psiParserSupport = context.getLayoutlibCallback().getFlag(
154cd6e47e4455cec8daa4570ac8073d93bd567d139Deepanshu Gupta                RenderParamsFlags.FLAG_KEY_XML_FILE_PARSER_SUPPORT);
155cd6e47e4455cec8daa4570ac8073d93bd567d139Deepanshu Gupta        if (psiParserSupport != null && psiParserSupport) {
156cd6e47e4455cec8daa4570ac8073d93bd567d139Deepanshu Gupta            parser = context.getLayoutlibCallback().getXmlFileParser(value);
157cd6e47e4455cec8daa4570ac8073d93bd567d139Deepanshu Gupta        }
158566b303365078fac9a454f1595add19e02631db3Diego Perez        if (parser == null) {
159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            File f = new File(value);
160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (f.isFile()) {
161566b303365078fac9a454f1595add19e02631db3Diego Perez                // let the framework inflate the color from the XML file, by
162566b303365078fac9a454f1595add19e02631db3Diego Perez                // providing an XmlPullParser
163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                try {
164566b303365078fac9a454f1595add19e02631db3Diego Perez                    parser = ParserFactory.create(f);
165566b303365078fac9a454f1595add19e02631db3Diego Perez                } catch (XmlPullParserException | FileNotFoundException e) {
166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            "Failed to parse file " + value, e, null /*data*/);
168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
169566b303365078fac9a454f1595add19e02631db3Diego Perez            }
170566b303365078fac9a454f1595add19e02631db3Diego Perez        }
171566b303365078fac9a454f1595add19e02631db3Diego Perez
172566b303365078fac9a454f1595add19e02631db3Diego Perez        if (parser != null) {
173566b303365078fac9a454f1595add19e02631db3Diego Perez            try {
174566b303365078fac9a454f1595add19e02631db3Diego Perez                BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
175566b303365078fac9a454f1595add19e02631db3Diego Perez                        parser, context, resValue.isFramework());
176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                try {
177566b303365078fac9a454f1595add19e02631db3Diego Perez                    // Advance the parser to the first element so we can detect if it's a
178566b303365078fac9a454f1595add19e02631db3Diego Perez                    // color list or a gradient color
179566b303365078fac9a454f1595add19e02631db3Diego Perez                    int type;
180566b303365078fac9a454f1595add19e02631db3Diego Perez                    //noinspection StatementWithEmptyBody
181566b303365078fac9a454f1595add19e02631db3Diego Perez                    while ((type = blockParser.next()) != XmlPullParser.START_TAG
182566b303365078fac9a454f1595add19e02631db3Diego Perez                            && type != XmlPullParser.END_DOCUMENT) {
183566b303365078fac9a454f1595add19e02631db3Diego Perez                        // Seek parser to start tag.
184566b303365078fac9a454f1595add19e02631db3Diego Perez                    }
185566b303365078fac9a454f1595add19e02631db3Diego Perez
186566b303365078fac9a454f1595add19e02631db3Diego Perez                    if (type != XmlPullParser.START_TAG) {
187566b303365078fac9a454f1595add19e02631db3Diego Perez                        throw new XmlPullParserException("No start tag found");
188566b303365078fac9a454f1595add19e02631db3Diego Perez                    }
189566b303365078fac9a454f1595add19e02631db3Diego Perez
190566b303365078fac9a454f1595add19e02631db3Diego Perez                    final String name = blockParser.getName();
191566b303365078fac9a454f1595add19e02631db3Diego Perez                    if (allowGradients && "gradient".equals(name)) {
192566b303365078fac9a454f1595add19e02631db3Diego Perez                        return ComplexColor_Accessor.createGradientColorFromXmlInner(
193566b303365078fac9a454f1595add19e02631db3Diego Perez                                context.getResources(),
194566b303365078fac9a454f1595add19e02631db3Diego Perez                                blockParser, blockParser,
195566b303365078fac9a454f1595add19e02631db3Diego Perez                                theme);
196566b303365078fac9a454f1595add19e02631db3Diego Perez                    } else if ("selector".equals(name)) {
197566b303365078fac9a454f1595add19e02631db3Diego Perez                        return ComplexColor_Accessor.createColorStateListFromXmlInner(
198566b303365078fac9a454f1595add19e02631db3Diego Perez                                context.getResources(),
199566b303365078fac9a454f1595add19e02631db3Diego Perez                                blockParser, blockParser,
200566b303365078fac9a454f1595add19e02631db3Diego Perez                                theme);
201566b303365078fac9a454f1595add19e02631db3Diego Perez                    }
202566b303365078fac9a454f1595add19e02631db3Diego Perez                } finally {
203566b303365078fac9a454f1595add19e02631db3Diego Perez                    blockParser.ensurePopped();
204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
205566b303365078fac9a454f1595add19e02631db3Diego Perez            } catch (XmlPullParserException e) {
206566b303365078fac9a454f1595add19e02631db3Diego Perez                Bridge.getLog().error(LayoutLog.TAG_BROKEN,
207566b303365078fac9a454f1595add19e02631db3Diego Perez                        "Failed to configure parser for " + value, e, null /*data*/);
208566b303365078fac9a454f1595add19e02631db3Diego Perez                // we'll return null below.
209566b303365078fac9a454f1595add19e02631db3Diego Perez            } catch (Exception e) {
210566b303365078fac9a454f1595add19e02631db3Diego Perez                // this is an error and not warning since the file existence is
211566b303365078fac9a454f1595add19e02631db3Diego Perez                // checked before attempting to parse it.
212566b303365078fac9a454f1595add19e02631db3Diego Perez                Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
213566b303365078fac9a454f1595add19e02631db3Diego Perez                        "Failed to parse file " + value, e, null /*data*/);
214566b303365078fac9a454f1595add19e02631db3Diego Perez
215566b303365078fac9a454f1595add19e02631db3Diego Perez                return null;
216566b303365078fac9a454f1595add19e02631db3Diego Perez            }
217566b303365078fac9a454f1595add19e02631db3Diego Perez        } else {
218566b303365078fac9a454f1595add19e02631db3Diego Perez            // try to load the color state list from an int
219566b303365078fac9a454f1595add19e02631db3Diego Perez            try {
220566b303365078fac9a454f1595add19e02631db3Diego Perez                int color = getColor(value);
221566b303365078fac9a454f1595add19e02631db3Diego Perez                return ColorStateList.valueOf(color);
222566b303365078fac9a454f1595add19e02631db3Diego Perez            } catch (NumberFormatException e) {
223566b303365078fac9a454f1595add19e02631db3Diego Perez                Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT,
224566b303365078fac9a454f1595add19e02631db3Diego Perez                        "Failed to convert " + value + " into a ColorStateList", e,
225566b303365078fac9a454f1595add19e02631db3Diego Perez                        null /*data*/);
226282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
229282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return null;
230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
233566b303365078fac9a454f1595add19e02631db3Diego Perez     * Returns a {@link ColorStateList} from the given {@link ResourceValue}
234566b303365078fac9a454f1595add19e02631db3Diego Perez     *
235566b303365078fac9a454f1595add19e02631db3Diego Perez     * @param resValue the value containing a color value or a file path to a complex color
236566b303365078fac9a454f1595add19e02631db3Diego Perez     * definition
237566b303365078fac9a454f1595add19e02631db3Diego Perez     * @param context the current context
238566b303365078fac9a454f1595add19e02631db3Diego Perez     */
239566b303365078fac9a454f1595add19e02631db3Diego Perez    @Nullable
240566b303365078fac9a454f1595add19e02631db3Diego Perez    public static ColorStateList getColorStateList(@NonNull ResourceValue resValue,
241566b303365078fac9a454f1595add19e02631db3Diego Perez            @NonNull BridgeContext context) {
242566b303365078fac9a454f1595add19e02631db3Diego Perez        return (ColorStateList) getInternalComplexColor(resValue, context, context.getTheme(),
243566b303365078fac9a454f1595add19e02631db3Diego Perez                false);
244566b303365078fac9a454f1595add19e02631db3Diego Perez    }
245566b303365078fac9a454f1595add19e02631db3Diego Perez
246566b303365078fac9a454f1595add19e02631db3Diego Perez    /**
247566b303365078fac9a454f1595add19e02631db3Diego Perez     * Returns a {@link ComplexColor} from the given {@link ResourceValue}
248566b303365078fac9a454f1595add19e02631db3Diego Perez     *
249566b303365078fac9a454f1595add19e02631db3Diego Perez     * @param resValue the value containing a color value or a file path to a complex color
250566b303365078fac9a454f1595add19e02631db3Diego Perez     * definition
251566b303365078fac9a454f1595add19e02631db3Diego Perez     * @param context the current context
252566b303365078fac9a454f1595add19e02631db3Diego Perez     */
253566b303365078fac9a454f1595add19e02631db3Diego Perez    @Nullable
254566b303365078fac9a454f1595add19e02631db3Diego Perez    public static ComplexColor getComplexColor(@NonNull ResourceValue resValue,
255566b303365078fac9a454f1595add19e02631db3Diego Perez            @NonNull BridgeContext context) {
256566b303365078fac9a454f1595add19e02631db3Diego Perez        return getInternalComplexColor(resValue, context, context.getTheme(), true);
257566b303365078fac9a454f1595add19e02631db3Diego Perez    }
258566b303365078fac9a454f1595add19e02631db3Diego Perez
259566b303365078fac9a454f1595add19e02631db3Diego Perez    /**
260282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Returns a drawable from the given value.
261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @param value The value that contains a path to a 9 patch, a bitmap or a xml based drawable,
262282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * or an hexadecimal color
263282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @param context the current context
264282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
265282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public static Drawable getDrawable(ResourceValue value, BridgeContext context) {
2664a605c6fa0027ee116beb29fbc9625721f0441f0Deepanshu Gupta        return getDrawable(value, context, null);
2674a605c6fa0027ee116beb29fbc9625721f0441f0Deepanshu Gupta    }
2684a605c6fa0027ee116beb29fbc9625721f0441f0Deepanshu Gupta
2694a605c6fa0027ee116beb29fbc9625721f0441f0Deepanshu Gupta    /**
2704a605c6fa0027ee116beb29fbc9625721f0441f0Deepanshu Gupta     * Returns a drawable from the given value.
2714a605c6fa0027ee116beb29fbc9625721f0441f0Deepanshu Gupta     * @param value The value that contains a path to a 9 patch, a bitmap or a xml based drawable,
2724a605c6fa0027ee116beb29fbc9625721f0441f0Deepanshu Gupta     * or an hexadecimal color
2734a605c6fa0027ee116beb29fbc9625721f0441f0Deepanshu Gupta     * @param context the current context
2744a605c6fa0027ee116beb29fbc9625721f0441f0Deepanshu Gupta     * @param theme the theme to be used to inflate the drawable.
2754a605c6fa0027ee116beb29fbc9625721f0441f0Deepanshu Gupta     */
2764a605c6fa0027ee116beb29fbc9625721f0441f0Deepanshu Gupta    public static Drawable getDrawable(ResourceValue value, BridgeContext context, Theme theme) {
27714bf0cef7eeed572a67c29a328581afac4decc20Deepanshu Gupta        if (value == null) {
27814bf0cef7eeed572a67c29a328581afac4decc20Deepanshu Gupta            return null;
27914bf0cef7eeed572a67c29a328581afac4decc20Deepanshu Gupta        }
280282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        String stringValue = value.getValue();
281282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (RenderResources.REFERENCE_NULL.equals(stringValue)) {
282282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return null;
283282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
285282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        String lowerCaseValue = stringValue.toLowerCase();
286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Density density = Density.MEDIUM;
288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (value instanceof DensityBasedResourceValue) {
289bc9d2a13f0bbeae4ebf04da5a0b0d2f7814b40e4Diego Perez            density = ((DensityBasedResourceValue) value).getResourceDensity();
290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (lowerCaseValue.endsWith(NinePatch.EXTENSION_9PATCH)) {
293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            File file = new File(stringValue);
294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (file.isFile()) {
295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                try {
296bc9d2a13f0bbeae4ebf04da5a0b0d2f7814b40e4Diego Perez                    return getNinePatchDrawable(new FileInputStream(file), density,
297bc9d2a13f0bbeae4ebf04da5a0b0d2f7814b40e4Diego Perez                            value.isFramework(), stringValue, context);
298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } catch (IOException e) {
299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    // failed to read the file, we'll return null below.
300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            "Failed lot load " + file.getAbsolutePath(), e, null /*data*/);
302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
304282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return null;
306bc9d2a13f0bbeae4ebf04da5a0b0d2f7814b40e4Diego Perez        } else if (lowerCaseValue.endsWith(".xml") || stringValue.startsWith("@aapt:_aapt/")) {
307282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // create a block parser for the file
308bc9d2a13f0bbeae4ebf04da5a0b0d2f7814b40e4Diego Perez            try {
309bc9d2a13f0bbeae4ebf04da5a0b0d2f7814b40e4Diego Perez                XmlPullParser parser = context.getLayoutlibCallback().getParser(value);
310bc9d2a13f0bbeae4ebf04da5a0b0d2f7814b40e4Diego Perez                if (parser == null) {
311bc9d2a13f0bbeae4ebf04da5a0b0d2f7814b40e4Diego Perez                    File drawableFile = new File(stringValue);
312bc9d2a13f0bbeae4ebf04da5a0b0d2f7814b40e4Diego Perez                    if (drawableFile.isFile()) {
313bc9d2a13f0bbeae4ebf04da5a0b0d2f7814b40e4Diego Perez                        parser = ParserFactory.create(drawableFile);
314282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
316bc9d2a13f0bbeae4ebf04da5a0b0d2f7814b40e4Diego Perez
317bc9d2a13f0bbeae4ebf04da5a0b0d2f7814b40e4Diego Perez                BridgeXmlBlockParser blockParser =
318bc9d2a13f0bbeae4ebf04da5a0b0d2f7814b40e4Diego Perez                        new BridgeXmlBlockParser(parser, context, value.isFramework());
319bc9d2a13f0bbeae4ebf04da5a0b0d2f7814b40e4Diego Perez                try {
320bc9d2a13f0bbeae4ebf04da5a0b0d2f7814b40e4Diego Perez                    return Drawable.createFromXml(context.getResources(), blockParser, theme);
321bc9d2a13f0bbeae4ebf04da5a0b0d2f7814b40e4Diego Perez                } finally {
322bc9d2a13f0bbeae4ebf04da5a0b0d2f7814b40e4Diego Perez                    blockParser.ensurePopped();
323bc9d2a13f0bbeae4ebf04da5a0b0d2f7814b40e4Diego Perez                }
324bc9d2a13f0bbeae4ebf04da5a0b0d2f7814b40e4Diego Perez            } catch (Exception e) {
325bc9d2a13f0bbeae4ebf04da5a0b0d2f7814b40e4Diego Perez                // this is an error and not warning since the file existence is checked before
326bc9d2a13f0bbeae4ebf04da5a0b0d2f7814b40e4Diego Perez                // attempting to parse it.
327bc9d2a13f0bbeae4ebf04da5a0b0d2f7814b40e4Diego Perez                Bridge.getLog().error(null, "Failed to parse file " + stringValue, e,
328282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        null /*data*/);
329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
330282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
331282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return null;
332282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            File bmpFile = new File(stringValue);
334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (bmpFile.isFile()) {
335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                try {
336282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    Bitmap bitmap = Bridge.getCachedBitmap(stringValue,
337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            value.isFramework() ? null : context.getProjectKey());
338282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
339282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (bitmap == null) {
340bc9d2a13f0bbeae4ebf04da5a0b0d2f7814b40e4Diego Perez                        bitmap =
341bc9d2a13f0bbeae4ebf04da5a0b0d2f7814b40e4Diego Perez                                Bitmap_Delegate.createBitmap(bmpFile, false /*isMutable*/, density);
342282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        Bridge.setCachedBitmap(stringValue, bitmap,
343282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                value.isFramework() ? null : context.getProjectKey());
344282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
345282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
346282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    return new BitmapDrawable(context.getResources(), bitmap);
347282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } catch (IOException e) {
348282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    // we'll return null below
349282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
350282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            "Failed lot load " + bmpFile.getAbsolutePath(), e, null /*data*/);
351282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
352282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } else {
353282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // attempt to get a color from the value
354282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                try {
355282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    int color = getColor(stringValue);
356282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    return new ColorDrawable(color);
357282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                } catch (NumberFormatException e) {
358282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    // we'll return null below.
359282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT,
360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            "Failed to convert " + stringValue + " into a drawable", e,
361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                            null /*data*/);
362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return null;
367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
369789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez    /**
370789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez     * Returns a {@link Typeface} given a font name. The font name, can be a system font family
371789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez     * (like sans-serif) or a full path if the font is to be loaded from resources.
372789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez     */
373789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez    public static Typeface getFont(String fontName, BridgeContext context, Theme theme, boolean
374789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez            isFramework) {
375789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez        if (fontName == null) {
376789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez            return null;
377789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez        }
378789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez
379789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez        if (Typeface_Accessor.isSystemFont(fontName)) {
380789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez            // Shortcut for the case where we are asking for a system font name. Those are not
381789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez            // loaded using external resources.
382789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez            return null;
383789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez        }
384789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez
385789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez        // Check if this is an asset that we've already loaded dynamically
386789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez        Typeface typeface = Typeface.findFromCache(context.getAssets(), fontName);
387789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez        if (typeface != null) {
388789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez            return typeface;
389789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez        }
390789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez
391789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez        String lowerCaseValue = fontName.toLowerCase();
392789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez        if (lowerCaseValue.endsWith(".xml")) {
393789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez            // create a block parser for the file
394789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez            Boolean psiParserSupport = context.getLayoutlibCallback().getFlag(
395789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez                    RenderParamsFlags.FLAG_KEY_XML_FILE_PARSER_SUPPORT);
396789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez            XmlPullParser parser = null;
397789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez            if (psiParserSupport != null && psiParserSupport) {
398789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez                parser = context.getLayoutlibCallback().getXmlFileParser(fontName);
399789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez            }
400789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez            else {
401789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez                File f = new File(fontName);
402789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez                if (f.isFile()) {
403789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez                    try {
404789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez                        parser = ParserFactory.create(f);
405789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez                    } catch (XmlPullParserException | FileNotFoundException e) {
406789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez                        // this is an error and not warning since the file existence is checked before
407789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez                        // attempting to parse it.
408789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez                        Bridge.getLog().error(null, "Failed to parse file " + fontName,
409789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez                                e, null /*data*/);
410789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez                    }
411789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez                }
412789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez            }
413789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez
414789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez            if (parser != null) {
415789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez                BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
416789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez                        parser, context, isFramework);
417789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez                try {
418789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez                    FontConfig config = FontResourcesParser.parse(blockParser, context
419789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez                            .getResources());
420789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez                    typeface = Typeface.createFromResources(config, context.getAssets(),
421789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez                            fontName);
422789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez                } catch (XmlPullParserException | IOException e) {
423789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez                    Bridge.getLog().error(null, "Failed to parse file " + fontName,
424789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez                            e, null /*data*/);
425789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez                } finally {
426789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez                    blockParser.ensurePopped();
427789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez                }
428789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez            } else {
429789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez                Bridge.getLog().error(LayoutLog.TAG_BROKEN,
430789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez                        String.format("File %s does not exist (or is not a file)", fontName),
431789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez                        null /*data*/);
432789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez            }
433789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez        } else {
434789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez            typeface = Typeface.createFromResources(context.getAssets(), fontName, 0);
435789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez        }
436789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez
437789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez        return typeface;
438789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez    }
439789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez
440789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez    /**
441789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez     * Returns a {@link Typeface} given a font name. The font name, can be a system font family
442789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez     * (like sans-serif) or a full path if the font is to be loaded from resources.
443789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez     */
444789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez    public static Typeface getFont(ResourceValue value, BridgeContext context, Theme theme) {
445789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez        if (value == null) {
446789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez            return null;
447789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez        }
448789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez
449789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez        return getFont(value.getValue(), context, theme, value.isFramework());
450789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez    }
451789c4b4b14880621f05e7750f594b24bc93fcff9Diego Perez
452282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private static Drawable getNinePatchDrawable(InputStream inputStream, Density density,
453282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            boolean isFramework, String cacheKey, BridgeContext context) throws IOException {
454282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // see if we still have both the chunk and the bitmap in the caches
455282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        NinePatchChunk chunk = Bridge.getCached9Patch(cacheKey,
456282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                isFramework ? null : context.getProjectKey());
457282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Bitmap bitmap = Bridge.getCachedBitmap(cacheKey,
458282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                isFramework ? null : context.getProjectKey());
459282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
460282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // if either chunk or bitmap is null, then we reload the 9-patch file.
461282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (chunk == null || bitmap == null) {
462282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            try {
463282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                NinePatch ninePatch = NinePatch.load(inputStream, true /*is9Patch*/,
464282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        false /* convert */);
465282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (ninePatch != null) {
466282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (chunk == null) {
467282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        chunk = ninePatch.getChunk();
468282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
469282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        Bridge.setCached9Patch(cacheKey, chunk,
470282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                isFramework ? null : context.getProjectKey());
471282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
472282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
473282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    if (bitmap == null) {
474282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        bitmap = Bitmap_Delegate.createBitmap(ninePatch.getImage(),
475282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                false /*isMutable*/,
476282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                density);
477282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
478282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        Bridge.setCachedBitmap(cacheKey, bitmap,
479282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                isFramework ? null : context.getProjectKey());
480282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
481282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
482282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } catch (MalformedURLException e) {
483282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // URL is wrong, we'll return null below
484282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
485282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
486282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
487282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (chunk != null && bitmap != null) {
488282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int[] padding = chunk.getPadding();
489282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Rect paddingRect = new Rect(padding[0], padding[1], padding[2], padding[3]);
490282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
491282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return new NinePatchDrawable(context.getResources(), bitmap,
492282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    NinePatch_Delegate.serialize(chunk),
493282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    paddingRect, null);
494282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
495282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
496282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return null;
497282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
498282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
499fc8f4aad7395eca11f6d9b82eb266b1f4ee5041bDeepanshu Gupta    /**
500fc8f4aad7395eca11f6d9b82eb266b1f4ee5041bDeepanshu Gupta     * Looks for an attribute in the current theme.
501fc8f4aad7395eca11f6d9b82eb266b1f4ee5041bDeepanshu Gupta     *
502fc8f4aad7395eca11f6d9b82eb266b1f4ee5041bDeepanshu Gupta     * @param resources the render resources
503fc8f4aad7395eca11f6d9b82eb266b1f4ee5041bDeepanshu Gupta     * @param name the name of the attribute
504fc8f4aad7395eca11f6d9b82eb266b1f4ee5041bDeepanshu Gupta     * @param defaultValue the default value.
505fc8f4aad7395eca11f6d9b82eb266b1f4ee5041bDeepanshu Gupta     * @param isFrameworkAttr if the attribute is in android namespace
506fc8f4aad7395eca11f6d9b82eb266b1f4ee5041bDeepanshu Gupta     * @return the value of the attribute or the default one if not found.
507fc8f4aad7395eca11f6d9b82eb266b1f4ee5041bDeepanshu Gupta     */
508fc8f4aad7395eca11f6d9b82eb266b1f4ee5041bDeepanshu Gupta    public static boolean getBooleanThemeValue(@NonNull RenderResources resources, String name,
509fc8f4aad7395eca11f6d9b82eb266b1f4ee5041bDeepanshu Gupta            boolean isFrameworkAttr, boolean defaultValue) {
510fc8f4aad7395eca11f6d9b82eb266b1f4ee5041bDeepanshu Gupta        ResourceValue value = resources.findItemInTheme(name, isFrameworkAttr);
511fc8f4aad7395eca11f6d9b82eb266b1f4ee5041bDeepanshu Gupta        value = resources.resolveResValue(value);
512fc8f4aad7395eca11f6d9b82eb266b1f4ee5041bDeepanshu Gupta        if (value == null) {
513fc8f4aad7395eca11f6d9b82eb266b1f4ee5041bDeepanshu Gupta            return defaultValue;
514fc8f4aad7395eca11f6d9b82eb266b1f4ee5041bDeepanshu Gupta        }
515fc8f4aad7395eca11f6d9b82eb266b1f4ee5041bDeepanshu Gupta        return XmlUtils.convertValueToBoolean(value.getValue(), defaultValue);
516fc8f4aad7395eca11f6d9b82eb266b1f4ee5041bDeepanshu Gupta    }
517fc8f4aad7395eca11f6d9b82eb266b1f4ee5041bDeepanshu Gupta
518282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // ------- TypedValue stuff
519282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // This is taken from //device/libs/utils/ResourceTypes.cpp
520282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
521282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private static final class UnitEntry {
522282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        String name;
523282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        int type;
524282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        int unit;
525282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        float scale;
526282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
527282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        UnitEntry(String name, int type, int unit, float scale) {
528282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            this.name = name;
529282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            this.type = type;
530282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            this.unit = unit;
531282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            this.scale = scale;
532282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
533282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
534282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
535282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private final static UnitEntry[] sUnitNames = new UnitEntry[] {
536282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        new UnitEntry("px", TypedValue.TYPE_DIMENSION, TypedValue.COMPLEX_UNIT_PX, 1.0f),
537282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        new UnitEntry("dip", TypedValue.TYPE_DIMENSION, TypedValue.COMPLEX_UNIT_DIP, 1.0f),
538282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        new UnitEntry("dp", TypedValue.TYPE_DIMENSION, TypedValue.COMPLEX_UNIT_DIP, 1.0f),
539282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        new UnitEntry("sp", TypedValue.TYPE_DIMENSION, TypedValue.COMPLEX_UNIT_SP, 1.0f),
540282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        new UnitEntry("pt", TypedValue.TYPE_DIMENSION, TypedValue.COMPLEX_UNIT_PT, 1.0f),
541282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        new UnitEntry("in", TypedValue.TYPE_DIMENSION, TypedValue.COMPLEX_UNIT_IN, 1.0f),
542282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        new UnitEntry("mm", TypedValue.TYPE_DIMENSION, TypedValue.COMPLEX_UNIT_MM, 1.0f),
543282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        new UnitEntry("%", TypedValue.TYPE_FRACTION, TypedValue.COMPLEX_UNIT_FRACTION, 1.0f/100),
544282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        new UnitEntry("%p", TypedValue.TYPE_FRACTION, TypedValue.COMPLEX_UNIT_FRACTION_PARENT, 1.0f/100),
545282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    };
546282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
547282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
548282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Returns the raw value from the given attribute float-type value string.
549282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * This object is only valid until the next call on to {@link ResourceHelper}.
550282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
551282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public static TypedValue getValue(String attribute, String value, boolean requireUnit) {
552282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (parseFloatAttribute(attribute, value, mValue, requireUnit)) {
553282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return mValue;
554282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
555282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
556282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return null;
557282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
558282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
559282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
560282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Parse a float attribute and return the parsed value into a given TypedValue.
561282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @param attribute the name of the attribute. Can be null if <var>requireUnit</var> is false.
562282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @param value the string value of the attribute
563282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @param outValue the TypedValue to receive the parsed value
564282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @param requireUnit whether the value is expected to contain a unit.
565282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @return true if success.
566282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
567171804201dd556f8ce7ee7618661a5c8ee71507aDeepanshu Gupta    public static boolean parseFloatAttribute(String attribute, @NonNull String value,
568282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            TypedValue outValue, boolean requireUnit) {
5691a12b805698c7cba9c2daa78c76c055afbdfa9fcDeepanshu Gupta        assert !requireUnit || attribute != null;
570282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
571282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // remove the space before and after
572282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        value = value.trim();
573282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        int len = value.length();
574282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
575282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (len <= 0) {
576282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return false;
577282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
578282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
579282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // check that there's no non ascii characters.
580282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        char[] buf = value.toCharArray();
581282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (int i = 0 ; i < len ; i++) {
582282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (buf[i] > 255) {
583282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return false;
584282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
585282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
586282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
587282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // check the first character
588458f2a7bbbcc45d12b575fe9f3b2f8e1a20f9b1cDeepanshu Gupta        if ((buf[0] < '0' || buf[0] > '9') && buf[0] != '.' && buf[0] != '-' && buf[0] != '+') {
589282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return false;
590282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
591282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
592282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // now look for the string that is after the float...
593282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Matcher m = sFloatPattern.matcher(value);
594282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (m.matches()) {
595282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String f_str = m.group(1);
596282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            String end = m.group(2);
597282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
598282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            float f;
599282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            try {
600282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                f = Float.parseFloat(f_str);
601282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } catch (NumberFormatException e) {
602282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // this shouldn't happen with the regexp above.
603282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return false;
604282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
605282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
606282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (end.length() > 0 && end.charAt(0) != ' ') {
607282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                // Might be a unit...
608282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (parseUnit(end, outValue, sFloatOut)) {
609282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    computeTypedValue(outValue, f, sFloatOut[0]);
610282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    return true;
611282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
612282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return false;
613282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
614282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
615282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // make sure it's only spaces at the end.
616282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            end = end.trim();
617282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
618282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (end.length() == 0) {
619282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (outValue != null) {
6201a12b805698c7cba9c2daa78c76c055afbdfa9fcDeepanshu Gupta                    if (!requireUnit) {
621282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        outValue.type = TypedValue.TYPE_FLOAT;
622282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        outValue.data = Float.floatToIntBits(f);
623282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    } else {
624282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        // no unit when required? Use dp and out an error.
625282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        applyUnit(sUnitNames[1], outValue, sFloatOut);
626282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        computeTypedValue(outValue, f, sFloatOut[0]);
627282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
628282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                        Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE,
629282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                String.format(
630282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        "Dimension \"%1$s\" in attribute \"%2$s\" is missing unit!",
631282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                        value, attribute),
632282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                                null);
633282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    }
634282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    return true;
635282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
636282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
637282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
638282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
639282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return false;
640282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
641282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
642282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private static void computeTypedValue(TypedValue outValue, float value, float scale) {
643282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        value *= scale;
644282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        boolean neg = value < 0;
645282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (neg) {
646282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            value = -value;
647282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
648282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        long bits = (long)(value*(1<<23)+.5f);
649282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        int radix;
650282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        int shift;
651282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if ((bits&0x7fffff) == 0) {
652282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Always use 23p0 if there is no fraction, just to make
653282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // things easier to read.
654282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            radix = TypedValue.COMPLEX_RADIX_23p0;
655282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            shift = 23;
656282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if ((bits&0xffffffffff800000L) == 0) {
657282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Magnitude is zero -- can fit in 0 bits of precision.
658282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            radix = TypedValue.COMPLEX_RADIX_0p23;
659282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            shift = 0;
660282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if ((bits&0xffffffff80000000L) == 0) {
661282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Magnitude can fit in 8 bits of precision.
662282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            radix = TypedValue.COMPLEX_RADIX_8p15;
663282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            shift = 8;
664282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else if ((bits&0xffffff8000000000L) == 0) {
665282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Magnitude can fit in 16 bits of precision.
666282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            radix = TypedValue.COMPLEX_RADIX_16p7;
667282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            shift = 16;
668282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
669282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // Magnitude needs entire range, so no fractional part.
670282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            radix = TypedValue.COMPLEX_RADIX_23p0;
671282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            shift = 23;
672282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
673282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        int mantissa = (int)(
674282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            (bits>>shift) & TypedValue.COMPLEX_MANTISSA_MASK);
675282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (neg) {
676282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            mantissa = (-mantissa) & TypedValue.COMPLEX_MANTISSA_MASK;
677282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
678282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        outValue.data |=
679282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            (radix<<TypedValue.COMPLEX_RADIX_SHIFT)
680282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            | (mantissa<<TypedValue.COMPLEX_MANTISSA_SHIFT);
681282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
682282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
683282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private static boolean parseUnit(String str, TypedValue outValue, float[] outScale) {
684282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        str = str.trim();
685282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
686282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        for (UnitEntry unit : sUnitNames) {
687282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (unit.name.equals(str)) {
688282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                applyUnit(unit, outValue, outScale);
689282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return true;
690282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
691282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
692282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
693282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return false;
694282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
695282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
696282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private static void applyUnit(UnitEntry unit, TypedValue outValue, float[] outScale) {
697282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        outValue.type = unit.type;
6981a12b805698c7cba9c2daa78c76c055afbdfa9fcDeepanshu Gupta        // COMPLEX_UNIT_SHIFT is 0 and hence intelliJ complains about it. Suppress the warning.
6991a12b805698c7cba9c2daa78c76c055afbdfa9fcDeepanshu Gupta        //noinspection PointlessBitwiseExpression
700282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        outValue.data = unit.unit << TypedValue.COMPLEX_UNIT_SHIFT;
701282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        outScale[0] = unit.scale;
702282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
703282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
704282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
705