aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/resources/platform/AttributeInfo.java
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/resources/platform/AttributeInfo.java')
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/resources/platform/AttributeInfo.java355
1 files changed, 355 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/resources/platform/AttributeInfo.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/resources/platform/AttributeInfo.java
new file mode 100755
index 000000000..e246975bb
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/resources/platform/AttributeInfo.java
@@ -0,0 +1,355 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ide.common.resources.platform;
+
+import static com.android.SdkConstants.ANDROID_PREFIX;
+import static com.android.SdkConstants.ANDROID_THEME_PREFIX;
+import static com.android.SdkConstants.ID_PREFIX;
+import static com.android.SdkConstants.NEW_ID_PREFIX;
+import static com.android.SdkConstants.PREFIX_THEME_REF;
+import static com.android.SdkConstants.VALUE_FALSE;
+import static com.android.SdkConstants.VALUE_TRUE;
+import static com.android.ide.common.api.IAttributeInfo.Format.BOOLEAN;
+import static com.android.ide.common.api.IAttributeInfo.Format.COLOR;
+import static com.android.ide.common.api.IAttributeInfo.Format.DIMENSION;
+import static com.android.ide.common.api.IAttributeInfo.Format.ENUM;
+import static com.android.ide.common.api.IAttributeInfo.Format.FLAG;
+import static com.android.ide.common.api.IAttributeInfo.Format.FLOAT;
+import static com.android.ide.common.api.IAttributeInfo.Format.FRACTION;
+import static com.android.ide.common.api.IAttributeInfo.Format.INTEGER;
+import static com.android.ide.common.api.IAttributeInfo.Format.STRING;
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+import com.android.ide.common.api.IAttributeInfo;
+import com.android.ide.common.resources.ResourceRepository;
+import com.android.resources.ResourceType;
+import com.google.common.base.Splitter;
+
+import java.util.EnumSet;
+import java.util.regex.Pattern;
+
+
+/**
+ * Information about an attribute as gathered from the attrs.xml file where
+ * the attribute was declared. This must include a format (string, reference, float, etc.),
+ * possible flag or enum values, whether it's deprecated and its javadoc.
+ */
+public class AttributeInfo implements IAttributeInfo {
+ /** XML Name of the attribute */
+ private String mName;
+
+ /** Formats of the attribute. Cannot be null. Should have at least one format. */
+ private EnumSet<Format> mFormats;
+ /** Values for enum. null for other types. */
+ private String[] mEnumValues;
+ /** Values for flag. null for other types. */
+ private String[] mFlagValues;
+ /** Short javadoc (i.e. the first sentence). */
+ private String mJavaDoc;
+ /** Documentation for deprecated attributes. Null if not deprecated. */
+ private String mDeprecatedDoc;
+ /** The source class defining this attribute */
+ private String mDefinedBy;
+
+ /**
+ * @param name The XML Name of the attribute
+ * @param formats The formats of the attribute. Cannot be null.
+ * Should have at least one format.
+ */
+ public AttributeInfo(@NonNull String name, @NonNull EnumSet<Format> formats) {
+ mName = name;
+ mFormats = formats;
+ }
+
+ /**
+ * @param name The XML Name of the attribute
+ * @param formats The formats of the attribute. Cannot be null.
+ * Should have at least one format.
+ * @param javadoc Short javadoc (i.e. the first sentence).
+ */
+ public AttributeInfo(@NonNull String name, @NonNull EnumSet<Format> formats, String javadoc) {
+ mName = name;
+ mFormats = formats;
+ mJavaDoc = javadoc;
+ }
+
+ public AttributeInfo(AttributeInfo info) {
+ mName = info.mName;
+ mFormats = info.mFormats;
+ mEnumValues = info.mEnumValues;
+ mFlagValues = info.mFlagValues;
+ mJavaDoc = info.mJavaDoc;
+ mDeprecatedDoc = info.mDeprecatedDoc;
+ }
+
+ /**
+ * Sets the XML Name of the attribute
+ *
+ * @param name the new name to assign
+ */
+ public void setName(String name) {
+ mName = name;
+ }
+
+ /** Returns the XML Name of the attribute */
+ @Override
+ public @NonNull String getName() {
+ return mName;
+ }
+ /** Returns the formats of the attribute. Cannot be null.
+ * Should have at least one format. */
+ @Override
+ public @NonNull EnumSet<Format> getFormats() {
+ return mFormats;
+ }
+ /** Returns the values for enums. null for other types. */
+ @Override
+ public String[] getEnumValues() {
+ return mEnumValues;
+ }
+ /** Returns the values for flags. null for other types. */
+ @Override
+ public String[] getFlagValues() {
+ return mFlagValues;
+ }
+ /** Returns a short javadoc, .i.e. the first sentence. */
+ @Override
+ public @NonNull String getJavaDoc() {
+ return mJavaDoc;
+ }
+ /** Returns the documentation for deprecated attributes. Null if not deprecated. */
+ @Override
+ public String getDeprecatedDoc() {
+ return mDeprecatedDoc;
+ }
+
+ /** Sets the values for enums. null for other types. */
+ public AttributeInfo setEnumValues(String[] values) {
+ mEnumValues = values;
+ return this;
+ }
+
+ /** Sets the values for flags. null for other types. */
+ public AttributeInfo setFlagValues(String[] values) {
+ mFlagValues = values;
+ return this;
+ }
+
+ /** Sets a short javadoc, .i.e. the first sentence. */
+ public void setJavaDoc(String javaDoc) {
+ mJavaDoc = javaDoc;
+ }
+
+ /** Sets the documentation for deprecated attributes. Null if not deprecated. */
+ public void setDeprecatedDoc(String deprecatedDoc) {
+ mDeprecatedDoc = deprecatedDoc;
+ }
+
+ /**
+ * Sets the name of the class (fully qualified class name) which defined
+ * this attribute
+ *
+ * @param definedBy the name of the class (fully qualified class name) which
+ * defined this attribute
+ */
+ public void setDefinedBy(String definedBy) {
+ mDefinedBy = definedBy;
+ }
+
+ /**
+ * Returns the name of the class (fully qualified class name) which defined
+ * this attribute
+ *
+ * @return the name of the class (fully qualified class name) which defined
+ * this attribute
+ */
+ @Override
+ public @NonNull String getDefinedBy() {
+ return mDefinedBy;
+ }
+
+ private final static Pattern INTEGER_PATTERN = Pattern.compile("-?[0-9]+"); //$NON-NLS-1$
+ private final static Pattern FLOAT_PATTERN =
+ Pattern.compile("-?[0-9]?(\\.[0-9]+)?"); //$NON-NLS-1$
+ private final static Pattern DIMENSION_PATTERN =
+ Pattern.compile("-?[0-9]+(\\.[0-9]+)?(dp|dip|sp|px|pt|in|mm)"); //$NON-NLS-1$
+
+ /**
+ * Checks the given value and returns true only if it is a valid XML value
+ * for this attribute.
+ *
+ * @param value the XML value to check
+ * @param projectResources project resources to validate resource URLs with,
+ * if any
+ * @param frameworkResources framework resources to validate resource URLs
+ * with, if any
+ * @return true if the value is valid, false otherwise
+ */
+ public boolean isValid(
+ @NonNull String value,
+ @Nullable ResourceRepository projectResources,
+ @Nullable ResourceRepository frameworkResources) {
+
+ if (mFormats.contains(STRING) || mFormats.isEmpty()) {
+ // Anything is allowed
+ return true;
+ }
+
+ // All other formats require a nonempty string
+ if (value.isEmpty()) {
+ // Except for flags
+ if (mFormats.contains(FLAG)) {
+ return true;
+ }
+
+ return false;
+ }
+ char first = value.charAt(0);
+
+ // There are many attributes which are incorrectly marked in the attrs.xml
+ // file, such as "duration", "minHeight", etc. These are marked as only
+ // accepting "integer", but also appear to accept "reference". Therefore,
+ // in these cases, be more lenient. (This happens for theme references too,
+ // such as ?android:attr/listPreferredItemHeight)
+ if ((first == '@' || first == '?') /* && mFormats.contains(REFERENCE)*/) {
+ if (value.equals("@null")) {
+ return true;
+ }
+
+ if (value.startsWith(NEW_ID_PREFIX) || value.startsWith(ID_PREFIX)) {
+ // These are handled in the IdGeneratingResourceFile; we shouldn't
+ // complain about not finding ids in the repository yet since they may
+ // not yet have been defined (@+id's can be defined in the same layout,
+ // later on.)
+ return true;
+ }
+
+ if (value.startsWith(ANDROID_PREFIX) || value.startsWith(ANDROID_THEME_PREFIX)) {
+ if (frameworkResources != null) {
+ return frameworkResources.hasResourceItem(value);
+ }
+ } else if (projectResources != null) {
+ return projectResources.hasResourceItem(value);
+ }
+
+ // Validate resource string
+ String url = value;
+ int typeEnd = url.indexOf('/', 1);
+ if (typeEnd != -1) {
+ int typeBegin = url.startsWith("@+") ? 2 : 1; //$NON-NLS-1$
+ int colon = url.lastIndexOf(':', typeEnd);
+ if (colon != -1) {
+ typeBegin = colon + 1;
+ }
+ String typeName = url.substring(typeBegin, typeEnd);
+ ResourceType type = ResourceType.getEnum(typeName);
+ if (type != null) {
+ // TODO: Validate that the name portion conforms to the rules
+ // (is an identifier but not a keyword, etc.)
+ // Also validate that the prefix before the colon is either
+ // not there or is "android"
+
+ //int nameBegin = typeEnd + 1;
+ //String name = url.substring(nameBegin);
+ return true;
+ }
+ } else if (value.startsWith(PREFIX_THEME_REF)) {
+ if (projectResources != null) {
+ return projectResources.hasResourceItem(ResourceType.ATTR,
+ value.substring(PREFIX_THEME_REF.length()));
+ } else {
+ // Until proven otherwise
+ return true;
+ }
+ }
+ }
+
+ if (mFormats.contains(ENUM) && mEnumValues != null) {
+ for (String e : mEnumValues) {
+ if (value.equals(e)) {
+ return true;
+ }
+ }
+ }
+
+ if (mFormats.contains(FLAG) && mFlagValues != null) {
+ for (String v : Splitter.on('|').split(value)) {
+ for (String e : mFlagValues) {
+ if (v.equals(e)) {
+ return true;
+ }
+ }
+ }
+ }
+
+ if (mFormats.contains(DIMENSION)) {
+ if (DIMENSION_PATTERN.matcher(value).matches()) {
+ return true;
+ }
+ }
+
+ if (mFormats.contains(BOOLEAN)) {
+ if (value.equalsIgnoreCase(VALUE_TRUE) || value.equalsIgnoreCase(VALUE_FALSE)) {
+ return true;
+ }
+ }
+
+ if (mFormats.contains(FLOAT)) {
+ if (Character.isDigit(first) || first == '-' || first == '.') {
+ if (FLOAT_PATTERN.matcher(value).matches()) {
+ return true;
+ }
+ // AAPT accepts more general floats, such as ".1",
+ try {
+ Float.parseFloat(value);
+ return true;
+ } catch (NumberFormatException nufe) {
+ // Not a float
+ }
+ }
+ }
+
+ if (mFormats.contains(INTEGER)) {
+ if (Character.isDigit(first) || first == '-') {
+ if (INTEGER_PATTERN.matcher(value).matches()) {
+ return true;
+ }
+ }
+ }
+
+ if (mFormats.contains(COLOR)) {
+ if (first == '#' && value.length() <= 9) { // Only allowed 32 bit ARGB
+ try {
+ // Use Long.parseLong rather than Integer.parseInt to not overflow on
+ // 32 big hex values like "ff191919"
+ Long.parseLong(value.substring(1), 16);
+ return true;
+ } catch (NumberFormatException nufe) {
+ // Not a valid color number
+ }
+ }
+ }
+
+ if (mFormats.contains(FRACTION)) {
+ // should end with % or %p
+ return true;
+ }
+
+ return false;
+ }
+}