am e43a64e3: Merge "Changes for a quick, pre-migration bug sprint:" into lmp-docs

* commit 'e43a64e3336548094571885944afc28792e24fa0':
  Changes for a quick, pre-migration bug sprint:
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 4e2ff0b..a904460 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -17,7 +17,6 @@
 package android.app;
 
 import android.app.ActivityManager.StackInfo;
-import android.app.ProfilerInfo;
 import android.content.ComponentName;
 import android.content.IIntentReceiver;
 import android.content.IIntentSender;
@@ -2189,17 +2188,12 @@
             return true;
         }
 
-        case GET_ACTIVITY_CONTAINER_TRANSACTION: {
+        case GET_ACTIVITY_DISPLAY_ID_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder activityToken = data.readStrongBinder();
-            IActivityContainer activityContainer = getEnclosingActivityContainer(activityToken);
+            int displayId = getActivityDisplayId(activityToken);
             reply.writeNoException();
-            if (activityContainer != null) {
-                reply.writeInt(1);
-                reply.writeStrongBinder(activityContainer.asBinder());
-            } else {
-                reply.writeInt(0);
-            }
+            reply.writeInt(displayId);
             return true;
         }
 
@@ -5169,26 +5163,21 @@
         reply.recycle();
     }
 
-    public IActivityContainer getEnclosingActivityContainer(IBinder activityToken)
-            throws RemoteException {
+    @Override
+    public int getActivityDisplayId(IBinder activityToken) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(activityToken);
-        mRemote.transact(GET_ACTIVITY_CONTAINER_TRANSACTION, data, reply, 0);
+        mRemote.transact(GET_ACTIVITY_DISPLAY_ID_TRANSACTION, data, reply, 0);
         reply.readException();
-        final int result = reply.readInt();
-        final IActivityContainer res;
-        if (result == 1) {
-            res = IActivityContainer.Stub.asInterface(reply.readStrongBinder());
-        } else {
-            res = null;
-        }
+        final int displayId = reply.readInt();
         data.recycle();
         reply.recycle();
-        return res;
+        return displayId;
     }
 
+    @Override
     public IBinder getHomeActivityToken() throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index dd49009..647566a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2312,10 +2312,7 @@
 
         final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
         try {
-            IActivityContainer container =
-                    ActivityManagerNative.getDefault().getEnclosingActivityContainer(r.token);
-            final int displayId =
-                    container == null ? Display.DEFAULT_DISPLAY : container.getDisplayId();
+            int displayId = ActivityManagerNative.getDefault().getActivityDisplayId(r.token);
             if (displayId > Display.DEFAULT_DISPLAY) {
                 Display display = dm.getRealDisplay(displayId, r.token);
                 baseContext = appContext.createDisplayContext(display);
@@ -2323,6 +2320,7 @@
         } catch (RemoteException e) {
         }
 
+
         // For debugging purposes, if the activity's package name contains the value of
         // the "debug.use-second-display" system property as a substring, then show
         // its content on a secondary display if there is one.
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index be26f30..1a8785b 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -435,8 +435,7 @@
 
     public void deleteActivityContainer(IActivityContainer container) throws RemoteException;
 
-    public IActivityContainer getEnclosingActivityContainer(IBinder activityToken)
-            throws RemoteException;
+    public int getActivityDisplayId(IBinder activityToken) throws RemoteException;
 
     public IBinder getHomeActivityToken() throws RemoteException;
 
@@ -746,7 +745,7 @@
     int GET_PERSISTED_URI_PERMISSIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+181;
     int APP_NOT_RESPONDING_VIA_PROVIDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+182;
     int GET_HOME_ACTIVITY_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+183;
-    int GET_ACTIVITY_CONTAINER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+184;
+    int GET_ACTIVITY_DISPLAY_ID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+184;
     int DELETE_ACTIVITY_CONTAINER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+185;
 
 
diff --git a/core/java/android/content/pm/ParceledListSlice.java b/core/java/android/content/pm/ParceledListSlice.java
index 8a43472..335a45e 100644
--- a/core/java/android/content/pm/ParceledListSlice.java
+++ b/core/java/android/content/pm/ParceledListSlice.java
@@ -30,6 +30,12 @@
  * Transfer a large list of Parcelable objects across an IPC.  Splits into
  * multiple transactions if needed.
  *
+ * Caveat: for efficiency and security, all elements must be the same concrete type.
+ * In order to avoid writing the class name of each object, we must ensure that
+ * each object is the same type, or else unparceling then reparceling the data may yield
+ * a different result if the class name encoded in the Parcelable is a Base type.
+ * See b/17671747.
+ *
  * @hide
  */
 public class ParceledListSlice<T extends Parcelable> implements Parcelable {
@@ -56,13 +62,25 @@
         if (N <= 0) {
             return;
         }
+
         Parcelable.Creator<T> creator = p.readParcelableCreator(loader);
+        Class<?> listElementClass = null;
+
         int i = 0;
         while (i < N) {
             if (p.readInt() == 0) {
                 break;
             }
-            mList.add(p.readCreator(creator, loader));
+
+            final T parcelable = p.readCreator(creator, loader);
+            if (listElementClass == null) {
+                listElementClass = parcelable.getClass();
+            } else {
+                verifySameType(listElementClass, parcelable.getClass());
+            }
+
+            mList.add(parcelable);
+
             if (DEBUG) Log.d(TAG, "Read inline #" + i + ": " + mList.get(mList.size()-1));
             i++;
         }
@@ -82,7 +100,11 @@
                 return;
             }
             while (i < N && reply.readInt() != 0) {
-                mList.add(reply.readCreator(creator, loader));
+                final T parcelable = reply.readCreator(creator, loader);
+                verifySameType(listElementClass, parcelable.getClass());
+
+                mList.add(parcelable);
+
                 if (DEBUG) Log.d(TAG, "Read extra #" + i + ": " + mList.get(mList.size()-1));
                 i++;
             }
@@ -91,6 +113,14 @@
         }
     }
 
+    private static void verifySameType(final Class<?> expected, final Class<?> actual) {
+        if (!actual.equals(expected)) {
+            throw new IllegalArgumentException("Can't unparcel type "
+                    + actual.getName() + " in list of type "
+                    + expected.getName());
+        }
+    }
+
     public List<T> getList() {
         return mList;
     }
@@ -116,11 +146,16 @@
         dest.writeInt(N);
         if (DEBUG) Log.d(TAG, "Writing " + N + " items");
         if (N > 0) {
+            final Class<?> listElementClass = mList.get(0).getClass();
             dest.writeParcelableCreator(mList.get(0));
             int i = 0;
             while (i < N && dest.dataSize() < MAX_FIRST_IPC_SIZE) {
                 dest.writeInt(1);
-                mList.get(i).writeToParcel(dest, callFlags);
+
+                final T parcelable = mList.get(i);
+                verifySameType(listElementClass, parcelable.getClass());
+                parcelable.writeToParcel(dest, callFlags);
+
                 if (DEBUG) Log.d(TAG, "Wrote inline #" + i + ": " + mList.get(i));
                 i++;
             }
@@ -137,7 +172,11 @@
                         if (DEBUG) Log.d(TAG, "Writing more @" + i + " of " + N);
                         while (i < N && reply.dataSize() < MAX_IPC_SIZE) {
                             reply.writeInt(1);
-                            mList.get(i).writeToParcel(reply, callFlags);
+
+                            final T parcelable = mList.get(i);
+                            verifySameType(listElementClass, parcelable.getClass());
+                            parcelable.writeToParcel(reply, callFlags);
+
                             if (DEBUG) Log.d(TAG, "Wrote extra #" + i + ": " + mList.get(i));
                             i++;
                         }
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index d7b75db..41d1eb2 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -610,7 +610,12 @@
         return NULL;
     }
 
-    const size_t size = bitmap->getSize();
+    const int64_t size64 = bitmap->computeSize64();
+    if (!sk_64_isS32(size64)) {
+        doThrowIAE(env, "bitmap size exceeds 32 bits");
+        return NULL;
+    }
+    const size_t size = sk_64_asS32(size64);
     jbyteArray arrayObj = (jbyteArray) env->CallObjectMethod(gVMRuntime,
                                                              gVMRuntime_newNonMovableArray,
                                                              gByte_class, size);
diff --git a/core/jni/android/graphics/NinePatchPeeker.cpp b/core/jni/android/graphics/NinePatchPeeker.cpp
index 1dafa1b..d99ddeb 100644
--- a/core/jni/android/graphics/NinePatchPeeker.cpp
+++ b/core/jni/android/graphics/NinePatchPeeker.cpp
@@ -24,7 +24,9 @@
     if (!strcmp("npTc", tag) && length >= sizeof(Res_png_9patch)) {
         Res_png_9patch* patch = (Res_png_9patch*) data;
         size_t patchSize = patch->serializedSize();
-        assert(length == patchSize);
+        if (length != patchSize) {
+            return false;
+        }
         // You have to copy the data because it is owned by the png reader
         Res_png_9patch* patchNew = (Res_png_9patch*) malloc(patchSize);
         memcpy(patchNew, patch, patchSize);
diff --git a/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java b/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java
new file mode 100644
index 0000000..e5a92bf
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java
@@ -0,0 +1,263 @@
+package android.content.pm;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ParceledListSliceTest extends TestCase {
+
+    public void testSmallList() throws Exception {
+        final int objectCount = 100;
+        List<SmallObject> list = new ArrayList<SmallObject>();
+        for (int i = 0; i < objectCount; i++) {
+            list.add(new SmallObject(i * 2, (i * 2) + 1));
+        }
+
+        ParceledListSlice<SmallObject> slice;
+
+        Parcel parcel = Parcel.obtain();
+        try {
+            parcel.writeParcelable(new ParceledListSlice<SmallObject>(list), 0);
+            parcel.setDataPosition(0);
+            slice = parcel.readParcelable(getClass().getClassLoader());
+        } finally {
+            parcel.recycle();
+        }
+
+        assertNotNull(slice);
+        assertNotNull(slice.getList());
+        assertEquals(objectCount, slice.getList().size());
+
+        for (int i = 0; i < objectCount; i++) {
+            assertEquals(i * 2, slice.getList().get(i).mFieldA);
+            assertEquals((i * 2) + 1, slice.getList().get(i).mFieldB);
+        }
+    }
+
+    private static int measureLargeObject() {
+        Parcel p = Parcel.obtain();
+        try {
+            new LargeObject(0, 0, 0, 0, 0).writeToParcel(p, 0);
+            return p.dataPosition();
+        } finally {
+            p.recycle();
+        }
+    }
+
+    /**
+     * Test that when the list is large, the data is successfully parceled
+     * and unparceled (the implementation will send pieces of the list in
+     * separate round-trips to avoid the IPC limit).
+     */
+    public void testLargeList() throws Exception {
+        final int thresholdBytes = 256 * 1024;
+        final int objectCount = thresholdBytes / measureLargeObject();
+
+        List<LargeObject> list = new ArrayList<LargeObject>();
+        for (int i = 0; i < objectCount; i++) {
+            list.add(new LargeObject(
+                    i * 5,
+                    (i * 5) + 1,
+                    (i * 5) + 2,
+                    (i * 5) + 3,
+                    (i * 5) + 4
+            ));
+        }
+
+        ParceledListSlice<LargeObject> slice;
+
+        Parcel parcel = Parcel.obtain();
+        try {
+            parcel.writeParcelable(new ParceledListSlice<LargeObject>(list), 0);
+            parcel.setDataPosition(0);
+            slice = parcel.readParcelable(getClass().getClassLoader());
+        } finally {
+            parcel.recycle();
+        }
+
+        assertNotNull(slice);
+        assertNotNull(slice.getList());
+        assertEquals(objectCount, slice.getList().size());
+
+        for (int i = 0; i < objectCount; i++) {
+            assertEquals(i * 5, slice.getList().get(i).mFieldA);
+            assertEquals((i * 5) + 1, slice.getList().get(i).mFieldB);
+            assertEquals((i * 5) + 2, slice.getList().get(i).mFieldC);
+            assertEquals((i * 5) + 3, slice.getList().get(i).mFieldD);
+            assertEquals((i * 5) + 4, slice.getList().get(i).mFieldE);
+        }
+    }
+
+    /**
+     * Test that only homogeneous elements may be unparceled.
+     */
+    public void testHomogeneousElements() throws Exception {
+        List<BaseObject> list = new ArrayList<BaseObject>();
+        list.add(new LargeObject(0, 1, 2, 3, 4));
+        list.add(new SmallObject(5, 6));
+        list.add(new SmallObject(7, 8));
+
+        Parcel parcel = Parcel.obtain();
+        try {
+            writeEvilParceledListSlice(parcel, list);
+            parcel.setDataPosition(0);
+            try {
+                ParceledListSlice.CREATOR.createFromParcel(parcel, getClass().getClassLoader());
+                assertTrue("Unparceled heterogeneous ParceledListSlice", false);
+            } catch (IllegalArgumentException e) {
+                // Success, we're not allowed to process heterogeneous
+                // elements in a ParceledListSlice.
+            }
+        } finally {
+            parcel.recycle();
+        }
+    }
+
+    /**
+     * Write a ParcelableListSlice that uses the BaseObject base class as the Creator.
+     * This is dangerous, as it may affect how the data is unparceled, then later parceled
+     * by the system, leading to a self-modifying data security vulnerability.
+     */
+    private static <T extends BaseObject> void writeEvilParceledListSlice(Parcel dest, List<T> list) {
+        final int listCount = list.size();
+
+        // Number of items.
+        dest.writeInt(listCount);
+
+        // The type/creator to use when unparceling. Here we use the base class
+        // to simulate an attack on ParceledListSlice.
+        dest.writeString(BaseObject.class.getName());
+
+        for (int i = 0; i < listCount; i++) {
+            // 1 means the item is present.
+            dest.writeInt(1);
+            list.get(i).writeToParcel(dest, 0);
+        }
+    }
+
+    public abstract static class BaseObject implements Parcelable {
+        protected static final int TYPE_SMALL = 0;
+        protected static final int TYPE_LARGE = 1;
+
+        protected void writeToParcel(Parcel dest, int flags, int type) {
+            dest.writeInt(type);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        /**
+         * This is *REALLY* bad, but we're doing it in the test to ensure that we handle
+         * the possible exploit when unparceling an object with the BaseObject written as
+         * Creator.
+         */
+        public static final Creator<BaseObject> CREATOR = new Creator<BaseObject>() {
+            @Override
+            public BaseObject createFromParcel(Parcel source) {
+                switch (source.readInt()) {
+                    case TYPE_SMALL:
+                        return SmallObject.createFromParcelBody(source);
+                    case TYPE_LARGE:
+                        return LargeObject.createFromParcelBody(source);
+                    default:
+                        throw new IllegalArgumentException("Unknown type");
+                }
+            }
+
+            @Override
+            public BaseObject[] newArray(int size) {
+                return new BaseObject[size];
+            }
+        };
+    }
+
+    public static class SmallObject extends BaseObject {
+        public int mFieldA;
+        public int mFieldB;
+
+        public SmallObject(int a, int b) {
+            mFieldA = a;
+            mFieldB = b;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags, TYPE_SMALL);
+            dest.writeInt(mFieldA);
+            dest.writeInt(mFieldB);
+        }
+
+        public static SmallObject createFromParcelBody(Parcel source) {
+            return new SmallObject(source.readInt(), source.readInt());
+        }
+
+        public static final Creator<SmallObject> CREATOR = new Creator<SmallObject>() {
+            @Override
+            public SmallObject createFromParcel(Parcel source) {
+                // Consume the type (as it is always written out).
+                source.readInt();
+                return createFromParcelBody(source);
+            }
+
+            @Override
+            public SmallObject[] newArray(int size) {
+                return new SmallObject[size];
+            }
+        };
+    }
+
+    public static class LargeObject extends BaseObject {
+        public int mFieldA;
+        public int mFieldB;
+        public int mFieldC;
+        public int mFieldD;
+        public int mFieldE;
+
+        public LargeObject(int a, int b, int c, int d, int e) {
+            mFieldA = a;
+            mFieldB = b;
+            mFieldC = c;
+            mFieldD = d;
+            mFieldE = e;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags, TYPE_LARGE);
+            dest.writeInt(mFieldA);
+            dest.writeInt(mFieldB);
+            dest.writeInt(mFieldC);
+            dest.writeInt(mFieldD);
+            dest.writeInt(mFieldE);
+        }
+
+        public static LargeObject createFromParcelBody(Parcel source) {
+            return new LargeObject(
+                    source.readInt(),
+                    source.readInt(),
+                    source.readInt(),
+                    source.readInt(),
+                    source.readInt()
+            );
+        }
+
+        public static final Creator<LargeObject> CREATOR = new Creator<LargeObject>() {
+            @Override
+            public LargeObject createFromParcel(Parcel source) {
+                // Consume the type (as it is always written out).
+                source.readInt();
+                return createFromParcelBody(source);
+            }
+
+            @Override
+            public LargeObject[] newArray(int size) {
+                return new LargeObject[size];
+            }
+        };
+    }
+}
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index ac5eca08..07df5ae 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -107,9 +107,9 @@
                        yDivsOffset(0), colorsOffset(0) { }
 
     int8_t wasDeserialized;
-    int8_t numXDivs;
-    int8_t numYDivs;
-    int8_t numColors;
+    uint8_t numXDivs;
+    uint8_t numYDivs;
+    uint8_t numColors;
 
     // The offset (from the start of this structure) to the xDivs & yDivs
     // array for this 9patch. To get a pointer to this array, call
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8dfb321..3215144 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -55,6 +55,7 @@
 import android.util.ArraySet;
 import android.util.SparseIntArray;
 
+import android.view.Display;
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IAppOpsService;
@@ -8721,14 +8722,13 @@
     }
 
     @Override
-    public IActivityContainer getEnclosingActivityContainer(IBinder activityToken)
-            throws RemoteException {
+    public int getActivityDisplayId(IBinder activityToken) throws RemoteException {
         synchronized (this) {
             ActivityStack stack = ActivityRecord.getStackLocked(activityToken);
-            if (stack != null) {
-                return stack.mActivityContainer;
+            if (stack != null && stack.mActivityContainer.isAttachedLocked()) {
+                return stack.mActivityContainer.getDisplayId();
             }
-            return null;
+            return Display.DEFAULT_DISPLAY;
         }
     }
 
diff --git a/tools/layoutlib/.idea/codeStyleSettings.xml b/tools/layoutlib/.idea/codeStyleSettings.xml
index a04e440..89f7b34 100644
--- a/tools/layoutlib/.idea/codeStyleSettings.xml
+++ b/tools/layoutlib/.idea/codeStyleSettings.xml
@@ -5,7 +5,6 @@
       <value>
         <option name="FIELD_NAME_PREFIX" value="m" />
         <option name="STATIC_FIELD_NAME_PREFIX" value="s" />
-        <option name="USE_FQ_CLASS_NAMES_IN_JAVADOC" value="false" />
         <option name="INSERT_INNER_CLASS_IMPORTS" value="true" />
         <option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" />
         <option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" />
@@ -34,11 +33,13 @@
         <option name="JD_ADD_BLANK_AFTER_RETURN" value="true" />
         <option name="JD_DO_NOT_WRAP_ONE_LINE_COMMENTS" value="true" />
         <option name="WRAP_COMMENTS" value="true" />
+        <JavaCodeStyleSettings>
+          <option name="CLASS_NAMES_IN_JAVADOC" value="3" />
+        </JavaCodeStyleSettings>
         <XML>
           <option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
         </XML>
         <codeStyleSettings language="JAVA">
-          <option name="INDENT_CASE_FROM_SWITCH" value="false" />
           <option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
           <option name="CALL_PARAMETERS_WRAP" value="1" />
           <option name="METHOD_PARAMETERS_WRAP" value="1" />
diff --git a/tools/layoutlib/.idea/misc.xml b/tools/layoutlib/.idea/misc.xml
index fd63e6c..fa48f70 100644
--- a/tools/layoutlib/.idea/misc.xml
+++ b/tools/layoutlib/.idea/misc.xml
@@ -12,5 +12,4 @@
   <component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" assert-keyword="true" jdk-15="true" project-jdk-name="1.7" project-jdk-type="JavaSDK">
     <output url="file://$PROJECT_DIR$/out" />
   </component>
-</project>
-
+</project>
\ No newline at end of file
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeAssetManager.java b/tools/layoutlib/bridge/src/android/content/res/BridgeAssetManager.java
index c41a4ee..2691e56 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeAssetManager.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeAssetManager.java
@@ -16,12 +16,13 @@
 
 package android.content.res;
 
+import com.android.ide.common.rendering.api.AssetRepository;
 import com.android.layoutlib.bridge.Bridge;
 
-import android.content.res.AssetManager;
-
 public class BridgeAssetManager extends AssetManager {
 
+    private AssetRepository mAssetRepository;
+
     /**
      * This initializes the static field {@link AssetManager#sSystem} which is used
      * by methods who get a global asset manager using {@link AssetManager#getSystem()}.
@@ -48,6 +49,14 @@
         AssetManager.sSystem = null;
     }
 
-    private BridgeAssetManager() {
+    public void setAssetRepository(AssetRepository assetRepository) {
+        mAssetRepository = assetRepository;
+    }
+
+    public AssetRepository getAssetRepository() {
+        return mAssetRepository;
+    }
+
+    public BridgeAssetManager() {
     }
 }
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
index 66126af..96ca250 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
@@ -178,11 +178,21 @@
         Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
 
         if (value != null) {
+            ResourceValue resourceValue = value.getSecond();
             try {
-                return ResourceHelper.getColor(value.getSecond().getValue());
+                return ResourceHelper.getColor(resourceValue.getValue());
             } catch (NumberFormatException e) {
-                Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT, e.getMessage(), e,
-                        null /*data*/);
+                // Check if the value passed is a file. If it is, mostly likely, user is referencing
+                // a color state list from a place where they should reference only a pure color.
+                String message;
+                if (new File(resourceValue.getValue()).isFile()) {
+                    String resource = (resourceValue.isFramework() ? "@android:" : "@") + "color/"
+                      + resourceValue.getName();
+                    message = "Hexadecimal color expected, found Color State List for " + resource;
+                } else {
+                    message = e.getMessage();
+                }
+                Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT, message, e, null);
                 return 0;
             }
         }
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
index a2bd6d7..18036927 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
@@ -614,15 +614,27 @@
 
             int pos = value.indexOf('/');
             String idName = value.substring(pos + 1);
+            boolean create = value.startsWith("@+");
+            boolean isFrameworkId =
+                    mPlatformFile || value.startsWith("@android") || value.startsWith("@+android");
 
-            // if this is a framework id
-            if (mPlatformFile || value.startsWith("@android") || value.startsWith("@+android")) {
-                // look for idName in the android R classes
-                return mContext.getFrameworkResourceValue(ResourceType.ID, idName, defValue);
+            // Look for the idName in project or android R class depending on isPlatform.
+            if (create) {
+                Integer idValue;
+                if (isFrameworkId) {
+                    idValue = Bridge.getResourceId(ResourceType.ID, idName);
+                } else {
+                    idValue = mContext.getProjectCallback().getResourceId(ResourceType.ID, idName);
+                }
+                return idValue == null ? defValue : idValue;
             }
-
-            // look for idName in the project R class.
-            return mContext.getProjectResourceValue(ResourceType.ID, idName, defValue);
+            // This calls the same method as in if(create), but doesn't create a dynamic id, if
+            // one is not found.
+            if (isFrameworkId) {
+                return mContext.getFrameworkResourceValue(ResourceType.ID, idName, defValue);
+            } else {
+                return mContext.getProjectResourceValue(ResourceType.ID, idName, defValue);
+            }
         }
 
         // not a direct id valid reference? resolve it
diff --git a/tools/layoutlib/bridge/src/android/graphics/BlendComposite.java b/tools/layoutlib/bridge/src/android/graphics/BlendComposite.java
index a3ec2cc..e4fcf1b 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BlendComposite.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BlendComposite.java
@@ -29,75 +29,31 @@
  * The class is adapted from a demo tool for Blending Modes written by
  * Romain Guy (romainguy@android.com). The tool is available at
  * http://www.curious-creature.org/2006/09/20/new-blendings-modes-for-java2d/
+ *
+ * This class has been adapted for applying color filters. When applying color filters, the src
+ * image should not extend beyond the dest image, but in our implementation of the filters, it does.
+ * To compensate for the effect, we recompute the alpha value of the src image before applying
+ * the color filter as it should have been applied.
  */
 public final class BlendComposite implements Composite {
     public enum BlendingMode {
-        NORMAL,
-        AVERAGE,
-        MULTIPLY,
-        SCREEN,
-        DARKEN,
-        LIGHTEN,
-        OVERLAY,
-        HARD_LIGHT,
-        SOFT_LIGHT,
-        DIFFERENCE,
-        NEGATION,
-        EXCLUSION,
-        COLOR_DODGE,
-        INVERSE_COLOR_DODGE,
-        SOFT_DODGE,
-        COLOR_BURN,
-        INVERSE_COLOR_BURN,
-        SOFT_BURN,
-        REFLECT,
-        GLOW,
-        FREEZE,
-        HEAT,
-        ADD,
-        SUBTRACT,
-        STAMP,
-        RED,
-        GREEN,
-        BLUE,
-        HUE,
-        SATURATION,
-        COLOR,
-        LUMINOSITY
-    }
+        MULTIPLY(),
+        SCREEN(),
+        DARKEN(),
+        LIGHTEN(),
+        OVERLAY(),
+        ADD();
 
-    public static final BlendComposite Normal = new BlendComposite(BlendingMode.NORMAL);
-    public static final BlendComposite Average = new BlendComposite(BlendingMode.AVERAGE);
-    public static final BlendComposite Multiply = new BlendComposite(BlendingMode.MULTIPLY);
-    public static final BlendComposite Screen = new BlendComposite(BlendingMode.SCREEN);
-    public static final BlendComposite Darken = new BlendComposite(BlendingMode.DARKEN);
-    public static final BlendComposite Lighten = new BlendComposite(BlendingMode.LIGHTEN);
-    public static final BlendComposite Overlay = new BlendComposite(BlendingMode.OVERLAY);
-    public static final BlendComposite HardLight = new BlendComposite(BlendingMode.HARD_LIGHT);
-    public static final BlendComposite SoftLight = new BlendComposite(BlendingMode.SOFT_LIGHT);
-    public static final BlendComposite Difference = new BlendComposite(BlendingMode.DIFFERENCE);
-    public static final BlendComposite Negation = new BlendComposite(BlendingMode.NEGATION);
-    public static final BlendComposite Exclusion = new BlendComposite(BlendingMode.EXCLUSION);
-    public static final BlendComposite ColorDodge = new BlendComposite(BlendingMode.COLOR_DODGE);
-    public static final BlendComposite InverseColorDodge = new BlendComposite(BlendingMode.INVERSE_COLOR_DODGE);
-    public static final BlendComposite SoftDodge = new BlendComposite(BlendingMode.SOFT_DODGE);
-    public static final BlendComposite ColorBurn = new BlendComposite(BlendingMode.COLOR_BURN);
-    public static final BlendComposite InverseColorBurn = new BlendComposite(BlendingMode.INVERSE_COLOR_BURN);
-    public static final BlendComposite SoftBurn = new BlendComposite(BlendingMode.SOFT_BURN);
-    public static final BlendComposite Reflect = new BlendComposite(BlendingMode.REFLECT);
-    public static final BlendComposite Glow = new BlendComposite(BlendingMode.GLOW);
-    public static final BlendComposite Freeze = new BlendComposite(BlendingMode.FREEZE);
-    public static final BlendComposite Heat = new BlendComposite(BlendingMode.HEAT);
-    public static final BlendComposite Add = new BlendComposite(BlendingMode.ADD);
-    public static final BlendComposite Subtract = new BlendComposite(BlendingMode.SUBTRACT);
-    public static final BlendComposite Stamp = new BlendComposite(BlendingMode.STAMP);
-    public static final BlendComposite Red = new BlendComposite(BlendingMode.RED);
-    public static final BlendComposite Green = new BlendComposite(BlendingMode.GREEN);
-    public static final BlendComposite Blue = new BlendComposite(BlendingMode.BLUE);
-    public static final BlendComposite Hue = new BlendComposite(BlendingMode.HUE);
-    public static final BlendComposite Saturation = new BlendComposite(BlendingMode.SATURATION);
-    public static final BlendComposite Color = new BlendComposite(BlendingMode.COLOR);
-    public static final BlendComposite Luminosity = new BlendComposite(BlendingMode.LUMINOSITY);
+        private final BlendComposite mComposite;
+
+        BlendingMode() {
+            mComposite = new BlendComposite(this);
+        }
+
+        BlendComposite getBlendComposite() {
+            return mComposite;
+        }
+    }
 
     private float alpha;
     private BlendingMode mode;
@@ -112,21 +68,16 @@
     }
 
     public static BlendComposite getInstance(BlendingMode mode) {
-        return new BlendComposite(mode);
+        return mode.getBlendComposite();
     }
 
     public static BlendComposite getInstance(BlendingMode mode, float alpha) {
+        if (alpha > 0.9999f) {
+            return getInstance(mode);
+        }
         return new BlendComposite(mode, alpha);
     }
 
-    public BlendComposite derive(BlendingMode mode) {
-        return this.mode == mode ? this : new BlendComposite(mode, getAlpha());
-    }
-
-    public BlendComposite derive(float alpha) {
-        return this.alpha == alpha ? this : new BlendComposite(getMode(), alpha);
-    }
-
     public float getAlpha() {
         return alpha;
     }
@@ -157,11 +108,7 @@
 
         BlendComposite bc = (BlendComposite) obj;
 
-        if (mode != bc.mode) {
-            return false;
-        }
-
-        return alpha == bc.alpha;
+        return mode == bc.mode && alpha == bc.alpha;
     }
 
     public CompositeContext createContext(ColorModel srcColorModel,
@@ -220,6 +167,11 @@
                         dstPixel[2] = (pixel      ) & 0xFF;
                         dstPixel[3] = (pixel >> 24) & 0xFF;
 
+                        // ---- Modified from original ----
+                        // recompute src pixel for transparency.
+                        srcPixel[3] *= dstPixel[3] / 0xFF;
+                        // ---- Modification ends ----
+
                         result = blender.blend(srcPixel, dstPixel, result);
 
                         // mixes the result with the opacity
@@ -246,123 +198,8 @@
     private static abstract class Blender {
         public abstract int[] blend(int[] src, int[] dst, int[] result);
 
-        private static void RGBtoHSL(int r, int g, int b, float[] hsl) {
-            float var_R = (r / 255f);
-            float var_G = (g / 255f);
-            float var_B = (b / 255f);
-
-            float var_Min;
-            float var_Max;
-            float del_Max;
-
-            if (var_R > var_G) {
-                var_Min = var_G;
-                var_Max = var_R;
-            } else {
-                var_Min = var_R;
-                var_Max = var_G;
-            }
-            if (var_B > var_Max) {
-                var_Max = var_B;
-            }
-            if (var_B < var_Min) {
-                var_Min = var_B;
-            }
-
-            del_Max = var_Max - var_Min;
-
-            float H, S, L;
-            L = (var_Max + var_Min) / 2f;
-
-            if (del_Max - 0.01f <= 0.0f) {
-                H = 0;
-                S = 0;
-            } else {
-                if (L < 0.5f) {
-                    S = del_Max / (var_Max + var_Min);
-                } else {
-                    S = del_Max / (2 - var_Max - var_Min);
-                }
-
-                float del_R = (((var_Max - var_R) / 6f) + (del_Max / 2f)) / del_Max;
-                float del_G = (((var_Max - var_G) / 6f) + (del_Max / 2f)) / del_Max;
-                float del_B = (((var_Max - var_B) / 6f) + (del_Max / 2f)) / del_Max;
-
-                if (var_R == var_Max) {
-                    H = del_B - del_G;
-                } else if (var_G == var_Max) {
-                    H = (1 / 3f) + del_R - del_B;
-                } else {
-                    H = (2 / 3f) + del_G - del_R;
-                }
-                if (H < 0) {
-                    H += 1;
-                }
-                if (H > 1) {
-                    H -= 1;
-                }
-            }
-
-            hsl[0] = H;
-            hsl[1] = S;
-            hsl[2] = L;
-        }
-
-        private static void HSLtoRGB(float h, float s, float l, int[] rgb) {
-            int R, G, B;
-
-            if (s - 0.01f <= 0.0f) {
-                R = (int) (l * 255.0f);
-                G = (int) (l * 255.0f);
-                B = (int) (l * 255.0f);
-            } else {
-                float var_1, var_2;
-                if (l < 0.5f) {
-                    var_2 = l * (1 + s);
-                } else {
-                    var_2 = (l + s) - (s * l);
-                }
-                var_1 = 2 * l - var_2;
-
-                R = (int) (255.0f * hue2RGB(var_1, var_2, h + (1.0f / 3.0f)));
-                G = (int) (255.0f * hue2RGB(var_1, var_2, h));
-                B = (int) (255.0f * hue2RGB(var_1, var_2, h - (1.0f / 3.0f)));
-            }
-
-            rgb[0] = R;
-            rgb[1] = G;
-            rgb[2] = B;
-        }
-
-        private static float hue2RGB(float v1, float v2, float vH) {
-            if (vH < 0.0f) {
-                vH += 1.0f;
-            }
-            if (vH > 1.0f) {
-                vH -= 1.0f;
-            }
-            if ((6.0f * vH) < 1.0f) {
-                return (v1 + (v2 - v1) * 6.0f * vH);
-            }
-            if ((2.0f * vH) < 1.0f) {
-                return (v2);
-            }
-            if ((3.0f * vH) < 2.0f) {
-                return (v1 + (v2 - v1) * ((2.0f / 3.0f) - vH) * 6.0f);
-            }
-            return (v1);
-        }
-
         public static Blender getBlenderFor(BlendComposite composite) {
             switch (composite.getMode()) {
-                case NORMAL:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            System.arraycopy(src, 0, result, 0, 4);
-                            return result;
-                        }
-                    };
                 case ADD:
                     return new Blender() {
                         @Override
@@ -373,65 +210,6 @@
                             return result;
                         }
                     };
-                case AVERAGE:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            for (int i = 0; i < 3; i++) {
-                                result[i] = (src[i] + dst[i]) >> 1;
-                            }
-                            result[3] = Math.min(255, src[3] + dst[3]);
-                            return result;
-                        }
-                    };
-                case BLUE:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            System.arraycopy(dst, 0, result, 0, 3);
-                            result[3] = Math.min(255, src[3] + dst[3]);
-                            return result;
-                        }
-                    };
-                case COLOR:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            float[] srcHSL = new float[3];
-                            RGBtoHSL(src[0], src[1], src[2], srcHSL);
-                            float[] dstHSL = new float[3];
-                            RGBtoHSL(dst[0], dst[1], dst[2], dstHSL);
-
-                            HSLtoRGB(srcHSL[0], srcHSL[1], dstHSL[2], result);
-                            result[3] = Math.min(255, src[3] + dst[3]);
-
-                            return result;
-                        }
-                    };
-                case COLOR_BURN:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            for (int i = 0; i < 3; i++) {
-                                result[i] = src[i] == 0 ? 0 :
-                                    Math.max(0, 255 - (((255 - dst[i]) << 8) / src[i]));
-                            }
-                            result[3] = Math.min(255, src[3] + dst[3]);
-                            return result;
-                        }
-                    };
-                case COLOR_DODGE:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            for (int i = 0; i < 3; i++) {
-                                result[i] = src[i] == 255 ? 255 :
-                                    Math.min((dst[i] << 8) / (255 - src[i]), 255);
-                            }
-                            result[3] = Math.min(255, src[3] + dst[3]);
-                            return result;
-                        }
-                    };
                 case DARKEN:
                     return new Blender() {
                         @Override
@@ -443,136 +221,6 @@
                             return result;
                         }
                     };
-                case DIFFERENCE:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            for (int i = 0; i < 3; i++) {
-                                result[i] = dst[i] + src[i] - (dst[i] * src[i] >> 7);
-                            }
-                            result[3] = Math.min(255, src[3] + dst[3]);
-                            return result;
-                        }
-                    };
-                case EXCLUSION:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            for (int i = 0; i < 3; i++) {
-                                result[i] = dst[i] + src[i] - (dst[i] * src[i] >> 7);
-                            }
-                            result[3] = Math.min(255, src[3] + dst[3]);
-                            return result;
-                        }
-                    };
-                case FREEZE:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            for (int i = 0; i < 3; i++) {
-                                result[i] = src[i] == 0 ? 0 :
-                                    Math.max(0, 255 - (255 - dst[i]) * (255 - dst[i]) / src[i]);
-                            }
-                            result[3] = Math.min(255, src[3] + dst[3]);
-                            return result;
-                        }
-                    };
-                case GLOW:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            for (int i = 0; i < 3; i++) {
-                                result[i] = dst[i] == 255 ? 255 :
-                                    Math.min(255, src[i] * src[i] / (255 - dst[i]));
-                            }
-                            result[3] = Math.min(255, src[3] + dst[3]);
-                            return result;
-                        }
-                    };
-                case GREEN:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            return new int[] {
-                                dst[0],
-                                dst[1],
-                                src[2],
-                                Math.min(255, src[3] + dst[3])
-                            };
-                        }
-                    };
-                case HARD_LIGHT:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            return new int[] {
-                                src[0] < 128 ? dst[0] * src[0] >> 7 :
-                                    255 - ((255 - src[0]) * (255 - dst[0]) >> 7),
-                                src[1] < 128 ? dst[1] * src[1] >> 7 :
-                                    255 - ((255 - src[1]) * (255 - dst[1]) >> 7),
-                                src[2] < 128 ? dst[2] * src[2] >> 7 :
-                                    255 - ((255 - src[2]) * (255 - dst[2]) >> 7),
-                                Math.min(255, src[3] + dst[3])
-                            };
-                        }
-                    };
-                case HEAT:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            return new int[] {
-                                dst[0] == 0 ? 0 : Math.max(0, 255 - (255 - src[0]) * (255 - src[0]) / dst[0]),
-                                dst[1] == 0 ? 0 : Math.max(0, 255 - (255 - src[1]) * (255 - src[1]) / dst[1]),
-                                dst[2] == 0 ? 0 : Math.max(0, 255 - (255 - src[2]) * (255 - src[2]) / dst[2]),
-                                Math.min(255, src[3] + dst[3])
-                            };
-                        }
-                    };
-                case HUE:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            float[] srcHSL = new float[3];
-                            RGBtoHSL(src[0], src[1], src[2], srcHSL);
-                            float[] dstHSL = new float[3];
-                            RGBtoHSL(dst[0], dst[1], dst[2], dstHSL);
-
-                            HSLtoRGB(srcHSL[0], dstHSL[1], dstHSL[2], result);
-                            result[3] = Math.min(255, src[3] + dst[3]);
-
-                            return result;
-                        }
-                    };
-                case INVERSE_COLOR_BURN:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            return new int[] {
-                                dst[0] == 0 ? 0 :
-                                    Math.max(0, 255 - (((255 - src[0]) << 8) / dst[0])),
-                                dst[1] == 0 ? 0 :
-                                    Math.max(0, 255 - (((255 - src[1]) << 8) / dst[1])),
-                                dst[2] == 0 ? 0 :
-                                    Math.max(0, 255 - (((255 - src[2]) << 8) / dst[2])),
-                                Math.min(255, src[3] + dst[3])
-                            };
-                        }
-                    };
-                case INVERSE_COLOR_DODGE:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            return new int[] {
-                                dst[0] == 255 ? 255 :
-                                    Math.min((src[0] << 8) / (255 - dst[0]), 255),
-                                dst[1] == 255 ? 255 :
-                                    Math.min((src[1] << 8) / (255 - dst[1]), 255),
-                                dst[2] == 255 ? 255 :
-                                    Math.min((src[2] << 8) / (255 - dst[2]), 255),
-                                Math.min(255, src[3] + dst[3])
-                            };
-                        }
-                    };
                 case LIGHTEN:
                     return new Blender() {
                         @Override
@@ -584,21 +232,6 @@
                             return result;
                         }
                     };
-                case LUMINOSITY:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            float[] srcHSL = new float[3];
-                            RGBtoHSL(src[0], src[1], src[2], srcHSL);
-                            float[] dstHSL = new float[3];
-                            RGBtoHSL(dst[0], dst[1], dst[2], dstHSL);
-
-                            HSLtoRGB(dstHSL[0], dstHSL[1], srcHSL[2], result);
-                            result[3] = Math.min(255, src[3] + dst[3]);
-
-                            return result;
-                        }
-                    };
                 case MULTIPLY:
                     return new Blender() {
                         @Override
@@ -606,22 +239,10 @@
                             for (int i = 0; i < 3; i++) {
                                 result[i] = (src[i] * dst[i]) >> 8;
                             }
-                            result[3] = Math.min(255, src[3] + dst[3]);
+                            result[3] = Math.min(255, src[3] + dst[3] - (src[3] * dst[3]) / 255);
                             return result;
                         }
                     };
-                case NEGATION:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            return new int[] {
-                                255 - Math.abs(255 - dst[0] - src[0]),
-                                255 - Math.abs(255 - dst[1] - src[1]),
-                                255 - Math.abs(255 - dst[2] - src[2]),
-                                Math.min(255, src[3] + dst[3])
-                            };
-                        }
-                    };
                 case OVERLAY:
                     return new Blender() {
                         @Override
@@ -634,123 +255,15 @@
                             return result;
                         }
                     };
-                case RED:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            return new int[] {
-                                src[0],
-                                dst[1],
-                                dst[2],
-                                Math.min(255, src[3] + dst[3])
-                            };
-                        }
-                    };
-                case REFLECT:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            return new int[] {
-                                src[0] == 255 ? 255 : Math.min(255, dst[0] * dst[0] / (255 - src[0])),
-                                src[1] == 255 ? 255 : Math.min(255, dst[1] * dst[1] / (255 - src[1])),
-                                src[2] == 255 ? 255 : Math.min(255, dst[2] * dst[2] / (255 - src[2])),
-                                Math.min(255, src[3] + dst[3])
-                            };
-                        }
-                    };
-                case SATURATION:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            float[] srcHSL = new float[3];
-                            RGBtoHSL(src[0], src[1], src[2], srcHSL);
-                            float[] dstHSL = new float[3];
-                            RGBtoHSL(dst[0], dst[1], dst[2], dstHSL);
-
-                            HSLtoRGB(dstHSL[0], srcHSL[1], dstHSL[2], result);
-                            result[3] = Math.min(255, src[3] + dst[3]);
-
-                            return result;
-                        }
-                    };
                 case SCREEN:
                     return new Blender() {
                         @Override
                         public int[] blend(int[] src, int[] dst, int[] result) {
-                            return new int[] {
-                                255 - ((255 - src[0]) * (255 - dst[0]) >> 8),
-                                255 - ((255 - src[1]) * (255 - dst[1]) >> 8),
-                                255 - ((255 - src[2]) * (255 - dst[2]) >> 8),
-                                Math.min(255, src[3] + dst[3])
-                            };
-                        }
-                    };
-                case SOFT_BURN:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            return new int[] {
-                                dst[0] + src[0] < 256 ?
-	                                (dst[0] == 255 ? 255 :
-                                        Math.min(255, (src[0] << 7) / (255 - dst[0]))) :
-                                            Math.max(0, 255 - (((255 - dst[0]) << 7) / src[0])),
-                                dst[1] + src[1] < 256 ?
-	                                (dst[1] == 255 ? 255 :
-                                        Math.min(255, (src[1] << 7) / (255 - dst[1]))) :
-                                            Math.max(0, 255 - (((255 - dst[1]) << 7) / src[1])),
-                                dst[2] + src[2] < 256 ?
-	                                (dst[2] == 255 ? 255 :
-                                        Math.min(255, (src[2] << 7) / (255 - dst[2]))) :
-                                            Math.max(0, 255 - (((255 - dst[2]) << 7) / src[2])),
-                                Math.min(255, src[3] + dst[3])
-                            };
-                        }
-                    };
-                case SOFT_DODGE:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            return new int[] {
-                                dst[0] + src[0] < 256 ?
-                                    (src[0] == 255 ? 255 :
-                                        Math.min(255, (dst[0] << 7) / (255 - src[0]))) :
-                                            Math.max(0, 255 - (((255 - src[0]) << 7) / dst[0])),
-                                dst[1] + src[1] < 256 ?
-                                    (src[1] == 255 ? 255 :
-                                        Math.min(255, (dst[1] << 7) / (255 - src[1]))) :
-                                            Math.max(0, 255 - (((255 - src[1]) << 7) / dst[1])),
-                                dst[2] + src[2] < 256 ?
-                                    (src[2] == 255 ? 255 :
-                                        Math.min(255, (dst[2] << 7) / (255 - src[2]))) :
-                                            Math.max(0, 255 - (((255 - src[2]) << 7) / dst[2])),
-                                Math.min(255, src[3] + dst[3])
-                            };
-                        }
-                    };
-                case SOFT_LIGHT:
-                    break;
-                case STAMP:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            return new int[] {
-                                Math.max(0, Math.min(255, dst[0] + 2 * src[0] - 256)),
-                                Math.max(0, Math.min(255, dst[1] + 2 * src[1] - 256)),
-                                Math.max(0, Math.min(255, dst[2] + 2 * src[2] - 256)),
-                                Math.min(255, src[3] + dst[3])
-                            };
-                        }
-                    };
-                case SUBTRACT:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            return new int[] {
-                                Math.max(0, src[0] + dst[0] - 256),
-                                Math.max(0, src[1] + dst[1] - 256),
-                                Math.max(0, src[2] + dst[2] - 256),
-                                Math.min(255, src[3] + dst[3])
-                            };
+                            result[0] = 255 - ((255 - src[0]) * (255 - dst[0]) >> 8);
+                            result[1] = 255 - ((255 - src[1]) * (255 - dst[1]) >> 8);
+                            result[2] = 255 - ((255 - src[2]) * (255 - dst[2]) >> 8);
+                            result[3] = Math.min(255, src[3] + dst[3]);
+                            return result;
                         }
                     };
             }
diff --git a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
index ab79664..42de4ec 100644
--- a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
@@ -18,21 +18,28 @@
 
 import com.android.annotations.NonNull;
 import com.android.annotations.Nullable;
+import com.android.ide.common.rendering.api.AssetRepository;
 import com.android.ide.common.rendering.api.LayoutLog;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.impl.DelegateManager;
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
 
 import android.content.res.AssetManager;
+import android.content.res.BridgeAssetManager;
 
 import java.awt.Font;
 import java.awt.FontFormatException;
 import java.io.File;
 import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Scanner;
 import java.util.Set;
 
@@ -56,10 +63,28 @@
     public static final int BOLD_FONT_WEIGHT_DELTA = 300;
     public static final int BOLD_FONT_WEIGHT = 700;
 
-    // FONT_SUFFIX_ITALIC will always match FONT_SUFFIX_BOLDITALIC and hence it must be checked
-    // separately.
     private static final String FONT_SUFFIX_ITALIC = "Italic.ttf";
     private static final String FN_ALL_FONTS_LIST = "fontsInSdk.txt";
+    private static final String EXTENSION_OTF = ".otf";
+
+    private static final int CACHE_SIZE = 10;
+    // The cache has a drawback that if the font file changed after the font object was created,
+    // we will not update it.
+    private static final Map<String, FontInfo> sCache =
+            new LinkedHashMap<String, FontInfo>(CACHE_SIZE) {
+        @Override
+        protected boolean removeEldestEntry(Entry<String, FontInfo> eldest) {
+            return size() > CACHE_SIZE;
+        }
+
+        @Override
+        public FontInfo put(String key, FontInfo value) {
+            // renew this entry.
+            FontInfo removed = remove(key);
+            super.put(key, value);
+            return removed;
+        }
+    };
 
     /**
      * A class associating {@link Font} with its metadata.
@@ -194,7 +219,7 @@
             try {
                 return Font.createFont(Font.TRUETYPE_FONT, f);
             } catch (Exception e) {
-                if (path.endsWith(".otf") && e instanceof FontFormatException) {
+                if (path.endsWith(EXTENSION_OTF) && e instanceof FontFormatException) {
                     // If we aren't able to load an Open Type font, don't log a warning just yet.
                     // We wait for a case where font is being used. Only then we try to log the
                     // warning.
@@ -281,8 +306,74 @@
 
     @LayoutlibDelegate
     /*package*/ static boolean nAddFontFromAsset(long nativeFamily, AssetManager mgr, String path) {
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Typeface.createFromAsset is not supported.", null, null);
+        FontFamily_Delegate ffd = sManager.getDelegate(nativeFamily);
+        ffd.mValid = true;
+        if (mgr == null) {
+            return false;
+        }
+        if (mgr instanceof BridgeAssetManager) {
+            InputStream fontStream = null;
+            try {
+                AssetRepository assetRepository = ((BridgeAssetManager) mgr).getAssetRepository();
+                if (assetRepository == null) {
+                    Bridge.getLog().error(LayoutLog.TAG_MISSING_ASSET, "Asset not found: " + path,
+                            null);
+                    return false;
+                }
+                if (!assetRepository.isSupported()) {
+                    // Don't log any warnings on unsupported IDEs.
+                    return false;
+                }
+                // Check cache
+                FontInfo fontInfo = sCache.get(path);
+                if (fontInfo != null) {
+                    // renew the font's lease.
+                    sCache.put(path, fontInfo);
+                    ffd.addFont(fontInfo);
+                    return true;
+                }
+                fontStream = assetRepository.openAsset(path, AssetManager.ACCESS_STREAMING);
+                if (fontStream == null) {
+                    Bridge.getLog().error(LayoutLog.TAG_MISSING_ASSET, "Asset not found: " + path,
+                            path);
+                    return false;
+                }
+                Font font = Font.createFont(Font.TRUETYPE_FONT, fontStream);
+                fontInfo = new FontInfo();
+                fontInfo.mFont = font;
+                fontInfo.mWeight = font.isBold() ? BOLD_FONT_WEIGHT : DEFAULT_FONT_WEIGHT;
+                fontInfo.mIsItalic = font.isItalic();
+                ffd.addFont(fontInfo);
+                return true;
+            } catch (IOException e) {
+                Bridge.getLog().error(LayoutLog.TAG_MISSING_ASSET, "Unable to load font " + path, e,
+                        path);
+            } catch (FontFormatException e) {
+                if (path.endsWith(EXTENSION_OTF)) {
+                    // otf fonts are not supported on the user's config (JRE version + OS)
+                    Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+                            "OpenType fonts are not supported yet: " + path, null, path);
+                } else {
+                    Bridge.getLog().error(LayoutLog.TAG_BROKEN,
+                            "Unable to load font " + path, e, path);
+                }
+            } finally {
+                if (fontStream != null) {
+                    try {
+                        fontStream.close();
+                    } catch (IOException ignored) {
+                    }
+                }
+            }
+            return false;
+        }
+        // This should never happen. AssetManager is a final class (from user's perspective), and
+        // we've replaced every creation of AssetManager with our implementation. We create an
+        // exception and log it, but continue with rest of the rendering, without loading this font.
+        Bridge.getLog().error(LayoutLog.TAG_BROKEN,
+                "You have found a bug in the rendering library. Please file a bug at b.android.com.",
+                new RuntimeException("Asset Manager is not an instance of BridgeAssetManager"),
+                null);
         return false;
     }
 
diff --git a/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
index 4ac376c..1ca94dc 100644
--- a/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
@@ -103,7 +103,7 @@
     // For filtering the colors, the src image should contain the "color" only for pixel values
     // which are not transparent in the target image. But, we are using a simple rectangular image
     // completely filled with color. Hence some Composite rules do not apply as intended. However,
-    // in such cases, they can usually be mapped to some other mode, which produces an
+    // in such cases, they can usually be mapped to some other mode, which produces an approximately
     // equivalent result.
     private Mode getCompatibleMode(Mode mode) {
         Mode m = mode;
diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
index 36102f1..7ca4c47 100644
--- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
@@ -35,6 +35,8 @@
 
 import java.io.File;
 
+import static com.android.layoutlib.bridge.android.BridgeContext.getBaseContext;
+
 /**
  * Custom implementation of {@link LayoutInflater} to handle custom views.
  */
@@ -56,7 +58,12 @@
 
     protected BridgeInflater(LayoutInflater original, Context newContext) {
         super(original, newContext);
-        mProjectCallback = null;
+        newContext = getBaseContext(newContext);
+        if (newContext instanceof BridgeContext) {
+            mProjectCallback = ((BridgeContext) newContext).getProjectCallback();
+        } else {
+            mProjectCallback = null;
+        }
     }
 
     /**
@@ -151,9 +158,7 @@
     @Override
     public View inflate(int resource, ViewGroup root) {
         Context context = getContext();
-        while (context instanceof ContextThemeWrapper) {
-            context = ((ContextThemeWrapper) context).getBaseContext();
-        }
+        context = getBaseContext(context);
         if (context instanceof BridgeContext) {
             BridgeContext bridgeContext = (BridgeContext)context;
 
@@ -179,7 +184,7 @@
                         XmlPullParser parser = ParserFactory.create(f);
 
                         BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser(
-                                parser, bridgeContext, false);
+                                parser, bridgeContext, value.isFramework());
 
                         return inflate(bridgeParser, root);
                     } catch (Exception e) {
@@ -217,9 +222,7 @@
 
     private void setupViewInContext(View view, AttributeSet attrs) {
         Context context = getContext();
-        while (context instanceof ContextThemeWrapper) {
-            context = ((ContextThemeWrapper) context).getBaseContext();
-        }
+        context = getBaseContext(context);
         if (context instanceof BridgeContext) {
             BridgeContext bc = (BridgeContext) context;
             // get the view key
diff --git a/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java b/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java
index dafc96b..08a97d6 100644
--- a/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java
@@ -48,9 +48,7 @@
             AttributeSet attrs) {
         if (menuItem instanceof BridgeMenuItemImpl) {
             Context context = thisInflater.getContext();
-            while (context instanceof ContextThemeWrapper) {
-                context = ((ContextThemeWrapper) context).getBaseContext();
-            }
+            context = BridgeContext.getBaseContext(context);
             if (context instanceof BridgeContext) {
                 Object viewKey = BridgeInflater.getViewKeyFromParser(
                         attrs, ((BridgeContext) context), null, false);
diff --git a/tools/layoutlib/bridge/src/android/view/ViewGroup_Delegate.java b/tools/layoutlib/bridge/src/android/view/ViewGroup_Delegate.java
index a6c00f7..82ae1df 100644
--- a/tools/layoutlib/bridge/src/android/view/ViewGroup_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/ViewGroup_Delegate.java
@@ -71,8 +71,10 @@
         int x = 0;
         if (outline.mRect != null) {
             Shadow s = getRectShadow(parent, canvas, child, outline);
-            shadow = s.mShadow;
-            x = -s.mShadowWidth;
+            if (s != null) {
+              shadow = s.mShadow;
+              x = -s.mShadowWidth;
+            }
         } else if (outline.mPath != null) {
             shadow = getPathShadow(child, outline, canvas);
         }
@@ -120,9 +122,7 @@
     @NonNull
     private static DisplayMetrics getMetrics(View view) {
         Context context = view.getContext();
-        while (context instanceof ContextThemeWrapper) {
-            context = ((ContextThemeWrapper) context).getBaseContext();
-        }
+        context = BridgeContext.getBaseContext(context);
         if (context instanceof BridgeContext) {
             return ((BridgeContext) context).getMetrics();
         }
@@ -132,6 +132,9 @@
 
     private static BufferedImage getPathShadow(View child, Outline outline, Canvas canvas) {
         Rect clipBounds = canvas.getClipBounds();
+        if (clipBounds.isEmpty()) {
+          return null;
+        }
         BufferedImage image = new BufferedImage(clipBounds.width(), clipBounds.height(),
                 BufferedImage.TYPE_INT_ARGB);
         Graphics2D graphics = image.createGraphics();
diff --git a/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java b/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java
index 8d1d0c1..bb95c4e 100644
--- a/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java
@@ -19,7 +19,6 @@
 import com.android.layoutlib.bridge.android.BridgeContext;
 
 import android.content.Context;
-import android.view.ContextThemeWrapper;
 import android.view.View;
 
 /**
@@ -42,9 +41,7 @@
             CharSequence title, int showAsAction) {
         super(menu, group, id, categoryOrder, ordering, title, showAsAction);
         Context context = menu.getContext();
-        while (context instanceof ContextThemeWrapper) {
-            context = ((ContextThemeWrapper) context).getBaseContext();
-        }
+        context = BridgeContext.getBaseContext(context);
         if (context instanceof BridgeContext) {
             mContext = ((BridgeContext) context);
         }
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 8523f1a..ef7b85b 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
@@ -17,6 +17,7 @@
 package com.android.layoutlib.bridge.android;
 
 import com.android.annotations.Nullable;
+import com.android.ide.common.rendering.api.AssetRepository;
 import com.android.ide.common.rendering.api.ILayoutPullParser;
 import com.android.ide.common.rendering.api.IProjectCallback;
 import com.android.ide.common.rendering.api.LayoutLog;
@@ -39,6 +40,7 @@
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.ContextWrapper;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.IntentSender;
@@ -47,6 +49,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
+import android.content.res.BridgeAssetManager;
 import android.content.res.BridgeResources;
 import android.content.res.BridgeTypedArray;
 import android.content.res.Configuration;
@@ -101,6 +104,7 @@
      * used to populate the mViewKeyMap.
      */
     private final HashMap<Object, Object> mViewKeyHelpMap = new HashMap<Object, Object>();
+    private final BridgeAssetManager mAssets;
     private Resources mSystemResources;
     private final Object mProjectKey;
     private final DisplayMetrics mMetrics;
@@ -140,6 +144,7 @@
      */
     public BridgeContext(Object projectKey, DisplayMetrics metrics,
             RenderResources renderResources,
+            AssetRepository assets,
             IProjectCallback projectCallback,
             Configuration config,
             int targetSdkVersion,
@@ -150,6 +155,8 @@
 
         mRenderResources = renderResources;
         mConfig = config;
+        mAssets = new BridgeAssetManager();
+        mAssets.setAssetRepository(assets);
 
         mApplicationInfo = new ApplicationInfo();
         mApplicationInfo.targetSdkVersion = targetSdkVersion;
@@ -288,6 +295,11 @@
             value = mRenderResources.resolveResValue(value);
         }
 
+        if (value == null) {
+            // unable to find the attribute.
+            return false;
+        }
+
         // check if this is a style resource
         if (value instanceof StyleResourceValue) {
             // get the id that will represent this style.
@@ -295,7 +307,6 @@
             return true;
         }
 
-
         int a;
         // if this is a framework value.
         if (value.isFramework()) {
@@ -914,6 +925,13 @@
         return defValue;
     }
 
+    public static Context getBaseContext(Context context) {
+        while (context instanceof ContextWrapper) {
+            context = ((ContextWrapper) context).getBaseContext();
+        }
+        return context;
+    }
+
     //------------ NOT OVERRIDEN --------------------
 
     @Override
@@ -1071,9 +1089,8 @@
     }
 
     @Override
-    public AssetManager getAssets() {
-        // pass
-        return null;
+    public BridgeAssetManager getAssets() {
+        return mAssets;
     }
 
     @Override
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java
new file mode 100644
index 0000000..ee57067
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2015 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.bars;
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+import com.android.ide.common.rendering.api.RenderResources;
+import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.ide.common.rendering.api.SessionParams;
+import com.android.ide.common.rendering.api.StyleResourceValue;
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.impl.ResourceHelper;
+import com.android.resources.ResourceType;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+
+/**
+ * Assumes that the AppCompat library is present in the project's classpath and creates an
+ * actionbar around it.
+ */
+public class AppCompatActionBar extends BridgeActionBar {
+
+    private Object mWindowDecorActionBar;
+    private static final String WINDOW_ACTION_BAR_CLASS = "android.support.v7.internal.app.WindowDecorActionBar";
+    private Class<?> mWindowActionBarClass;
+
+    /**
+     * Inflate the action bar and attach it to {@code parentView}
+     */
+    public AppCompatActionBar(@NonNull BridgeContext context, @NonNull SessionParams params,
+            @NonNull ViewGroup parentView) {
+        super(context, params, parentView);
+        int contentRootId = context.getProjectResourceValue(ResourceType.ID,
+                "action_bar_activity_content", 0);
+        View contentView = getDecorContent().findViewById(contentRootId);
+        if (contentView != null) {
+            assert contentView instanceof FrameLayout;
+            setContentRoot((FrameLayout) contentView);
+        } else {
+            // Something went wrong. Create a new FrameLayout in the enclosing layout.
+            FrameLayout contentRoot = new FrameLayout(context);
+            setMatchParent(contentRoot);
+            mEnclosingLayout.addView(contentRoot);
+            setContentRoot(contentRoot);
+        }
+        try {
+            Class[] constructorParams = {View.class};
+            Object[] constructorArgs = {getDecorContent()};
+            mWindowDecorActionBar = params.getProjectCallback().loadView(WINDOW_ACTION_BAR_CLASS,
+                    constructorParams, constructorArgs);
+
+            mWindowActionBarClass = mWindowDecorActionBar == null ? null :
+                    mWindowDecorActionBar.getClass();
+            setupActionBar();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    protected ResourceValue getLayoutResource(BridgeContext context) {
+        // We always assume that the app has requested the action bar.
+        return context.getRenderResources().getProjectResource(ResourceType.LAYOUT,
+                "abc_screen_toolbar");
+    }
+
+    @Override
+    protected LayoutInflater getInflater(BridgeContext context) {
+        // Other than the resource resolution part, the code has been taken from the support
+        // library. see code from line 269 onwards in
+        // https://android.googlesource.com/platform/frameworks/support/+/android-5.1.0_r1/v7/appcompat/src/android/support/v7/app/ActionBarActivityDelegateBase.java
+        Context themedContext = context;
+        RenderResources resources = context.getRenderResources();
+        ResourceValue actionBarTheme = resources.findItemInTheme("actionBarTheme", false);
+        if (actionBarTheme != null) {
+            // resolve it, if needed.
+            actionBarTheme = resources.resolveResValue(actionBarTheme);
+        }
+        if (actionBarTheme instanceof StyleResourceValue) {
+            int styleId = context.getDynamicIdByStyle(((StyleResourceValue) actionBarTheme));
+            if (styleId != 0) {
+                themedContext = new ContextThemeWrapper(context, styleId);
+            }
+        }
+        return LayoutInflater.from(themedContext);
+    }
+
+    @Override
+    protected void setTitle(CharSequence title) {
+        if (title != null && mWindowDecorActionBar != null) {
+            Method setTitle = getMethod(mWindowActionBarClass, "setTitle", CharSequence.class);
+            invoke(setTitle, mWindowDecorActionBar, title);
+        }
+    }
+
+    @Override
+    protected void setSubtitle(CharSequence subtitle) {
+        if (subtitle != null && mWindowDecorActionBar != null) {
+            Method setSubtitle = getMethod(mWindowActionBarClass, "setSubtitle", CharSequence.class);
+            invoke(setSubtitle, mWindowDecorActionBar, subtitle);
+        }
+    }
+
+    @Override
+    protected void setIcon(String icon) {
+        // Do this only if the action bar doesn't already have an icon.
+        if (icon != null && !icon.isEmpty() && mWindowDecorActionBar != null) {
+            if (invoke(getMethod(mWindowActionBarClass, "hasIcon"), mWindowDecorActionBar)
+                    == Boolean.TRUE) {
+                Drawable iconDrawable = getDrawable(icon, false);
+                if (iconDrawable != null) {
+                    Method setIcon = getMethod(mWindowActionBarClass, "setIcon", Drawable.class);
+                    invoke(setIcon, mWindowDecorActionBar, iconDrawable);
+                }
+            }
+        }
+    }
+
+    @Override
+    protected void setHomeAsUp(boolean homeAsUp) {
+        if (mWindowDecorActionBar != null) {
+            Method setHomeAsUp = getMethod(mWindowActionBarClass,
+                    "setDefaultDisplayHomeAsUpEnabled", boolean.class);
+            invoke(setHomeAsUp, mWindowDecorActionBar, homeAsUp);
+        }
+    }
+
+    @Override
+    public void createMenuPopup() {
+        // it's hard to addd menus to appcompat's actionbar, since it'll use a lot of reflection.
+        // so we skip it for now.
+    }
+
+    @Nullable
+    private static Method getMethod(Class<?> owner, String name, Class<?>... parameterTypes) {
+        try {
+            return owner == null ? null : owner.getMethod(name, parameterTypes);
+        } catch (NoSuchMethodException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    @Nullable
+    private static Object invoke(Method method, Object owner, Object... args) {
+        try {
+            return method == null ? null : method.invoke(owner, args);
+        } catch (InvocationTargetException e) {
+            e.printStackTrace();
+        } catch (IllegalAccessException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    // TODO: this is duplicated from FrameworkActionBarWrapper$WindowActionBarWrapper
+    @Nullable
+    private Drawable getDrawable(@NonNull String name, boolean isFramework) {
+        RenderResources res = mBridgeContext.getRenderResources();
+        ResourceValue value = res.findResValue(name, isFramework);
+        value = res.resolveResValue(value);
+        if (value != null) {
+            return ResourceHelper.getDrawable(value, mBridgeContext);
+        }
+        return null;
+    }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/BridgeActionBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/BridgeActionBar.java
new file mode 100644
index 0000000..2a83ea1
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/BridgeActionBar.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2015 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.bars;
+
+import com.android.annotations.NonNull;
+import com.android.ide.common.rendering.api.ActionBarCallback;
+import com.android.ide.common.rendering.api.ActionBarCallback.HomeButtonStyle;
+import com.android.ide.common.rendering.api.RenderResources;
+import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.ide.common.rendering.api.SessionParams;
+import com.android.layoutlib.bridge.android.BridgeContext;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.FrameLayout;
+import android.widget.RelativeLayout;
+
+/**
+ * An abstraction over two implementations of the ActionBar - framework and appcompat.
+ */
+public abstract class BridgeActionBar {
+    // Store a reference to the context so that we don't have to cast it repeatedly.
+    @NonNull protected final BridgeContext mBridgeContext;
+    @NonNull protected final SessionParams mParams;
+    // A Layout that contains the inflated action bar. The menu popup is added to this layout.
+    @NonNull protected final ViewGroup mEnclosingLayout;
+
+    private final View mDecorContent;
+    private final ActionBarCallback mCallback;
+
+    @SuppressWarnings("NullableProblems")  // Should be initialized by subclasses.
+    @NonNull private FrameLayout mContentRoot;
+
+    public BridgeActionBar(@NonNull BridgeContext context, @NonNull SessionParams params,
+            @NonNull ViewGroup parentView) {
+        mBridgeContext = context;
+        mParams = params;
+        mCallback = params.getProjectCallback().getActionBarCallback();
+        ResourceValue layoutName = getLayoutResource(context);
+        if (layoutName == null) {
+            throw new RuntimeException("Unable to find the layout for Action Bar.");
+        }
+        int layoutId;
+        if (layoutName.isFramework()) {
+            layoutId = context.getFrameworkResourceValue(layoutName.getResourceType(),
+                    layoutName.getName(), 0);
+        } else {
+            layoutId = context.getProjectResourceValue(layoutName.getResourceType(),
+                    layoutName.getName(), 0);
+
+        }
+        if (layoutId == 0) {
+            throw new RuntimeException(
+                    String.format("Unable to resolve attribute \"%1$s\" of type \"%2$s\"",
+                            layoutName.getName(), layoutName.getResourceType()));
+        }
+        if (mCallback.isOverflowPopupNeeded()) {
+            // Create a RelativeLayout around the action bar, to which the overflow popup may be
+            // added.
+            mEnclosingLayout = new RelativeLayout(mBridgeContext);
+            setMatchParent(mEnclosingLayout);
+            parentView.addView(mEnclosingLayout);
+        } else {
+            mEnclosingLayout = parentView;
+        }
+
+        // Inflate action bar layout.
+        mDecorContent = getInflater(context).inflate(layoutId, mEnclosingLayout, true);
+
+    }
+
+    /**
+     * Returns the Layout Resource that should be used to inflate the action bar. This layout
+     * should cover the complete screen, and have a FrameLayout included, where the content will
+     * be inflated.
+     */
+    protected abstract ResourceValue getLayoutResource(BridgeContext context);
+
+    protected LayoutInflater getInflater(BridgeContext context) {
+        return LayoutInflater.from(context);
+    }
+
+    protected void setContentRoot(@NonNull FrameLayout contentRoot) {
+        mContentRoot = contentRoot;
+    }
+
+    @NonNull
+    public FrameLayout getContentRoot() {
+        return mContentRoot;
+    }
+
+    /**
+     * Returns the view inflated. This should contain both the ActionBar and the app content in it.
+     */
+    protected View getDecorContent() {
+        return mDecorContent;
+    }
+
+    /** Setup things like the title, subtitle, icon etc. */
+    protected void setupActionBar() {
+        setTitle();
+        setSutTitle();
+        setIcon();
+        setHomeAsUp(mCallback.getHomeButtonStyle() == HomeButtonStyle.SHOW_HOME_AS_UP);
+    }
+
+    protected abstract void setTitle(CharSequence title);
+    protected abstract void setSubtitle(CharSequence subtitle);
+    protected abstract void setIcon(String icon);
+    protected abstract void setHomeAsUp(boolean homeAsUp);
+
+    private void setTitle() {
+        RenderResources res = mBridgeContext.getRenderResources();
+
+        String title = mParams.getAppLabel();
+        ResourceValue titleValue = res.findResValue(title, false);
+        if (titleValue != null && titleValue.getValue() != null) {
+            setTitle(titleValue.getValue());
+        } else {
+            setTitle(title);
+        }
+    }
+
+    private void setSutTitle() {
+        String subTitle = mCallback.getSubTitle();
+        if (subTitle != null) {
+            setSubtitle(subTitle);
+        }
+    }
+
+    private void setIcon() {
+        String appIcon = mParams.getAppIcon();
+        if (appIcon != null) {
+            setIcon(appIcon);
+        }
+    }
+
+    public abstract void createMenuPopup();
+
+    public ActionBarCallback getCallBack() {
+        return mCallback;
+    }
+
+    protected static void setMatchParent(View view) {
+        view.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
+                LayoutParams.MATCH_PARENT));
+    }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FrameworkActionBar.java
similarity index 76%
rename from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java
rename to tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FrameworkActionBar.java
index 2ff8d37..a1c9065 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FrameworkActionBar.java
@@ -31,7 +31,7 @@
 import android.content.res.TypedArray;
 import android.util.DisplayMetrics;
 import android.util.TypedValue;
-import android.view.LayoutInflater;
+import android.view.InflateException;
 import android.view.View;
 import android.view.View.MeasureSpec;
 import android.view.ViewGroup;
@@ -44,70 +44,30 @@
 
 import java.util.ArrayList;
 
-public class ActionBarLayout {
+/**
+ * Creates the ActionBar as done by the framework.
+ */
+public class FrameworkActionBar extends BridgeActionBar {
 
     private static final String LAYOUT_ATTR_NAME = "windowActionBarFullscreenDecorLayout";
 
     // The Action Bar
-    @NonNull
-    private CustomActionBarWrapper mActionBar;
-
-    // Store another reference to the context so that we don't have to cast it repeatedly.
-    @NonNull
-    private final BridgeContext mBridgeContext;
-
-    @NonNull
-    private FrameLayout mContentRoot;
+    @NonNull private FrameworkActionBarWrapper mActionBar;
 
     // A fake parent for measuring views.
-    @Nullable
-    private ViewGroup mMeasureParent;
-
-    // A Layout that contains the inflated action bar. The menu popup is added to this layout.
-    @NonNull
-    private final RelativeLayout mEnclosingLayout;
+    @Nullable private ViewGroup mMeasureParent;
 
     /**
      * Inflate the action bar and attach it to {@code parentView}
      */
-    public ActionBarLayout(@NonNull BridgeContext context, @NonNull SessionParams params,
+    public FrameworkActionBar(@NonNull BridgeContext context, @NonNull SessionParams params,
             @NonNull ViewGroup parentView) {
+        super(context, params, parentView);
 
-        mBridgeContext = context;
+        View decorContent = getDecorContent();
 
-        ResourceValue layoutName = context.getRenderResources()
-                .findItemInTheme(LAYOUT_ATTR_NAME, true);
-        if (layoutName != null) {
-            // We may need to resolve the reference obtained.
-            layoutName = context.getRenderResources().findResValue(layoutName.getValue(),
-                    layoutName.isFramework());
-        }
-        int layoutId = 0;
-        String error = null;
-        if (layoutName == null) {
-            error = "Unable to find action bar layout (" + LAYOUT_ATTR_NAME
-                    + ") in the current theme.";
-        } else {
-            layoutId = context.getFrameworkResourceValue(layoutName.getResourceType(),
-                    layoutName.getName(), 0);
-            if (layoutId == 0) {
-                error = String.format("Unable to resolve attribute \"%s\" of type \"%s\"",
-                        layoutName.getName(), layoutName.getResourceType());
-            }
-        }
-        if (layoutId == 0) {
-            throw new RuntimeException(error);
-        }
-        // Create a RelativeLayout to hold the action bar. The layout is needed so that we may
-        // add the menu popup to it.
-        mEnclosingLayout = new RelativeLayout(mBridgeContext);
-        setMatchParent(mEnclosingLayout);
-        parentView.addView(mEnclosingLayout);
-
-        // Inflate action bar layout.
-        View decorContent = LayoutInflater.from(context).inflate(layoutId, mEnclosingLayout, true);
-
-        mActionBar = CustomActionBarWrapper.getActionBarWrapper(context, params, decorContent);
+        mActionBar = FrameworkActionBarWrapper.getActionBarWrapper(context, getCallBack(),
+                decorContent);
 
         FrameLayout contentRoot = (FrameLayout) mEnclosingLayout.findViewById(android.R.id.content);
 
@@ -117,27 +77,62 @@
             contentRoot = new FrameLayout(context);
             setMatchParent(contentRoot);
             mEnclosingLayout.addView(contentRoot);
-            mContentRoot = contentRoot;
+            setContentRoot(contentRoot);
         } else {
-            mContentRoot = contentRoot;
-            mActionBar.setupActionBar();
+            setContentRoot(contentRoot);
+            setupActionBar();
             mActionBar.inflateMenus();
         }
     }
 
-    private void setMatchParent(View view) {
-        view.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
-                LayoutParams.MATCH_PARENT));
+    @Override
+    protected ResourceValue getLayoutResource(BridgeContext context) {
+        ResourceValue layoutName =
+                context.getRenderResources().findItemInTheme(LAYOUT_ATTR_NAME, true);
+        if (layoutName != null) {
+            // We may need to resolve the reference obtained.
+            layoutName = context.getRenderResources().findResValue(layoutName.getValue(),
+                    layoutName.isFramework());
+        }
+        if (layoutName == null) {
+             throw new InflateException("Unable to find action bar layout (" + LAYOUT_ATTR_NAME
+                    + ") in the current theme.");
+        }
+        return layoutName;
+    }
+
+    @Override
+    protected void setupActionBar() {
+        super.setupActionBar();
+        mActionBar.setupActionBar();
+    }
+
+    @Override
+    protected void setHomeAsUp(boolean homeAsUp) {
+        mActionBar.setHomeAsUp(homeAsUp);
+    }
+
+    @Override
+    protected void setTitle(CharSequence title) {
+        mActionBar.setTitle(title);
+    }
+
+    @Override
+    protected void setSubtitle(CharSequence subtitle) {
+        mActionBar.setSubTitle(subtitle);
+    }
+
+    @Override
+    protected void setIcon(String icon) {
+        mActionBar.setIcon(icon);
     }
 
     /**
      * Creates a Popup and adds it to the content frame. It also adds another {@link FrameLayout} to
      * the content frame which shall serve as the new content root.
      */
+    @Override
     public void createMenuPopup() {
-        assert mEnclosingLayout.getChildCount() == 1
-                : "Action Bar Menus have already been created.";
-
         if (!isOverflowPopupNeeded()) {
             return;
         }
@@ -193,11 +188,6 @@
         return needed;
     }
 
-    @NonNull
-    public FrameLayout getContentRoot() {
-        return mContentRoot;
-    }
-
     // Copied from com.android.internal.view.menu.MenuPopHelper.measureContentWidth()
     private int measureContentWidth(@NonNull ListAdapter adapter) {
         // Menus don't tend to be long, so this is more sane than it looks.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomActionBarWrapper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FrameworkActionBarWrapper.java
similarity index 81%
rename from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomActionBarWrapper.java
rename to tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FrameworkActionBarWrapper.java
index 6db722e..44c2cd8 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomActionBarWrapper.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FrameworkActionBarWrapper.java
@@ -19,10 +19,8 @@
 import com.android.annotations.NonNull;
 import com.android.annotations.Nullable;
 import com.android.ide.common.rendering.api.ActionBarCallback;
-import com.android.ide.common.rendering.api.ActionBarCallback.HomeButtonStyle;
 import com.android.ide.common.rendering.api.RenderResources;
 import com.android.ide.common.rendering.api.ResourceValue;
-import com.android.ide.common.rendering.api.SessionParams;
 import com.android.internal.R;
 import com.android.internal.app.ToolbarActionBar;
 import com.android.internal.app.WindowDecorActionBar;
@@ -54,10 +52,9 @@
 /**
  * A common API to access {@link ToolbarActionBar} and {@link WindowDecorActionBar}.
  */
-public abstract class CustomActionBarWrapper {
+public abstract class FrameworkActionBarWrapper {
 
     @NonNull protected ActionBar mActionBar;
-    @NonNull protected SessionParams mParams;
     @NonNull protected ActionBarCallback mCallback;
     @NonNull protected BridgeContext mContext;
 
@@ -68,49 +65,48 @@
      *                     ?attr/windowActionBarFullscreenDecorLayout
      */
     @NonNull
-    public static CustomActionBarWrapper getActionBarWrapper(@NonNull BridgeContext context,
-            @NonNull SessionParams params, @NonNull View decorContent) {
+    public static FrameworkActionBarWrapper getActionBarWrapper(@NonNull BridgeContext context,
+            @NonNull ActionBarCallback callback, @NonNull View decorContent) {
         View view = decorContent.findViewById(R.id.action_bar);
         if (view instanceof Toolbar) {
-            return new ToolbarWrapper(context, params, ((Toolbar) view));
+            return new ToolbarWrapper(context, callback, (Toolbar) view);
         } else if (view instanceof ActionBarView) {
-            return new WindowActionBarWrapper(context, params, decorContent,
-                    ((ActionBarView) view));
+            return new WindowActionBarWrapper(context, callback, decorContent,
+                    (ActionBarView) view);
         } else {
             throw new IllegalStateException("Can't make an action bar out of " +
                     view.getClass().getSimpleName());
         }
     }
 
-    CustomActionBarWrapper(@NonNull BridgeContext context, @NonNull SessionParams params,
+    FrameworkActionBarWrapper(@NonNull BridgeContext context, ActionBarCallback callback,
             @NonNull ActionBar actionBar) {
         mActionBar = actionBar;
-        mParams = params;
-        mCallback = params.getProjectCallback().getActionBarCallback();
+        mCallback = callback;
         mContext = context;
     }
 
+    /** A call to setup any custom properties. */
     protected void setupActionBar() {
-        // Do the things that are common to all implementations.
-        RenderResources res = mContext.getRenderResources();
+        // Nothing to do here.
+    }
 
-        String title = mParams.getAppLabel();
-        ResourceValue titleValue = res.findResValue(title, false);
-        if (titleValue != null && titleValue.getValue() != null) {
-            mActionBar.setTitle(titleValue.getValue());
-        } else {
-            mActionBar.setTitle(title);
-        }
+    public void setTitle(CharSequence title) {
+        mActionBar.setTitle(title);
+    }
 
-        String subTitle = mCallback.getSubTitle();
+    public void setSubTitle(CharSequence subTitle) {
         if (subTitle != null) {
             mActionBar.setSubtitle(subTitle);
         }
+    }
 
-        // Add show home as up icon.
-        if (mCallback.getHomeButtonStyle() == HomeButtonStyle.SHOW_HOME_AS_UP) {
-            mActionBar.setDisplayOptions(0xFF, ActionBar.DISPLAY_HOME_AS_UP);
-        }
+    public void setHomeAsUp(boolean homeAsUp) {
+        mActionBar.setDisplayHomeAsUpEnabled(homeAsUp);
+    }
+
+    public void setIcon(String icon) {
+        // Nothing to do.
     }
 
     protected boolean isSplit() {
@@ -186,15 +182,14 @@
      * Material theme uses {@link Toolbar} as the action bar. This wrapper provides access to
      * Toolbar using a common API.
      */
-    private static class ToolbarWrapper extends CustomActionBarWrapper {
+    private static class ToolbarWrapper extends FrameworkActionBarWrapper {
 
         @NonNull
         private final Toolbar mToolbar;  // This is the view.
 
-        ToolbarWrapper(@NonNull BridgeContext context, @NonNull SessionParams params,
+        ToolbarWrapper(@NonNull BridgeContext context, @NonNull ActionBarCallback callback,
                 @NonNull Toolbar toolbar) {
-            super(context, params, new ToolbarActionBar(toolbar, "", new WindowCallback())
-            );
+            super(context, callback, new ToolbarActionBar(toolbar, "", new WindowCallback()));
             mToolbar = toolbar;
         }
 
@@ -248,19 +243,17 @@
      * Holo theme uses {@link WindowDecorActionBar} as the action bar. This wrapper provides
      * access to it using a common API.
      */
-    private static class WindowActionBarWrapper extends CustomActionBarWrapper {
+    private static class WindowActionBarWrapper extends FrameworkActionBarWrapper {
 
-        @NonNull
-        private final WindowDecorActionBar mActionBar;
-        @NonNull
-        private final ActionBarView mActionBarView;
-        @NonNull
-        private final View mDecorContentRoot;
+        @NonNull private final WindowDecorActionBar mActionBar;
+        @NonNull private final ActionBarView mActionBarView;
+        @NonNull private final View mDecorContentRoot;
         private MenuBuilder mMenuBuilder;
 
-        public WindowActionBarWrapper(@NonNull BridgeContext context, @NonNull SessionParams params,
-                @NonNull View decorContentRoot, @NonNull ActionBarView actionBarView) {
-            super(context, params, new WindowDecorActionBar(decorContentRoot));
+        public WindowActionBarWrapper(@NonNull BridgeContext context,
+                @NonNull ActionBarCallback callback, @NonNull View decorContentRoot,
+                @NonNull ActionBarView actionBarView) {
+            super(context, callback, new WindowDecorActionBar(decorContentRoot));
             mActionBarView = actionBarView;
             mActionBar = ((WindowDecorActionBar) super.mActionBar);
             mDecorContentRoot = decorContentRoot;
@@ -268,7 +261,6 @@
 
         @Override
         protected void setupActionBar() {
-            super.setupActionBar();
 
             // Set the navigation mode.
             int navMode = mCallback.getNavigationMode();
@@ -278,16 +270,6 @@
                 setupTabs(3);
             }
 
-            String icon = mParams.getAppIcon();
-            // If the action bar style doesn't specify an icon, set the icon obtained from the
-            // session params.
-            if (!mActionBar.hasIcon() && icon != null) {
-                Drawable iconDrawable = getDrawable(icon, false);
-                if (iconDrawable != null) {
-                    mActionBar.setIcon(iconDrawable);
-                }
-            }
-
             // Set action bar to be split, if needed.
             ViewGroup splitView = (ViewGroup) mDecorContentRoot.findViewById(R.id.split_action_bar);
             if (splitView != null) {
@@ -300,6 +282,17 @@
         }
 
         @Override
+        public void setIcon(String icon) {
+            // Set the icon only if the action bar doesn't specify an icon.
+            if (!mActionBar.hasIcon() && icon != null) {
+                Drawable iconDrawable = getDrawable(icon, false);
+                if (iconDrawable != null) {
+                    mActionBar.setIcon(iconDrawable);
+                }
+            }
+        }
+
+        @Override
         protected void inflateMenus() {
             super.inflateMenus();
             // The super implementation doesn't set the menu on the view. Set it here.
@@ -340,7 +333,7 @@
 
         @Override
         int getMenuPopupMargin() {
-            return -ActionBarLayout.getPixelValue("10dp", mContext.getMetrics());
+            return -FrameworkActionBar.getPixelValue("10dp", mContext.getMetrics());
         }
 
         // TODO: Use an adapter, like List View to set up tabs.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
index 60f5331..127cb72 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
@@ -35,7 +35,6 @@
 
 import android.content.res.Configuration;
 import android.os.HandlerThread_Delegate;
-import android.os.Looper;
 import android.util.DisplayMetrics;
 import android.view.ViewConfiguration_Accessor;
 import android.view.inputmethod.InputMethodManager;
@@ -71,7 +70,7 @@
     /**
      * Creates a renderAction.
      * <p>
-     * This <b>must</b> be followed by a call to {@link RenderAction#init()}, which act as a
+     * This <b>must</b> be followed by a call to {@link RenderAction#init(long)}, which act as a
      * call to {@link RenderAction#acquire(long)}
      *
      * @param params the RenderParams. This must be a copy that the action can keep
@@ -121,8 +120,8 @@
 
         // build the context
         mContext = new BridgeContext(mParams.getProjectKey(), metrics, resources,
-                mParams.getProjectCallback(), getConfiguration(), mParams.getTargetSdkVersion(),
-                mParams.isRtlSupported());
+                mParams.getAssets(), mParams.getProjectCallback(), getConfiguration(),
+                mParams.getTargetSdkVersion(), mParams.isRtlSupported());
 
         setUp();
 
@@ -139,7 +138,7 @@
      * The preparation can fail if another rendering took too long and the timeout was elapsed.
      *
      * More than one call to this from the same thread will have no effect and will return
-     * {@link Result#SUCCESS}.
+     * {@link Result.Status#SUCCESS}.
      *
      * After scene actions have taken place, only one call to {@link #release()} must be
      * done.
@@ -173,7 +172,7 @@
      * Acquire the lock so that the scene can be acted upon.
      * <p>
      * This returns null if the lock was just acquired, otherwise it returns
-     * {@link Result#SUCCESS} if the lock already belonged to that thread, or another
+     * {@link Result.Status#SUCCESS} if the lock already belonged to that thread, or another
      * instance (see {@link Result#getStatus()}) if an error occurred.
      *
      * @param timeout the time to wait if another rendering is happening.
@@ -184,11 +183,11 @@
      */
     private Result acquireLock(long timeout) {
         ReentrantLock lock = Bridge.getLock();
-        if (lock.isHeldByCurrentThread() == false) {
+        if (!lock.isHeldByCurrentThread()) {
             try {
                 boolean acquired = lock.tryLock(timeout, TimeUnit.MILLISECONDS);
 
-                if (acquired == false) {
+                if (!acquired) {
                     return ERROR_TIMEOUT.createResult();
                 }
             } catch (InterruptedException e) {
@@ -308,7 +307,7 @@
      */
     protected void checkLock() {
         ReentrantLock lock = Bridge.getLock();
-        if (lock.isHeldByCurrentThread() == false) {
+        if (!lock.isHeldByCurrentThread()) {
             throw new IllegalStateException("scene must be acquired first. see #acquire(long)");
         }
         if (sCurrentContext != mContext) {
@@ -347,6 +346,7 @@
         config.screenWidthDp = hardwareConfig.getScreenWidth() / density.getDpiValue();
         config.screenHeightDp = hardwareConfig.getScreenHeight() / density.getDpiValue();
         if (config.screenHeightDp < config.screenWidthDp) {
+            //noinspection SuspiciousNameCombination
             config.smallestScreenWidthDp = config.screenHeightDp;
         } else {
             config.smallestScreenWidthDp = config.screenWidthDp;
@@ -367,6 +367,7 @@
                 config.orientation = Configuration.ORIENTATION_LANDSCAPE;
                 break;
             case SQUARE:
+                //noinspection deprecation
                 config.orientation = Configuration.ORIENTATION_SQUARE;
                 break;
             }
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 4637bfd..b086355 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
@@ -51,11 +51,13 @@
 import com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes;
 import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
 import com.android.layoutlib.bridge.android.SessionParamsFlags;
+import com.android.layoutlib.bridge.bars.BridgeActionBar;
+import com.android.layoutlib.bridge.bars.AppCompatActionBar;
 import com.android.layoutlib.bridge.bars.Config;
 import com.android.layoutlib.bridge.bars.NavigationBar;
 import com.android.layoutlib.bridge.bars.StatusBar;
 import com.android.layoutlib.bridge.bars.TitleBar;
-import com.android.layoutlib.bridge.bars.ActionBarLayout;
+import com.android.layoutlib.bridge.bars.FrameworkActionBar;
 import com.android.layoutlib.bridge.impl.binding.FakeAdapter;
 import com.android.layoutlib.bridge.impl.binding.FakeExpandableAdapter;
 import com.android.resources.Density;
@@ -354,7 +356,7 @@
 
                 // if the theme says no title/action bar, then the size will be 0
                 if (mActionBarSize > 0) {
-                    ActionBarLayout actionBar = createActionBar(context, params, backgroundLayout);
+                    BridgeActionBar actionBar = createActionBar(context, params, backgroundLayout);
                     actionBar.createMenuPopup();
                     mContentRoot = actionBar.getContentRoot();
                 } else if (mTitleBarSize > 0) {
@@ -1112,8 +1114,7 @@
             }
         } else {
             // action bar overrides title bar so only look for this one if action bar is hidden
-            boolean windowNoTitle = getBooleanThemeValue(resources,
-                    "windowNoTitle", false, !isThemeAppCompat(resources));
+            boolean windowNoTitle = getBooleanThemeValue(resources, "windowNoTitle", false, true);
 
             if (!windowNoTitle) {
 
@@ -1190,8 +1191,22 @@
         // android.support.v7.app.ActionBarActivity, and not care about the theme name at all.
         if (mIsThemeAppCompat == null) {
             StyleResourceValue defaultTheme = resources.getDefaultTheme();
-            StyleResourceValue val = resources.getStyle("Theme.AppCompat", false);
-            mIsThemeAppCompat = defaultTheme == val || resources.themeIsParentOf(val, defaultTheme);
+          // We can't simply check for parent using resources.themeIsParentOf() since the
+          // inheritance structure isn't really what one would expect. The first common parent
+          // between Theme.AppCompat.Light and Theme.AppCompat is Theme.Material (for v21).
+            boolean isThemeAppCompat = false;
+            for (int i = 0; i < 50; i++) {
+                // for loop ensures that we don't run into cyclic theme inheritance.
+                if (defaultTheme.getName().startsWith("Theme.AppCompat")) {
+                    isThemeAppCompat = true;
+                    break;
+                }
+                defaultTheme = resources.getParent(defaultTheme);
+                if (defaultTheme == null) {
+                    break;
+                }
+            }
+            mIsThemeAppCompat = isThemeAppCompat;
         }
         return mIsThemeAppCompat;
     }
@@ -1647,9 +1662,13 @@
     /**
      * Creates the action bar. Also queries the project callback for missing information.
      */
-    private ActionBarLayout createActionBar(BridgeContext context, SessionParams params,
+    private BridgeActionBar createActionBar(BridgeContext context, SessionParams params,
             ViewGroup parentView) {
-        return new ActionBarLayout(context, params, parentView);
+        if (mIsThemeAppCompat == Boolean.TRUE) {
+            return new AppCompatActionBar(context, params, parentView);
+        } else {
+            return new FrameworkActionBar(context, params, parentView);
+        }
     }
 
     public BufferedImage getImage() {