1953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll/*
2953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll * Copyright (C) 2008 The Android Open Source Project
3953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll *
4953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll * Licensed under the Eclipse Public License, Version 1.0 (the "License");
5953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll * you may not use this file except in compliance with the License.
6953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll * You may obtain a copy of the License at
7953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll *
8953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll *      http://www.eclipse.org/org/documents/epl-v10.php
9953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll *
10953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll * Unless required by applicable law or agreed to in writing, software
11953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll * distributed under the License is distributed on an "AS IS" BASIS,
12953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll * See the License for the specific language governing permissions and
14953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll * limitations under the License.
15953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll */
16953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll
17f85ad3e3e3f3686d0bdaa3177ed10348cf72375eRaphael Mollpackage com.android.ide.common.resources.platform;
18953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll
19f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbyeimport static com.android.SdkConstants.ANDROID_PREFIX;
20f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbyeimport static com.android.SdkConstants.ANDROID_THEME_PREFIX;
21f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbyeimport static com.android.SdkConstants.ID_PREFIX;
22f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbyeimport static com.android.SdkConstants.NEW_ID_PREFIX;
235a56f60c78b0cff7867d9708fb0033f9f4f53211Tor Norbyeimport static com.android.SdkConstants.PREFIX_THEME_REF;
24f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbyeimport static com.android.SdkConstants.VALUE_FALSE;
25f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbyeimport static com.android.SdkConstants.VALUE_TRUE;
26f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbyeimport static com.android.ide.common.api.IAttributeInfo.Format.BOOLEAN;
27f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbyeimport static com.android.ide.common.api.IAttributeInfo.Format.COLOR;
28f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbyeimport static com.android.ide.common.api.IAttributeInfo.Format.DIMENSION;
29f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbyeimport static com.android.ide.common.api.IAttributeInfo.Format.ENUM;
30f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbyeimport static com.android.ide.common.api.IAttributeInfo.Format.FLAG;
31f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbyeimport static com.android.ide.common.api.IAttributeInfo.Format.FLOAT;
32f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbyeimport static com.android.ide.common.api.IAttributeInfo.Format.FRACTION;
33f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbyeimport static com.android.ide.common.api.IAttributeInfo.Format.INTEGER;
34f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbyeimport static com.android.ide.common.api.IAttributeInfo.Format.STRING;
35f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye
3661684adfd7345f1a0df24bcf9176e6f528295bbbTor Norbyeimport com.android.annotations.NonNull;
37f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbyeimport com.android.annotations.Nullable;
382be70bde5a6dcd6447c32ef55866020be372f96cTor Norbyeimport com.android.ide.common.api.IAttributeInfo;
39f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbyeimport com.android.ide.common.resources.ResourceRepository;
40f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbyeimport com.android.resources.ResourceType;
41f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbyeimport com.google.common.base.Splitter;
42953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll
4361684adfd7345f1a0df24bcf9176e6f528295bbbTor Norbyeimport java.util.EnumSet;
44f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbyeimport java.util.regex.Pattern;
4561684adfd7345f1a0df24bcf9176e6f528295bbbTor Norbye
46953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll
47953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll/**
48953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll * Information about an attribute as gathered from the attrs.xml file where
49953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll * the attribute was declared. This must include a format (string, reference, float, etc.),
50953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll * possible flag or enum values, whether it's deprecated and its javadoc.
51953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll */
52953aeea61efb31402198b969478d1bda5dcbe613Raphael Mollpublic class AttributeInfo implements IAttributeInfo {
53953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    /** XML Name of the attribute */
54953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    private String mName;
55953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll
56953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    /** Formats of the attribute. Cannot be null. Should have at least one format. */
5761684adfd7345f1a0df24bcf9176e6f528295bbbTor Norbye    private EnumSet<Format> mFormats;
58953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    /** Values for enum. null for other types. */
59953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    private String[] mEnumValues;
60953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    /** Values for flag. null for other types. */
61953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    private String[] mFlagValues;
62953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    /** Short javadoc (i.e. the first sentence). */
63953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    private String mJavaDoc;
64953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    /** Documentation for deprecated attributes. Null if not deprecated. */
65953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    private String mDeprecatedDoc;
66e287bc8580e19d72a911615475b353790cf000ebTor Norbye    /** The source class defining this attribute */
67e287bc8580e19d72a911615475b353790cf000ebTor Norbye    private String mDefinedBy;
68953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll
69953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    /**
70953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll     * @param name The XML Name of the attribute
71953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll     * @param formats The formats of the attribute. Cannot be null.
72953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll     *                Should have at least one format.
73953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll     */
7461684adfd7345f1a0df24bcf9176e6f528295bbbTor Norbye    public AttributeInfo(@NonNull String name, @NonNull EnumSet<Format> formats) {
75953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll        mName = name;
76953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll        mFormats = formats;
77953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    }
78953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll
79953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    /**
80953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll     * @param name The XML Name of the attribute
81953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll     * @param formats The formats of the attribute. Cannot be null.
82953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll     *                Should have at least one format.
83953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll     * @param javadoc Short javadoc (i.e. the first sentence).
84953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll     */
8561684adfd7345f1a0df24bcf9176e6f528295bbbTor Norbye    public AttributeInfo(@NonNull String name, @NonNull EnumSet<Format> formats, String javadoc) {
86953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll        mName = name;
87953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll        mFormats = formats;
88953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll        mJavaDoc = javadoc;
89953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    }
90953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll
91953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    public AttributeInfo(AttributeInfo info) {
92953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll        mName = info.mName;
93953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll        mFormats = info.mFormats;
94953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll        mEnumValues = info.mEnumValues;
95953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll        mFlagValues = info.mFlagValues;
96953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll        mJavaDoc = info.mJavaDoc;
97953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll        mDeprecatedDoc = info.mDeprecatedDoc;
98953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    }
99953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll
10057f1244facb6c3de1fe8011ab66cdc3dd9ce0b61Tor Norbye    /**
10157f1244facb6c3de1fe8011ab66cdc3dd9ce0b61Tor Norbye     * Sets the XML Name of the attribute
10257f1244facb6c3de1fe8011ab66cdc3dd9ce0b61Tor Norbye     *
10357f1244facb6c3de1fe8011ab66cdc3dd9ce0b61Tor Norbye     * @param name the new name to assign
10457f1244facb6c3de1fe8011ab66cdc3dd9ce0b61Tor Norbye     */
10557f1244facb6c3de1fe8011ab66cdc3dd9ce0b61Tor Norbye    public void setName(String name) {
10657f1244facb6c3de1fe8011ab66cdc3dd9ce0b61Tor Norbye        mName = name;
10757f1244facb6c3de1fe8011ab66cdc3dd9ce0b61Tor Norbye    }
10857f1244facb6c3de1fe8011ab66cdc3dd9ce0b61Tor Norbye
109953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    /** Returns the XML Name of the attribute */
110ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye    @Override
1117e4b8e9d595e45baa9d87cdb8282f02759e73abcTor Norbye    public @NonNull String getName() {
112953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll        return mName;
113953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    }
114953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    /** Returns the formats of the attribute. Cannot be null.
115953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll     *  Should have at least one format. */
116ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye    @Override
1177e4b8e9d595e45baa9d87cdb8282f02759e73abcTor Norbye    public @NonNull EnumSet<Format> getFormats() {
118953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll        return mFormats;
119953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    }
120953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    /** Returns the values for enums. null for other types. */
121ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye    @Override
122953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    public String[] getEnumValues() {
123953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll        return mEnumValues;
124953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    }
125953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    /** Returns the values for flags. null for other types. */
126ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye    @Override
127953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    public String[] getFlagValues() {
128953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll        return mFlagValues;
129953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    }
130953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    /** Returns a short javadoc, .i.e. the first sentence. */
131ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye    @Override
1327e4b8e9d595e45baa9d87cdb8282f02759e73abcTor Norbye    public @NonNull String getJavaDoc() {
133953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll        return mJavaDoc;
134953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    }
135953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    /** Returns the documentation for deprecated attributes. Null if not deprecated. */
136ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye    @Override
137953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    public String getDeprecatedDoc() {
138953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll        return mDeprecatedDoc;
139953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    }
140953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll
141953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    /** Sets the values for enums. null for other types. */
142953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    public AttributeInfo setEnumValues(String[] values) {
143953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll        mEnumValues = values;
144953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll        return this;
145953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    }
146953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll
147953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    /** Sets the values for flags. null for other types. */
148953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    public AttributeInfo setFlagValues(String[] values) {
149953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll        mFlagValues = values;
150953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll        return this;
151953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    }
152953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll
153953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    /** Sets a short javadoc, .i.e. the first sentence. */
154953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    public void setJavaDoc(String javaDoc) {
155953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll        mJavaDoc = javaDoc;
156953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    }
157953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll
158953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    /** Sets the documentation for deprecated attributes. Null if not deprecated. */
159953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    public void setDeprecatedDoc(String deprecatedDoc) {
160953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll        mDeprecatedDoc = deprecatedDoc;
161953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll    }
162e287bc8580e19d72a911615475b353790cf000ebTor Norbye
163e287bc8580e19d72a911615475b353790cf000ebTor Norbye    /**
164e287bc8580e19d72a911615475b353790cf000ebTor Norbye     * Sets the name of the class (fully qualified class name) which defined
165e287bc8580e19d72a911615475b353790cf000ebTor Norbye     * this attribute
166e287bc8580e19d72a911615475b353790cf000ebTor Norbye     *
167e287bc8580e19d72a911615475b353790cf000ebTor Norbye     * @param definedBy the name of the class (fully qualified class name) which
168e287bc8580e19d72a911615475b353790cf000ebTor Norbye     *            defined this attribute
169e287bc8580e19d72a911615475b353790cf000ebTor Norbye     */
170e287bc8580e19d72a911615475b353790cf000ebTor Norbye    public void setDefinedBy(String definedBy) {
171e287bc8580e19d72a911615475b353790cf000ebTor Norbye        mDefinedBy = definedBy;
172e287bc8580e19d72a911615475b353790cf000ebTor Norbye    }
173e287bc8580e19d72a911615475b353790cf000ebTor Norbye
174e287bc8580e19d72a911615475b353790cf000ebTor Norbye    /**
175e287bc8580e19d72a911615475b353790cf000ebTor Norbye     * Returns the name of the class (fully qualified class name) which defined
176e287bc8580e19d72a911615475b353790cf000ebTor Norbye     * this attribute
177e287bc8580e19d72a911615475b353790cf000ebTor Norbye     *
178e287bc8580e19d72a911615475b353790cf000ebTor Norbye     * @return the name of the class (fully qualified class name) which defined
179e287bc8580e19d72a911615475b353790cf000ebTor Norbye     *         this attribute
180e287bc8580e19d72a911615475b353790cf000ebTor Norbye     */
181ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye    @Override
1827e4b8e9d595e45baa9d87cdb8282f02759e73abcTor Norbye    public @NonNull String getDefinedBy() {
183e287bc8580e19d72a911615475b353790cf000ebTor Norbye        return mDefinedBy;
184e287bc8580e19d72a911615475b353790cf000ebTor Norbye    }
185f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye
186f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye    private final static Pattern INTEGER_PATTERN = Pattern.compile("-?[0-9]+"); //$NON-NLS-1$
187f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye    private final static Pattern FLOAT_PATTERN =
188f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            Pattern.compile("-?[0-9]?(\\.[0-9]+)?"); //$NON-NLS-1$
189f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye    private final static Pattern DIMENSION_PATTERN =
190f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            Pattern.compile("-?[0-9]+(\\.[0-9]+)?(dp|dip|sp|px|pt|in|mm)"); //$NON-NLS-1$
191f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye
192f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye    /**
193f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye     * Checks the given value and returns true only if it is a valid XML value
194f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye     * for this attribute.
195f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye     *
196f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye     * @param value the XML value to check
197f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye     * @param projectResources project resources to validate resource URLs with,
198f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye     *            if any
199f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye     * @param frameworkResources framework resources to validate resource URLs
200f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye     *            with, if any
201f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye     * @return true if the value is valid, false otherwise
202f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye     */
203f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye    public boolean isValid(
204f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            @NonNull String value,
205f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            @Nullable ResourceRepository projectResources,
206f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            @Nullable ResourceRepository frameworkResources) {
207f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye
208f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        if (mFormats.contains(STRING) || mFormats.isEmpty()) {
209f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            // Anything is allowed
210f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            return true;
211f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        }
212f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye
213f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        // All other formats require a nonempty string
214f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        if (value.isEmpty()) {
2155a56f60c78b0cff7867d9708fb0033f9f4f53211Tor Norbye            // Except for flags
2165a56f60c78b0cff7867d9708fb0033f9f4f53211Tor Norbye            if (mFormats.contains(FLAG)) {
2175a56f60c78b0cff7867d9708fb0033f9f4f53211Tor Norbye                return true;
2185a56f60c78b0cff7867d9708fb0033f9f4f53211Tor Norbye            }
2195a56f60c78b0cff7867d9708fb0033f9f4f53211Tor Norbye
220f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            return false;
221f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        }
222f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        char first = value.charAt(0);
223f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye
224f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        // There are many attributes which are incorrectly marked in the attrs.xml
225f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        // file, such as "duration", "minHeight", etc. These are marked as only
226f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        // accepting "integer", but also appear to accept "reference". Therefore,
227f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        // in these cases, be more lenient. (This happens for theme references too,
228f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        // such as ?android:attr/listPreferredItemHeight)
229f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        if ((first == '@' || first == '?') /* && mFormats.contains(REFERENCE)*/) {
230f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            if (value.equals("@null")) {
231f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                return true;
232f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            }
233f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye
234f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            if (value.startsWith(NEW_ID_PREFIX) || value.startsWith(ID_PREFIX)) {
235f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                // These are handled in the IdGeneratingResourceFile; we shouldn't
236f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                // complain about not finding ids in the repository yet since they may
237f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                // not yet have been defined (@+id's can be defined in the same layout,
238f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                // later on.)
239f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                return true;
240f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            }
241f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye
242f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            if (value.startsWith(ANDROID_PREFIX) || value.startsWith(ANDROID_THEME_PREFIX)) {
243f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                if (frameworkResources != null) {
244f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                    return frameworkResources.hasResourceItem(value);
245f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                }
246f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            } else if (projectResources != null) {
247f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                return projectResources.hasResourceItem(value);
248f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            }
249f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye
250f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            // Validate resource string
251f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            String url = value;
252f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            int typeEnd = url.indexOf('/', 1);
253f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            if (typeEnd != -1) {
254f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                int typeBegin = url.startsWith("@+") ? 2 : 1; //$NON-NLS-1$
255f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                int colon = url.lastIndexOf(':', typeEnd);
256f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                if (colon != -1) {
257f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                    typeBegin = colon + 1;
258f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                }
259f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                String typeName = url.substring(typeBegin, typeEnd);
260f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                ResourceType type = ResourceType.getEnum(typeName);
261f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                if (type != null) {
262f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                    // TODO: Validate that the name portion conforms to the rules
263f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                    // (is an identifier but not a keyword, etc.)
264f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                    // Also validate that the prefix before the colon is either
265f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                    // not there or is "android"
266f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye
267f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                    //int nameBegin = typeEnd + 1;
268f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                    //String name = url.substring(nameBegin);
269f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                    return true;
270f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                }
2715a56f60c78b0cff7867d9708fb0033f9f4f53211Tor Norbye            } else if (value.startsWith(PREFIX_THEME_REF)) {
2725a56f60c78b0cff7867d9708fb0033f9f4f53211Tor Norbye                if (projectResources != null) {
2735a56f60c78b0cff7867d9708fb0033f9f4f53211Tor Norbye                    return projectResources.hasResourceItem(ResourceType.ATTR,
2745a56f60c78b0cff7867d9708fb0033f9f4f53211Tor Norbye                            value.substring(PREFIX_THEME_REF.length()));
2755a56f60c78b0cff7867d9708fb0033f9f4f53211Tor Norbye                } else {
2765a56f60c78b0cff7867d9708fb0033f9f4f53211Tor Norbye                    // Until proven otherwise
2775a56f60c78b0cff7867d9708fb0033f9f4f53211Tor Norbye                    return true;
2785a56f60c78b0cff7867d9708fb0033f9f4f53211Tor Norbye                }
279f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            }
280f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        }
281f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye
282f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        if (mFormats.contains(ENUM) && mEnumValues != null) {
283f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            for (String e : mEnumValues) {
284f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                if (value.equals(e)) {
285f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                    return true;
286f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                }
287f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            }
288f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        }
289f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye
290f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        if (mFormats.contains(FLAG) && mFlagValues != null) {
291f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            for (String v : Splitter.on('|').split(value)) {
292f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                for (String e : mFlagValues) {
293f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                    if (v.equals(e)) {
294f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                        return true;
295f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                    }
296f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                }
297f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            }
298f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        }
299f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye
300f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        if (mFormats.contains(DIMENSION)) {
301f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            if (DIMENSION_PATTERN.matcher(value).matches()) {
302f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                return true;
303f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            }
304f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        }
305f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye
306f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        if (mFormats.contains(BOOLEAN)) {
3075a56f60c78b0cff7867d9708fb0033f9f4f53211Tor Norbye            if (value.equalsIgnoreCase(VALUE_TRUE) || value.equalsIgnoreCase(VALUE_FALSE)) {
308f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                return true;
309f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            }
310f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        }
311f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye
312f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        if (mFormats.contains(FLOAT)) {
313f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            if (Character.isDigit(first) || first == '-' || first == '.') {
314f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                if (FLOAT_PATTERN.matcher(value).matches()) {
315f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                    return true;
316f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                }
317f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                // AAPT accepts more general floats, such as ".1",
318f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                try {
319f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                    Float.parseFloat(value);
320f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                    return true;
321f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                } catch (NumberFormatException nufe) {
322f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                    // Not a float
323f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                }
324f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            }
325f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        }
326f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye
327f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        if (mFormats.contains(INTEGER)) {
328f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            if (Character.isDigit(first) || first == '-') {
329f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                if (INTEGER_PATTERN.matcher(value).matches()) {
330f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                    return true;
331f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                }
332f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            }
333f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        }
334f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye
335f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        if (mFormats.contains(COLOR)) {
336f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            if (first == '#' && value.length() <= 9) { // Only allowed 32 bit ARGB
337f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                try {
338f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                    // Use Long.parseLong rather than Integer.parseInt to not overflow on
339f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                    // 32 big hex values like "ff191919"
340f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                    Long.parseLong(value.substring(1), 16);
341f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                    return true;
342f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                } catch (NumberFormatException nufe) {
343f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                    // Not a valid color number
344f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye                }
345f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            }
346f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        }
347f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye
348f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        if (mFormats.contains(FRACTION)) {
349f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            // should end with % or %p
350f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye            return true;
351f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        }
352f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye
353f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye        return false;
354f48bde52e60fefec0763cad1b45bc1dcd1bf0841Tor Norbye    }
355953aeea61efb31402198b969478d1bda5dcbe613Raphael Moll}
356