OSDN Git Service

LayoutLib: import of the GB layoutlib.
[android-x86/frameworks-base.git] / tools / layoutlib / bridge / src / com / android / layoutlib / bridge / android / BridgeTypedArray.java
  * limitations under the License.
  */
 
-package com.android.layoutlib.bridge;
+package com.android.layoutlib.bridge.android;
 
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.ide.common.rendering.api.RenderResources;
+import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.ide.common.rendering.api.StyleResourceValue;
 import com.android.internal.util.XmlUtils;
-import com.android.layoutlib.api.IResourceValue;
-import com.android.layoutlib.api.IStyleResourceValue;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.BridgeConstants;
+import com.android.layoutlib.bridge.impl.ResourceHelper;
+import com.android.resources.ResourceType;
 
 import org.kxml2.io.KXmlParser;
 import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
 
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
@@ -29,43 +36,43 @@ import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
 import android.util.DisplayMetrics;
 import android.util.TypedValue;
+import android.view.LayoutInflater_Delegate;
 import android.view.ViewGroup.LayoutParams;
 
 import java.io.File;
-import java.io.FileReader;
+import java.io.FileInputStream;
+import java.util.Arrays;
 import java.util.Map;
 
 /**
- * TODO: describe.
+ * Custom implementation of TypedArray to handle non compiled resources.
  */
 public final class BridgeTypedArray extends TypedArray {
 
-    @SuppressWarnings("hiding")
-    private BridgeResources mResources;
+    private BridgeResources mBridgeResources;
     private BridgeContext mContext;
-    @SuppressWarnings("hiding")
-    private IResourceValue[] mData;
+    private ResourceValue[] mResourceData;
     private String[] mNames;
     private final boolean mPlatformFile;
 
     public BridgeTypedArray(BridgeResources resources, BridgeContext context, int len,
             boolean platformFile) {
         super(null, null, null, 0);
-        mResources = resources;
+        mBridgeResources = resources;
         mContext = context;
         mPlatformFile = platformFile;
-        mData = new IResourceValue[len];
+        mResourceData = new ResourceValue[len];
         mNames = new String[len];
     }
 
     /** A bridge-specific method that sets a value in the type array */
-    public void bridgeSetValue(int index, String name, IResourceValue value) {
-        mData[index] = value;
+    public void bridgeSetValue(int index, String name, ResourceValue value) {
+        mResourceData[index] = value;
         mNames[index] = name;
     }
 
     /**
-     * Seals the array after all calls to {@link #bridgeSetValue(int, String, IResourceValue)} have
+     * Seals the array after all calls to {@link #bridgeSetValue(int, String, ResourceValue)} have
      * been done.
      * <p/>This allows to compute the list of non default values, permitting
      * {@link #getIndexCount()} to return the proper value.
@@ -74,7 +81,7 @@ public final class BridgeTypedArray extends TypedArray {
         // fills TypedArray.mIndices which is used to implement getIndexCount/getIndexAt
         // first count the array size
         int count = 0;
-        for (IResourceValue data : mData) {
+        for (ResourceValue data : mResourceData) {
             if (data != null) {
                 count++;
             }
@@ -86,8 +93,8 @@ public final class BridgeTypedArray extends TypedArray {
 
         // fill the array with the indices.
         int index = 1;
-        for (int i = 0 ; i < mData.length ; i++) {
-            if (mData[i] != null) {
+        for (int i = 0 ; i < mResourceData.length ; i++) {
+            if (mResourceData[i] != null) {
                 mIndices[index++] = i;
             }
         }
@@ -98,7 +105,7 @@ public final class BridgeTypedArray extends TypedArray {
      */
     @Override
     public int length() {
-        return mData.length;
+        return mResourceData.length;
     }
 
     /**
@@ -106,7 +113,7 @@ public final class BridgeTypedArray extends TypedArray {
      */
     @Override
     public Resources getResources() {
-        return mResources;
+        return mBridgeResources;
     }
 
     /**
@@ -119,9 +126,9 @@ public final class BridgeTypedArray extends TypedArray {
      */
     @Override
     public CharSequence getText(int index) {
-        if (mData[index] != null) {
+        if (mResourceData[index] != null) {
             // FIXME: handle styled strings!
-            return mData[index].getValue();
+            return mResourceData[index].getValue();
         }
 
         return null;
@@ -137,8 +144,8 @@ public final class BridgeTypedArray extends TypedArray {
      */
     @Override
     public String getString(int index) {
-        if (mData[index] != null) {
-            return mData[index].getValue();
+        if (mResourceData[index] != null) {
+            return mResourceData[index].getValue();
         }
 
         return null;
@@ -154,11 +161,11 @@ public final class BridgeTypedArray extends TypedArray {
      */
     @Override
     public boolean getBoolean(int index, boolean defValue) {
-        if (mData[index] == null) {
+        if (mResourceData[index] == null) {
             return defValue;
         }
 
-        String s = mData[index].getValue();
+        String s = mResourceData[index].getValue();
         if (s != null) {
             return XmlUtils.convertValueToBoolean(s, defValue);
         }
@@ -176,11 +183,15 @@ public final class BridgeTypedArray extends TypedArray {
      */
     @Override
     public int getInt(int index, int defValue) {
-        if (mData[index] == null) {
+        if (mResourceData[index] == null) {
             return defValue;
         }
 
-        String s = mData[index].getValue();
+        String s = mResourceData[index].getValue();
+
+        if (RenderResources.REFERENCE_NULL.equals(s)) {
+            return defValue;
+        }
 
         try {
             return (s == null) ? defValue : XmlUtils.convertValueToInt(s, defValue);
@@ -204,9 +215,10 @@ public final class BridgeTypedArray extends TypedArray {
                 if (i != null) {
                     result |= i.intValue();
                 } else {
-                    mContext.getLogger().warning(String.format(
-                            "Unknown constant \"%s\" in attribute \"%2$s\"",
-                            keyword, mNames[index]));
+                    Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
+                            String.format(
+                                "\"%s\" in attribute \"%2$s\" is not a valid value",
+                                keyword, mNames[index]), null /*data*/);
                 }
             }
             return result;
@@ -224,19 +236,20 @@ public final class BridgeTypedArray extends TypedArray {
      */
     @Override
     public float getFloat(int index, float defValue) {
-        if (mData[index] == null) {
+        if (mResourceData[index] == null) {
             return defValue;
         }
 
-        String s = mData[index].getValue();
+        String s = mResourceData[index].getValue();
 
         if (s != null) {
             try {
                 return Float.parseFloat(s);
             } catch (NumberFormatException e) {
-                mContext.getLogger().warning(String.format(
-                        "Unable to convert \"%s\" into a float in attribute \"%2$s\"",
-                        s, mNames[index]));
+                Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
+                        String.format(
+                            "\"%s\" in attribute \"%2$s\" cannot be converted to float.",
+                            s, mNames[index]), null /*data*/);
 
                 // we'll return the default value below.
             }
@@ -258,19 +271,14 @@ public final class BridgeTypedArray extends TypedArray {
      */
     @Override
     public int getColor(int index, int defValue) {
-        if (mData[index] == null) {
+        if (mResourceData[index] == null) {
             return defValue;
         }
 
-        String s = mData[index].getValue();
-        try {
-            return ResourceHelper.getColor(s);
-        } catch (NumberFormatException e) {
-            mContext.getLogger().warning(String.format(
-                    "Unable to convert \"%s\" into a color in attribute \"%2$s\"",
-                    s, mNames[index]));
-
-            // we'll return the default value below.
+        ColorStateList colorStateList = ResourceHelper.getColorStateList(
+                mResourceData[index], mContext);
+        if (colorStateList != null) {
+            return colorStateList.getDefaultColor();
         }
 
         return defValue;
@@ -287,49 +295,56 @@ public final class BridgeTypedArray extends TypedArray {
      */
     @Override
     public ColorStateList getColorStateList(int index) {
-        if (mData[index] == null) {
+        if (mResourceData[index] == null) {
             return null;
         }
 
-        String value = mData[index].getValue();
+        ResourceValue resValue = mResourceData[index];
+        String value = resValue.getValue();
 
         if (value == null) {
             return null;
         }
 
-        try {
-            int color = ResourceHelper.getColor(value);
-            return ColorStateList.valueOf(color);
-        } catch (NumberFormatException e) {
-            // if it's not a color value, we'll attempt to read the xml based color below.
+        if (RenderResources.REFERENCE_NULL.equals(value)) {
+            return null;
         }
 
         // let the framework inflate the ColorStateList from the XML file.
-        try {
-            File f = new File(value);
-            if (f.isFile()) {
+        File f = new File(value);
+        if (f.isFile()) {
+            try {
                 KXmlParser parser = new KXmlParser();
                 parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-                parser.setInput(new FileReader(f));
-
-                ColorStateList colorStateList = ColorStateList.createFromXml(
-                        mContext.getResources(),
-                        // FIXME: we need to know if this resource is platform or not
-                        new BridgeXmlBlockParser(parser, mContext, false));
-                return colorStateList;
+                parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$);
+
+                BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
+                        parser, mContext, resValue.isFramework());
+                try {
+                    return ColorStateList.createFromXml(mContext.getResources(), blockParser);
+                } finally {
+                    blockParser.ensurePopped();
+                }
+            } catch (XmlPullParserException e) {
+                Bridge.getLog().error(LayoutLog.TAG_BROKEN,
+                        "Failed to configure parser for " + value, e, null /*data*/);
+                return null;
+            } catch (Exception e) {
+                // this is an error and not warning since the file existence is checked before
+                // attempting to parse it.
+                Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
+                        "Failed to parse file " + value, e, null /*data*/);
+
+                return null;
             }
-        } catch (Exception e) {
-            // this is an error and not warning since the file existence is checked before
-            // attempting to parse it.
-            mContext.getLogger().error(e);
-
-            // return null below.
         }
 
-        // looks like were unable to resolve the color value.
-        mContext.getLogger().warning(String.format(
-                "Unable to resolve color value \"%1$s\" in attribute \"%2$s\"",
-                value, mNames[index]));
+        try {
+            int color = ResourceHelper.getColor(value);
+            return ColorStateList.valueOf(color);
+        } catch (NumberFormatException e) {
+            Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT, e.getMessage(), e, null /*data*/);
+        }
 
         return null;
     }
@@ -345,19 +360,20 @@ public final class BridgeTypedArray extends TypedArray {
      */
     @Override
     public int getInteger(int index, int defValue) {
-        if (mData[index] == null) {
+        if (mResourceData[index] == null) {
             return defValue;
         }
 
-        String s = mData[index].getValue();
+        String s = mResourceData[index].getValue();
 
         if (s != null) {
             try {
                 return Integer.parseInt(s);
             } catch (NumberFormatException e) {
-                mContext.getLogger().warning(String.format(
-                        "Unable to convert \"%s\" into a integer in attribute \"%2$s\"",
-                        s, mNames[index]));
+                Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
+                        String.format(
+                            "\"%s\" in attribute \"%2$s\" cannont be converted to an integer.",
+                            s, mNames[index]), null /*data*/);
 
                 // The default value is returned below.
             }
@@ -384,11 +400,11 @@ public final class BridgeTypedArray extends TypedArray {
      */
     @Override
     public float getDimension(int index, float defValue) {
-        if (mData[index] == null) {
+        if (mResourceData[index] == null) {
             return defValue;
         }
 
-        String s = mData[index].getValue();
+        String s = mResourceData[index].getValue();
 
         if (s == null) {
             return defValue;
@@ -397,16 +413,19 @@ public final class BridgeTypedArray extends TypedArray {
             return LayoutParams.MATCH_PARENT;
         } else if (s.equals(BridgeConstants.WRAP_CONTENT)) {
             return LayoutParams.WRAP_CONTENT;
+        } else if (RenderResources.REFERENCE_NULL.equals(s)) {
+            return defValue;
         }
 
         if (ResourceHelper.stringToFloat(s, mValue)) {
-            return mValue.getDimension(mResources.mMetrics);
+            return mValue.getDimension(mBridgeResources.mMetrics);
         }
 
         // looks like we were unable to resolve the dimension value
-        mContext.getLogger().warning(String.format(
-                "Unable to resolve dimension value \"%1$s\" in attribute \"%2$s\"",
-                s, mNames[index]));
+        Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
+                String.format(
+                    "\"%1$s\" in attribute \"%2$s\" is not a valid format.",
+                    s, mNames[index]), null /*data*/);
 
         return defValue;
     }
@@ -453,31 +472,23 @@ public final class BridgeTypedArray extends TypedArray {
      */
     @Override
     public int getDimensionPixelSize(int index, int defValue) {
-        if (mData[index] == null) {
-            return defValue;
-        }
-
-        String s = mData[index].getValue();
+        try {
+            return getDimension(index);
+        } catch (RuntimeException e) {
+            if (mResourceData[index] != null) {
+                String s = mResourceData[index].getValue();
+
+                if (s != null) {
+                    // looks like we were unable to resolve the dimension value
+                    Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
+                            String.format(
+                                "\"%1$s\" in attribute \"%2$s\" is not a valid format.",
+                                s, mNames[index]), null /*data*/);
+                }
+            }
 
-        if (s == null) {
             return defValue;
-        } else if (s.equals(BridgeConstants.MATCH_PARENT) ||
-                s.equals(BridgeConstants.FILL_PARENT)) {
-            return LayoutParams.MATCH_PARENT;
-        } else if (s.equals(BridgeConstants.WRAP_CONTENT)) {
-            return LayoutParams.WRAP_CONTENT;
         }
-
-        // FIXME huh?
-
-        float f = getDimension(index, defValue);
-        final int res = (int)(f+0.5f);
-        if (res != 0) return res;
-        if (f == 0) return 0;
-        if (f > 0) return 1;
-
-        throw new UnsupportedOperationException("Can't convert to dimension: " +
-                Integer.toString(index));
     }
 
     /**
@@ -494,7 +505,20 @@ public final class BridgeTypedArray extends TypedArray {
      */
     @Override
     public int getLayoutDimension(int index, String name) {
-        return getDimensionPixelSize(index, 0);
+        try {
+            // this will throw an exception
+            return getDimension(index);
+        } catch (RuntimeException e) {
+
+            if (LayoutInflater_Delegate.sIsInInclude) {
+                throw new RuntimeException();
+            }
+
+            Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
+                    "You must supply a " + name + " attribute.", null);
+
+            return 0;
+        }
     }
 
     @Override
@@ -502,6 +526,36 @@ public final class BridgeTypedArray extends TypedArray {
         return getDimensionPixelSize(index, defValue);
     }
 
+    private int getDimension(int index) {
+        if (mResourceData[index] == null) {
+            throw new RuntimeException();
+        }
+
+        String s = mResourceData[index].getValue();
+
+        if (s == null) {
+            throw new RuntimeException();
+        } else if (s.equals(BridgeConstants.MATCH_PARENT) ||
+                s.equals(BridgeConstants.FILL_PARENT)) {
+            return LayoutParams.MATCH_PARENT;
+        } else if (s.equals(BridgeConstants.WRAP_CONTENT)) {
+            return LayoutParams.WRAP_CONTENT;
+        } else if (RenderResources.REFERENCE_NULL.equals(s)) {
+            throw new RuntimeException();
+        }
+
+        if (ResourceHelper.stringToFloat(s, mValue)) {
+            float f = mValue.getDimension(mBridgeResources.mMetrics);
+
+            final int res = (int)(f+0.5f);
+            if (res != 0) return res;
+            if (f == 0) return 0;
+            if (f > 0) return 1;
+        }
+
+        throw new RuntimeException();
+    }
+
     /**
      * Retrieve a fractional unit attribute at <var>index</var>.
      *
@@ -519,11 +573,11 @@ public final class BridgeTypedArray extends TypedArray {
      */
     @Override
     public float getFraction(int index, int base, int pbase, float defValue) {
-        if (mData[index] == null) {
+        if (mResourceData[index] == null) {
             return defValue;
         }
 
-        String value = mData[index].getValue();
+        String value = mResourceData[index].getValue();
         if (value == null) {
             return defValue;
         }
@@ -533,9 +587,10 @@ public final class BridgeTypedArray extends TypedArray {
         }
 
         // looks like we were unable to resolve the fraction value
-        mContext.getLogger().warning(String.format(
-                "Unable to resolve fraction value \"%1$s\" in attribute \"%2$s\"",
-                value, mNames[index]));
+        Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
+                String.format(
+                    "\"%1$s\" in attribute \"%2$s\" cannont be converted to a fraction.",
+                    value, mNames[index]), null /*data*/);
 
         return defValue;
     }
@@ -556,8 +611,8 @@ public final class BridgeTypedArray extends TypedArray {
      */
     @Override
     public int getResourceId(int index, int defValue) {
-        // get the IResource for this index
-        IResourceValue resValue = mData[index];
+        // get the Resource for this index
+        ResourceValue resValue = mResourceData[index];
 
         // no data, return the default value.
         if (resValue == null) {
@@ -565,24 +620,30 @@ public final class BridgeTypedArray extends TypedArray {
         }
 
         // check if this is a style resource
-        if (resValue instanceof IStyleResourceValue) {
+        if (resValue instanceof StyleResourceValue) {
             // get the id that will represent this style.
-            return mContext.getDynamicIdByStyle((IStyleResourceValue)resValue);
+            return mContext.getDynamicIdByStyle((StyleResourceValue)resValue);
+        }
+
+        if (RenderResources.REFERENCE_NULL.equals(resValue.getValue())) {
+            return defValue;
         }
 
-        // if the attribute was a reference to an id, and not a declaration of an id (@+id), then
-        // the xml attribute value was "resolved" which leads us to a IResourceValue with
-        // getType() returning "id" and getName() returning the id name
+        // if the attribute was a reference to a resource, and not a declaration of an id (@+id),
+        // then the xml attribute value was "resolved" which leads us to a ResourceValue with a
+        // valid getType() and getName() returning a resource name.
         // (and getValue() returning null!). We need to handle this!
-        if (resValue.getType() != null && resValue.getType().equals(BridgeConstants.RES_ID)) {
+        if (resValue.getResourceType() != null) {
             // if this is a framework id
             if (mPlatformFile || resValue.isFramework()) {
                 // look for idName in the android R classes
-                return mContext.getFrameworkIdValue(resValue.getName(), defValue);
+                return mContext.getFrameworkResourceValue(
+                        resValue.getResourceType(), resValue.getName(), defValue);
             }
 
             // look for idName in the project R class.
-            return mContext.getProjectIdValue(resValue.getName(), defValue);
+            return mContext.getProjectResourceValue(
+                    resValue.getResourceType(), resValue.getName(), defValue);
         }
 
         // else, try to get the value, and resolve it somehow.
@@ -619,29 +680,33 @@ public final class BridgeTypedArray extends TypedArray {
             // if this is a framework id
             if (mPlatformFile || value.startsWith("@android") || value.startsWith("@+android")) {
                 // look for idName in the android R classes
-                return mContext.getFrameworkIdValue(idName, defValue);
+                return mContext.getFrameworkResourceValue(ResourceType.ID, idName, defValue);
             }
 
             // look for idName in the project R class.
-            return mContext.getProjectIdValue(idName, defValue);
+            return mContext.getProjectResourceValue(ResourceType.ID, idName, defValue);
         }
 
         // not a direct id valid reference? resolve it
         Integer idValue = null;
 
         if (resValue.isFramework()) {
-            idValue = Bridge.getResourceValue(resValue.getType(), resValue.getName());
+            idValue = Bridge.getResourceId(resValue.getResourceType(),
+                    resValue.getName());
         } else {
-            idValue = mContext.getProjectCallback().getResourceValue(
-                    resValue.getType(), resValue.getName());
+            idValue = mContext.getProjectCallback().getResourceId(
+                    resValue.getResourceType(), resValue.getName());
         }
 
         if (idValue != null) {
             return idValue.intValue();
         }
 
-        mContext.getLogger().warning(String.format(
-                "Unable to resolve id \"%1$s\" for attribute \"%2$s\"", value, mNames[index]));
+        Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_RESOLVE,
+                String.format(
+                    "Unable to resolve id \"%1$s\" for attribute \"%2$s\"", value, mNames[index]),
+                    resValue);
+
         return defValue;
     }
 
@@ -657,28 +722,17 @@ public final class BridgeTypedArray extends TypedArray {
      */
     @Override
     public Drawable getDrawable(int index) {
-        if (mData[index] == null) {
+        if (mResourceData[index] == null) {
             return null;
         }
 
-        IResourceValue value = mData[index];
+        ResourceValue value = mResourceData[index];
         String stringValue = value.getValue();
-        if (stringValue == null || BridgeConstants.REFERENCE_NULL.equals(stringValue)) {
+        if (stringValue == null || RenderResources.REFERENCE_NULL.equals(stringValue)) {
             return null;
         }
 
-        Drawable d = ResourceHelper.getDrawable(value, mContext, mData[index].isFramework());
-
-        if (d != null) {
-            return d;
-        }
-
-        // looks like we were unable to resolve the drawable
-        mContext.getLogger().warning(String.format(
-                "Unable to resolve drawable \"%1$s\" in attribute \"%2$s\"", stringValue,
-                mNames[index]));
-
-        return null;
+        return ResourceHelper.getDrawable(value, mContext);
     }
 
 
@@ -694,18 +748,23 @@ public final class BridgeTypedArray extends TypedArray {
      */
     @Override
     public CharSequence[] getTextArray(int index) {
-        if (mData[index] == null) {
+        if (mResourceData[index] == null) {
             return null;
         }
 
-        String value = mData[index].getValue();
+        String value = mResourceData[index].getValue();
         if (value != null) {
+            if (RenderResources.REFERENCE_NULL.equals(value)) {
+                return null;
+            }
+
             return new CharSequence[] { value };
         }
 
-        mContext.getLogger().warning(String.format(
-                String.format("Unknown value for getTextArray(%d) => %s", //DEBUG
-                index, mData[index].getName())));
+        Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
+                String.format(
+                    String.format("Unknown value for getTextArray(%d) => %s", //DEBUG
+                    index, mResourceData[index].getName())), null /*data*/);
 
         return null;
     }
@@ -721,11 +780,11 @@ public final class BridgeTypedArray extends TypedArray {
      */
     @Override
     public boolean getValue(int index, TypedValue outValue) {
-        if (mData[index] == null) {
+        if (mResourceData[index] == null) {
             return false;
         }
 
-        String s = mData[index].getValue();
+        String s = mResourceData[index].getValue();
 
         return ResourceHelper.stringToFloat(s, outValue);
     }
@@ -739,7 +798,7 @@ public final class BridgeTypedArray extends TypedArray {
      */
     @Override
     public boolean hasValue(int index) {
-        return mData[index] != null;
+        return mResourceData[index] != null;
     }
 
     /**
@@ -786,6 +845,6 @@ public final class BridgeTypedArray extends TypedArray {
 
     @Override
     public String toString() {
-        return mData.toString();
+        return Arrays.toString(mResourceData);
     }
  }