Merge "Update getLayoutDirectionFromLocale() for using ICU"
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 20dc792..94a4afa 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -52,6 +52,8 @@
 import android.media.AudioManager;
 import android.net.ConnectivityManager;
 import android.net.IConnectivityManager;
+import android.net.INetworkPolicyManager;
+import android.net.NetworkPolicyManager;
 import android.net.ThrottleManager;
 import android.net.IThrottleManager;
 import android.net.Uri;
@@ -339,6 +341,14 @@
                     return new LocationManager(ILocationManager.Stub.asInterface(b));
                 }});
 
+        registerService(NETWORK_POLICY_SERVICE, new ServiceFetcher() {
+            @Override
+            public Object createService(ContextImpl ctx) {
+                return new NetworkPolicyManager(INetworkPolicyManager.Stub.asInterface(
+                        ServiceManager.getService(NETWORK_POLICY_SERVICE)));
+            }
+        });
+
         registerService(NOTIFICATION_SERVICE, new ServiceFetcher() {
                 public Object createService(ContextImpl ctx) {
                     final Context outerContext = ctx.getOuterContext();
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index b88e5cf..28559cc 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -23,6 +23,7 @@
 import android.database.Cursor;
 import android.database.CursorWrapper;
 import android.net.ConnectivityManager;
+import android.net.NetworkPolicyManager;
 import android.net.Uri;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
@@ -170,7 +171,6 @@
      */
     public final static int STATUS_FAILED = 1 << 4;
 
-
     /**
      * Value of COLUMN_ERROR_CODE when the download has completed with an error that doesn't fit
      * under any other error code.
@@ -249,6 +249,14 @@
     public final static int PAUSED_UNKNOWN = 4;
 
     /**
+     * Value of {@link #COLUMN_REASON} when the download has been paused because
+     * of {@link NetworkPolicyManager} controls on the requesting application.
+     *
+     * @hide
+     */
+    public final static int PAUSED_BY_POLICY = 5;
+
+    /**
      * Broadcast intent action sent by the download manager when a download completes.
      */
     public final static String ACTION_DOWNLOAD_COMPLETE = "android.intent.action.DOWNLOAD_COMPLETE";
@@ -796,6 +804,7 @@
                     parts.add(statusClause("=", Downloads.Impl.STATUS_WAITING_TO_RETRY));
                     parts.add(statusClause("=", Downloads.Impl.STATUS_WAITING_FOR_NETWORK));
                     parts.add(statusClause("=", Downloads.Impl.STATUS_QUEUED_FOR_WIFI));
+                    parts.add(statusClause("=", Downloads.Impl.STATUS_PAUSED_BY_POLICY));
                 }
                 if ((mStatusFlags & STATUS_SUCCESSFUL) != 0) {
                     parts.add(statusClause("=", Downloads.Impl.STATUS_SUCCESS));
@@ -1266,6 +1275,9 @@
                 case Downloads.Impl.STATUS_QUEUED_FOR_WIFI:
                     return PAUSED_QUEUED_FOR_WIFI;
 
+                case Downloads.Impl.STATUS_PAUSED_BY_POLICY:
+                    return PAUSED_BY_POLICY;
+
                 default:
                     return PAUSED_UNKNOWN;
             }
@@ -1321,6 +1333,7 @@
                 case Downloads.Impl.STATUS_WAITING_TO_RETRY:
                 case Downloads.Impl.STATUS_WAITING_FOR_NETWORK:
                 case Downloads.Impl.STATUS_QUEUED_FOR_WIFI:
+                case Downloads.Impl.STATUS_PAUSED_BY_POLICY:
                     return STATUS_PAUSED;
 
                 case Downloads.Impl.STATUS_SUCCESS:
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 538a06e..0d4d9a9 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -115,6 +115,20 @@
         }
     }
 
+    public void registerListener(INetworkPolicyListener listener) {
+        try {
+            mService.registerListener(listener);
+        } catch (RemoteException e) {
+        }
+    }
+
+    public void unregisterListener(INetworkPolicyListener listener) {
+        try {
+            mService.unregisterListener(listener);
+        } catch (RemoteException e) {
+        }
+    }
+
     /**
      * Compute the last cycle boundary for the given {@link NetworkPolicy}. For
      * example, if cycle day is 20th, and today is June 15th, it will return May
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index 3db1827..98d9c8fa 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -1238,7 +1238,103 @@
     }
 
     /**
-     * Fields and helpers for interacting with Events.
+     * Constants and helpers for the Events table, which contains details of a
+     * single event. <h3>Operations</h3> All operations can be done either as an
+     * app or as a sync adapter. To perform an operation as a sync adapter
+     * {@link #CALLER_IS_SYNCADAPTER} should be set to true in the Uri
+     * parameters and {@link #ACCOUNT_NAME} and {@link #ACCOUNT_TYPE} must be
+     * set. Sync adapters have write access to more columns but are restricted
+     * to a single account at a time.
+     * <dl>
+     * <dt><b>Insert</b></dt>
+     * <dd>When inserting a new event the following fields must be included:
+     * <ul>
+     * <li>dtstart</li>
+     * <li>dtend -or- a (rrule or rdate) and a duration</li>
+     * <li>a calendar_id</li>
+     * </ul>
+     * There are also further requirements when inserting or updating an event.
+     * See the section on Writing to Events.</dd>
+     * <dt><b>Update</b></dt>
+     * <dd>To perform an update on an Event the {@link Events#_ID} of the event
+     * must be provided either as an appended id to the Uri (
+     * {@link ContentUris#withAppendedId}) or as the first selection item--the
+     * selection should start with "_id=?" and the first selectionArg should be
+     * the _id of the event. Updating an event must respect the same rules as
+     * inserting and is further restricted in the fields that can be written.
+     * See the section on Writing to Events.</dd>
+     * <dt><b>Delete</b></dt>
+     * <dd>Events can be deleted either by the {@link Events#_ID} as an appended
+     * id on the Uri or using any standard selection. If an appended id is used
+     * a selection is not allowed. There are two versions of delete: as an app
+     * and as a sync adapter. An app delete will set the deleted column on an
+     * event and remove all instances of that event. A sync adapter delete will
+     * remove the event from the database and all associated data.</dd>
+     * <dt><b>Query</b></dt>
+     * <dd>Querying the Events table will get you all information about a set of
+     * events except their reminders, attendees, and extended properties. There
+     * will be one row returned for each event that matches the query selection,
+     * or at most a single row if the {@link Events#_ID} is appended to the Uri.
+     * Recurring events will only return a single row regardless of the number
+     * of times that event repeats.</dd>
+     * </dl>
+     * <h3>Writing to Events</h3> There are further restrictions on all Updates
+     * and Inserts in the Events table:
+     * <ul>
+     * <li>If allDay is set to 1 eventTimezone must be {@link Time#TIMEZONE_UTC}
+     * and the time must correspond to a midnight boundary.</li>
+     * <li>Exceptions are not allowed to recur. If rrule or rdate is not empty,
+     * original_id and original_sync_id must be empty.</li>
+     * <li>In general a calendar_id should not be modified after insertion. This
+     * is not explicitly forbidden but many sync adapters will not behave in an
+     * expected way if the calendar_id is modified.</li>
+     * </ul>
+     * The following Events columns are writable by both an app and a sync
+     * adapter.
+     * <ul>
+     * <li>{@link #CALENDAR_ID}</li>
+     * <li>{@link #ORGANIZER}</li>
+     * <li>{@link #TITLE}</li>
+     * <li>{@link #EVENT_LOCATION}</li>
+     * <li>{@link #DESCRIPTION}</li>
+     * <li>{@link #EVENT_COLOR}</li>
+     * <li>{@link #DTSTART}</li>
+     * <li>{@link #DTEND}</li>
+     * <li>{@link #EVENT_TIMEZONE}</li>
+     * <li>{@link #EVENT_END_TIMEZONE}</li>
+     * <li>{@link #DURATION}</li>
+     * <li>{@link #ALL_DAY}</li>
+     * <li>{@link #RRULE}</li>
+     * <li>{@link #RDATE}</li>
+     * <li>{@link #EXRULE}</li>
+     * <li>{@link #EXDATE}</li>
+     * <li>{@link #ORIGINAL_ID}</li>
+     * <li>{@link #ORIGINAL_SYNC_ID}</li>
+     * <li>{@link #ORIGINAL_INSTANCE_TIME}</li>
+     * <li>{@link #ORIGINAL_ALL_DAY}</li>
+     * <li>{@link #ACCESS_LEVEL}</li>
+     * <li>{@link #AVAILABILITY}</li>
+     * <li>{@link #GUESTS_CAN_MODIFY}</li>
+     * <li>{@link #GUESTS_CAN_INVITE_OTHERS}</li>
+     * <li>{@link #GUESTS_CAN_SEE_GUESTS}</li>
+     * </ul>
+     * The following Events columns are writable only by a sync adapter
+     * <ul>
+     * <li>{@link #DIRTY}</li>
+     * <li>{@link #_SYNC_ID}</li>
+     * <li>{@link #SYNC_DATA1}</li>
+     * <li>{@link #SYNC_DATA2}</li>
+     * <li>{@link #SYNC_DATA3}</li>
+     * <li>{@link #SYNC_DATA4}</li>
+     * <li>{@link #SYNC_DATA5}</li>
+     * <li>{@link #SYNC_DATA6}</li>
+     * <li>{@link #SYNC_DATA7}</li>
+     * <li>{@link #SYNC_DATA8}</li>
+     * <li>{@link #SYNC_DATA9}</li>
+     * <li>{@link #SYNC_DATA10}</li>
+     * </ul>
+     * The remaining columns are either updated by the provider only or are
+     * views into other tables and cannot be changed through the Events table.
      */
     public static final class Events implements BaseColumns, SyncColumns, EventsColumns,
             CalendarsColumns {
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index 3c4bb79..0a8c3ca 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -17,6 +17,7 @@
 package android.provider;
 
 import android.app.DownloadManager;
+import android.net.NetworkPolicyManager;
 import android.net.Uri;
 
 /**
@@ -547,6 +548,14 @@
         }
 
         /**
+         * This download has been paused because requesting application has been
+         * blocked by {@link NetworkPolicyManager}.
+         *
+         * @hide
+         */
+        public static final int STATUS_PAUSED_BY_POLICY = 189;
+
+        /**
          * This download hasn't stated yet
          */
         public static final int STATUS_PENDING = 190;
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 9eddf23..a3de285 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -349,7 +349,7 @@
             }
         }
         mPendingAnimations.clear();
-        mView.getHandler().removeCallbacks(mAnimationStarter);
+        mView.removeCallbacks(mAnimationStarter);
     }
 
     /**
@@ -705,7 +705,7 @@
 
         NameValuesHolder nameValuePair = new NameValuesHolder(constantName, startValue, byValue);
         mPendingAnimations.add(nameValuePair);
-        mView.getHandler().removeCallbacks(mAnimationStarter);
+        mView.removeCallbacks(mAnimationStarter);
         mView.post(mAnimationStarter);
     }
 
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 383842d..07855d9 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -16,8 +16,7 @@
 
 package com.android.server;
 
-import static android.Manifest.permission.READ_PHONE_STATE;
-import static android.Manifest.permission.UPDATE_DEVICE_STATS;
+import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
 import static android.net.ConnectivityManager.isNetworkTypeValid;
 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
 import static android.net.NetworkPolicyManager.RULE_REJECT_PAID;
@@ -1142,8 +1141,7 @@
         @Override
         public void onRulesChanged(int uid, int uidRules) {
             // only someone like NPMS should only be calling us
-            // TODO: create permission for modifying data policy
-            mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG);
+            mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
 
             if (LOGD_RULES) {
                 Slog.d(TAG, "onRulesChanged(uid=" + uid + ", uidRules=" + uidRules + ")");
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index dac0044..9cbe82d 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -747,6 +747,9 @@
 
     @Override
     public void registerListener(INetworkPolicyListener listener) {
+        // TODO: create permission for observing network policy
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+
         mListeners.register(listener);
 
         synchronized (mRulesLock) {
@@ -767,6 +770,9 @@
 
     @Override
     public void unregisterListener(INetworkPolicyListener listener) {
+        // TODO: create permission for observing network policy
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+
         mListeners.unregister(listener);
     }
 
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 151fde7..ee5f3f5 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -28,6 +28,7 @@
     <uses-permission android:name="android.permission.MANAGE_APP_TOKENS" />
     <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
     <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
+    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 7380fc1..47fa68e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -25,11 +25,11 @@
 import com.android.ide.common.rendering.api.StyleResourceValue;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.BridgeConstants;
+import com.android.layoutlib.bridge.impl.ParserFactory;
 import com.android.layoutlib.bridge.impl.Stack;
 import com.android.resources.ResourceType;
 import com.android.util.Pair;
 
-import org.kxml2.io.KXmlParser;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -206,6 +206,9 @@
      * @param parser the parser to add.
      */
     public void pushParser(BridgeXmlBlockParser parser) {
+        if (ParserFactory.LOG_PARSER) {
+            System.out.println("PUSH " + parser.getParser().toString());
+        }
         mParserStack.push(parser);
     }
 
@@ -213,7 +216,10 @@
      * Removes the parser at the top of the stack
      */
     public void popParser() {
-        mParserStack.pop();
+        BridgeXmlBlockParser parser = mParserStack.pop();
+        if (ParserFactory.LOG_PARSER) {
+            System.out.println("POPD " + parser.getParser().toString());
+        }
     }
 
     /**
@@ -346,9 +352,7 @@
                 // we need to create a pull parser around the layout XML file, and then
                 // give that to our XmlBlockParser
                 try {
-                    KXmlParser parser = new KXmlParser();
-                    parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-                    parser.setInput(new FileInputStream(xml), "UTF-8"); //$NON-NLS-1$);
+                    XmlPullParser parser = ParserFactory.create(xml);
 
                     // set the resource ref to have correct view cookies
                     mBridgeInflater.setResourceReference(resource);
@@ -687,25 +691,25 @@
      */
     private BridgeTypedArray createStyleBasedTypedArray(StyleResourceValue style, int[] attrs)
             throws Resources.NotFoundException {
-        AtomicBoolean frameworkAttributes = new AtomicBoolean();
-        AtomicReference<String> attrName = new AtomicReference<String>();
-        TreeMap<Integer, String> styleNameMap = searchAttrs(attrs, frameworkAttributes, attrName);
 
         BridgeTypedArray ta = ((BridgeResources) mSystemResources).newTypeArray(attrs.length,
-                style.isFramework(), frameworkAttributes.get(), attrName.get());
+                false, true, null);
 
-        // loop through all the values in the style map, and init the TypedArray with
-        // the style we got from the dynamic id
-        for (Entry<Integer, String> styleAttribute : styleNameMap.entrySet()) {
-            int index = styleAttribute.getKey().intValue();
+        // for each attribute, get its name so that we can search it in the style
+        for (int i = 0 ; i < attrs.length ; i++) {
+            Pair<ResourceType, String> resolvedResource = Bridge.resolveResourceId(attrs[i]);
+            if (resolvedResource != null) {
+                String attrName = resolvedResource.getSecond();
+                // look for the value in the given style
+                ResourceValue resValue = mRenderResources.findItemInStyle(style, attrName);
 
-            String name = styleAttribute.getValue();
+                if (resValue != null) {
+                    // resolve it to make sure there are no references left.
+                    ta.bridgeSetValue(i, attrName, mRenderResources.resolveResValue(resValue));
 
-            // get the value from the style, or its parent styles.
-            ResourceValue resValue = mRenderResources.findItemInStyle(style, name);
-
-            // resolve it to make sure there are no references left.
-            ta.bridgeSetValue(index, name, mRenderResources.resolveResValue(resValue));
+                    resValue = mRenderResources.resolveResValue(resValue);
+                }
+            }
         }
 
         ta.sealArray();
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
index 7c90a31..4a6393d 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
@@ -22,10 +22,10 @@
 import com.android.ide.common.rendering.api.ResourceReference;
 import com.android.ide.common.rendering.api.ResourceValue;
 import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.ParserFactory;
 import com.android.resources.ResourceType;
 import com.android.util.Pair;
 
-import org.kxml2.io.KXmlParser;
 import org.xmlpull.v1.XmlPullParser;
 
 import android.content.Context;
@@ -36,7 +36,6 @@
 import android.view.ViewGroup;
 
 import java.io.File;
-import java.io.FileInputStream;
 
 /**
  * Custom implementation of {@link LayoutInflater} to handle custom views.
@@ -175,9 +174,7 @@
                 File f = new File(value.getValue());
                 if (f.isFile()) {
                     try {
-                        KXmlParser parser = new KXmlParser();
-                        parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-                        parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$
+                        XmlPullParser parser = ParserFactory.create(f);
 
                         BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser(
                                 parser, bridgeContext, false);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
index d0b90fb..1756496 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
@@ -21,12 +21,12 @@
 import com.android.ide.common.rendering.api.ResourceValue;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.BridgeConstants;
+import com.android.layoutlib.bridge.impl.ParserFactory;
 import com.android.layoutlib.bridge.impl.ResourceHelper;
 import com.android.ninepatch.NinePatch;
 import com.android.resources.ResourceType;
 import com.android.util.Pair;
 
-import org.kxml2.io.KXmlParser;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -131,14 +131,16 @@
                 platformStyleable, styleableName);
     }
 
-    private ResourceValue getResourceValue(int id, boolean[] platformResFlag_out) {
+    private Pair<String, ResourceValue> getResourceValue(int id, boolean[] platformResFlag_out) {
         // first get the String related to this id in the framework
         Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(id);
 
         if (resourceInfo != null) {
             platformResFlag_out[0] = true;
-            return mContext.getRenderResources().getFrameworkResource(
-                    resourceInfo.getFirst(), resourceInfo.getSecond());
+            String attributeName = resourceInfo.getSecond();
+
+            return Pair.of(attributeName, mContext.getRenderResources().getFrameworkResource(
+                    resourceInfo.getFirst(), attributeName));
         }
 
         // didn't find a match in the framework? look in the project.
@@ -147,8 +149,10 @@
 
             if (resourceInfo != null) {
                 platformResFlag_out[0] = false;
-                return mContext.getRenderResources().getProjectResource(
-                        resourceInfo.getFirst(), resourceInfo.getSecond());
+                String attributeName = resourceInfo.getSecond();
+
+                return Pair.of(attributeName, mContext.getRenderResources().getProjectResource(
+                        resourceInfo.getFirst(), attributeName));
             }
         }
 
@@ -157,10 +161,10 @@
 
     @Override
     public Drawable getDrawable(int id) throws NotFoundException {
-        ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
 
         if (value != null) {
-            return ResourceHelper.getDrawable(value, mContext);
+            return ResourceHelper.getDrawable(value.getSecond(), mContext);
         }
 
         // id was not found or not resolved. Throw a NotFoundException.
@@ -172,11 +176,11 @@
 
     @Override
     public int getColor(int id) throws NotFoundException {
-        ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
 
         if (value != null) {
             try {
-                return ResourceHelper.getColor(value.getValue());
+                return ResourceHelper.getColor(value.getSecond().getValue());
             } catch (NumberFormatException e) {
                 Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT, e.getMessage(), e,
                         null /*data*/);
@@ -193,10 +197,11 @@
 
     @Override
     public ColorStateList getColorStateList(int id) throws NotFoundException {
-        ResourceValue resValue = getResourceValue(id, mPlatformResourceFlag);
+        Pair<String, ResourceValue> resValue = getResourceValue(id, mPlatformResourceFlag);
 
         if (resValue != null) {
-            ColorStateList stateList = ResourceHelper.getColorStateList(resValue, mContext);
+            ColorStateList stateList = ResourceHelper.getColorStateList(resValue.getSecond(),
+                    mContext);
             if (stateList != null) {
                 return stateList;
             }
@@ -211,10 +216,10 @@
 
     @Override
     public CharSequence getText(int id) throws NotFoundException {
-        ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
 
         if (value != null) {
-            return value.getValue();
+            return value.getSecond().getValue();
         }
 
         // id was not found or not resolved. Throw a NotFoundException.
@@ -226,9 +231,10 @@
 
     @Override
     public XmlResourceParser getLayout(int id) throws NotFoundException {
-        ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+        Pair<String, ResourceValue> v = getResourceValue(id, mPlatformResourceFlag);
 
-        if (value != null) {
+        if (v != null) {
+            ResourceValue value = v.getSecond();
             XmlPullParser parser = null;
 
             try {
@@ -243,9 +249,7 @@
                     if (xml.isFile()) {
                         // we need to create a pull parser around the layout XML file, and then
                         // give that to our XmlBlockParser
-                        parser = new KXmlParser();
-                        parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-                        parser.setInput(new FileInputStream(xml), "UTF-8"); //$NON-NLS-1$);
+                        parser = ParserFactory.create(xml);
                     }
                 }
 
@@ -271,9 +275,10 @@
 
     @Override
     public XmlResourceParser getAnimation(int id) throws NotFoundException {
-        ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+        Pair<String, ResourceValue> v = getResourceValue(id, mPlatformResourceFlag);
 
-        if (value != null) {
+        if (v != null) {
+            ResourceValue value = v.getSecond();
             XmlPullParser parser = null;
 
             try {
@@ -281,9 +286,7 @@
                 if (xml.isFile()) {
                     // we need to create a pull parser around the layout XML file, and then
                     // give that to our XmlBlockParser
-                    parser = new KXmlParser();
-                    parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-                    parser.setInput(new FileInputStream(xml), "UTF-8"); //$NON-NLS-1$);
+                    parser = ParserFactory.create(xml);
 
                     return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]);
                 }
@@ -317,10 +320,10 @@
 
     @Override
     public float getDimension(int id) throws NotFoundException {
-        ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
 
         if (value != null) {
-            String v = value.getValue();
+            String v = value.getSecond().getValue();
 
             if (v != null) {
                 if (v.equals(BridgeConstants.MATCH_PARENT) ||
@@ -330,7 +333,8 @@
                     return LayoutParams.WRAP_CONTENT;
                 }
 
-                if (ResourceHelper.stringToFloat(v, mTmpValue) &&
+                if (ResourceHelper.parseFloatAttribute(
+                        value.getFirst(), v, mTmpValue, true /*requireUnit*/) &&
                         mTmpValue.type == TypedValue.TYPE_DIMENSION) {
                     return mTmpValue.getDimension(mMetrics);
                 }
@@ -346,13 +350,14 @@
 
     @Override
     public int getDimensionPixelOffset(int id) throws NotFoundException {
-        ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
 
         if (value != null) {
-            String v = value.getValue();
+            String v = value.getSecond().getValue();
 
             if (v != null) {
-                if (ResourceHelper.stringToFloat(v, mTmpValue) &&
+                if (ResourceHelper.parseFloatAttribute(
+                        value.getFirst(), v, mTmpValue, true /*requireUnit*/) &&
                         mTmpValue.type == TypedValue.TYPE_DIMENSION) {
                     return TypedValue.complexToDimensionPixelOffset(mTmpValue.data, mMetrics);
                 }
@@ -368,13 +373,14 @@
 
     @Override
     public int getDimensionPixelSize(int id) throws NotFoundException {
-        ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
 
         if (value != null) {
-            String v = value.getValue();
+            String v = value.getSecond().getValue();
 
             if (v != null) {
-                if (ResourceHelper.stringToFloat(v, mTmpValue) &&
+                if (ResourceHelper.parseFloatAttribute(
+                        value.getFirst(), v, mTmpValue, true /*requireUnit*/) &&
                         mTmpValue.type == TypedValue.TYPE_DIMENSION) {
                     return TypedValue.complexToDimensionPixelSize(mTmpValue.data, mMetrics);
                 }
@@ -390,10 +396,10 @@
 
     @Override
     public int getInteger(int id) throws NotFoundException {
-        ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
 
-        if (value != null && value.getValue() != null) {
-            String v = value.getValue();
+        if (value != null && value.getSecond().getValue() != null) {
+            String v = value.getSecond().getValue();
             int radix = 10;
             if (v.startsWith("0x")) {
                 v = v.substring(2);
@@ -445,10 +451,10 @@
 
     @Override
     public String getString(int id) throws NotFoundException {
-        ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
 
-        if (value != null && value.getValue() != null) {
-            return value.getValue();
+        if (value != null && value.getSecond().getValue() != null) {
+            return value.getSecond().getValue();
         }
 
         // id was not found or not resolved. Throw a NotFoundException.
@@ -461,13 +467,14 @@
     @Override
     public void getValue(int id, TypedValue outValue, boolean resolveRefs)
             throws NotFoundException {
-        ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
 
         if (value != null) {
-            String v = value.getValue();
+            String v = value.getSecond().getValue();
 
             if (v != null) {
-                if (ResourceHelper.stringToFloat(v, outValue)) {
+                if (ResourceHelper.parseFloatAttribute(value.getFirst(), v, outValue,
+                        false /*requireUnit*/)) {
                     return;
                 }
 
@@ -490,19 +497,17 @@
 
     @Override
     public XmlResourceParser getXml(int id) throws NotFoundException {
-        ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
 
         if (value != null) {
-            String v = value.getValue();
+            String v = value.getSecond().getValue();
 
             if (v != null) {
                 // check this is a file
-                File f = new File(value.getValue());
+                File f = new File(v);
                 if (f.isFile()) {
                     try {
-                        KXmlParser parser = new KXmlParser();
-                        parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-                        parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$);
+                        XmlPullParser parser = ParserFactory.create(f);
 
                         return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]);
                     } catch (XmlPullParserException e) {
@@ -535,9 +540,7 @@
 
         File f = new File(file);
         try {
-            KXmlParser parser = new KXmlParser();
-            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-            parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$);
+            XmlPullParser parser = ParserFactory.create(f);
 
             return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]);
         } catch (XmlPullParserException e) {
@@ -554,10 +557,10 @@
 
     @Override
     public InputStream openRawResource(int id) throws NotFoundException {
-        ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
 
         if (value != null) {
-            String path = value.getValue();
+            String path = value.getSecond().getValue();
 
             if (path != null) {
                 // check this is a file
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
index b1fbf08..260cdc8 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
@@ -24,10 +24,10 @@
 import com.android.internal.util.XmlUtils;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.BridgeConstants;
+import com.android.layoutlib.bridge.impl.ParserFactory;
 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;
 
@@ -41,7 +41,6 @@
 import android.view.ViewGroup.LayoutParams;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.util.Arrays;
 import java.util.Map;
 
@@ -211,7 +210,7 @@
         Map<String, Integer> map = null;
         if (mPlatformStyleable) {
             map = Bridge.getEnumValues(mNames[index]);
-        } else {
+        } else if (mStyleableName != null) {
             // get the styleable matching the resolved name
             RenderResources res = mContext.getRenderResources();
             ResourceValue styleable = res.getProjectResource(ResourceType.DECLARE_STYLEABLE,
@@ -331,9 +330,7 @@
         File f = new File(value);
         if (f.isFile()) {
             try {
-                KXmlParser parser = new KXmlParser();
-                parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-                parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$);
+                XmlPullParser parser = ParserFactory.create(f);
 
                 BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
                         parser, mContext, resValue.isFramework());
@@ -377,26 +374,7 @@
      */
     @Override
     public int getInteger(int index, int defValue) {
-        if (mResourceData[index] == null) {
-            return defValue;
-        }
-
-        String s = mResourceData[index].getValue();
-
-        if (s != null) {
-            try {
-                return Integer.parseInt(s);
-            } catch (NumberFormatException e) {
-                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.
-            }
-        }
-
-        return defValue;
+        return getInt(index, defValue);
     }
 
     /**
@@ -434,7 +412,7 @@
             return defValue;
         }
 
-        if (ResourceHelper.stringToFloat(s, mValue)) {
+        if (ResourceHelper.parseFloatAttribute(mNames[index], s, mValue, true /*requireUnit*/)) {
             return mValue.getDimension(mBridgeResources.mMetrics);
         }
 
@@ -561,7 +539,7 @@
             throw new RuntimeException();
         }
 
-        if (ResourceHelper.stringToFloat(s, mValue)) {
+        if (ResourceHelper.parseFloatAttribute(mNames[index], s, mValue, true /*requireUnit*/)) {
             float f = mValue.getDimension(mBridgeResources.mMetrics);
 
             final int res = (int)(f+0.5f);
@@ -599,14 +577,15 @@
             return defValue;
         }
 
-        if (ResourceHelper.stringToFloat(value, mValue)) {
+        if (ResourceHelper.parseFloatAttribute(mNames[index], value, mValue,
+                false /*requireUnit*/)) {
             return mValue.getFraction(base, pbase);
         }
 
         // looks like we were unable to resolve the fraction value
         Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
                 String.format(
-                    "\"%1$s\" in attribute \"%2$s\" cannont be converted to a fraction.",
+                    "\"%1$s\" in attribute \"%2$s\" cannot be converted to a fraction.",
                     value, mNames[index]), null /*data*/);
 
         return defValue;
@@ -803,7 +782,8 @@
 
         String s = mResourceData[index].getValue();
 
-        return ResourceHelper.stringToFloat(s, outValue);
+        return ResourceHelper.parseFloatAttribute(mNames[index], s, outValue,
+                false /*requireUnit*/);
     }
 
     /**
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java
index 70dbaa4..1016b32 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java
@@ -18,6 +18,7 @@
 
 
 import com.android.ide.common.rendering.api.ILayoutPullParser;
+import com.android.layoutlib.bridge.impl.ParserFactory;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -54,6 +55,10 @@
      * @param platformFile Indicates whether the the file is a platform file or not.
      */
     public BridgeXmlBlockParser(XmlPullParser parser, BridgeContext context, boolean platformFile) {
+        if (ParserFactory.LOG_PARSER) {
+            System.out.println("CRTE " + parser.toString());
+        }
+
         mParser = parser;
         mContext = context;
         mPlatformFile = platformFile;
@@ -65,6 +70,10 @@
         }
     }
 
+    public XmlPullParser getParser() {
+        return mParser;
+    }
+
     public boolean isPlatformFile() {
         return mPlatformFile;
     }
@@ -247,18 +256,63 @@
     public int next() throws XmlPullParserException, IOException {
         if (!mStarted) {
             mStarted = true;
+
+            if (ParserFactory.LOG_PARSER) {
+                System.out.println("STRT " + mParser.toString());
+            }
+
             return START_DOCUMENT;
         }
+
         int ev = mParser.next();
 
+        if (ParserFactory.LOG_PARSER) {
+            System.out.println("NEXT " + mParser.toString() + " " +
+                    eventTypeToString(mEventType) + " -> " + eventTypeToString(ev));
+        }
+
         if (ev == END_TAG && mParser.getDepth() == 1) {
             // done with parser remove it from the context stack.
             ensurePopped();
+
+            if (ParserFactory.LOG_PARSER) {
+                System.out.println("");
+            }
         }
+
         mEventType = ev;
         return ev;
     }
 
+    public static String eventTypeToString(int eventType) {
+        switch (eventType) {
+            case START_DOCUMENT:
+                return "START_DOC";
+            case END_DOCUMENT:
+                return "END_DOC";
+            case START_TAG:
+                return "START_TAG";
+            case END_TAG:
+                return "END_TAG";
+            case TEXT:
+                return "TEXT";
+            case CDSECT:
+                return "CDSECT";
+            case ENTITY_REF:
+                return "ENTITY_REF";
+            case IGNORABLE_WHITESPACE:
+                return "IGNORABLE_WHITESPACE";
+            case PROCESSING_INSTRUCTION:
+                return "PROCESSING_INSTRUCTION";
+            case COMMENT:
+                return "COMMENT";
+            case DOCDECL:
+                return "DOCDECL";
+        }
+
+        return "????";
+    }
+
     public void require(int type, String namespace, String name)
             throws XmlPullParserException {
         if (type != getEventType()
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
index 060e6ee..df701d5 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
@@ -22,11 +22,11 @@
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.android.BridgeContext;
 import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
+import com.android.layoutlib.bridge.impl.ParserFactory;
 import com.android.layoutlib.bridge.impl.ResourceHelper;
 import com.android.resources.Density;
 import com.android.resources.ResourceType;
 
-import org.kxml2.io.KXmlParser;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -60,7 +60,7 @@
 
     protected abstract TextView getStyleableTextView();
 
-    protected CustomBar(Context context, Density density, String layoutPath)
+    protected CustomBar(Context context, Density density, String layoutPath, String name)
             throws XmlPullParserException {
         super(context);
         setOrientation(LinearLayout.HORIZONTAL);
@@ -69,11 +69,8 @@
         LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
 
-        KXmlParser parser = new KXmlParser();
-        parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-        parser.setInput(
-                getClass().getResourceAsStream(layoutPath),
-                "UTF8"); //$NON-NLS-1$
+        XmlPullParser parser = ParserFactory.create(getClass().getResourceAsStream(layoutPath),
+                name);
 
         BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser(
                 parser, (BridgeContext) context, false /*platformFile*/);
@@ -230,7 +227,8 @@
 
                 if (textSize != null) {
                     TypedValue out = new TypedValue();
-                    if (ResourceHelper.stringToFloat(textSize.getValue(), out)) {
+                    if (ResourceHelper.parseFloatAttribute("textSize", textSize.getValue(), out,
+                            true /*requireUnit*/)) {
                         textView.setTextSize(
                                 out.getDimension(bridgeContext.getResources().mMetrics));
                     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java
index 3af4e3a..f6edea4 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java
@@ -29,7 +29,7 @@
 
     public FakeActionBar(Context context, Density density, String label, String icon)
             throws XmlPullParserException {
-        super(context, density, "/bars/action_bar.xml");
+        super(context, density, "/bars/action_bar.xml", "action_bar.xml");
 
         // Cannot access the inside items through id because no R.id values have been
         // created for them.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java
index 9fab51a..5569e06 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java
@@ -30,7 +30,7 @@
 public class PhoneSystemBar extends CustomBar {
 
     public PhoneSystemBar(Context context, Density density) throws XmlPullParserException {
-        super(context, density, "/bars/phone_system_bar.xml");
+        super(context, density, "/bars/phone_system_bar.xml", "phone_system_bar.xml");
 
         setGravity(mGravity | Gravity.RIGHT);
         setBackgroundColor(0xFF000000);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TabletSystemBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TabletSystemBar.java
index 5ca68fa..456ddb4 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TabletSystemBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TabletSystemBar.java
@@ -29,7 +29,7 @@
 public class TabletSystemBar extends CustomBar {
 
     public TabletSystemBar(Context context, Density density) throws XmlPullParserException {
-        super(context, density, "/bars/tablet_system_bar.xml");
+        super(context, density, "/bars/tablet_system_bar.xml", "tablet_system_bar.xml");
 
         setBackgroundColor(0xFF000000);
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TitleBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TitleBar.java
index d7401d9..5f5ebc4 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TitleBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TitleBar.java
@@ -29,7 +29,7 @@
 
     public TitleBar(Context context, Density density, String label)
             throws XmlPullParserException {
-        super(context, density, "/bars/title_bar.xml");
+        super(context, density, "/bars/title_bar.xml", "title_bar.xml");
 
         // Cannot access the inside items through id because no R.id values have been
         // created for them.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java
new file mode 100644
index 0000000..a235ec3
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.layoutlib.bridge.impl;
+
+
+import org.kxml2.io.KXmlParser;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+
+/**
+ * A factory for {@link XmlPullParser}.
+ *
+ */
+public class ParserFactory {
+
+    private final static String ENCODING = "UTF-8"; //$NON-NLS-1$
+
+    public final static boolean LOG_PARSER = false;
+
+    public static XmlPullParser create(File f)
+            throws XmlPullParserException, FileNotFoundException {
+        KXmlParser parser = instantiateParser(f.getName());
+        parser.setInput(new FileInputStream(f), ENCODING);
+        return parser;
+    }
+
+    public static XmlPullParser create(InputStream stream, String name)
+            throws XmlPullParserException {
+        KXmlParser parser = instantiateParser(name);
+        parser.setInput(stream, ENCODING);
+        return parser;
+    }
+
+    private static KXmlParser instantiateParser(String name) throws XmlPullParserException {
+        KXmlParser parser;
+        if (name != null) {
+            parser = new CustomParser(name);
+        } else {
+            parser = new KXmlParser();
+        }
+        parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
+        return parser;
+    }
+
+    private static class CustomParser extends KXmlParser {
+        private final String mName;
+
+        CustomParser(String name) {
+            super();
+            mName = name;
+        }
+
+        @Override
+        public String toString() {
+            return mName;
+        }
+    }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index b800519..aa30e29 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -984,7 +984,8 @@
                         "status_bar_height");
 
                 if (value != null) {
-                    TypedValue typedValue = ResourceHelper.getValue(value.getValue());
+                    TypedValue typedValue = ResourceHelper.getValue("status_bar_height",
+                            value.getValue(), true /*requireUnit*/);
                     if (typedValue != null) {
                         // compute the pixel value based on the display metrics
                         mStatusBarSize = (int)typedValue.getDimension(metrics);
@@ -1016,7 +1017,8 @@
 
             if (value != null) {
                 // get the numerical value, if available
-                TypedValue typedValue = ResourceHelper.getValue(value.getValue());
+                TypedValue typedValue = ResourceHelper.getValue("actionBarSize", value.getValue(),
+                        true /*requireUnit*/);
                 if (typedValue != null) {
                     // compute the pixel value based on the display metrics
                     mActionBarSize = (int)typedValue.getDimension(metrics);
@@ -1040,7 +1042,8 @@
 
                 if (value != null) {
                     // get the numerical value, if available
-                    TypedValue typedValue = ResourceHelper.getValue(value.getValue());
+                    TypedValue typedValue = ResourceHelper.getValue("windowTitleSize",
+                            value.getValue(), true /*requireUnit*/);
                     if (typedValue != null) {
                         // compute the pixel value based on the display metrics
                         mTitleBarSize = (int)typedValue.getDimension(metrics);
@@ -1062,7 +1065,8 @@
                     "status_bar_height");
 
             if (value != null) {
-                TypedValue typedValue = ResourceHelper.getValue(value.getValue());
+                TypedValue typedValue = ResourceHelper.getValue("status_bar_height",
+                        value.getValue(), true /*requireUnit*/);
                 if (typedValue != null) {
                     // compute the pixel value based on the display metrics
                     mSystemBarSize = (int)typedValue.getDimension(metrics);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
index e5efa4e..6dcb693 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
@@ -27,7 +27,6 @@
 import com.android.ninepatch.NinePatchChunk;
 import com.android.resources.Density;
 
-import org.kxml2.io.KXmlParser;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -121,9 +120,7 @@
                 try {
                     // let the framework inflate the ColorStateList from the XML file, by
                     // providing an XmlPullParser
-                    KXmlParser parser = new KXmlParser();
-                    parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-                    parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$);
+                    XmlPullParser parser = ParserFactory.create(f);
 
                     BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
                             parser, context, resValue.isFramework());
@@ -203,9 +200,7 @@
             if (f.isFile()) {
                 try {
                     // let the framework inflate the Drawable from the XML file.
-                    KXmlParser parser = new KXmlParser();
-                    parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-                    parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$);
+                    XmlPullParser parser = ParserFactory.create(f);
 
                     BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
                             parser, context, value.isFramework());
@@ -341,11 +336,11 @@
     };
 
     /**
-     * Returns the raw value from the given string.
+     * Returns the raw value from the given attribute float-type value string.
      * This object is only valid until the next call on to {@link ResourceHelper}.
      */
-    public static TypedValue getValue(String s) {
-        if (stringToFloat(s, mValue)) {
+    public static TypedValue getValue(String attribute, String value, boolean requireUnit) {
+        if (parseFloatAttribute(attribute, value, mValue, requireUnit)) {
             return mValue;
         }
 
@@ -353,22 +348,27 @@
     }
 
     /**
-     * Convert the string into a {@link TypedValue}.
-     * @param s
-     * @param outValue
+     * Parse a float attribute and return the parsed value into a given TypedValue.
+     * @param attribute the name of the attribute. Can be null if <var>requireUnit</var> is false.
+     * @param value the string value of the attribute
+     * @param outValue the TypedValue to receive the parsed value
+     * @param requireUnit whether the value is expected to contain a unit.
      * @return true if success.
      */
-    public static boolean stringToFloat(String s, TypedValue outValue) {
+    public static boolean parseFloatAttribute(String attribute, String value,
+            TypedValue outValue, boolean requireUnit) {
+        assert requireUnit == false || attribute != null;
+
         // remove the space before and after
-        s = s.trim();
-        int len = s.length();
+        value = value.trim();
+        int len = value.length();
 
         if (len <= 0) {
             return false;
         }
 
         // check that there's no non ascii characters.
-        char[] buf = s.toCharArray();
+        char[] buf = value.toCharArray();
         for (int i = 0 ; i < len ; i++) {
             if (buf[i] > 255) {
                 return false;
@@ -381,7 +381,7 @@
         }
 
         // now look for the string that is after the float...
-        Matcher m = sFloatPattern.matcher(s);
+        Matcher m = sFloatPattern.matcher(value);
         if (m.matches()) {
             String f_str = m.group(1);
             String end = m.group(2);
@@ -397,45 +397,7 @@
             if (end.length() > 0 && end.charAt(0) != ' ') {
                 // Might be a unit...
                 if (parseUnit(end, outValue, sFloatOut)) {
-
-                    f *= sFloatOut[0];
-                    boolean neg = f < 0;
-                    if (neg) {
-                        f = -f;
-                    }
-                    long bits = (long)(f*(1<<23)+.5f);
-                    int radix;
-                    int shift;
-                    if ((bits&0x7fffff) == 0) {
-                        // Always use 23p0 if there is no fraction, just to make
-                        // things easier to read.
-                        radix = TypedValue.COMPLEX_RADIX_23p0;
-                        shift = 23;
-                    } else if ((bits&0xffffffffff800000L) == 0) {
-                        // Magnitude is zero -- can fit in 0 bits of precision.
-                        radix = TypedValue.COMPLEX_RADIX_0p23;
-                        shift = 0;
-                    } else if ((bits&0xffffffff80000000L) == 0) {
-                        // Magnitude can fit in 8 bits of precision.
-                        radix = TypedValue.COMPLEX_RADIX_8p15;
-                        shift = 8;
-                    } else if ((bits&0xffffff8000000000L) == 0) {
-                        // Magnitude can fit in 16 bits of precision.
-                        radix = TypedValue.COMPLEX_RADIX_16p7;
-                        shift = 16;
-                    } else {
-                        // Magnitude needs entire range, so no fractional part.
-                        radix = TypedValue.COMPLEX_RADIX_23p0;
-                        shift = 23;
-                    }
-                    int mantissa = (int)(
-                        (bits>>shift) & TypedValue.COMPLEX_MANTISSA_MASK);
-                    if (neg) {
-                        mantissa = (-mantissa) & TypedValue.COMPLEX_MANTISSA_MASK;
-                    }
-                    outValue.data |=
-                        (radix<<TypedValue.COMPLEX_RADIX_SHIFT)
-                        | (mantissa<<TypedValue.COMPLEX_MANTISSA_SHIFT);
+                    computeTypedValue(outValue, f, sFloatOut[0]);
                     return true;
                 }
                 return false;
@@ -446,8 +408,20 @@
 
             if (end.length() == 0) {
                 if (outValue != null) {
-                    outValue.type = TypedValue.TYPE_FLOAT;
-                    outValue.data = Float.floatToIntBits(f);
+                    if (requireUnit == false) {
+                        outValue.type = TypedValue.TYPE_FLOAT;
+                        outValue.data = Float.floatToIntBits(f);
+                    } else {
+                        // no unit when required? Use dp and out an error.
+                        applyUnit(sUnitNames[1], outValue, sFloatOut);
+                        computeTypedValue(outValue, f, sFloatOut[0]);
+
+                        Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE,
+                                String.format(
+                                        "Dimension \"%1$s\" in attribute \"%2$s\" is missing unit!",
+                                        value, attribute),
+                                null);
+                    }
                     return true;
                 }
             }
@@ -456,20 +430,64 @@
         return false;
     }
 
+    private static void computeTypedValue(TypedValue outValue, float value, float scale) {
+        value *= scale;
+        boolean neg = value < 0;
+        if (neg) {
+            value = -value;
+        }
+        long bits = (long)(value*(1<<23)+.5f);
+        int radix;
+        int shift;
+        if ((bits&0x7fffff) == 0) {
+            // Always use 23p0 if there is no fraction, just to make
+            // things easier to read.
+            radix = TypedValue.COMPLEX_RADIX_23p0;
+            shift = 23;
+        } else if ((bits&0xffffffffff800000L) == 0) {
+            // Magnitude is zero -- can fit in 0 bits of precision.
+            radix = TypedValue.COMPLEX_RADIX_0p23;
+            shift = 0;
+        } else if ((bits&0xffffffff80000000L) == 0) {
+            // Magnitude can fit in 8 bits of precision.
+            radix = TypedValue.COMPLEX_RADIX_8p15;
+            shift = 8;
+        } else if ((bits&0xffffff8000000000L) == 0) {
+            // Magnitude can fit in 16 bits of precision.
+            radix = TypedValue.COMPLEX_RADIX_16p7;
+            shift = 16;
+        } else {
+            // Magnitude needs entire range, so no fractional part.
+            radix = TypedValue.COMPLEX_RADIX_23p0;
+            shift = 23;
+        }
+        int mantissa = (int)(
+            (bits>>shift) & TypedValue.COMPLEX_MANTISSA_MASK);
+        if (neg) {
+            mantissa = (-mantissa) & TypedValue.COMPLEX_MANTISSA_MASK;
+        }
+        outValue.data |=
+            (radix<<TypedValue.COMPLEX_RADIX_SHIFT)
+            | (mantissa<<TypedValue.COMPLEX_MANTISSA_SHIFT);
+    }
+
     private static boolean parseUnit(String str, TypedValue outValue, float[] outScale) {
         str = str.trim();
 
         for (UnitEntry unit : sUnitNames) {
             if (unit.name.equals(str)) {
-                outValue.type = unit.type;
-                outValue.data = unit.unit << TypedValue.COMPLEX_UNIT_SHIFT;
-                outScale[0] = unit.scale;
-
+                applyUnit(unit, outValue, outScale);
                 return true;
             }
         }
 
         return false;
     }
+
+    private static void applyUnit(UnitEntry unit, TypedValue outValue, float[] outScale) {
+        outValue.type = unit.type;
+        outValue.data = unit.unit << TypedValue.COMPLEX_UNIT_SHIFT;
+        outScale[0] = unit.scale;
+    }
 }
 
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java
index 70d5446..96436fe 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java
@@ -16,14 +16,11 @@
 
 package com.android.layoutlib.bridge.android;
 
-import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
+import com.android.layoutlib.bridge.impl.ParserFactory;
 
-import org.kxml2.io.KXmlParser;
 import org.w3c.dom.Node;
 import org.xmlpull.v1.XmlPullParser;
 
-import java.io.InputStream;
-
 import junit.framework.TestCase;
 
 public class BridgeXmlBlockParserTest extends TestCase {
@@ -39,12 +36,12 @@
     }
 
     public void testXmlBlockParser() throws Exception {
-        XmlPullParser parser = new KXmlParser();
-        parser = new BridgeXmlBlockParser(parser, null, false /* platformResourceFlag */);
 
-        InputStream input = this.getClass().getClassLoader().getResourceAsStream(
-            "com/android/layoutlib/testdata/layout1.xml");
-        parser.setInput(input, "UTF-8"); //$NON-NLS-1$
+        XmlPullParser parser = ParserFactory.create(
+                getClass().getResourceAsStream("com/android/layoutlib/testdata/layout1.xml"),
+                        "layout1.xml");
+
+        parser = new BridgeXmlBlockParser(parser, null, false /* platformResourceFlag */);
 
         assertEquals(XmlPullParser.START_DOCUMENT, parser.next());