Merge "Make ImageProcessing work." into honeycomb
diff --git a/api/11.xml b/api/11.xml
index 1733652..1ac57a1 100644
--- a/api/11.xml
+++ b/api/11.xml
@@ -4250,6 +4250,17 @@
  visibility="public"
 >
 </field>
+<field name="fastScrollTextColor"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843611"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="fastScrollThumbDrawable"
  type="int"
  transient="false"
@@ -5812,6 +5823,17 @@
  visibility="public"
 >
 </field>
+<field name="largeHeap"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843612"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="largeScreens"
  type="int"
  transient="false"
@@ -11462,6 +11484,28 @@
  visibility="public"
 >
 </field>
+<field name="notification_large_icon_height"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17104902"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="notification_large_icon_width"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17104901"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="thumbnail_height"
  type="int"
  transient="false"
@@ -25114,17 +25158,6 @@
  visibility="public"
 >
 </field>
-<field name="TASKS_GET_THUMBNAILS"
- type="int"
- transient="false"
- volatile="false"
- value="4096"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 </class>
 <class name="ActivityManager.MemoryInfo"
  extends="java.lang.Object"
@@ -25523,16 +25556,6 @@
  visibility="public"
 >
 </field>
-<field name="thumbnail"
- type="android.graphics.Bitmap"
- transient="false"
- volatile="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 </class>
 <class name="ActivityManager.RunningAppProcessInfo"
  extends="java.lang.Object"
@@ -38947,6 +38970,17 @@
  visibility="public"
 >
 </method>
+<method name="clearViews"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</method>
 <method name="createView"
  return="android.appwidget.AppWidgetHostView"
  abstract="false"
@@ -48119,6 +48153,17 @@
  visibility="public"
 >
 </method>
+<method name="getObbDir"
+ return="java.io.File"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getPackageCodePath"
  return="java.lang.String"
  abstract="true"
@@ -49727,6 +49772,17 @@
  visibility="public"
 >
 </method>
+<method name="getObbDir"
+ return="java.io.File"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getPackageCodePath"
  return="java.lang.String"
  abstract="false"
@@ -58210,6 +58266,17 @@
  visibility="public"
 >
 </field>
+<field name="FLAG_LARGE_HEAP"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1048576"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="FLAG_PERSISTENT"
  type="int"
  transient="false"
@@ -60220,6 +60287,19 @@
 <exception name="PackageManager.NameNotFoundException" type="android.content.pm.PackageManager.NameNotFoundException">
 </exception>
 </method>
+<method name="getPackageObbPaths"
+ return="java.lang.String[]"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+</method>
 <method name="getPackagesForUid"
  return="java.lang.String[]"
  abstract="true"
@@ -60706,6 +60786,21 @@
 <parameter name="installerPackageName" type="java.lang.String">
 </parameter>
 </method>
+<method name="setPackageObbPaths"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+<parameter name="paths" type="java.lang.String[]">
+</parameter>
+</method>
 <field name="COMPONENT_ENABLED_STATE_DEFAULT"
  type="int"
  transient="false"
@@ -137446,6 +137541,34 @@
 <parameter name="params" type="Params...">
 </parameter>
 </method>
+<method name="execute"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="runnable" type="java.lang.Runnable">
+</parameter>
+</method>
+<method name="executeOnExecutor"
+ return="android.os.AsyncTask&lt;Params, Progress, Result&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="exec" type="java.util.concurrent.Executor">
+</parameter>
+<parameter name="params" type="Params...">
+</parameter>
+</method>
 <method name="get"
  return="Result"
  abstract="false"
@@ -137578,6 +137701,16 @@
 <parameter name="values" type="Progress...">
 </parameter>
 </method>
+<field name="THREAD_POOL_EXECUTOR"
+ type="java.util.concurrent.ThreadPoolExecutor"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <class name="AsyncTask.Status"
  extends="java.lang.Enum"
@@ -185171,6 +185304,19 @@
 <exception name="PackageManager.NameNotFoundException" type="android.content.pm.PackageManager.NameNotFoundException">
 </exception>
 </method>
+<method name="getPackageObbPaths"
+ return="java.lang.String[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+</method>
 <method name="getPackagesForUid"
  return="java.lang.String[]"
  abstract="false"
@@ -185670,6 +185816,21 @@
 <parameter name="path" type="java.lang.String">
 </parameter>
 </method>
+<method name="setPackageObbPaths"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+<parameter name="paths" type="java.lang.String[]">
+</parameter>
+</method>
 </class>
 <class name="MockResources"
  extends="android.content.res.Resources"
@@ -238084,6 +238245,34 @@
 >
 </field>
 </class>
+<class name="WebViewFragment"
+ extends="android.app.Fragment"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="WebViewFragment"
+ type="android.webkit.WebViewFragment"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="getWebView"
+ return="android.webkit.WebView"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
 </package>
 <package name="android.widget"
 >
diff --git a/api/current.xml b/api/current.xml
index d141409..6b79074 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -25158,17 +25158,6 @@
  visibility="public"
 >
 </field>
-<field name="TASKS_GET_THUMBNAILS"
- type="int"
- transient="false"
- volatile="false"
- value="4096"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 </class>
 <class name="ActivityManager.MemoryInfo"
  extends="java.lang.Object"
@@ -25567,16 +25556,6 @@
  visibility="public"
 >
 </field>
-<field name="thumbnail"
- type="android.graphics.Bitmap"
- transient="false"
- volatile="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 </class>
 <class name="ActivityManager.RunningAppProcessInfo"
  extends="java.lang.Object"
@@ -48174,6 +48153,17 @@
  visibility="public"
 >
 </method>
+<method name="getObbDir"
+ return="java.io.File"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getPackageCodePath"
  return="java.lang.String"
  abstract="true"
@@ -49782,6 +49772,17 @@
  visibility="public"
 >
 </method>
+<method name="getObbDir"
+ return="java.io.File"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getPackageCodePath"
  return="java.lang.String"
  abstract="false"
@@ -61561,6 +61562,36 @@
  visibility="public"
 >
 </field>
+<field name="externalCacheSize"
+ type="long"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="externalDataSize"
+ type="long"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="externalMediaSize"
+ type="long"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="packageName"
  type="java.lang.String"
  transient="false"
@@ -95576,6 +95607,17 @@
  visibility="public"
 >
 </field>
+<field name="TOUCHABLE_INSETS_REGION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="TOUCHABLE_INSETS_VISIBLE"
  type="int"
  transient="false"
@@ -95607,6 +95649,16 @@
  visibility="public"
 >
 </field>
+<field name="touchableRegion"
+ type="android.graphics.Region"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="visibleTopInsets"
  type="int"
  transient="false"
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 1590bf4..5705057 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -1192,4 +1192,16 @@
     public static int getCurrentAnimationsCount() {
         return sAnimations.get().size();
     }
+
+    /**
+     * Clear all animations on this thread, without canceling or ending them.
+     * This should be used with caution.
+     *
+     * @hide
+     */
+    public static void clearAllAnimations() {
+        sAnimations.get().clear();
+        sPendingAnimations.get().clear();
+        sDelayedAnims.get().clear();
+    }
 }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 4eae14b..d5aa961 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -122,6 +122,8 @@
         /**
          * Thumbnail representation of the task's last state.  Must
          * use {@link ActivityManager#TASKS_GET_THUMBNAILS} to have this set.
+         * @hide -- this is not scalable, need to have a separate API to get
+         * the bitmap.
          */
         public Bitmap thumbnail;
 
@@ -203,6 +205,7 @@
     /**
      * Flag for use with {@link #getRecentTasks}: also return the thumbnail
      * bitmap (if available) for each recent task.
+     * @hide
      */
     public static final int TASKS_GET_THUMBNAILS = 0x0001000;
     
@@ -214,8 +217,7 @@
      * actual number returned may be smaller, depending on how many tasks the
      * user has started and the maximum number the system can remember.
      * @param flags Information about what to return.  May be any combination
-     * of {@link #RECENT_WITH_EXCLUDED}, {@link #RECENT_IGNORE_UNAVAILABLE},
-     * and {@link #TASKS_GET_THUMBNAILS}.
+     * of {@link #RECENT_WITH_EXCLUDED} and {@link #RECENT_IGNORE_UNAVAILABLE}.
      * 
      * @return Returns a list of RecentTaskInfo records describing each of
      * the recent tasks.
@@ -261,8 +263,8 @@
         public ComponentName topActivity;
 
         /**
-         * Thumbnail representation of the task's current state.  Must
-         * use {@link ActivityManager#TASKS_GET_THUMBNAILS} to have this set.
+         * Thumbnail representation of the task's current state.  Currently
+         * always null.
          */
         public Bitmap thumbnail;
 
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index e133ea0..6f63990 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -153,6 +153,7 @@
     private File mPreferencesDir;
     private File mFilesDir;
     private File mCacheDir;
+    private File mObbDir;
     private File mExternalFilesDir;
     private File mExternalCacheDir;
 
@@ -647,6 +648,17 @@
     }
 
     @Override
+    public File getObbDir() {
+        synchronized (mSync) {
+            if (mObbDir == null) {
+                mObbDir = Environment.getExternalStorageAppObbDirectory(
+                        getPackageName());
+            }
+            return mObbDir;
+        }
+    }
+
+    @Override
     public File getCacheDir() {
         synchronized (mSync) {
             if (mCacheDir == null) {
diff --git a/core/java/android/app/NativeActivity.java b/core/java/android/app/NativeActivity.java
index a5c49ec..35cc324 100644
--- a/core/java/android/app/NativeActivity.java
+++ b/core/java/android/app/NativeActivity.java
@@ -84,7 +84,7 @@
     private boolean mDestroyed;
     
     private native int loadNativeCode(String path, String funcname, MessageQueue queue,
-            String internalDataPath, String externalDataPath, int sdkVersion,
+            String internalDataPath, String obbPath, String externalDataPath, int sdkVersion,
             AssetManager assetMgr, byte[] savedState);
     private native void unloadNativeCode(int handle);
     
@@ -191,7 +191,7 @@
                 ? savedInstanceState.getByteArray(KEY_NATIVE_SAVED_STATE) : null;
 
         mNativeHandle = loadNativeCode(path, funcname, Looper.myQueue(),
-                 getFilesDir().toString(),
+                 getFilesDir().toString(), getObbDir().toString(),
                  Environment.getExternalStorageAppFilesDirectory(ai.packageName).toString(),
                  Build.VERSION.SDK_INT, getAssets(), nativeSavedState);
         
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index 4f8ee93..d8adc6c 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -94,8 +94,12 @@
     public AppWidgetHostView(Context context, int animationIn, int animationOut) {
         super(context);
         mContext = context;
+
+        // We want to segregate the view ids within AppWidgets to prevent
+        // problems when those ids collide with view ids in the AppWidgetHost.
+        setIsRootNamespace(true);
     }
-    
+
     /**
      * Set the AppWidget that will be displayed by this view.
      */
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 227df21..d14cf4d 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -516,6 +516,13 @@
     public abstract File getExternalFilesDir(String type);
 
     /**
+     * Return the directory where this application's OBB files (if there
+     * are any) can be found.  Note if the application does not have any OBB
+     * files, this directory may not exist.
+     */
+    public abstract File getObbDir();
+
+    /**
      * Returns the absolute path to the application specific cache directory
      * on the filesystem. These files will be ones that get deleted first when the
      * device runs low on storage.
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 545144e..3928aaf 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -191,6 +191,11 @@
     }
     
     @Override
+    public File getObbDir() {
+        return mBase.getObbDir();
+    }
+    
+    @Override
     public File getCacheDir() {
         return mBase.getCacheDir();
     }
diff --git a/core/java/android/content/pm/PackageStats.java b/core/java/android/content/pm/PackageStats.java
index 9464321..28a2886 100755
--- a/core/java/android/content/pm/PackageStats.java
+++ b/core/java/android/content/pm/PackageStats.java
@@ -19,20 +19,44 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import java.util.Arrays;
-
 /**
  * implementation of PackageStats associated with a
  * application package.
  */
 public class PackageStats implements Parcelable {
+    /** Name of the package to which this stats applies. */
     public String packageName;
+
+    /** Size of the code (e.g., APK) */
     public long codeSize;
+
+    /**
+     * Size of the internal data size for the application. (e.g.,
+     * /data/data/<app>)
+     */
     public long dataSize;
+
+    /** Size of cache used by the application. (e.g., /data/data/<app>/cache) */
     public long cacheSize;
-    
+
+    /**
+     * Size of the external data used by the application (e.g.,
+     * <sdcard>/Android/data/<app>)
+     */
+    public long externalDataSize;
+
+    /**
+     * Size of the external cache used by the application (i.e., on the SD
+     * card). If this is a subdirectory of the data directory, this size will be
+     * subtracted out of the external data size.
+     */
+    public long externalCacheSize;
+
+    /** Size of the external media size used by the application. */
+    public long externalMediaSize;
+
     public static final Parcelable.Creator<PackageStats> CREATOR
-    = new Parcelable.Creator<PackageStats>() {
+            = new Parcelable.Creator<PackageStats>() {
         public PackageStats createFromParcel(Parcel in) {
             return new PackageStats(in);
         }
@@ -41,29 +65,49 @@
             return new PackageStats[size];
         }
     };
-    
+
     public String toString() {
-        return "PackageStats{"
-        + Integer.toHexString(System.identityHashCode(this))
-        + " " + packageName + "}";
+        final StringBuilder sb = new StringBuilder("PackageStats{");
+        sb.append(Integer.toHexString(System.identityHashCode(this)));
+        sb.append(" packageName=");
+        sb.append(packageName);
+        sb.append(",codeSize=");
+        sb.append(codeSize);
+        sb.append(",dataSize=");
+        sb.append(dataSize);
+        sb.append(",cacheSize=");
+        sb.append(cacheSize);
+        sb.append(",externalDataSize=");
+        sb.append(externalDataSize);
+        sb.append(",externalCacheSize=");
+        sb.append(externalCacheSize);
+        sb.append(",externalMediaSize=");
+        sb.append(externalMediaSize);
+        return sb.toString();
     }
-    
+
     public PackageStats(String pkgName) {
         packageName = pkgName;
     }
-    
+
     public PackageStats(Parcel source) {
         packageName = source.readString();
         codeSize = source.readLong();
         dataSize = source.readLong();
         cacheSize = source.readLong();
+        externalDataSize = source.readLong();
+        externalCacheSize = source.readLong();
+        externalMediaSize = source.readLong();
     }
-    
+
     public PackageStats(PackageStats pStats) {
         packageName = pStats.packageName;
         codeSize = pStats.codeSize;
         dataSize = pStats.dataSize;
         cacheSize = pStats.cacheSize;
+        externalDataSize = pStats.externalDataSize;
+        externalCacheSize = pStats.externalCacheSize;
+        externalMediaSize = pStats.externalMediaSize;
     }
 
     public int describeContents() {
@@ -75,5 +119,8 @@
         dest.writeLong(codeSize);
         dest.writeLong(dataSize);
         dest.writeLong(cacheSize);
+        dest.writeLong(externalDataSize);
+        dest.writeLong(externalCacheSize);
+        dest.writeLong(externalMediaSize);
     }
 }
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index 406b091..6baf1c2 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -283,6 +283,7 @@
         
         private Rect mContentInsetsBuffer = null;
         private Rect mVisibleInsetsBuffer = null;
+        private Region mTouchableAreaBuffer = null;
         
         Translator(float applicationScale, float applicationInvertedScale) {
             this.applicationScale = applicationScale;
@@ -395,14 +396,25 @@
 
         /**
          * Translate the visible insets in application window to Screen. This uses
-         * the internal buffer for content insets to avoid extra object allocation.
+         * the internal buffer for visible insets to avoid extra object allocation.
          */
-        public Rect getTranslatedVisbileInsets(Rect visibleInsets) {
+        public Rect getTranslatedVisibleInsets(Rect visibleInsets) {
             if (mVisibleInsetsBuffer == null) mVisibleInsetsBuffer = new Rect();
             mVisibleInsetsBuffer.set(visibleInsets);
             translateRectInAppWindowToScreen(mVisibleInsetsBuffer);
             return mVisibleInsetsBuffer;
         }
+
+        /**
+         * Translate the touchable area in application window to Screen. This uses
+         * the internal buffer for touchable area to avoid extra object allocation.
+         */
+        public Region getTranslatedTouchableArea(Region touchableArea) {
+            if (mTouchableAreaBuffer == null) mTouchableAreaBuffer = new Region();
+            mTouchableAreaBuffer.set(touchableArea);
+            mTouchableAreaBuffer.scale(applicationScale);
+            return mTouchableAreaBuffer;
+        }
     }
 
     /**
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 23b9ad5..4d25bac 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -25,6 +25,7 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Rect;
+import android.graphics.Region;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.ResultReceiver;
@@ -283,11 +284,13 @@
                 View decor = getWindow().getWindow().getDecorView();
                 info.contentInsets.top = info.visibleInsets.top
                         = decor.getHeight();
+                info.touchableRegion.setEmpty();
                 info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
             } else {
                 onComputeInsets(mTmpInsets);
                 info.contentInsets.top = mTmpInsets.contentTopInsets;
                 info.visibleInsets.top = mTmpInsets.visibleTopInsets;
+                info.touchableRegion.set(mTmpInsets.touchableRegion);
                 info.setTouchableInsets(mTmpInsets.touchableInsets);
             }
         }
@@ -510,7 +513,14 @@
          * of the input method window.
          */
         public int visibleTopInsets;
-        
+
+        /**
+         * This is the region of the UI that is touchable.  It is used when
+         * {@link #touchableInsets} is set to {@link #TOUCHABLE_INSETS_REGION}.
+         * The region should be specified relative to the origin of the window frame.
+         */
+        public final Region touchableRegion = new Region();
+
         /**
          * Option for {@link #touchableInsets}: the entire window frame
          * can be touched.
@@ -531,11 +541,19 @@
          */
         public static final int TOUCHABLE_INSETS_VISIBLE
                 = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE;
-        
+
+        /**
+         * Option for {@link #touchableInsets}: the region specified by
+         * {@link #touchableRegion} can be touched.
+         */
+        public static final int TOUCHABLE_INSETS_REGION
+                = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
+
         /**
          * Determine which area of the window is touchable by the user.  May
          * be one of: {@link #TOUCHABLE_INSETS_FRAME},
-         * {@link #TOUCHABLE_INSETS_CONTENT}, or {@link #TOUCHABLE_INSETS_VISIBLE}. 
+         * {@link #TOUCHABLE_INSETS_CONTENT}, {@link #TOUCHABLE_INSETS_VISIBLE},
+         * or {@link #TOUCHABLE_INSETS_REGION}.
          */
         public int touchableInsets;
     }
@@ -950,6 +968,7 @@
         }
         outInsets.visibleTopInsets = loc[1];
         outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_VISIBLE;
+        outInsets.touchableRegion.setEmpty();
     }
     
     /**
@@ -2153,6 +2172,7 @@
         p.println("Last computed insets:");
         p.println("  contentTopInsets=" + mTmpInsets.contentTopInsets
                 + " visibleTopInsets=" + mTmpInsets.visibleTopInsets
-                + " touchableInsets=" + mTmpInsets.touchableInsets);
+                + " touchableInsets=" + mTmpInsets.touchableInsets
+                + " touchableRegion=" + mTmpInsets.touchableRegion);
     }
 }
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 4f188f8..cc95642 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -107,6 +107,10 @@
             = new File (new File(getDirectory("EXTERNAL_STORAGE", "/sdcard"),
                     "Android"), "media");
 
+    private static final File EXTERNAL_STORAGE_ANDROID_OBB_DIRECTORY
+            = new File (new File(getDirectory("EXTERNAL_STORAGE", "/sdcard"),
+                    "Android"), "obb");
+
     private static final File DOWNLOAD_CACHE_DIRECTORY
             = getDirectory("DOWNLOAD_CACHE", "/cache");
 
@@ -304,6 +308,14 @@
     }
     
     /**
+     * Generates the raw path to an application's OBB files
+     * @hide
+     */
+    public static File getExternalStorageAppObbDirectory(String packageName) {
+        return new File(EXTERNAL_STORAGE_ANDROID_OBB_DIRECTORY, packageName);
+    }
+    
+    /**
      * Generates the path to an application's files.
      * @hide
      */
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index a5f405a..1218e81 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -101,7 +101,7 @@
      * {@link android.view.ViewTreeObserver.InternalInsetsInfo}.
      */
     void setInsets(IWindow window, int touchableInsets, in Rect contentInsets,
-            in Rect visibleInsets);
+            in Rect visibleInsets, in Region touchableRegion);
     
     /**
      * Return the current display size in which the window is being laid out,
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index e228537..96f8cdc 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -1229,24 +1229,34 @@
         }
 
         if (computesInternalInsets) {
-            ViewTreeObserver.InternalInsetsInfo insets = attachInfo.mGivenInternalInsets;
-            final Rect givenContent = attachInfo.mGivenInternalInsets.contentInsets;
-            final Rect givenVisible = attachInfo.mGivenInternalInsets.visibleInsets;
-            givenContent.left = givenContent.top = givenContent.right
-                    = givenContent.bottom = givenVisible.left = givenVisible.top
-                    = givenVisible.right = givenVisible.bottom = 0;
+            // Clear the original insets.
+            final ViewTreeObserver.InternalInsetsInfo insets = attachInfo.mGivenInternalInsets;
+            insets.reset();
+
+            // Compute new insets in place.
             attachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
-            Rect contentInsets = insets.contentInsets;
-            Rect visibleInsets = insets.visibleInsets;
-            if (mTranslator != null) {
-                contentInsets = mTranslator.getTranslatedContentInsets(contentInsets);
-                visibleInsets = mTranslator.getTranslatedVisbileInsets(visibleInsets);
-            }
+
+            // Tell the window manager.
             if (insetsPending || !mLastGivenInsets.equals(insets)) {
                 mLastGivenInsets.set(insets);
+
+                // Translate insets to screen coordinates if needed.
+                final Rect contentInsets;
+                final Rect visibleInsets;
+                final Region touchableRegion;
+                if (mTranslator != null) {
+                    contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets);
+                    visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets);
+                    touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion);
+                } else {
+                    contentInsets = insets.contentInsets;
+                    visibleInsets = insets.visibleInsets;
+                    touchableRegion = insets.touchableRegion;
+                }
+
                 try {
                     sWindowSession.setInsets(mWindow, insets.mTouchableInsets,
-                            contentInsets, visibleInsets);
+                            contentInsets, visibleInsets, touchableRegion);
                 } catch (RemoteException e) {
                 }
             }
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index 06a0fa6..db87175 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import android.graphics.Rect;
+import android.graphics.Region;
 
 import java.util.ArrayList;
 import java.util.concurrent.CopyOnWriteArrayList;
@@ -126,11 +127,18 @@
         public final Rect contentInsets = new Rect();
         
         /**
-         * Offsets from the fram of the window at which windows behind it
+         * Offsets from the frame of the window at which windows behind it
          * are visible.
          */
         public final Rect visibleInsets = new Rect();
-        
+
+        /**
+         * Touchable region defined relative to the origin of the frame of the window.
+         * Only used when {@link #setTouchableInsets(int)} is called with
+         * the option {@link #TOUCHABLE_INSETS_REGION}.
+         */
+        public final Region touchableRegion = new Region();
+
         /**
          * Option for {@link #setTouchableInsets(int)}: the entire window frame
          * can be touched.
@@ -148,11 +156,17 @@
          * the visible insets can be touched.
          */
         public static final int TOUCHABLE_INSETS_VISIBLE = 2;
-        
+
+        /**
+         * Option for {@link #setTouchableInsets(int)}: the area inside of
+         * the provided touchable region in {@link #touchableRegion} can be touched.
+         */
+        public static final int TOUCHABLE_INSETS_REGION = 3;
+
         /**
          * Set which parts of the window can be touched: either
          * {@link #TOUCHABLE_INSETS_FRAME}, {@link #TOUCHABLE_INSETS_CONTENT},
-         * or {@link #TOUCHABLE_INSETS_VISIBLE}. 
+         * {@link #TOUCHABLE_INSETS_VISIBLE}, or {@link #TOUCHABLE_INSETS_REGION}.
          */
         public void setTouchableInsets(int val) {
             mTouchableInsets = val;
@@ -165,11 +179,9 @@
         int mTouchableInsets;
         
         void reset() {
-            final Rect givenContent = contentInsets;
-            final Rect givenVisible = visibleInsets;
-            givenContent.left = givenContent.top = givenContent.right
-                    = givenContent.bottom = givenVisible.left = givenVisible.top
-                    = givenVisible.right = givenVisible.bottom = 0;
+            contentInsets.setEmpty();
+            visibleInsets.setEmpty();
+            touchableRegion.setEmpty();
             mTouchableInsets = TOUCHABLE_INSETS_FRAME;
         }
         
@@ -179,13 +191,16 @@
                     return false;
                 }
                 InternalInsetsInfo other = (InternalInsetsInfo)o;
+                if (mTouchableInsets != other.mTouchableInsets) {
+                    return false;
+                }
                 if (!contentInsets.equals(other.contentInsets)) {
                     return false;
                 }
                 if (!visibleInsets.equals(other.visibleInsets)) {
                     return false;
                 }
-                return mTouchableInsets == other.mTouchableInsets;
+                return touchableRegion.equals(other.touchableRegion);
             } catch (ClassCastException e) {
                 return false;
             }
@@ -194,6 +209,7 @@
         void set(InternalInsetsInfo other) {
             contentInsets.set(other.contentInsets);
             visibleInsets.set(other.visibleInsets);
+            touchableRegion.set(other.touchableRegion);
             mTouchableInsets = other.mTouchableInsets;
         }
     }
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index 264af71..2c10077 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -1,5 +1,4 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
+/* Copyright (C) 2010 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.
@@ -209,22 +208,19 @@
             }
         }
 
-        if (fromIndex == -1 && toIndex == NUM_ACTIVE_VIEWS -1) {
+        if (fromIndex == -1 && toIndex == getNumActiveViews() -1) {
             // Fade item in
             if (view.getAlpha() == 1) {
                 view.setAlpha(0);
             }
-            view.setScaleX(1 - PERSPECTIVE_SCALE_FACTOR);
-            view.setScaleY(1 - PERSPECTIVE_SCALE_FACTOR);
-            view.setTranslationX(mPerspectiveShiftX);
-            view.setTranslationY(0);
+            transformViewAtIndex(toIndex, view, false);
             view.setVisibility(VISIBLE);
 
             alphaOa = ObjectAnimator.ofFloat(view, "alpha", view.getAlpha(), 1.0f);
             alphaOa.setDuration(FADE_IN_ANIMATION_DURATION);
             if (oldAlphaOa != null) oldAlphaOa.cancel();
             alphaOa.start();
-            view.setTagInternal(com.android.internal.R.id.viewAlphaAnimation, 
+            view.setTagInternal(com.android.internal.R.id.viewAlphaAnimation,
                     new WeakReference<ObjectAnimator>(alphaOa));
         } else if (fromIndex == 0 && toIndex == 1) {
             // Slide item in
@@ -270,7 +266,7 @@
             alphaOa.setDuration(STACK_RELAYOUT_DURATION);
             if (oldAlphaOa != null) oldAlphaOa.cancel();
             alphaOa.start();
-            view.setTagInternal(com.android.internal.R.id.viewAlphaAnimation, 
+            view.setTagInternal(com.android.internal.R.id.viewAlphaAnimation,
                     new WeakReference<ObjectAnimator>(alphaOa));
         }
 
@@ -284,16 +280,20 @@
         final float maxPerspectiveShiftY = mPerspectiveShiftY;
         final float maxPerspectiveShiftX = mPerspectiveShiftX;
 
-        index = mMaxNumActiveViews - index - 1;
-        if (index == mMaxNumActiveViews - 1) index--;
+        if (mStackMode == ITEMS_SLIDE_DOWN) {
+            index = mMaxNumActiveViews - index - 1;
+            if (index == mMaxNumActiveViews - 1) index--;
+        } else {
+            index--;
+            if (index < 0) index++;
+        }
 
         float r = (index * 1.0f) / (mMaxNumActiveViews - 2);
 
         final float scale = 1 - PERSPECTIVE_SCALE_FACTOR * (1 - r);
 
-        int stackDirection = (mStackMode == ITEMS_SLIDE_UP) ? 1 : -1;
-        float perspectiveTranslationY = -stackDirection * r * maxPerspectiveShiftY;
-        float scaleShiftCorrectionY = stackDirection * (1 - scale) *
+        float perspectiveTranslationY = r * maxPerspectiveShiftY;
+        float scaleShiftCorrectionY = (scale - 1) *
                 (getMeasuredHeight() * (1 - PERSPECTIVE_SHIFT_FACTOR_Y) / 2.0f);
         final float transY = perspectiveTranslationY + scaleShiftCorrectionY;
 
@@ -302,7 +302,7 @@
                 (getMeasuredWidth() * (1 - PERSPECTIVE_SHIFT_FACTOR_X) / 2.0f);
         final float transX = perspectiveTranslationX + scaleShiftCorrectionX;
 
-        // If this view is currently being animated for a certain position, we need to cancel 
+        // If this view is currently being animated for a certain position, we need to cancel
         // this animation so as not to interfere with the new transformation.
         Object tag = view.getTag(com.android.internal.R.id.viewAnimation);
         if (tag instanceof WeakReference<?>) {
@@ -515,11 +515,12 @@
 
     private void beginGestureIfNeeded(float deltaY) {
         if ((int) Math.abs(deltaY) > mTouchSlop && mSwipeGestureType == GESTURE_NONE) {
-            int swipeGestureType = deltaY < 0 ? GESTURE_SLIDE_UP : GESTURE_SLIDE_DOWN;
+            final int swipeGestureType = deltaY < 0 ? GESTURE_SLIDE_UP : GESTURE_SLIDE_DOWN;
             cancelLongPress();
             requestDisallowInterceptTouchEvent(true);
 
             if (mAdapter == null) return;
+            final int adapterCount = mAdapter.getCount();
 
             int activeIndex;
             if (mStackMode == ITEMS_SLIDE_UP) {
@@ -528,13 +529,20 @@
                 activeIndex = (swipeGestureType == GESTURE_SLIDE_DOWN) ? 1 : 0;
             }
 
+            boolean endOfStack = mLoopViews && adapterCount == 1 && 
+                ((mStackMode == ITEMS_SLIDE_UP && swipeGestureType == GESTURE_SLIDE_UP) ||
+                 (mStackMode == ITEMS_SLIDE_DOWN && swipeGestureType == GESTURE_SLIDE_DOWN));
+            boolean beginningOfStack = mLoopViews && adapterCount == 1 && 
+                ((mStackMode == ITEMS_SLIDE_DOWN && swipeGestureType == GESTURE_SLIDE_UP) ||
+                 (mStackMode == ITEMS_SLIDE_UP && swipeGestureType == GESTURE_SLIDE_DOWN));
+
             int stackMode;
-            if (mLoopViews) {
+            if (mLoopViews && !beginningOfStack && !endOfStack) {
                 stackMode = StackSlider.NORMAL_MODE;
-            } else if (mCurrentWindowStartUnbounded + activeIndex == -1) {
+            } else if (mCurrentWindowStartUnbounded + activeIndex == -1 || beginningOfStack) {
                 activeIndex++;
                 stackMode = StackSlider.BEGINNING_OF_STACK_MODE;
-            } else if (mCurrentWindowStartUnbounded + activeIndex == mAdapter.getCount() - 1) {
+            } else if (mCurrentWindowStartUnbounded + activeIndex == adapterCount - 1 || endOfStack) {
                 stackMode = StackSlider.END_OF_STACK_MODE;
             } else {
                 stackMode = StackSlider.NORMAL_MODE;
@@ -989,6 +997,11 @@
     @Override
     public void advance() {
         long timeSinceLastInteraction = System.currentTimeMillis() - mLastInteractionTime;
+
+        if (mAdapter == null) return;
+        final int adapterCount = mAdapter.getCount();
+        if (adapterCount == 1 && mLoopViews) return;
+
         if (mSwipeGestureType == GESTURE_NONE &&
                 timeSinceLastInteraction > MIN_TIME_BETWEEN_INTERACTION_AND_AUTOADVANCE) {
             showNext();
@@ -1266,4 +1279,4 @@
             mask.recycle();
         }
     }
-}
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java
index 8e491e9..8825c02 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuView.java
@@ -20,7 +20,6 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
-import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.Gravity;
 import android.view.View;
@@ -44,6 +43,7 @@
     private MenuBuilder mMenu;
 
     private int mMaxItems;
+    private int mWidthLimit;
     private boolean mReserveOverflow;
     private OverflowMenuButton mOverflowButton;
     private MenuPopupHelper mOverflowPopup;
@@ -91,6 +91,7 @@
         final int screen = res.getConfiguration().screenLayout;
         mReserveOverflow = (screen & Configuration.SCREENLAYOUT_SIZE_MASK) ==
                 Configuration.SCREENLAYOUT_SIZE_XLARGE;
+        mWidthLimit = res.getDisplayMetrics().widthPixels / 2;
         
         TypedArray a = context.obtainStyledAttributes(com.android.internal.R.styleable.Theme);
         mDivider = a.getDrawable(com.android.internal.R.styleable.Theme_dividerVertical);
@@ -108,6 +109,7 @@
         mReserveOverflow = (screen & Configuration.SCREENLAYOUT_SIZE_MASK) ==
                 Configuration.SCREENLAYOUT_SIZE_XLARGE;
         mMaxItems = getMaxActionButtons();
+        mWidthLimit = getResources().getDisplayMetrics().widthPixels / 2;
         if (mMenu != null) {
             mMenu.setMaxActionItems(mMaxItems);
             updateChildren(false);
@@ -172,6 +174,19 @@
     }
 
     public void initialize(MenuBuilder menu, int menuType) {
+        int width = mWidthLimit;
+        if (mReserveOverflow) {
+            if (mOverflowButton == null) {
+                OverflowMenuButton button = new OverflowMenuButton(mContext);
+                mOverflowButton = button;
+            }
+            final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+            mOverflowButton.measure(spec, spec);
+            width -= mOverflowButton.getMeasuredWidth();
+        }
+
+        menu.setActionWidthLimit(width);
+
         menu.setMaxActionItems(mMaxItems);
         mMenu = menu;
         updateChildren(true);
@@ -219,9 +234,11 @@
                 if (itemCount > 0) {
                     addView(makeDividerView(), makeDividerLayoutParams());
                 }
-                OverflowMenuButton button = new OverflowMenuButton(mContext);
-                addView(button);
-                mOverflowButton = button;
+                if (mOverflowButton == null) {
+                    OverflowMenuButton button = new OverflowMenuButton(mContext);
+                    mOverflowButton = button;
+                }
+                addView(mOverflowButton);
             } else {
                 mOverflowButton = null;
             }
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index 830c2c1..588b10c 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -27,9 +27,10 @@
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.Parcelable;
-import android.util.Log;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 import android.util.TypedValue;
+import android.view.ContextMenu.ContextMenuInfo;
 import android.view.ContextThemeWrapper;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
@@ -38,8 +39,8 @@
 import android.view.MenuItem;
 import android.view.SubMenu;
 import android.view.View;
+import android.view.View.MeasureSpec;
 import android.view.ViewGroup;
-import android.view.ContextMenu.ContextMenuInfo;
 import android.widget.AdapterView;
 import android.widget.BaseAdapter;
 
@@ -164,6 +165,10 @@
      */
     private int mMaxActionItems;
     /**
+     * The total width limit in pixels for all action items within a menu
+     */
+    private int mActionWidthLimit;
+    /**
      * Whether or not the items (or any one item's action state) has changed since it was
      * last fetched.
      */
@@ -208,6 +213,11 @@
     
     private boolean mOptionalIconsVisible = false;
 
+    private ViewGroup mMeasureActionButtonParent;
+
+    // Group IDs that have been added as actions - used temporarily, allocated here for reuse.
+    private final SparseBooleanArray mActionButtonGroups = new SparseBooleanArray();
+
     private static int getAlertDialogTheme(Context context) {
         TypedValue outValue = new TypedValue();
         context.getTheme().resolveAttribute(com.android.internal.R.attr.alertDialogTheme,
@@ -1035,6 +1045,44 @@
         return mVisibleItems;
     }
     
+    /**
+     * @return A fake action button parent view for obtaining child views.
+     */
+    private ViewGroup getMeasureActionButtonParent() {
+        if (mMeasureActionButtonParent == null) {
+            mMeasureActionButtonParent = (ViewGroup) mMenuTypes[TYPE_ACTION_BUTTON].getInflater()
+                    .inflate(LAYOUT_RES_FOR_TYPE[TYPE_ACTION_BUTTON], null, false);
+        }
+        return mMeasureActionButtonParent;
+    }
+
+    /**
+     * This method determines which menu items get to be 'action items' that will appear
+     * in an action bar and which items should be 'overflow items' in a secondary menu.
+     * The rules are as follows:
+     *
+     * <p>Items are considered for inclusion in the order specified within the menu.
+     * There is a limit of mMaxActionItems as a total count, optionally including the overflow
+     * menu button itself. This is a soft limit; if an item shares a group ID with an item
+     * previously included as an action item, the new item will stay with its group and become
+     * an action item itself even if it breaks the max item count limit. This is done to
+     * limit the conceptual complexity of the items presented within an action bar. Only a few
+     * unrelated concepts should be presented to the user in this space, and groups are treated
+     * as a single concept.
+     *
+     * <p>There is also a hard limit of consumed measurable space: mActionWidthLimit. This
+     * limit may be broken by a single item that exceeds the remaining space, but no further
+     * items may be added. If an item that is part of a group cannot fit within the remaining
+     * measured width, the entire group will be demoted to overflow. This is done to ensure room
+     * for navigation and other affordances in the action bar as well as reduce general UI clutter.
+     *
+     * <p>The space freed by demoting a full group cannot be consumed by future menu items.
+     * Once items begin to overflow, all future items become overflow items as well. This is
+     * to avoid inadvertent reordering that may break the app's intended design.
+     *
+     * @param reserveActionOverflow true if an overflow button should consume one space
+     *                              in the available item count
+     */
     private void flagActionItems(boolean reserveActionOverflow) {
         if (reserveActionOverflow != mReserveActionOverflow) {
             mReserveActionOverflow = reserveActionOverflow;
@@ -1048,9 +1096,13 @@
         final ArrayList<MenuItemImpl> visibleItems = getVisibleItems();
         final int itemsSize = visibleItems.size();
         int maxActions = mMaxActionItems;
+        int widthLimit = mActionWidthLimit;
+        final int querySpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+        final ViewGroup parent = getMeasureActionButtonParent();
 
         int requiredItems = 0;
         int requestedItems = 0;
+        int firstActionWidth = 0;
         boolean hasOverflow = false;
         for (int i = 0; i < itemsSize; i++) {
             MenuItemImpl item = visibleItems.get(i);
@@ -1070,12 +1122,68 @@
         }
         maxActions -= requiredItems;
 
+        final SparseBooleanArray seenGroups = mActionButtonGroups;
+        seenGroups.clear();
+
         // Flag as many more requested items as will fit.
         for (int i = 0; i < itemsSize; i++) {
             MenuItemImpl item = visibleItems.get(i);
-            if (item.requestsActionButton()) {
-                item.setIsActionButton(maxActions > 0);
+
+            if (item.requiresActionButton()) {
+                View v = item.getActionView();
+                if (v == null) {
+                    v = item.getItemView(TYPE_ACTION_BUTTON, parent);
+                }
+                v.measure(querySpec, querySpec);
+                final int measuredWidth = v.getMeasuredWidth();
+                widthLimit -= measuredWidth;
+                if (firstActionWidth == 0) {
+                    firstActionWidth = measuredWidth;
+                }
+                final int groupId = item.getGroupId();
+                if (groupId != 0) {
+                    seenGroups.put(groupId, true);
+                }
+            } else if (item.requestsActionButton()) {
+                // Items in a group with other items that already have an action slot
+                // can break the max actions rule, but not the width limit.
+                final int groupId = item.getGroupId();
+                final boolean inGroup = seenGroups.get(groupId);
+                boolean isAction = (maxActions > 0 || inGroup) && widthLimit > 0;
                 maxActions--;
+
+                if (isAction) {
+                    View v = item.getActionView();
+                    if (v == null) {
+                        v = item.getItemView(TYPE_ACTION_BUTTON, parent);
+                    }
+                    v.measure(querySpec, querySpec);
+                    final int measuredWidth = v.getMeasuredWidth();
+                    widthLimit -= measuredWidth;
+                    if (firstActionWidth == 0) {
+                        firstActionWidth = measuredWidth;
+                    }
+
+                    // Did this push the entire first item past halfway?
+                    if (widthLimit + firstActionWidth <= 0) {
+                        isAction = false;
+                    }
+                }
+
+                if (isAction && groupId != 0) {
+                    seenGroups.put(groupId, true);
+                } else if (inGroup) {
+                    // We broke the width limit. Demote the whole group, they all overflow now.
+                    seenGroups.put(groupId, false);
+                    for (int j = 0; j < i; j++) {
+                        MenuItemImpl areYouMyGroupie = visibleItems.get(j);
+                        if (areYouMyGroupie.getGroupId() == groupId) {
+                            areYouMyGroupie.setIsActionButton(false);
+                        }
+                    }
+                }
+
+                item.setIsActionButton(isAction);
             }
         }
 
@@ -1108,6 +1216,11 @@
         mIsActionItemsStale = true;
     }
 
+    void setActionWidthLimit(int widthLimit) {
+        mActionWidthLimit = widthLimit;
+        mIsActionItemsStale = true;
+    }
+
     public void clearHeader() {
         mHeaderIcon = null;
         mHeaderTitle = null;
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index d28bdc9..f023e94 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -63,7 +63,6 @@
 extern int register_android_graphics_Movie(JNIEnv* env);
 extern int register_android_graphics_NinePatch(JNIEnv*);
 extern int register_android_graphics_PathEffect(JNIEnv* env);
-extern int register_android_graphics_Region(JNIEnv* env);
 extern int register_android_graphics_Shader(JNIEnv* env);
 extern int register_android_graphics_Typeface(JNIEnv* env);
 extern int register_android_graphics_YuvImage(JNIEnv* env);
@@ -111,6 +110,7 @@
 extern int register_android_graphics_Picture(JNIEnv*);
 extern int register_android_graphics_PorterDuff(JNIEnv* env);
 extern int register_android_graphics_Rasterizer(JNIEnv* env);
+extern int register_android_graphics_Region(JNIEnv* env);
 extern int register_android_graphics_SurfaceTexture(JNIEnv* env);
 extern int register_android_graphics_Xfermode(JNIEnv* env);
 extern int register_android_graphics_PixelFormat(JNIEnv* env);
diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp
index 723cd37..c43b5ce 100644
--- a/core/jni/android/graphics/Region.cpp
+++ b/core/jni/android/graphics/Region.cpp
@@ -1,8 +1,30 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #include "SkRegion.h"
 #include "SkPath.h"
 #include "GraphicsJNI.h"
 
+#include <binder/Parcel.h>
+#include "android_util_Binder.h"
+
 #include <jni.h>
+#include <android_runtime/AndroidRuntime.h>
+
+namespace android {
 
 static jfieldID gRegion_nativeInstanceFieldID;
 
@@ -134,9 +156,6 @@
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
-#include <binder/Parcel.h>
-#include "android_util_Binder.h"
-
 static SkRegion* Region_createFromParcel(JNIEnv* env, jobject clazz, jobject parcel)
 {
     if (parcel == NULL) {
@@ -215,8 +234,6 @@
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
-#include <android_runtime/AndroidRuntime.h>
-
 static JNINativeMethod gRegionIterMethods[] = {
     { "nativeConstructor",  "(I)I",                         (void*)RegionIter_constructor   },
     { "nativeDestructor",   "(I)V",                         (void*)RegionIter_destructor    },
@@ -268,3 +285,9 @@
     return android::AndroidRuntime::registerNativeMethods(env, "android/graphics/RegionIterator",
                                                        gRegionIterMethods, SK_ARRAY_COUNT(gRegionIterMethods));
 }
+
+SkRegion* android_graphics_Region_getSkRegion(JNIEnv* env, jobject regionObj) {
+    return GetSkRegion(env, regionObj);
+}
+
+} // namespace android
diff --git a/core/jni/android/graphics/Region.h b/core/jni/android/graphics/Region.h
new file mode 100644
index 0000000..c15f06e
--- /dev/null
+++ b/core/jni/android/graphics/Region.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_GRAPHICS_REGION_H
+#define _ANDROID_GRAPHICS_REGION_H
+
+#include "jni.h"
+#include "SkRegion.h"
+
+namespace android {
+
+/* Gets the underlying SkRegion from a Region object. */
+extern SkRegion* android_graphics_Region_getSkRegion(JNIEnv* env, jobject regionObj);
+
+} // namespace android
+
+#endif // _ANDROID_GRAPHICS_REGION_H
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index c1229f3..88de94f 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -25,8 +25,8 @@
 #include <utils/Log.h>
 #include <utils/misc.h>
 
-#include "android/graphics/GraphicsJNI.h"
 #include "jni.h"
+#include "JNIHelp.h"
 
 // ----------------------------------------------------------------------------
 
@@ -35,57 +35,127 @@
 static const char* const OutOfResourcesException =
     "android/graphics/SurfaceTexture$OutOfResourcesException";
 
-struct st_t {
-    jfieldID surfaceTexture;
+struct fields_t {
+    jfieldID  surfaceTexture;
+    jmethodID postEvent;
 };
-static st_t st;
+static fields_t fields;
 
 // ----------------------------------------------------------------------------
 
-static void setSurfaceTexture(JNIEnv* env, jobject clazz,
+static void SurfaceTexture_setSurfaceTexture(JNIEnv* env, jobject thiz,
         const sp<SurfaceTexture>& surfaceTexture)
 {
     SurfaceTexture* const p =
-        (SurfaceTexture*)env->GetIntField(clazz, st.surfaceTexture);
+        (SurfaceTexture*)env->GetIntField(thiz, fields.surfaceTexture);
     if (surfaceTexture.get()) {
-        surfaceTexture->incStrong(clazz);
+        surfaceTexture->incStrong(thiz);
     }
     if (p) {
-        p->decStrong(clazz);
+        p->decStrong(thiz);
     }
-    env->SetIntField(clazz, st.surfaceTexture, (int)surfaceTexture.get());
+    env->SetIntField(thiz, fields.surfaceTexture, (int)surfaceTexture.get());
 }
 
-sp<SurfaceTexture> getSurfaceTexture(JNIEnv* env, jobject clazz)
+sp<SurfaceTexture> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz)
 {
     sp<SurfaceTexture> surfaceTexture(
-        (SurfaceTexture*)env->GetIntField(clazz, st.surfaceTexture));
+        (SurfaceTexture*)env->GetIntField(thiz, fields.surfaceTexture));
     return surfaceTexture;
 }
 
 // ----------------------------------------------------------------------------
 
-static void SurfaceTexture_init(JNIEnv* env, jobject clazz, jint texName)
+class JNISurfaceTextureContext : public SurfaceTexture::FrameAvailableListener
 {
-    sp<SurfaceTexture> surfaceTexture(new SurfaceTexture(texName));
+public:
+    JNISurfaceTextureContext(JNIEnv* env, jobject weakThiz, jclass clazz);
+    virtual ~JNISurfaceTextureContext();
+    virtual void onFrameAvailable();
 
-    if (surfaceTexture == 0) {
-        doThrow(env, OutOfResourcesException);
-        return;
-    }
-    setSurfaceTexture(env, clazz, surfaceTexture);
+private:
+    jobject mWeakThiz;
+    jclass mClazz;
+};
+
+JNISurfaceTextureContext::JNISurfaceTextureContext(JNIEnv* env,
+        jobject weakThiz, jclass clazz) :
+    mWeakThiz(env->NewGlobalRef(weakThiz)),
+    mClazz((jclass)env->NewGlobalRef(clazz))
+{}
+
+JNISurfaceTextureContext::~JNISurfaceTextureContext()
+{
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    env->DeleteGlobalRef(mWeakThiz);
+    env->DeleteGlobalRef(mClazz);
 }
 
-static void SurfaceTexture_updateTexImage(JNIEnv* env, jobject clazz)
+void JNISurfaceTextureContext::onFrameAvailable()
 {
-    sp<SurfaceTexture> surfaceTexture(getSurfaceTexture(env, clazz));
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    env->CallStaticVoidMethod(mClazz, fields.postEvent, mWeakThiz);
+}
+
+// ----------------------------------------------------------------------------
+
+static void SurfaceTexture_classInit(JNIEnv* env, jclass clazz)
+{
+    fields.surfaceTexture = env->GetFieldID(clazz,
+            ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "I");
+    if (fields.surfaceTexture == NULL) {
+        LOGE("can't find android/graphics/SurfaceTexture.%s",
+                ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID);
+    }
+
+    fields.postEvent = env->GetStaticMethodID(clazz, "postEventFromNative",
+            "(Ljava/lang/Object;)V");
+    if (fields.postEvent == NULL) {
+        LOGE("can't find android/graphics/SurfaceTexture.postEventFromNative");
+    }
+
+}
+
+static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jint texName,
+        jobject weakThiz)
+{
+    sp<SurfaceTexture> surfaceTexture(new SurfaceTexture(texName));
+    if (surfaceTexture == 0) {
+        jniThrowException(env, OutOfResourcesException,
+                "Unable to create native SurfaceTexture");
+        return;
+    }
+    SurfaceTexture_setSurfaceTexture(env, thiz, surfaceTexture);
+
+    jclass clazz = env->GetObjectClass(thiz);
+    if (clazz == NULL) {
+        jniThrowRuntimeException(env,
+                "Can't find android/graphics/SurfaceTexture");
+        return;
+    }
+
+    sp<JNISurfaceTextureContext> ctx(new JNISurfaceTextureContext(env, weakThiz,
+            clazz));
+    surfaceTexture->setFrameAvailableListener(ctx);
+}
+
+static void SurfaceTexture_finalize(JNIEnv* env, jobject thiz)
+{
+    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
+    surfaceTexture->setFrameAvailableListener(0);
+    SurfaceTexture_setSurfaceTexture(env, thiz, 0);
+}
+
+static void SurfaceTexture_updateTexImage(JNIEnv* env, jobject thiz)
+{
+    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
     surfaceTexture->updateTexImage();
 }
 
-static void SurfaceTexture_getTransformMatrix(JNIEnv* env, jobject clazz,
+static void SurfaceTexture_getTransformMatrix(JNIEnv* env, jobject thiz,
         jfloatArray jmtx)
 {
-    sp<SurfaceTexture> surfaceTexture(getSurfaceTexture(env, clazz));
+    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
     float* mtx = env->GetFloatArrayElements(jmtx, NULL);
     surfaceTexture->getTransformMatrix(mtx);
     env->ReleaseFloatArrayElements(jmtx, mtx, 0);
@@ -94,21 +164,15 @@
 // ----------------------------------------------------------------------------
 
 const char* const kSurfaceTextureClassPathName = "android/graphics/SurfaceTexture";
-static void nativeClassInit(JNIEnv* env, jclass clazz);
 
 static JNINativeMethod gSurfaceTextureMethods[] = {
-    {"nativeClassInit",     "()V",  (void*)nativeClassInit },
-    {"init",                "(I)V", (void*)SurfaceTexture_init },
-    {"updateTexImage",      "()V",  (void*)SurfaceTexture_updateTexImage },
-    {"getTransformMatrixImpl", "([F)V",  (void*)SurfaceTexture_getTransformMatrix },
+    {"nativeClassInit",          "()V",   (void*)SurfaceTexture_classInit },
+    {"nativeInit",               "(ILjava/lang/Object;)V", (void*)SurfaceTexture_init },
+    {"nativeFinalize",            "()V",  (void*)SurfaceTexture_finalize },
+    {"nativeUpdateTexImage",     "()V",   (void*)SurfaceTexture_updateTexImage },
+    {"nativeGetTransformMatrix", "([F)V", (void*)SurfaceTexture_getTransformMatrix },
 };
 
-static void nativeClassInit(JNIEnv* env, jclass clazz)
-{
-    st.surfaceTexture = env->GetFieldID(clazz,
-            ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "I");
-}
-
 int register_android_graphics_SurfaceTexture(JNIEnv* env)
 {
     int err = 0;
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index b033878..0430a81 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -500,8 +500,9 @@
     void* dlhandle;
     ANativeActivity_createFunc* createActivityFunc;
     
-    String8 internalDataPath;
-    String8 externalDataPath;
+    String8 internalDataPathObj;
+    String8 externalDataPathObj;
+    String8 obbPathObj;
     
     sp<ANativeWindow> nativeWindow;
     int32_t lastWindowWidth;
@@ -641,8 +642,8 @@
 
 static jint
 loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jstring funcName,
-        jobject messageQueue,
-        jstring internalDataDir, jstring externalDataDir, int sdkVersion,
+        jobject messageQueue, jstring internalDataDir, jstring obbDir,
+        jstring externalDataDir, int sdkVersion,
         jobject jAssetMgr, jbyteArray savedState)
 {
     LOG_TRACE("loadNativeCode_native");
@@ -699,19 +700,24 @@
         code->clazz = env->NewGlobalRef(clazz);
 
         const char* dirStr = env->GetStringUTFChars(internalDataDir, NULL);
-        code->internalDataPath = dirStr;
-        code->internalDataPath = code->internalDataPath.string();
-        env->ReleaseStringUTFChars(path, dirStr);
+        code->internalDataPathObj = dirStr;
+        code->internalDataPath = code->internalDataPathObj.string();
+        env->ReleaseStringUTFChars(internalDataDir, dirStr);
     
         dirStr = env->GetStringUTFChars(externalDataDir, NULL);
-        code->externalDataPath = dirStr;
-        code->externalDataPath = code->externalDataPath.string();
-        env->ReleaseStringUTFChars(path, dirStr);
+        code->externalDataPathObj = dirStr;
+        code->externalDataPath = code->externalDataPathObj.string();
+        env->ReleaseStringUTFChars(externalDataDir, dirStr);
 
         code->sdkVersion = sdkVersion;
         
         code->assetManager = assetManagerForJavaObject(env, jAssetMgr);
 
+        dirStr = env->GetStringUTFChars(obbDir, NULL);
+        code->obbPathObj = dirStr;
+        code->obbPath = code->obbPathObj.string();
+        env->ReleaseStringUTFChars(obbDir, dirStr);
+
         jbyte* rawSavedState = NULL;
         jsize rawSavedSize = 0;
         if (savedState != NULL) {
@@ -1022,7 +1028,7 @@
 }
 
 static const JNINativeMethod g_methods[] = {
-    { "loadNativeCode", "(Ljava/lang/String;Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;ILandroid/content/res/AssetManager;[B)I",
+    { "loadNativeCode", "(Ljava/lang/String;Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILandroid/content/res/AssetManager;[B)I",
             (void*)loadNativeCode_native },
     { "unloadNativeCode", "(I)V", (void*)unloadNativeCode_native },
     { "onStartNative", "(I)V", (void*)onStart_native },
diff --git a/core/res/res/layout/dialog_custom_title_holo.xml b/core/res/res/layout/dialog_custom_title_holo.xml
index 854873f..74b6070 100644
--- a/core/res/res/layout/dialog_custom_title_holo.xml
+++ b/core/res/res/layout/dialog_custom_title_holo.xml
@@ -23,10 +23,19 @@
     android:fitsSystemWindows="true">
     <FrameLayout android:id="@android:id/title_container"
         android:layout_width="match_parent"
-        android:layout_height="24dip"
+        android:layout_height="60dip"
         android:layout_weight="0"
+        android:gravity="center_vertical|left"
         style="?android:attr/windowTitleBackgroundStyle">
     </FrameLayout>
+    <ImageView android:id="@+id/titleDivider"
+            android:layout_width="match_parent"
+            android:layout_height="4dip"
+            android:scaleType="fitXY"
+            android:gravity="fill_horizontal"
+            android:paddingLeft="16dip"
+            android:paddingRight="16dip"
+            android:src="@android:drawable/divider_strong_holo" />
     <FrameLayout
         android:layout_width="match_parent" android:layout_height="wrap_content"
         android:layout_weight="1"
@@ -34,10 +43,6 @@
         android:foreground="?android:attr/windowContentOverlay">
         <FrameLayout android:id="@android:id/content"
             android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:paddingTop="6dip"
-            android:paddingBottom="10dip"
-            android:paddingLeft="10dip"
-            android:paddingRight="10dip" />
+            android:layout_height="match_parent" />
     </FrameLayout>
 </LinearLayout>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 1183915..c4e815e 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -2057,7 +2057,7 @@
 
     <!-- Window title -->
     <style name="WindowTitleBackground.Holo">
-        <item name="android:background">@android:drawable/title_bar</item>
+        <item name="android:background">@null</item>
     </style>
 
     <style name="WindowTitle.Holo">
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index 3eb0b03..64c209a 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -16,6 +16,11 @@
 
 package android.graphics;
 
+import java.lang.ref.WeakReference;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
 /**
  * Captures frames from an image stream as an OpenGL ES texture.
  *
@@ -32,6 +37,9 @@
  */
 public class SurfaceTexture {
 
+    private EventHandler mEventHandler;
+    private OnFrameAvailableListener mOnFrameAvailableListener;
+
     @SuppressWarnings("unused")
     private int mSurfaceTexture;
 
@@ -59,7 +67,15 @@
      * @param texName the OpenGL texture object name (e.g. generated via glGenTextures)
      */
     public SurfaceTexture(int texName) {
-        init(texName);
+        Looper looper;
+        if ((looper = Looper.myLooper()) != null) {
+            mEventHandler = new EventHandler(looper);
+        } else if ((looper = Looper.getMainLooper()) != null) {
+            mEventHandler = new EventHandler(looper);
+        } else {
+            mEventHandler = null;
+        }
+        nativeInit(texName, new WeakReference<SurfaceTexture>(this));
     }
 
     /**
@@ -69,7 +85,7 @@
      * thread invoking the callback.
      */
     public void setOnFrameAvailableListener(OnFrameAvailableListener l) {
-        // TODO: Implement this!
+        mOnFrameAvailableListener = l;
     }
 
     /**
@@ -77,8 +93,9 @@
      * called while the OpenGL ES context that owns the texture is bound to the thread.  It will
      * implicitly bind its texture to the GL_TEXTURE_EXTERNAL_OES texture target.
      */
-    public native void updateTexImage();
-
+    public void updateTexImage() {
+        nativeUpdateTexImage();
+    }
 
     /**
      * Retrieve the 4x4 texture coordinate transform matrix associated with the texture image set by
@@ -99,12 +116,48 @@
         if (mtx.length != 16) {
             throw new IllegalArgumentException();
         }
-        getTransformMatrixImpl(mtx);
+        nativeGetTransformMatrix(mtx);
     }
 
-    private native void getTransformMatrixImpl(float[] mtx);
+    protected void finalize() throws Throwable {
+        try {
+            nativeFinalize();
+        } finally {
+            super.finalize();
+        }
+    }
 
-    private native void init(int texName);
+    private class EventHandler extends Handler {
+        public EventHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            if (mOnFrameAvailableListener != null) {
+                mOnFrameAvailableListener.onFrameAvailable(SurfaceTexture.this);
+            }
+            return;
+        }
+    }
+
+    private static void postEventFromNative(Object selfRef) {
+        WeakReference weakSelf = (WeakReference)selfRef;
+        SurfaceTexture st = (SurfaceTexture)weakSelf.get();
+        if (st == null) {
+            return;
+        }
+
+        if (st.mEventHandler != null) {
+            Message m = st.mEventHandler.obtainMessage();
+            st.mEventHandler.sendMessage(m);
+        }
+    }
+
+    private native void nativeInit(int texName, Object weakSelf);
+    private native void nativeFinalize();
+    private native void nativeGetTransformMatrix(float[] mtx);
+    private native void nativeUpdateTexImage();
 
     /*
      * We use a class initializer to allow the native code to cache some
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 002e48b..79c33f5 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -40,6 +40,10 @@
     enum { MIN_BUFFER_SLOTS = 3 };
     enum { NUM_BUFFER_SLOTS = 32 };
 
+    struct FrameAvailableListener : public virtual RefBase {
+        virtual void onFrameAvailable() = 0;
+    };
+
     // tex indicates the name OpenGL texture to which images are to be streamed.
     // This texture name cannot be changed once the SurfaceTexture is created.
     SurfaceTexture(GLuint tex);
@@ -93,6 +97,10 @@
     // functions.
     void getTransformMatrix(float mtx[16]);
 
+    // setFrameAvailableListener sets the listener object that will be notified
+    // when a new frame becomes available.
+    void setFrameAvailableListener(const sp<FrameAvailableListener>& l);
+
 private:
 
     // freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for
@@ -195,6 +203,11 @@
     // to a buffer, but other processes do.
     Vector<sp<GraphicBuffer> > mAllocdBuffers;
 
+    // mFrameAvailableListener is the listener object that will be called when a
+    // new frame becomes available. If it is not NULL it will be called from
+    // queueBuffer.
+    sp<FrameAvailableListener> mFrameAvailableListener;
+
     // mMutex is the mutex used to prevent concurrent access to the member
     // variables of SurfaceTexture objects. It must be locked whenever the
     // member variables are accessed.
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 447de76..1dadd53 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -166,6 +166,9 @@
     mLastQueued = buf;
     mLastQueuedCrop = mNextCrop;
     mLastQueuedTransform = mNextTransform;
+    if (mFrameAvailableListener != 0) {
+        mFrameAvailableListener->onFrameAvailable();
+    }
     return OK;
 }
 
@@ -237,43 +240,68 @@
     LOGV("SurfaceTexture::updateTexImage");
     Mutex::Autolock lock(mMutex);
 
-    float* xform = mtxIdentity;
-    switch (mCurrentTransform) {
-        case 0:
-            xform = mtxIdentity;
-            break;
-        case NATIVE_WINDOW_TRANSFORM_FLIP_H:
-            xform = mtxFlipH;
-            break;
-        case NATIVE_WINDOW_TRANSFORM_FLIP_V:
-            xform = mtxFlipV;
-            break;
-        case NATIVE_WINDOW_TRANSFORM_ROT_90:
-            xform = mtxRot90;
-            break;
-        case NATIVE_WINDOW_TRANSFORM_ROT_180:
-            xform = mtxRot180;
-            break;
-        case NATIVE_WINDOW_TRANSFORM_ROT_270:
-            xform = mtxRot270;
-            break;
-        default:
-            LOGE("getTransformMatrix: unknown transform: %d", mCurrentTransform);
+    float xform[16];
+    for (int i = 0; i < 16; i++) {
+        xform[i] = mtxIdentity[i];
+    }
+    if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
+        float result[16];
+        mtxMul(result, xform, mtxFlipH);
+        for (int i = 0; i < 16; i++) {
+            xform[i] = result[i];
+        }
+    }
+    if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
+        float result[16];
+        mtxMul(result, xform, mtxFlipV);
+        for (int i = 0; i < 16; i++) {
+            xform[i] = result[i];
+        }
+    }
+    if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+        float result[16];
+        mtxMul(result, xform, mtxRot90);
+        for (int i = 0; i < 16; i++) {
+            xform[i] = result[i];
+        }
     }
 
     sp<GraphicBuffer>& buf(mSlots[mCurrentTexture].mGraphicBuffer);
-    float tx = float(mCurrentCrop.left) / float(buf->getWidth());
-    float ty = float(mCurrentCrop.bottom) / float(buf->getHeight());
-    float sx = float(mCurrentCrop.width()) / float(buf->getWidth());
-    float sy = float(mCurrentCrop.height()) / float(buf->getHeight());
+    float tx, ty, sx, sy;
+    if (!mCurrentCrop.isEmpty()) {
+        tx = float(mCurrentCrop.left) / float(buf->getWidth());
+        ty = float(buf->getHeight() - mCurrentCrop.bottom) /
+                float(buf->getHeight());
+        sx = float(mCurrentCrop.width()) / float(buf->getWidth());
+        sy = float(mCurrentCrop.height()) / float(buf->getHeight());
+    } else {
+        tx = 0.0f;
+        ty = 0.0f;
+        sx = 1.0f;
+        sy = 1.0f;
+    }
     float crop[16] = {
-        sx, 0, 0, sx*tx,
-        0, sy, 0, sy*ty,
+        sx, 0, 0, 0,
+        0, sy, 0, 0,
         0, 0, 1, 0,
-        0, 0, 0, 1,
+        sx*tx, sy*ty, 0, 1,
     };
 
-    mtxMul(mtx, crop, xform);
+    float mtxBeforeFlipV[16];
+    mtxMul(mtxBeforeFlipV, crop, xform);
+
+    // SurfaceFlinger expects the top of its window textures to be at a Y
+    // coordinate of 0, so SurfaceTexture must behave the same way.  We don't
+    // want to expose this to applications, however, so we must add an
+    // additional vertical flip to the transform after all the other transforms.
+    mtxMul(mtx, mtxFlipV, mtxBeforeFlipV);
+}
+
+void SurfaceTexture::setFrameAvailableListener(
+        const sp<FrameAvailableListener>& l) {
+    LOGV("SurfaceTexture::setFrameAvailableListener");
+    Mutex::Autolock lock(mMutex);
+    mFrameAvailableListener = l;
 }
 
 void SurfaceTexture::freeAllBuffers() {
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index 6e4c22e..41c9fe2 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -212,6 +212,7 @@
     GLenum type = mType->getElement()->getComponent().getGLType();
     GLenum format = mType->getElement()->getComponent().getGLFormat();
     GLenum target = (GLenum)getGLTarget();
+    rsAssert(mTextureID);
     glBindTexture(target, mTextureID);
     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
     GLenum t = GL_TEXTURE_2D;
diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp
index 1c6c5ac..001ac55 100644
--- a/libs/rs/rsThreadIO.cpp
+++ b/libs/rs/rsThreadIO.cpp
@@ -53,6 +53,10 @@
         waitForCommand = false;
         //LOGV("playCoreCommands 3 %i %i", cmdID, cmdSize);
 
+        if (cmdID >= (sizeof(gPlaybackFuncs) / sizeof(void *))) {
+            rsAssert(cmdID < (sizeof(gPlaybackFuncs) / sizeof(void *)));
+            LOGE("playCoreCommands error con %p, cmd %i", con, cmdID);
+        }
         gPlaybackFuncs[cmdID](con, data);
         mToCore.next();
     }
diff --git a/libs/rs/rsg_generator.c b/libs/rs/rsg_generator.c
index 1e468bb..4ac5b7f 100644
--- a/libs/rs/rsg_generator.c
+++ b/libs/rs/rsg_generator.c
@@ -219,7 +219,7 @@
         fprintf(f, "};\n\n");
     }
 
-    fprintf(f, "RsPlaybackFunc gPlaybackFuncs[] = {\n");
+    fprintf(f, "RsPlaybackFunc gPlaybackFuncs[%i] = {\n", apiCount + 1);
     fprintf(f, "    NULL,\n");
     for (ct=0; ct < apiCount; ct++) {
         fprintf(f, "    %s%s,\n", "rsp_", apis[ct].name);
@@ -265,7 +265,7 @@
             printFuncDecls(f, "rsi_", 1);
             printPlaybackFuncs(f, "rsp_");
             fprintf(f, "\n\ntypedef void (*RsPlaybackFunc)(Context *, const void *);\n");
-            fprintf(f, "extern RsPlaybackFunc gPlaybackFuncs[];\n");
+            fprintf(f, "extern RsPlaybackFunc gPlaybackFuncs[%i];\n", apiCount + 1);
 
             fprintf(f, "}\n");
             fprintf(f, "}\n");
diff --git a/native/android/looper.cpp b/native/android/looper.cpp
index 9f5cda9..615493f 100644
--- a/native/android/looper.cpp
+++ b/native/android/looper.cpp
@@ -19,9 +19,11 @@
 
 #include <android/looper.h>
 #include <utils/Looper.h>
+#include <binder/IPCThreadState.h>
 
 using android::Looper;
 using android::sp;
+using android::IPCThreadState;
 
 ALooper* ALooper_forThread() {
     return Looper::getForThread().get();
@@ -46,6 +48,7 @@
         return ALOOPER_POLL_ERROR;
     }
 
+    IPCThreadState::self()->flushCommands();
     return looper->pollOnce(timeoutMillis, outFd, outEvents, outData);
 }
 
@@ -55,7 +58,8 @@
         LOGE("ALooper_pollAll: No looper for this thread!");
         return ALOOPER_POLL_ERROR;
     }
-    
+
+    IPCThreadState::self()->flushCommands();
     return looper->pollAll(timeoutMillis, outFd, outEvents, outData);
 }
 
diff --git a/native/include/android/native_activity.h b/native/include/android/native_activity.h
index d89bc8b..a361846 100644
--- a/native/include/android/native_activity.h
+++ b/native/include/android/native_activity.h
@@ -91,6 +91,13 @@
      * uses this to access binary assets bundled inside its own .apk file.
      */
     AAssetManager* assetManager;
+
+    /**
+     * Available starting with Honeycomb: path to the directory containing
+     * the application's OBB files (if any).  If the app doesn't have any
+     * OBB files, this directory may not exist.
+     */
+    const char* obbPath;
 } ANativeActivity;
 
 /**
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 386cc5d..ed36171 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -62,6 +62,8 @@
         "EGL_KHR_image_base "
         "EGL_KHR_image_pixmap "
         "EGL_KHR_gl_texture_2D_image "
+        "EGL_KHR_gl_texture_cubemap_image "
+        "EGL_KHR_gl_renderbuffer_image "
         "EGL_KHR_fence_sync "
         "EGL_ANDROID_image_native_buffer "
         "EGL_ANDROID_swap_rectangle "
@@ -1471,6 +1473,29 @@
     return result;
 }
 
+// Note: Similar implementations of these functions also exist in
+// gl2.cpp and gl.cpp, and are used by applications that call the
+// exported entry points directly.
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
+
+static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES_impl = NULL;
+static PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES_impl = NULL;
+
+static void glEGLImageTargetTexture2DOES_wrapper(GLenum target, GLeglImageOES image)
+{
+    GLeglImageOES implImage =
+        (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
+    glEGLImageTargetTexture2DOES_impl(target, implImage);
+}
+
+static void glEGLImageTargetRenderbufferStorageOES_wrapper(GLenum target, GLeglImageOES image)
+{
+    GLeglImageOES implImage =
+        (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
+    glEGLImageTargetRenderbufferStorageOES_impl(target, implImage);
+}
+
 __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
 {
     // eglGetProcAddress() could be the very first function called
@@ -1531,6 +1556,16 @@
             }
             if (found) {
                 addr = gExtensionForwarders[slot];
+
+                if (!strcmp(procname, "glEGLImageTargetTexture2DOES")) {
+                    glEGLImageTargetTexture2DOES_impl = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)addr;
+                    addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetTexture2DOES_wrapper;
+                }
+                if (!strcmp(procname, "glEGLImageTargetRenderbufferStorageOES")) {
+                    glEGLImageTargetRenderbufferStorageOES_impl = (PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC)addr;
+                    addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetRenderbufferStorageOES_wrapper;
+                }
+
                 gGLExtentionMap.add(name, addr);
                 gGLExtentionSlot++;
             }
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index 0c85af8..2ec2226 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -165,8 +165,13 @@
         }
 
         @Override
-        public long calculateDirectorySize(String directory) throws RemoteException {
-            return MeasurementUtils.measureDirectory(directory);
+        public long calculateDirectorySize(String path) throws RemoteException {
+            final File directory = new File(path);
+            if (directory.exists() && directory.isDirectory()) {
+                return MeasurementUtils.measureDirectory(path);
+            } else {
+                return 0L;
+            }
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 73b6723..dfe0262 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -668,7 +668,8 @@
             if ((mPhoneState == TelephonyManager.CALL_STATE_IDLE) && isEvdo()){
                 iconLevel = getEvdoLevel();
                 if (false) {
-                    Slog.d(TAG, "use Evdo level=" + iconLevel + " to replace Cdma Level=" + getCdmaLevel());
+                    Slog.d(TAG, "use Evdo level=" + iconLevel + " to replace Cdma Level="
+                            + getCdmaLevel());
                 }
             } else {
                 iconLevel = getCdmaLevel();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AirplaneModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AirplaneModeController.java
index 1b2fcad..0d2538d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AirplaneModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AirplaneModeController.java
@@ -55,7 +55,6 @@
     }
 
     public void onCheckedChanged(CompoundButton view, boolean checked) {
-        Slog.d(TAG, "onCheckedChanged checked=" + checked + " mAirplaneMode=" + mAirplaneMode);
         if (checked != mAirplaneMode) {
             mAirplaneMode = checked;
             unsafe(checked);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 3a7bd90..e80e37d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -47,7 +47,6 @@
     int mRepeat;
     Runnable mCheckLongPress = new Runnable() {
         public void run() {
-            Slog.d("KeyButtonView", "longpress");
             if (isPressed()) {
                 mLongPressed = true;
                 mRepeat++;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HeightReceiver.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HeightReceiver.java
index 5616159..90c9568 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HeightReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HeightReceiver.java
@@ -73,12 +73,10 @@
     private void setPlugged(boolean plugged) {
         final Resources res = mContext.getResources();
 
-        Slog.d(TAG, "plugged=" + plugged);
         int height = -1;
         if (plugged) {
             final DisplayMetrics metrics = new DisplayMetrics();
             mWindowManager.getDefaultDisplay().getMetrics(metrics);
-            Slog.d(TAG, "metrics=" + metrics);
             height = metrics.heightPixels - 720;
         }
 
@@ -87,7 +85,8 @@
         if (height < minHeight) {
             height = minHeight;
         }
-        Slog.d(TAG, "using height=" + height + " old=" + mHeight);
+        Slog.i(TAG, "Resizing status bar plugged=" + plugged + " height="
+                + height + " old=" + mHeight);
         mHeight = height;
 
         final int N = mListeners.size();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
index d4ba693..add67b1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
@@ -242,6 +242,7 @@
     // Turn on the selected radio button at startup
     private void updateRadioButtonsByImiAndSubtype(
             InputMethodInfo imi, InputMethodSubtype subtype) {
+        if (imi == null) return;
         if (DEBUG) {
             Log.d(TAG, "Update radio buttons by " + imi.getId() + ", " + subtype);
         }
@@ -253,7 +254,7 @@
                 return;
             }
             Pair<InputMethodInfo, InputMethodSubtype> imiAndSubtype =
-                mRadioViewAndImiMap.get(radioView);
+                    mRadioViewAndImiMap.get(radioView);
             if (imiAndSubtype.first.getId().equals(imi.getId())
                     && (imiAndSubtype.second == null || imiAndSubtype.second.equals(subtype))) {
                 subtypeRadioButton.setChecked(true);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
index a2f6e3a..45a22b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
@@ -269,7 +269,8 @@
                 // fully closed, no animation necessary
             } else if (mVisible) {
                 if (DEBUG) {
-                    Slog.d(TAG, "panelHeight not zero but trying to open; scheduling an anim to open fully");
+                    Slog.d(TAG, "panelHeight not zero but trying to open; scheduling an anim"
+                            + " to open fully");
                 }
                 startAnimation(true);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java
index 07af466..9ca83e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java
@@ -95,7 +95,6 @@
     // Network
     // ----------------------------
     private void onClickNetwork() {
-        Slog.d(TAG, "onClickNetwork");
         getContext().startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS)
                 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
         getStatusBarManager().collapse();
@@ -104,7 +103,6 @@
     // Settings
     // ----------------------------
     private void onClickSettings() {
-        Slog.d(TAG, "onClickSettings");
         getContext().startActivity(new Intent(Settings.ACTION_SETTINGS)
                 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
         getStatusBarManager().collapse();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
index 2ebd067..e864577 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
@@ -143,7 +143,6 @@
                 hideWindow();
                 return true;
             } else if (action == MotionEvent.ACTION_DOWN) {
-                Slog.d(TAG, "ACTION_DOWN");
                 final ClipData clip = mClipping;
                 if (clip != null) {
                     final Bitmap icon = clip.getIcon();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index d8e3053..825877a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -596,7 +596,7 @@
             // TODO: immersive mode popups for tablet
         } else if (notification.notification.fullScreenIntent != null) {
             // not immersive & a full-screen alert should be shown
-            Slog.d(TAG, "Notification has fullScreenIntent and activity is not immersive;"
+            Slog.w(TAG, "Notification has fullScreenIntent and activity is not immersive;"
                     + " sending fullScreenIntent");
             try {
                 notification.notification.fullScreenIntent.send();
@@ -732,28 +732,28 @@
         // act accordingly
         if ((diff & StatusBarManager.DISABLE_CLOCK) != 0) {
             boolean show = (state & StatusBarManager.DISABLE_CLOCK) == 0;
-            Slog.d(TAG, "DISABLE_CLOCK: " + (show ? "no" : "yes"));
+            Slog.i(TAG, "DISABLE_CLOCK: " + (show ? "no" : "yes"));
             showClock(show);
         }
         if ((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
             boolean show = (state & StatusBarManager.DISABLE_SYSTEM_INFO) == 0;
-            Slog.d(TAG, "DISABLE_SYSTEM_INFO: " + (show ? "no" : "yes"));
+            Slog.i(TAG, "DISABLE_SYSTEM_INFO: " + (show ? "no" : "yes"));
             mNotificationTrigger.setVisibility(show ? View.VISIBLE : View.GONE);
         }
         if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
             if ((state & StatusBarManager.DISABLE_EXPAND) != 0) {
-                Slog.d(TAG, "DISABLE_EXPAND: yes");
+                Slog.i(TAG, "DISABLE_EXPAND: yes");
                 animateCollapse();
             }
         }
         if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
             if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
-                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
+                Slog.i(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
                 // synchronize with current shadow state
                 mNotificationIconArea.setVisibility(View.GONE);
                 mTicker.halt();
             } else {
-                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
+                Slog.i(TAG, "DISABLE_NOTIFICATION_ICONS: no");
                 // synchronize with current shadow state
                 mNotificationIconArea.setVisibility(View.VISIBLE);
             }
@@ -764,11 +764,11 @@
         }
         if ((diff & StatusBarManager.DISABLE_NAVIGATION) != 0) {
             if ((state & StatusBarManager.DISABLE_NAVIGATION) != 0) {
-                Slog.d(TAG, "DISABLE_NAVIGATION: yes");
+                Slog.i(TAG, "DISABLE_NAVIGATION: yes");
                 mNavigationArea.setVisibility(View.GONE);
                 mInputMethodSwitchButton.setScreenLocked(true);
             } else {
-                Slog.d(TAG, "DISABLE_NAVIGATION: no");
+                Slog.i(TAG, "DISABLE_NAVIGATION: no");
                 mNavigationArea.setVisibility(View.VISIBLE);
                 mInputMethodSwitchButton.setScreenLocked(false);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
index 4ee985d..98f718b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
@@ -65,7 +65,9 @@
                 }
             }
         }
-        Slog.d(TabletStatusBar.TAG, "TabletStatusBarView not intercepting event");
+        if (TabletStatusBar.DEBUG) {
+            Slog.d(TabletStatusBar.TAG, "TabletStatusBarView not intercepting event");
+        }
         return super.onInterceptTouchEvent(ev);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
index fa732c3..440d680 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
@@ -111,7 +111,6 @@
 
     public void remove(IBinder key, boolean advance) {
         if (mCurrentKey == key) {
-            Slog.d(TAG, "removed current");
             // Showing now
             if (advance) {
                 removeMessages(MSG_ADVANCE);
@@ -121,7 +120,6 @@
             // In the queue
             for (int i=0; i<QUEUE_LENGTH; i++) {
                 if (mKeys[i] == key) {
-                    Slog.d(TAG, "removed from queue: " + i);
                     for (; i<QUEUE_LENGTH-1; i++) {
                         mKeys[i] = mKeys[i+1];
                         mQueue[i] = mQueue[i+1];
diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java
index 79fbe0e..1b810d5 100644
--- a/policy/src/com/android/internal/policy/impl/LockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/LockScreen.java
@@ -311,8 +311,8 @@
         setFocusableInTouchMode(true);
         setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
 
-        updateMonitor.registerInfoCallback(this);
-        updateMonitor.registerSimStateCallback(this);
+        mUpdateMonitor.registerInfoCallback(this);
+        mUpdateMonitor.registerSimStateCallback(this);
 
         mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
         mSilentMode = isSilentMode();
@@ -414,6 +414,9 @@
     public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn,
             int batteryLevel) {
         if (DBG) Log.d(TAG, "onRefreshBatteryInfo(" + showBatteryInfo + ", " + pluggedIn + ")");
+
+        mStatusView.onRefreshBatteryInfo(showBatteryInfo, pluggedIn, batteryLevel);
+
         mShowingBatteryInfo = showBatteryInfo;
         mPluggedIn = pluggedIn;
         mBatteryLevel = batteryLevel;
diff --git a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
index b789288..eb4d930 100644
--- a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
@@ -135,9 +135,12 @@
         // numeric keys.
         if (mIsAlpha) {
             mPasswordEntry.setKeyListener(TextKeyListener.getInstance());
+            mStatusView.setHelpMessage(R.string.keyguard_password_enter_password_code,
+                    StatusView.LOCK_ICON);
         } else {
             mPasswordEntry.setKeyListener(DigitsKeyListener.getInstance());
-            mStatusView.setInstructionText(R.string.keyguard_password_enter_pin_password_code);
+            mStatusView.setHelpMessage(R.string.keyguard_password_enter_pin_code,
+                    StatusView.LOCK_ICON);
         }
 
         mKeyboardHelper.setVibratePattern(mLockPatternUtils.isTactileFeedbackEnabled() ?
@@ -151,6 +154,11 @@
         mStatusView.setCarrierText(LockScreen.getCarrierString(
                         mUpdateMonitor.getTelephonyPlmn(),
                         mUpdateMonitor.getTelephonySpn()));
+
+        mUpdateMonitor.registerInfoCallback(this);
+        //mUpdateMonitor.registerSimStateCallback(this);
+
+        resetStatusInfo();
     }
 
     @Override
@@ -204,6 +212,7 @@
         if (mLockPatternUtils.checkPassword(entry)) {
             mCallback.keyguardDone(true);
             mCallback.reportSuccessfulUnlockAttempt();
+            mStatusView.setInstructionText(null);
         } else if (entry.length() > MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT ) {
             // to avoid accidental lockout, only count attempts that are long enough to be a
             // real password. This may require some tweaking.
@@ -316,11 +325,8 @@
     }
 
     private void resetStatusInfo() {
-        if(mIsAlpha) {
-            mStatusView.setInstructionText(R.string.keyguard_password_enter_password_code);
-        } else {
-            mStatusView.setInstructionText(R.string.keyguard_password_enter_pin_password_code);
-        }
+        mStatusView.setInstructionText(null);
+        mStatusView.updateStatusLines(true);
     }
 
 }
diff --git a/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java b/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java
index 5d1455e..6815d50 100644
--- a/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java
@@ -169,6 +169,9 @@
         }
 
         mStatusView = new StatusView(this, mUpdateMonitor, mLockPatternUtils);
+        // This shows up when no other information is required on status1
+        mStatusView.setHelpMessage(R.string.lockscreen_pattern_instructions,
+                StatusView.LOCK_ICON);
 
         mLockPatternView = (LockPatternView) findViewById(R.id.lockPattern);
 
@@ -216,8 +219,8 @@
         // assume normal footer mode for now
         updateFooter(FooterMode.Normal);
 
-        updateMonitor.registerInfoCallback(this);
-        updateMonitor.registerSimStateCallback(this);
+        mUpdateMonitor.registerInfoCallback(this);
+        mUpdateMonitor.registerSimStateCallback(this);
         setFocusableInTouchMode(true);
 
         // until we get an update...
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index d6b7366..68c1453 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -197,7 +197,8 @@
             /* Another feature is enabled and the user is trying to enable the custom title feature */
             throw new AndroidRuntimeException("You cannot combine custom titles with other title features");
         }
-        if (((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) && (featureId != FEATURE_CUSTOM_TITLE)) {
+        if (((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) &&
+                (featureId != FEATURE_CUSTOM_TITLE) && (featureId != FEATURE_ACTION_MODE_OVERLAY)) {
 
             /* Custom title feature is enabled and the user is trying to enable another feature */
             throw new AndroidRuntimeException("You cannot combine custom titles with other title features");
diff --git a/policy/src/com/android/internal/policy/impl/StatusView.java b/policy/src/com/android/internal/policy/impl/StatusView.java
index 1caf0b7..4b91b65 100644
--- a/policy/src/com/android/internal/policy/impl/StatusView.java
+++ b/policy/src/com/android/internal/policy/impl/StatusView.java
@@ -19,10 +19,10 @@
 import android.widget.TextView;
 
 class StatusView {
-    private static final int LOCK_ICON = R.drawable.ic_lock_idle_lock;
-    private static final int ALARM_ICON = R.drawable.ic_lock_idle_alarm;
-    private static final int CHARGING_ICON = R.drawable.ic_lock_idle_charging;
-    private static final int BATTERY_LOW_ICON = R.drawable.ic_lock_idle_low_battery;
+    public static final int LOCK_ICON = R.drawable.ic_lock_idle_lock;
+    public static final int ALARM_ICON = R.drawable.ic_lock_idle_alarm;
+    public static final int CHARGING_ICON = R.drawable.ic_lock_idle_charging;
+    public static final int BATTERY_LOW_ICON = R.drawable.ic_lock_idle_low_battery;
 
     private String mDateFormatString;
 
@@ -49,6 +49,8 @@
 
     private TextView mAlarmStatus;
     private LockPatternUtils mLockPatternUtils;
+    private int mHelpMessageId;
+    private int mHelpIconId;
 
     private View findViewById(int id) {
         return mView.findViewById(id);
@@ -123,13 +125,13 @@
     void setInstructionText(int stringId) {
         mStatus1.setText(stringId);
         mStatus1.setCompoundDrawablesWithIntrinsicBounds(LOCK_ICON, 0, 0, 0);
-        mStatus1.setVisibility(View.VISIBLE);
+        mStatus1.setVisibility(stringId != 0 ? View.VISIBLE : View.INVISIBLE);
     }
 
     void setInstructionText(String string) {
         mStatus1.setText(string);
         mStatus1.setCompoundDrawablesWithIntrinsicBounds(LOCK_ICON, 0, 0, 0);
-        mStatus1.setVisibility(View.VISIBLE);
+        mStatus1.setVisibility(TextUtils.isEmpty(string) ? View.INVISIBLE : View.VISIBLE);
     }
 
     void setCarrierText(int stringId) {
@@ -148,8 +150,8 @@
      */
     void updateStatusLines(boolean showStatusLines) {
         if (!showStatusLines) {
-            mStatus1.setVisibility(showStatusLines ? View.VISIBLE : View.GONE);
-            mAlarmStatus.setVisibility(showStatusLines ? View.VISIBLE : View.GONE);
+            mStatus1.setVisibility(showStatusLines ? View.VISIBLE : View.INVISIBLE);
+            mAlarmStatus.setVisibility(showStatusLines ? View.VISIBLE : View.INVISIBLE);
             return;
         }
 
@@ -171,15 +173,14 @@
             mAlarmStatus.setText(nextAlarm);
             mAlarmStatus.setVisibility(View.VISIBLE);
         } else {
-            mAlarmStatus.setVisibility(View.GONE);
+            mAlarmStatus.setVisibility(View.INVISIBLE);
         }
 
         // Update Status1
-        if (mInstructions != null) {
+        if (!TextUtils.isEmpty(mInstructions)) {
             // Instructions only
-            final int resId = TextUtils.isEmpty(mInstructions) ? 0 : LOCK_ICON;
             mStatus1.setText(mInstructions);
-            mStatus1.setCompoundDrawablesWithIntrinsicBounds(resId, 0, 0, 0);
+            mStatus1.setCompoundDrawablesWithIntrinsicBounds(LOCK_ICON, 0, 0, 0);
             mStatus1.setVisibility(View.VISIBLE);
         } else if (mShowingBatteryInfo) {
             // Battery status
@@ -199,13 +200,22 @@
             }
             mStatus1.setVisibility(View.VISIBLE);
         } else {
-            // nothing specific to show; show general instructions
-            mStatus1.setText(R.string.lockscreen_pattern_instructions);
-            mStatus1.setCompoundDrawablesWithIntrinsicBounds(LOCK_ICON, 0,0, 0);
-            mStatus1.setVisibility(View.VISIBLE);
+            // nothing specific to show; show help message and icon, if provided
+            if (mHelpMessageId != 0) {
+                mStatus1.setText(mHelpMessageId);
+                mStatus1.setCompoundDrawablesWithIntrinsicBounds(mHelpIconId, 0,0, 0);
+                mStatus1.setVisibility(View.VISIBLE);
+            } else {
+                mStatus1.setVisibility(View.INVISIBLE);
+            }
         }
     }
 
+    void setHelpMessage(int messageId, int iconId) {
+        mHelpMessageId = messageId;
+        mHelpIconId = iconId;
+    }
+
     void refreshTimeAndDateDisplay() {
         if (mHasDate) {
             mDate.setText(DateFormat.format(mDateFormatString, new Date()));
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index b5a4bd2..e314145 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -154,6 +154,24 @@
     return true;
 }
 
+static void dumpRegion(String8& dump, const SkRegion& region) {
+    if (region.isEmpty()) {
+        dump.append("<empty>");
+        return;
+    }
+
+    bool first = true;
+    for (SkRegion::Iterator it(region); !it.done(); it.next()) {
+        if (first) {
+            first = false;
+        } else {
+            dump.append("|");
+        }
+        const SkIRect& rect = it.rect();
+        dump.appendFormat("[%d,%d][%d,%d]", rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
+    }
+}
+
 
 // --- InputDispatcher ---
 
@@ -495,7 +513,7 @@
             if (!(flags & InputWindow::FLAG_NOT_TOUCHABLE)) {
                 bool isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE
                         | InputWindow::FLAG_NOT_TOUCH_MODAL)) == 0;
-                if (isTouchModal || window->touchableAreaContainsPoint(x, y)) {
+                if (isTouchModal || window->touchableRegionContainsPoint(x, y)) {
                     // Found window.
                     return window;
                 }
@@ -1188,7 +1206,7 @@
                 if (! (flags & InputWindow::FLAG_NOT_TOUCHABLE)) {
                     bool isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE
                             | InputWindow::FLAG_NOT_TOUCH_MODAL)) == 0;
-                    if (isTouchModal || window->touchableAreaContainsPoint(x, y)) {
+                    if (isTouchModal || window->touchableRegionContainsPoint(x, y)) {
                         if (! screenWasOff || flags & InputWindow::FLAG_TOUCHABLE_WHEN_WAKING) {
                             newTouchedWindow = window;
                         }
@@ -2884,9 +2902,7 @@
             dump.appendFormat(INDENT2 "%d: name='%s', paused=%s, hasFocus=%s, hasWallpaper=%s, "
                     "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, "
                     "frame=[%d,%d][%d,%d], "
-                    "visibleFrame=[%d,%d][%d,%d], "
-                    "touchableArea=[%d,%d][%d,%d], "
-                    "ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
+                    "touchableRegion=",
                     i, window.name.string(),
                     toString(window.paused),
                     toString(window.hasFocus),
@@ -2896,11 +2912,9 @@
                     window.layoutParamsFlags, window.layoutParamsType,
                     window.layer,
                     window.frameLeft, window.frameTop,
-                    window.frameRight, window.frameBottom,
-                    window.visibleFrameLeft, window.visibleFrameTop,
-                    window.visibleFrameRight, window.visibleFrameBottom,
-                    window.touchableAreaLeft, window.touchableAreaTop,
-                    window.touchableAreaRight, window.touchableAreaBottom,
+                    window.frameRight, window.frameBottom);
+            dumpRegion(dump, window.touchableRegion);
+            dump.appendFormat(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
                     window.ownerPid, window.ownerUid,
                     window.dispatchingTimeout / 1000000.0);
         }
diff --git a/services/input/InputWindow.cpp b/services/input/InputWindow.cpp
index 9ce45f5..b552f6d 100644
--- a/services/input/InputWindow.cpp
+++ b/services/input/InputWindow.cpp
@@ -24,9 +24,8 @@
 
 // --- InputWindow ---
 
-bool InputWindow::touchableAreaContainsPoint(int32_t x, int32_t y) const {
-    return x >= touchableAreaLeft && x <= touchableAreaRight
-            && y >= touchableAreaTop && y <= touchableAreaBottom;
+bool InputWindow::touchableRegionContainsPoint(int32_t x, int32_t y) const {
+    return touchableRegion.contains(x, y);
 }
 
 bool InputWindow::frameContainsPoint(int32_t x, int32_t y) const {
diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h
index b3d5a65..9c43067 100644
--- a/services/input/InputWindow.h
+++ b/services/input/InputWindow.h
@@ -23,6 +23,8 @@
 #include <utils/Timers.h>
 #include <utils/String8.h>
 
+#include <SkRegion.h>
+
 #include "InputApplication.h"
 
 namespace android {
@@ -129,14 +131,7 @@
     int32_t frameTop;
     int32_t frameRight;
     int32_t frameBottom;
-    int32_t visibleFrameLeft;
-    int32_t visibleFrameTop;
-    int32_t visibleFrameRight;
-    int32_t visibleFrameBottom;
-    int32_t touchableAreaLeft;
-    int32_t touchableAreaTop;
-    int32_t touchableAreaRight;
-    int32_t touchableAreaBottom;
+    SkRegion touchableRegion;
     bool visible;
     bool canReceiveKeys;
     bool hasFocus;
@@ -146,7 +141,7 @@
     int32_t ownerPid;
     int32_t ownerUid;
 
-    bool touchableAreaContainsPoint(int32_t x, int32_t y) const;
+    bool touchableRegionContainsPoint(int32_t x, int32_t y) const;
     bool frameContainsPoint(int32_t x, int32_t y) const;
 
     /* Returns true if the window is of a trusted type that is allowed to silently
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 2b98795..7b4f246 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -2540,16 +2540,16 @@
                 ArrayList<String>>> enabledImes, String imeId, String subtypeHashCode) {
             for (Pair<String, ArrayList<String>> enabledIme: enabledImes) {
                 if (enabledIme.first.equals(imeId)) {
-                    final ArrayList<String> enabledSubtypes = enabledIme.second;
-                    if (enabledSubtypes.size() == 0) {
-                        // If there are no enabled subtypes, applicable subtypes are enabled
-                        // implicitly.
+                    final ArrayList<String> explicitlyEnabledSubtypes = enabledIme.second;
+                    if (explicitlyEnabledSubtypes.size() == 0) {
+                        // If there are no explicitly enabled subtypes, applicable subtypes are
+                        // enabled implicitly.
                         InputMethodInfo ime = mMethodMap.get(imeId);
                         // If IME is enabled and no subtypes are enabled, applicable subtypes
                         // are enabled implicitly, so needs to treat them to be enabled.
                         if (ime != null && ime.getSubtypes().size() > 0) {
                             List<InputMethodSubtype> implicitlySelectedSubtypes =
-                                getApplicableSubtypesLocked(mRes, ime.getSubtypes());
+                                    getApplicableSubtypesLocked(mRes, ime.getSubtypes());
                             if (implicitlySelectedSubtypes != null) {
                                 final int N = implicitlySelectedSubtypes.size();
                                 for (int i = 0; i < N; ++i) {
@@ -2561,7 +2561,7 @@
                             }
                         }
                     } else {
-                        for (String s: enabledSubtypes) {
+                        for (String s: explicitlyEnabledSubtypes) {
                             if (s.equals(subtypeHashCode)) {
                                 // If both imeId and subtypeId are enabled, return subtypeId.
                                 return s;
diff --git a/services/java/com/android/server/InputWindow.java b/services/java/com/android/server/InputWindow.java
index 1515290..2c2cdfe 100644
--- a/services/java/com/android/server/InputWindow.java
+++ b/services/java/com/android/server/InputWindow.java
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import android.graphics.Region;
 import android.view.InputChannel;
 
 /**
@@ -39,23 +40,14 @@
     // Dispatching timeout.
     public long dispatchingTimeoutNanos;
 
-    // Window frame area.
+    // Window frame.
     public int frameLeft;
     public int frameTop;
     public int frameRight;
     public int frameBottom;
 
-    // Window visible frame area.
-    public int visibleFrameLeft;
-    public int visibleFrameTop;
-    public int visibleFrameRight;
-    public int visibleFrameBottom;
-
-    // Window touchable area.
-    public int touchableAreaLeft;
-    public int touchableAreaTop;
-    public int touchableAreaRight;
-    public int touchableAreaBottom;
+    // Window touchable region.
+    public final Region touchableRegion = new Region();
 
     // Window is visible.
     public boolean visible;
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 1c3967d..19667d4 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -4806,6 +4806,74 @@
         abstract void handleReturnCode();
     }
 
+    class MeasureParams extends HandlerParams {
+        private final PackageStats mStats;
+        private boolean mSuccess;
+
+        private final IPackageStatsObserver mObserver;
+
+        public MeasureParams(PackageStats stats, boolean success,
+                IPackageStatsObserver observer) {
+            mObserver = observer;
+            mStats = stats;
+            mSuccess = success;
+        }
+
+        @Override
+        void handleStartCopy() throws RemoteException {
+            final boolean mounted;
+
+            if (Environment.isExternalStorageEmulated()) {
+                mounted = true;
+            } else {
+                final String status = Environment.getExternalStorageState();
+
+                mounted = status.equals(Environment.MEDIA_MOUNTED)
+                        || status.equals(Environment.MEDIA_MOUNTED_READ_ONLY);
+            }
+
+            if (mounted) {
+                final File externalCacheDir = Environment
+                        .getExternalStorageAppCacheDirectory(mStats.packageName);
+                final long externalCacheSize = mContainerService
+                        .calculateDirectorySize(externalCacheDir.getPath());
+                mStats.externalCacheSize = externalCacheSize;
+
+                final File externalDataDir = Environment
+                        .getExternalStorageAppDataDirectory(mStats.packageName);
+                long externalDataSize = mContainerService.calculateDirectorySize(externalDataDir
+                        .getPath());
+
+                if (externalCacheDir.getParentFile().equals(externalDataDir)) {
+                    externalDataSize -= externalCacheSize;
+                }
+                mStats.externalDataSize = externalDataSize;
+
+                final File externalMediaDir = Environment
+                        .getExternalStorageAppMediaDirectory(mStats.packageName);
+                mStats.externalMediaSize = mContainerService
+                        .calculateDirectorySize(externalCacheDir.getPath());
+            }
+        }
+
+        @Override
+        void handleReturnCode() {
+            if (mObserver != null) {
+                try {
+                    mObserver.onGetStatsCompleted(mStats, mSuccess);
+                } catch (RemoteException e) {
+                    Slog.i(TAG, "Observer no longer exists.");
+                }
+            }
+        }
+
+        @Override
+        void handleServiceError() {
+            Slog.e(TAG, "Could not measure application " + mStats.packageName
+                            + " external storage");
+        }
+    }
+
     class InstallParams extends HandlerParams {
         final IPackageInstallObserver observer;
         int flags;
@@ -6619,18 +6687,16 @@
         mHandler.post(new Runnable() {
             public void run() {
                 mHandler.removeCallbacks(this);
-                PackageStats lStats = new PackageStats(packageName);
-                final boolean succeded;
+                PackageStats stats = new PackageStats(packageName);
+
+                final boolean success;
                 synchronized (mInstallLock) {
-                    succeded = getPackageSizeInfoLI(packageName, lStats);
+                    success = getPackageSizeInfoLI(packageName, stats);
                 }
-                if(observer != null) {
-                    try {
-                        observer.onGetStatsCompleted(lStats, succeded);
-                    } catch (RemoteException e) {
-                        Log.i(TAG, "Observer no longer exists.");
-                    }
-                } //end if observer
+
+                Message msg = mHandler.obtainMessage(INIT_COPY);
+                msg.obj = new MeasureParams(stats, success, observer);
+                mHandler.sendMessage(msg);
             } //end run
         });
     }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 6f4b4c5..978946f 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -204,11 +204,9 @@
             // TODO: Use a more reliable check to see if this product should
             // support Bluetooth - see bug 988521
             if (SystemProperties.get("ro.kernel.qemu").equals("1")) {
-                Slog.i(TAG, "Registering null Bluetooth Service (emulator)");
-                ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE, null);
+                Slog.i(TAG, "No Bluetooh Service (emulator)");
             } else if (factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
-                Slog.i(TAG, "Registering null Bluetooth Service (factory test)");
-                ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE, null);
+                Slog.i(TAG, "No Bluetooth Service (factory test)");
             } else {
                 Slog.i(TAG, "Bluetooth Service");
                 bluetooth = new BluetoothService(context);
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index bdc779c..1b3725c 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -520,7 +520,7 @@
         int mRotation;
         int mAnimFlags;
 
-        private final Rect tmpRect = new Rect();
+        private final Region mTmpRegion = new Region();
 
         DragState(IBinder token, Surface surface, int flags, IBinder localWin) {
             mToken = token;
@@ -816,31 +816,13 @@
                     // not touchable == don't tell about drags
                     continue;
                 }
-                // account for the window's decor etc
-                tmpRect.set(child.mFrame);
-                if (child.mTouchableInsets == ViewTreeObserver
-                            .InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT) {
-                    // The point is inside of the window if it is
-                    // inside the frame, AND the content part of that
-                    // frame that was given by the application.
-                    tmpRect.left += child.mGivenContentInsets.left;
-                    tmpRect.top += child.mGivenContentInsets.top;
-                    tmpRect.right -= child.mGivenContentInsets.right;
-                    tmpRect.bottom -= child.mGivenContentInsets.bottom;
-                } else if (child.mTouchableInsets == ViewTreeObserver
-                            .InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE) {
-                    // The point is inside of the window if it is
-                    // inside the frame, AND the visible part of that
-                    // frame that was given by the application.
-                    tmpRect.left += child.mGivenVisibleInsets.left;
-                    tmpRect.top += child.mGivenVisibleInsets.top;
-                    tmpRect.right -= child.mGivenVisibleInsets.right;
-                    tmpRect.bottom -= child.mGivenVisibleInsets.bottom;
-                }
+
+                child.getTouchableRegion(mTmpRegion);
+
                 final int touchFlags = flags &
-                    (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                    | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
-                if (tmpRect.contains(x, y) || touchFlags == 0) {
+                        (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                                | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
+                if (mTmpRegion.contains(x, y) || touchFlags == 0) {
                     // Found it
                     touchedWin = child;
                     break;
@@ -2667,7 +2649,7 @@
 
     void setInsetsWindow(Session session, IWindow client,
             int touchableInsets, Rect contentInsets,
-            Rect visibleInsets) {
+            Rect visibleInsets, Region touchableRegion) {
         long origId = Binder.clearCallingIdentity();
         try {
             synchronized (mWindowMap) {
@@ -2676,6 +2658,7 @@
                     w.mGivenInsetsPending = false;
                     w.mGivenContentInsets.set(contentInsets);
                     w.mGivenVisibleInsets.set(visibleInsets);
+                    w.mGivenTouchableRegion.set(touchableRegion);
                     w.mTouchableInsets = touchableInsets;
                     mLayoutNeeded = true;
                     performLayoutAndPlaceSurfacesLocked();
@@ -5882,7 +5865,7 @@
             final InputWindow inputWindow = windowList.add();
             inputWindow.inputChannel = mDragState.mServerChannel;
             inputWindow.name = "drag";
-            inputWindow.layoutParamsFlags = 0;
+            inputWindow.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
             inputWindow.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
             inputWindow.dispatchingTimeoutNanos = DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
             inputWindow.visible = true;
@@ -5900,15 +5883,8 @@
             inputWindow.frameRight = mDisplay.getWidth();
             inputWindow.frameBottom = mDisplay.getHeight();
 
-            inputWindow.visibleFrameLeft = inputWindow.frameLeft;
-            inputWindow.visibleFrameTop = inputWindow.frameTop;
-            inputWindow.visibleFrameRight = inputWindow.frameRight;
-            inputWindow.visibleFrameBottom = inputWindow.frameBottom;
-
-            inputWindow.touchableAreaLeft = inputWindow.frameLeft;
-            inputWindow.touchableAreaTop = inputWindow.frameTop;
-            inputWindow.touchableAreaRight = inputWindow.frameRight;
-            inputWindow.touchableAreaBottom = inputWindow.frameBottom;
+            // The drag window cannot receive new touches.
+            inputWindow.touchableRegion.setEmpty();
         }
 
         /* Updates the cached window information provided to the input dispatcher. */
@@ -5973,40 +5949,8 @@
                 inputWindow.frameTop = frame.top;
                 inputWindow.frameRight = frame.right;
                 inputWindow.frameBottom = frame.bottom;
-                
-                final Rect visibleFrame = child.mVisibleFrame;
-                inputWindow.visibleFrameLeft = visibleFrame.left;
-                inputWindow.visibleFrameTop = visibleFrame.top;
-                inputWindow.visibleFrameRight = visibleFrame.right;
-                inputWindow.visibleFrameBottom = visibleFrame.bottom;
-                
-                switch (child.mTouchableInsets) {
-                    default:
-                    case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME:
-                        inputWindow.touchableAreaLeft = frame.left;
-                        inputWindow.touchableAreaTop = frame.top;
-                        inputWindow.touchableAreaRight = frame.right;
-                        inputWindow.touchableAreaBottom = frame.bottom;
-                        break;
-                        
-                    case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT: {
-                        Rect inset = child.mGivenContentInsets;
-                        inputWindow.touchableAreaLeft = frame.left + inset.left;
-                        inputWindow.touchableAreaTop = frame.top + inset.top;
-                        inputWindow.touchableAreaRight = frame.right - inset.right;
-                        inputWindow.touchableAreaBottom = frame.bottom - inset.bottom;
-                        break;
-                    }
-                        
-                    case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE: {
-                        Rect inset = child.mGivenVisibleInsets;
-                        inputWindow.touchableAreaLeft = frame.left + inset.left;
-                        inputWindow.touchableAreaTop = frame.top + inset.top;
-                        inputWindow.touchableAreaRight = frame.right - inset.right;
-                        inputWindow.touchableAreaBottom = frame.bottom - inset.bottom;
-                        break;
-                    }
-                }
+
+                child.getTouchableRegion(inputWindow.touchableRegion);
             }
 
             // Send windows to native code.
@@ -6516,9 +6460,9 @@
         }
 
         public void setInsets(IWindow window, int touchableInsets,
-                Rect contentInsets, Rect visibleInsets) {
+                Rect contentInsets, Rect visibleInsets, Region touchableArea) {
             setInsetsWindow(this, window, touchableInsets, contentInsets,
-                    visibleInsets);
+                    visibleInsets, touchableArea);
         }
 
         public void getDisplayFrame(IWindow window, Rect outDisplayFrame) {
@@ -6648,7 +6592,7 @@
             synchronized (mWindowMap) {
                 long ident = Binder.clearCallingIdentity();
                 try {
-                    if (mDragState.mToken != token) {
+                    if (mDragState == null || mDragState.mToken != token) {
                         Slog.w(TAG, "Invalid drop-result claim by " + window);
                         throw new IllegalStateException("reportDropResult() by non-recipient");
                     }
@@ -6857,6 +6801,11 @@
         final Rect mGivenVisibleInsets = new Rect();
 
         /**
+         * This is the given touchable area relative to the window frame, or null if none.
+         */
+        final Region mGivenTouchableRegion = new Region();
+
+        /**
          * Flag indicating whether the touchable region should be adjusted by
          * the visible insets; if false the area outside the visible insets is
          * NOT touchable, so we must use those to adjust the frame during hit
@@ -8139,6 +8088,36 @@
             return true;
         }
 
+        public void getTouchableRegion(Region outRegion) {
+            final Rect frame = mFrame;
+            switch (mTouchableInsets) {
+                default:
+                case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME:
+                    outRegion.set(frame);
+                    break;
+                case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT: {
+                    final Rect inset = mGivenContentInsets;
+                    outRegion.set(
+                            frame.left + inset.left, frame.top + inset.top,
+                            frame.right - inset.right, frame.bottom - inset.bottom);
+                    break;
+                }
+                case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE: {
+                    final Rect inset = mGivenVisibleInsets;
+                    outRegion.set(
+                            frame.left + inset.left, frame.top + inset.top,
+                            frame.right - inset.right, frame.bottom - inset.bottom);
+                    break;
+                }
+                case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION: {
+                    final Region givenTouchableRegion = mGivenTouchableRegion;
+                    outRegion.set(givenTouchableRegion);
+                    outRegion.translate(frame.left, frame.top);
+                    break;
+                }
+            }
+        }
+
         void dump(PrintWriter pw, String prefix) {
             pw.print(prefix); pw.print("mSession="); pw.print(mSession);
                     pw.print(" mClient="); pw.println(mClient.asBinder());
diff --git a/services/jni/com_android_server_InputWindow.cpp b/services/jni/com_android_server_InputWindow.cpp
index a4609a0..75154567c 100644
--- a/services/jni/com_android_server_InputWindow.cpp
+++ b/services/jni/com_android_server_InputWindow.cpp
@@ -21,6 +21,7 @@
 #include <android_runtime/AndroidRuntime.h>
 
 #include <android_view_InputChannel.h>
+#include <android/graphics/Region.h>
 #include "com_android_server_InputWindow.h"
 #include "com_android_server_InputWindowHandle.h"
 
@@ -39,14 +40,7 @@
     jfieldID frameTop;
     jfieldID frameRight;
     jfieldID frameBottom;
-    jfieldID visibleFrameLeft;
-    jfieldID visibleFrameTop;
-    jfieldID visibleFrameRight;
-    jfieldID visibleFrameBottom;
-    jfieldID touchableAreaLeft;
-    jfieldID touchableAreaTop;
-    jfieldID touchableAreaRight;
-    jfieldID touchableAreaBottom;
+    jfieldID touchableRegion;
     jfieldID visible;
     jfieldID canReceiveKeys;
     jfieldID hasFocus;
@@ -108,22 +102,17 @@
             gInputWindowClassInfo.frameRight);
     outInputWindow->frameBottom = env->GetIntField(inputWindowObj,
             gInputWindowClassInfo.frameBottom);
-    outInputWindow->visibleFrameLeft = env->GetIntField(inputWindowObj,
-            gInputWindowClassInfo.visibleFrameLeft);
-    outInputWindow->visibleFrameTop = env->GetIntField(inputWindowObj,
-            gInputWindowClassInfo.visibleFrameTop);
-    outInputWindow->visibleFrameRight = env->GetIntField(inputWindowObj,
-            gInputWindowClassInfo.visibleFrameRight);
-    outInputWindow->visibleFrameBottom = env->GetIntField(inputWindowObj,
-            gInputWindowClassInfo.visibleFrameBottom);
-    outInputWindow->touchableAreaLeft = env->GetIntField(inputWindowObj,
-            gInputWindowClassInfo.touchableAreaLeft);
-    outInputWindow->touchableAreaTop = env->GetIntField(inputWindowObj,
-            gInputWindowClassInfo.touchableAreaTop);
-    outInputWindow->touchableAreaRight = env->GetIntField(inputWindowObj,
-            gInputWindowClassInfo.touchableAreaRight);
-    outInputWindow->touchableAreaBottom = env->GetIntField(inputWindowObj,
-            gInputWindowClassInfo.touchableAreaBottom);
+
+    jobject regionObj = env->GetObjectField(inputWindowObj,
+            gInputWindowClassInfo.touchableRegion);
+    if (regionObj) {
+        SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj);
+        outInputWindow->touchableRegion.set(*region);
+        env->DeleteLocalRef(regionObj);
+    } else {
+        outInputWindow->touchableRegion.setEmpty();
+    }
+
     outInputWindow->visible = env->GetBooleanField(inputWindowObj,
             gInputWindowClassInfo.visible);
     outInputWindow->canReceiveKeys = env->GetBooleanField(inputWindowObj,
@@ -187,29 +176,8 @@
     GET_FIELD_ID(gInputWindowClassInfo.frameBottom, gInputWindowClassInfo.clazz,
             "frameBottom", "I");
 
-    GET_FIELD_ID(gInputWindowClassInfo.visibleFrameLeft, gInputWindowClassInfo.clazz,
-            "visibleFrameLeft", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.visibleFrameTop, gInputWindowClassInfo.clazz,
-            "visibleFrameTop", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.visibleFrameRight, gInputWindowClassInfo.clazz,
-            "visibleFrameRight", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.visibleFrameBottom, gInputWindowClassInfo.clazz,
-            "visibleFrameBottom", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.touchableAreaLeft, gInputWindowClassInfo.clazz,
-            "touchableAreaLeft", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.touchableAreaTop, gInputWindowClassInfo.clazz,
-            "touchableAreaTop", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.touchableAreaRight, gInputWindowClassInfo.clazz,
-            "touchableAreaRight", "I");
-
-    GET_FIELD_ID(gInputWindowClassInfo.touchableAreaBottom, gInputWindowClassInfo.clazz,
-            "touchableAreaBottom", "I");
+    GET_FIELD_ID(gInputWindowClassInfo.touchableRegion, gInputWindowClassInfo.clazz,
+            "touchableRegion", "Landroid/graphics/Region;");
 
     GET_FIELD_ID(gInputWindowClassInfo.visible, gInputWindowClassInfo.clazz,
             "visible", "Z");
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 154b822..65ad956 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2132,6 +2132,9 @@
     sh = (!sh) ? hw_h : sh;
     const size_t size = sw * sh * 4;
 
+    LOGD("screenshot: sw=%d, sh=%d, minZ=%d, maxZ=%d",
+            sw, sh, minLayerZ, maxLayerZ);
+
     // make sure to clear all GL error flags
     while ( glGetError() != GL_NO_ERROR ) ;
 
@@ -2146,6 +2149,9 @@
             GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, tname);
 
     GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
+
+    LOGD("screenshot: FBO created, status=0x%x", status);
+
     if (status == GL_FRAMEBUFFER_COMPLETE_OES) {
 
         // invert everything, b/c glReadPixel() below will invert the FB
@@ -2161,6 +2167,8 @@
         glClearColor(0,0,0,1);
         glClear(GL_COLOR_BUFFER_BIT);
 
+        LOGD("screenshot: glClear() issued");
+
         const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
         const size_t count = layers.size();
         for (size_t i=0 ; i<count ; ++i) {
@@ -2171,6 +2179,8 @@
             }
         }
 
+        LOGD("screenshot: All layers rendered");
+
         // XXX: this is needed on tegra
         glScissor(0, 0, sw, sh);
 
@@ -2185,6 +2195,10 @@
                     new MemoryHeapBase(size, 0, "screen-capture") );
             void* const ptr = base->getBase();
             if (ptr) {
+
+                LOGD("screenshot: about to call glReadPixels(0,0,%d,%d,...,%p)",
+                        sw, sh, ptr);
+
                 // capture the screen with glReadPixels()
                 glReadPixels(0, 0, sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, ptr);
                 if (glGetError() == GL_NO_ERROR) {
@@ -2197,25 +2211,32 @@
             } else {
                 result = NO_MEMORY;
             }
+
+            LOGD("screenshot: glReadPixels() returned %s", strerror(result));
+
         }
         glEnable(GL_SCISSOR_TEST);
         glViewport(0, 0, hw_w, hw_h);
         glMatrixMode(GL_PROJECTION);
         glPopMatrix();
         glMatrixMode(GL_MODELVIEW);
-
-
     } else {
         result = BAD_VALUE;
     }
 
+    LOGD("screenshot: about to release FBO resources");
+
     // release FBO resources
     glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
     glDeleteRenderbuffersOES(1, &tname);
     glDeleteFramebuffersOES(1, &name);
 
+    LOGD("screenshot: about to call compositionComplete()");
+
     hw.compositionComplete();
 
+    LOGD("screenshot: result = %s", strerror(result));
+
     return result;
 }
 
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 3b52252..0b4fc51 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -164,6 +164,11 @@
     }
 
     @Override
+    public File getObbDir() {
+        throw new UnsupportedOperationException();
+    }
+    
+    @Override
     public File getCacheDir() {
         throw new UnsupportedOperationException();
     }
diff --git a/tools/layoutlib/bridge/Android.mk b/tools/layoutlib/bridge/Android.mk
index 9b7bc5f..a0a7307 100644
--- a/tools/layoutlib/bridge/Android.mk
+++ b/tools/layoutlib/bridge/Android.mk
@@ -20,10 +20,11 @@
 
 LOCAL_JAVA_LIBRARIES := \
 	kxml2-2.3.0 \
-	layoutlib_api-prebuilt \
-	ninepatch-prebuilt
+	layoutlib_api-prebuilt
 
-LOCAL_STATIC_JAVA_LIBRARIES := temp_layoutlib
+LOCAL_STATIC_JAVA_LIBRARIES := \
+	temp_layoutlib \
+	ninepatch-prebuilt
 
 LOCAL_MODULE := layoutlib
 
diff --git a/tools/layoutlib/bridge/src/com/android/ide/common/resources/ResourceResolver.java b/tools/layoutlib/bridge/src/com/android/ide/common/resources/ResourceResolver.java
new file mode 100644
index 0000000..4c500e7
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/ide/common/resources/ResourceResolver.java
@@ -0,0 +1,560 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ide.common.resources;
+
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.ide.common.rendering.api.StyleResourceValue;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+public class ResourceResolver {
+
+    public final static String RES_ANIMATOR = "animator";
+    public final static String RES_STYLE = "style";
+    public final static String RES_ATTR = "attr";
+    public final static String RES_DIMEN = "dimen";
+    public final static String RES_DRAWABLE = "drawable";
+    public final static String RES_COLOR = "color";
+    public final static String RES_LAYOUT = "layout";
+    public final static String RES_STRING = "string";
+    public final static String RES_ID = "id";
+
+    public final static String REFERENCE_NULL = "@null";
+
+    private final static String REFERENCE_STYLE = RES_STYLE + "/";
+    private final static String PREFIX_ANDROID_RESOURCE_REF = "@android:";
+    private final static String PREFIX_RESOURCE_REF = "@";
+    private final static String PREFIX_ANDROID_THEME_REF = "?android:";
+    private final static String PREFIX_THEME_REF = "?";
+    private final static String PREFIX_ANDROID = "android:";
+
+
+    private final IFrameworkResourceIdProvider mFrameworkProvider;
+    private final Map<String, Map<String, ResourceValue>>  mProjectResources;
+    private final Map<String, Map<String, ResourceValue>>  mFrameworkResources;
+    private final LayoutLog mLogger;
+
+    private final Map<StyleResourceValue, StyleResourceValue> mStyleInheritanceMap =
+        new HashMap<StyleResourceValue, StyleResourceValue>();
+    private StyleResourceValue mTheme;
+
+    public interface IFrameworkResourceIdProvider {
+        Integer getId(String resType, String resName);
+    }
+
+    private ResourceResolver(
+            IFrameworkResourceIdProvider provider,
+            Map<String, Map<String, ResourceValue>> projectResources,
+            Map<String, Map<String, ResourceValue>> frameworkResources,
+            LayoutLog logger) {
+        mFrameworkProvider = provider;
+        mProjectResources = projectResources;
+        mFrameworkResources = frameworkResources;
+        mLogger = logger;
+    }
+
+    /**
+     * Creates a new ResourceResolver object.
+     *
+     * @param IFrameworkResourceIdProvider an optional framework resource ID provider
+     * @param projectResources the project resources.
+     * @param frameworkResources the framework resources.
+     * @param themeName the name of the current theme.
+     * @param isProjectTheme Is this a project theme?
+     * @return
+     */
+    public static ResourceResolver create(
+            IFrameworkResourceIdProvider provider,
+            Map<String, Map<String, ResourceValue>> projectResources,
+            Map<String, Map<String, ResourceValue>> frameworkResources,
+            String themeName, boolean isProjectTheme, LayoutLog logger) {
+
+        ResourceResolver resolver = new ResourceResolver(provider,
+                projectResources, frameworkResources,
+                logger);
+
+        resolver.computeStyleMaps(themeName, isProjectTheme);
+
+        return resolver;
+    }
+
+    public StyleResourceValue getTheme() {
+        return mTheme;
+    }
+
+    /**
+     * Returns a framework resource by type and name. The returned resource is resolved.
+     * @param resourceType the type of the resource
+     * @param resourceName the name of the resource
+     */
+    public ResourceValue getFrameworkResource(String resourceType, String resourceName) {
+        return getResource(resourceType, resourceName, mFrameworkResources);
+    }
+
+    /**
+     * Returns a project resource by type and name. The returned resource is resolved.
+     * @param resourceType the type of the resource
+     * @param resourceName the name of the resource
+     */
+    public ResourceValue getProjectResource(String resourceType, String resourceName) {
+        return getResource(resourceType, resourceName, mProjectResources);
+    }
+
+    /**
+     * Returns the {@link ResourceValue} matching a given name in the current theme. If the
+     * item is not directly available in the theme, the method looks in its parent theme.
+     *
+     * @param itemName the name of the item to search for.
+     * @return the {@link ResourceValue} object or <code>null</code>
+     */
+    public ResourceValue findItemInTheme(String itemName) {
+        if (mTheme != null) {
+            return findItemInStyle(mTheme, itemName);
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns the {@link ResourceValue} matching a given name in a given style. If the
+     * item is not directly available in the style, the method looks in its parent style.
+     *
+     * @param style the style to search in
+     * @param itemName the name of the item to search for.
+     * @return the {@link ResourceValue} object or <code>null</code>
+     */
+    public ResourceValue findItemInStyle(StyleResourceValue style, String itemName) {
+        ResourceValue item = style.findValue(itemName);
+
+        // if we didn't find it, we look in the parent style (if applicable)
+        if (item == null && mStyleInheritanceMap != null) {
+            StyleResourceValue parentStyle = mStyleInheritanceMap.get(style);
+            if (parentStyle != null) {
+                return findItemInStyle(parentStyle, itemName);
+            }
+        }
+
+        return item;
+    }
+
+    /**
+     * Searches for, and returns a {@link ResourceValue} by its reference.
+     * <p/>
+     * The reference format can be:
+     * <pre>@resType/resName</pre>
+     * <pre>@android:resType/resName</pre>
+     * <pre>@resType/android:resName</pre>
+     * <pre>?resType/resName</pre>
+     * <pre>?android:resType/resName</pre>
+     * <pre>?resType/android:resName</pre>
+     * Any other string format will return <code>null</code>.
+     * <p/>
+     * The actual format of a reference is <pre>@[namespace:]resType/resName</pre> but this method
+     * only support the android namespace.
+     *
+     * @param reference the resource reference to search for.
+     * @param forceFrameworkOnly if true all references are considered to be toward framework
+     *      resource even if the reference does not include the android: prefix.
+     * @return a {@link ResourceValue} or <code>null</code>.
+     */
+    public ResourceValue findResValue(String reference, boolean forceFrameworkOnly) {
+        if (reference == null) {
+            return null;
+        }
+        if (reference.startsWith(PREFIX_THEME_REF)) {
+            // no theme? no need to go further!
+            if (mTheme == null) {
+                return null;
+            }
+
+            boolean frameworkOnly = false;
+
+            // eliminate the prefix from the string
+            if (reference.startsWith(PREFIX_ANDROID_THEME_REF)) {
+                frameworkOnly = true;
+                reference = reference.substring(PREFIX_ANDROID_THEME_REF.length());
+            } else {
+                reference = reference.substring(PREFIX_THEME_REF.length());
+            }
+
+            // at this point, value can contain type/name (drawable/foo for instance).
+            // split it to make sure.
+            String[] segments = reference.split("\\/");
+
+            // we look for the referenced item name.
+            String referenceName = null;
+
+            if (segments.length == 2) {
+                // there was a resType in the reference. If it's attr, we ignore it
+                // else, we assert for now.
+                if (RES_ATTR.equals(segments[0])) {
+                    referenceName = segments[1];
+                } else {
+                    // At this time, no support for ?type/name where type is not "attr"
+                    return null;
+                }
+            } else {
+                // it's just an item name.
+                referenceName = segments[0];
+            }
+
+            // now we look for android: in the referenceName in order to support format
+            // such as: ?attr/android:name
+            if (referenceName.startsWith(PREFIX_ANDROID)) {
+                frameworkOnly = true;
+                referenceName = referenceName.substring(PREFIX_ANDROID.length());
+            }
+
+            // Now look for the item in the theme, starting with the current one.
+            if (frameworkOnly) {
+                // FIXME for now we do the same as if it didn't specify android:
+                return findItemInStyle(mTheme, referenceName);
+            }
+
+            return findItemInStyle(mTheme, referenceName);
+        } else if (reference.startsWith(PREFIX_RESOURCE_REF)) {
+            boolean frameworkOnly = false;
+
+            // check for the specific null reference value.
+            if (REFERENCE_NULL.equals(reference)) {
+                return null;
+            }
+
+            // Eliminate the prefix from the string.
+            if (reference.startsWith(PREFIX_ANDROID_RESOURCE_REF)) {
+                frameworkOnly = true;
+                reference = reference.substring(
+                        PREFIX_ANDROID_RESOURCE_REF.length());
+            } else {
+                reference = reference.substring(PREFIX_RESOURCE_REF.length());
+            }
+
+            // at this point, value contains type/[android:]name (drawable/foo for instance)
+            String[] segments = reference.split("\\/");
+
+            // now we look for android: in the resource name in order to support format
+            // such as: @drawable/android:name
+            if (segments[1].startsWith(PREFIX_ANDROID)) {
+                frameworkOnly = true;
+                segments[1] = segments[1].substring(PREFIX_ANDROID.length());
+            }
+
+            return findResValue(segments[0], segments[1],
+                    forceFrameworkOnly ? true :frameworkOnly);
+        }
+
+        // Looks like the value didn't reference anything. Return null.
+        return null;
+    }
+
+    /**
+     * Resolves the value of a resource, if the value references a theme or resource value.
+     * <p/>
+     * This method ensures that it returns a {@link ResourceValue} object that does not
+     * reference another resource.
+     * If the resource cannot be resolved, it returns <code>null</code>.
+     * <p/>
+     * If a value that does not need to be resolved is given, the method will return a new
+     * instance of {@link ResourceValue} that contains the input value.
+     *
+     * @param type the type of the resource
+     * @param name the name of the attribute containing this value.
+     * @param value the resource value, or reference to resolve
+     * @param isFrameworkValue whether the value is a framework value.
+     *
+     * @return the resolved resource value or <code>null</code> if it failed to resolve it.
+     */
+    public ResourceValue resolveValue(String type, String name, String value,
+            boolean isFrameworkValue) {
+        if (value == null) {
+            return null;
+        }
+
+        // get the ResourceValue referenced by this value
+        ResourceValue resValue = findResValue(value, isFrameworkValue);
+
+        // if resValue is null, but value is not null, this means it was not a reference.
+        // we return the name/value wrapper in a ResourceValue. the isFramework flag doesn't
+        // matter.
+        if (resValue == null) {
+            return new ResourceValue(type, name, value, isFrameworkValue);
+        }
+
+        // we resolved a first reference, but we need to make sure this isn't a reference also.
+        return resolveResValue(resValue);
+    }
+
+    /**
+     * Returns the {@link ResourceValue} referenced by the value of <var>value</var>.
+     * <p/>
+     * This method ensures that it returns a {@link ResourceValue} object that does not
+     * reference another resource.
+     * If the resource cannot be resolved, it returns <code>null</code>.
+     * <p/>
+     * If a value that does not need to be resolved is given, the method will return the input
+     * value.
+     *
+     * @param value the value containing the reference to resolve.
+     * @return a {@link ResourceValue} object or <code>null</code>
+     */
+    public ResourceValue resolveResValue(ResourceValue value) {
+        if (value == null) {
+            return null;
+        }
+
+        // if the resource value is a style, we simply return it.
+        if (value instanceof StyleResourceValue) {
+            return value;
+        }
+
+        // else attempt to find another ResourceValue referenced by this one.
+        ResourceValue resolvedValue = findResValue(value.getValue(), value.isFramework());
+
+        // if the value did not reference anything, then we simply return the input value
+        if (resolvedValue == null) {
+            return value;
+        }
+
+        // otherwise, we attempt to resolve this new value as well
+        return resolveResValue(resolvedValue);
+    }
+
+
+    /**
+     * Searches for, and returns a {@link ResourceValue} by its name, and type.
+     * @param resType the type of the resource
+     * @param resName  the name of the resource
+     * @param frameworkOnly if <code>true</code>, the method does not search in the
+     * project resources
+     */
+    private ResourceValue findResValue(String resType, String resName, boolean frameworkOnly) {
+        // map of ResouceValue for the given type
+        Map<String, ResourceValue> typeMap;
+
+        // if allowed, search in the project resources first.
+        if (frameworkOnly == false) {
+            typeMap = mProjectResources.get(resType);
+            if (typeMap != null) {
+                ResourceValue item = typeMap.get(resName);
+                if (item != null) {
+                    return item;
+                }
+            }
+        }
+
+        // now search in the framework resources.
+        typeMap = mFrameworkResources.get(resType);
+        if (typeMap != null) {
+            ResourceValue item = typeMap.get(resName);
+            if (item != null) {
+                return item;
+            }
+
+            // if it was not found and the type is an id, it is possible that the ID was
+            // generated dynamically when compiling the framework resources.
+            // Look for it in the R map.
+            if (mFrameworkProvider != null && RES_ID.equals(resType)) {
+                if (mFrameworkProvider.getId(resType, resName) != null) {
+                    return new ResourceValue(resType, resName, true);
+                }
+            }
+        }
+
+        // didn't find the resource anywhere.
+        // This is normal if the resource is an ID that is generated automatically.
+        // For other resources, we output a warning
+        if ("+id".equals(resType) == false && "+android:id".equals(resType) == false) { //$NON-NLS-1$ //$NON-NLS-2$
+            mLogger.warning(LayoutLog.TAG_RESOURCES_RESOLVE,
+                    "Couldn't resolve resource @" +
+                    (frameworkOnly ? "android:" : "") + resType + "/" + resName,
+                    new ResourceValue(resType, resName, frameworkOnly));
+        }
+        return null;
+    }
+
+    ResourceValue getResource(String resourceType, String resourceName,
+            Map<String, Map<String, ResourceValue>> resourceRepository) {
+        Map<String, ResourceValue> typeMap = resourceRepository.get(resourceType);
+        if (typeMap != null) {
+            ResourceValue item = typeMap.get(resourceName);
+            if (item != null) {
+                item = resolveResValue(item);
+                return item;
+            }
+        }
+
+        // didn't find the resource anywhere.
+        return null;
+
+    }
+
+    /**
+     * Compute style information from the given list of style for the project and framework.
+     * @param themeName the name of the current theme.
+     * @param isProjectTheme Is this a project theme?
+     */
+    private void computeStyleMaps(String themeName, boolean isProjectTheme) {
+        Map<String, ResourceValue> projectStyleMap = mProjectResources.get(RES_STYLE);
+        Map<String, ResourceValue> frameworkStyleMap = mFrameworkResources.get(RES_STYLE);
+
+        if (projectStyleMap != null && frameworkStyleMap != null) {
+            // first, get the theme
+            ResourceValue theme = null;
+
+            // project theme names have been prepended with a *
+            if (isProjectTheme) {
+                theme = projectStyleMap.get(themeName);
+            } else {
+                theme = frameworkStyleMap.get(themeName);
+            }
+
+            if (theme instanceof StyleResourceValue) {
+                // compute the inheritance map for both the project and framework styles
+                computeStyleInheritance(projectStyleMap.values(), projectStyleMap,
+                        frameworkStyleMap);
+
+                // Compute the style inheritance for the framework styles/themes.
+                // Since, for those, the style parent values do not contain 'android:'
+                // we want to force looking in the framework style only to avoid using
+                // similarly named styles from the project.
+                // To do this, we pass null in lieu of the project style map.
+                computeStyleInheritance(frameworkStyleMap.values(), null /*inProjectStyleMap */,
+                        frameworkStyleMap);
+
+                mTheme = (StyleResourceValue) theme;
+            }
+        }
+    }
+
+
+
+    /**
+     * Compute the parent style for all the styles in a given list.
+     * @param styles the styles for which we compute the parent.
+     * @param inProjectStyleMap the map of project styles.
+     * @param inFrameworkStyleMap the map of framework styles.
+     * @param outInheritanceMap the map of style inheritance. This is filled by the method.
+     */
+    private void computeStyleInheritance(Collection<ResourceValue> styles,
+            Map<String, ResourceValue> inProjectStyleMap,
+            Map<String, ResourceValue> inFrameworkStyleMap) {
+        for (ResourceValue value : styles) {
+            if (value instanceof StyleResourceValue) {
+                StyleResourceValue style = (StyleResourceValue)value;
+                StyleResourceValue parentStyle = null;
+
+                // first look for a specified parent.
+                String parentName = style.getParentStyle();
+
+                // no specified parent? try to infer it from the name of the style.
+                if (parentName == null) {
+                    parentName = getParentName(value.getName());
+                }
+
+                if (parentName != null) {
+                    parentStyle = getStyle(parentName, inProjectStyleMap, inFrameworkStyleMap);
+
+                    if (parentStyle != null) {
+                        mStyleInheritanceMap.put(style, parentStyle);
+                    }
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Computes the name of the parent style, or <code>null</code> if the style is a root style.
+     */
+    private String getParentName(String styleName) {
+        int index = styleName.lastIndexOf('.');
+        if (index != -1) {
+            return styleName.substring(0, index);
+        }
+
+        return null;
+    }
+
+    /**
+     * Searches for and returns the {@link StyleResourceValue} from a given name.
+     * <p/>The format of the name can be:
+     * <ul>
+     * <li>[android:]&lt;name&gt;</li>
+     * <li>[android:]style/&lt;name&gt;</li>
+     * <li>@[android:]style/&lt;name&gt;</li>
+     * </ul>
+     * @param parentName the name of the style.
+     * @param inProjectStyleMap the project style map. Can be <code>null</code>
+     * @param inFrameworkStyleMap the framework style map.
+     * @return The matching {@link StyleResourceValue} object or <code>null</code> if not found.
+     */
+    private StyleResourceValue getStyle(String parentName,
+            Map<String, ResourceValue> inProjectStyleMap,
+            Map<String, ResourceValue> inFrameworkStyleMap) {
+        boolean frameworkOnly = false;
+
+        String name = parentName;
+
+        // remove the useless @ if it's there
+        if (name.startsWith(PREFIX_RESOURCE_REF)) {
+            name = name.substring(PREFIX_RESOURCE_REF.length());
+        }
+
+        // check for framework identifier.
+        if (name.startsWith(PREFIX_ANDROID)) {
+            frameworkOnly = true;
+            name = name.substring(PREFIX_ANDROID.length());
+        }
+
+        // at this point we could have the format <type>/<name>. we want only the name as long as
+        // the type is style.
+        if (name.startsWith(REFERENCE_STYLE)) {
+            name = name.substring(REFERENCE_STYLE.length());
+        } else if (name.indexOf('/') != -1) {
+            return null;
+        }
+
+        ResourceValue parent = null;
+
+        // if allowed, search in the project resources.
+        if (frameworkOnly == false && inProjectStyleMap != null) {
+            parent = inProjectStyleMap.get(name);
+        }
+
+        // if not found, then look in the framework resources.
+        if (parent == null) {
+            parent = inFrameworkStyleMap.get(name);
+        }
+
+        // make sure the result is the proper class type and return it.
+        if (parent instanceof StyleResourceValue) {
+            return (StyleResourceValue)parent;
+        }
+
+        assert false;
+        mLogger.error(LayoutLog.TAG_RESOURCES_RESOLVE,
+                String.format("Unable to resolve parent style name: %s", parentName),
+                null /*data*/);
+
+        return null;
+    }
+
+
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
index 194687e..112af1e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
@@ -41,25 +41,6 @@
 
     public final static String R = "com.android.internal.R";
 
-    public final static String PREFIX_ANDROID_RESOURCE_REF = "@android:";
-    public final static String PREFIX_RESOURCE_REF = "@";
-    public final static String PREFIX_ANDROID_THEME_REF = "?android:";
-    public final static String PREFIX_THEME_REF = "?";
-
-    public final static String PREFIX_ANDROID = "android:";
-
-    public final static String RES_ANIMATOR = "animator";
-    public final static String RES_STYLE = "style";
-    public final static String RES_ATTR = "attr";
-    public final static String RES_DIMEN = "dimen";
-    public final static String RES_DRAWABLE = "drawable";
-    public final static String RES_COLOR = "color";
-    public final static String RES_LAYOUT = "layout";
-    public final static String RES_STRING = "string";
-    public final static String RES_ID = "id";
-
-    public final static String REFERENCE_STYLE = RES_STYLE + "/";
-    public final static String REFERENCE_NULL = "@null";
 
     public final static String MATCH_PARENT = "match_parent";
     public final static String FILL_PARENT = "fill_parent";
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 82e217a..f633201 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
@@ -20,6 +20,7 @@
 import com.android.ide.common.rendering.api.LayoutLog;
 import com.android.ide.common.rendering.api.ResourceValue;
 import com.android.ide.common.rendering.api.StyleResourceValue;
+import com.android.ide.common.resources.ResourceResolver;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.BridgeConstants;
 import com.android.layoutlib.bridge.impl.Stack;
@@ -76,12 +77,9 @@
     private Resources mResources;
     private Theme mTheme;
     private final HashMap<View, Object> mViewKeyMap = new HashMap<View, Object>();
-    private final StyleResourceValue mThemeValues;
     private final Object mProjectKey;
     private final DisplayMetrics mMetrics;
-    private final Map<String, Map<String, ResourceValue>> mProjectResources;
-    private final Map<String, Map<String, ResourceValue>> mFrameworkResources;
-    private final Map<StyleResourceValue, StyleResourceValue> mStyleInheritanceMap;
+    private final ResourceResolver mResourceResolver;
 
     private final Map<Object, Map<String, String>> mDefaultPropMaps =
         new IdentityHashMap<Object, Map<String,String>>();
@@ -116,19 +114,13 @@
      * @param projectCallback
      */
     public BridgeContext(Object projectKey, DisplayMetrics metrics,
-            StyleResourceValue currentTheme,
-            Map<String, Map<String, ResourceValue>> projectResources,
-            Map<String, Map<String, ResourceValue>> frameworkResources,
-            Map<StyleResourceValue, StyleResourceValue> styleInheritanceMap,
+            ResourceResolver resourceResolver,
             IProjectCallback projectCallback) {
         mProjectKey = projectKey;
         mMetrics = metrics;
         mProjectCallback = projectCallback;
 
-        mThemeValues = currentTheme;
-        mProjectResources = projectResources;
-        mFrameworkResources = frameworkResources;
-        mStyleInheritanceMap = styleInheritanceMap;
+        mResourceResolver = resourceResolver;
 
         mFragments.mCurState = Fragment.CREATED;
         mFragments.mActivity = this;
@@ -180,6 +172,10 @@
         return mProjectCallback;
     }
 
+    public ResourceResolver getResolver() {
+        return mResourceResolver;
+    }
+
     public Map<String, String> getDefaultPropMap(Object key) {
         return mDefaultPropMaps.get(key);
     }
@@ -265,7 +261,7 @@
 
     @Override
     public final TypedArray obtainStyledAttributes(int[] attrs) {
-        return createStyleBasedTypedArray(mThemeValues, attrs);
+        return createStyleBasedTypedArray(mResourceResolver.getTheme(), attrs);
     }
 
     @Override
@@ -362,7 +358,8 @@
             customStyle = set.getAttributeValue(null /* namespace*/, "style");
         }
         if (customStyle != null) {
-            ResourceValue item = findResValue(customStyle, false /*forceFrameworkOnly*/);
+            ResourceValue item = mResourceResolver.findResValue(customStyle,
+                    false /*forceFrameworkOnly*/);
 
             if (item instanceof StyleResourceValue) {
                 defStyleValues = (StyleResourceValue)item;
@@ -378,22 +375,21 @@
             }
 
             // look for the style in the current theme, and its parent:
-            if (mThemeValues != null) {
-                ResourceValue item = findItemInStyle(mThemeValues, defStyleName);
+            ResourceValue item = mResourceResolver.findItemInTheme(defStyleName);
 
-                if (item != null) {
-                    // item is a reference to a style entry. Search for it.
-                    item = findResValue(item.getValue(), false /*forceFrameworkOnly*/);
+            if (item != null) {
+                // item is a reference to a style entry. Search for it.
+                item = mResourceResolver.findResValue(item.getValue(),
+                        false /*forceFrameworkOnly*/);
 
-                    if (item instanceof StyleResourceValue) {
-                        defStyleValues = (StyleResourceValue)item;
-                    }
-                } else {
-                    Bridge.getLog().error(null,
-                            String.format(
-                                    "Failed to find style '%s' in current theme", defStyleName),
-                            null /*data*/);
+                if (item instanceof StyleResourceValue) {
+                    defStyleValues = (StyleResourceValue)item;
                 }
+            } else {
+                Bridge.getLog().error(null,
+                        String.format(
+                                "Failed to find style '%s' in current theme", defStyleName),
+                        null /*data*/);
             }
         }
 
@@ -425,13 +421,13 @@
 
                     // look for the value in the defStyle first (and its parent if needed)
                     if (defStyleValues != null) {
-                        resValue = findItemInStyle(defStyleValues, name);
+                        resValue = mResourceResolver.findItemInStyle(defStyleValues, name);
                     }
 
                     // if the item is not present in the defStyle, we look in the main theme (and
                     // its parent themes)
-                    if (resValue == null && mThemeValues != null) {
-                        resValue = findItemInStyle(mThemeValues, name);
+                    if (resValue == null) {
+                        resValue = mResourceResolver.findItemInTheme(name);
                     }
 
                     // if we found a value, we make sure this doesn't reference another value.
@@ -442,14 +438,15 @@
                             defaultPropMap.put(name, resValue.getValue());
                         }
 
-                        resValue = resolveResValue(resValue);
+                        resValue = mResourceResolver.resolveResValue(resValue);
                     }
 
                     ta.bridgeSetValue(index, name, resValue);
                 } else {
                     // there is a value in the XML, but we need to resolve it in case it's
                     // referencing another resource or a theme value.
-                    ta.bridgeSetValue(index, name, resolveValue(null, name, value, isPlatformFile));
+                    ta.bridgeSetValue(index, name,
+                            mResourceResolver.resolveValue(null, name, value, isPlatformFile));
                 }
             }
         }
@@ -487,10 +484,10 @@
             String name = styleAttribute.getValue();
 
             // get the value from the style, or its parent styles.
-            ResourceValue resValue = findItemInStyle(style, name);
+            ResourceValue resValue = mResourceResolver.findItemInStyle(style, name);
 
             // resolve it to make sure there are no references left.
-            ta.bridgeSetValue(index, name, resolveResValue(resValue));
+            ta.bridgeSetValue(index, name, mResourceResolver.resolveResValue(resValue));
         }
 
         ta.sealArray();
@@ -500,295 +497,6 @@
 
 
     /**
-     * Resolves the value of a resource, if the value references a theme or resource value.
-     * <p/>
-     * This method ensures that it returns a {@link ResourceValue} object that does not
-     * reference another resource.
-     * If the resource cannot be resolved, it returns <code>null</code>.
-     * <p/>
-     * If a value that does not need to be resolved is given, the method will return a new
-     * instance of {@link ResourceValue} that contains the input value.
-     *
-     * @param type the type of the resource
-     * @param name the name of the attribute containing this value.
-     * @param value the resource value, or reference to resolve
-     * @param isFrameworkValue whether the value is a framework value.
-     *
-     * @return the resolved resource value or <code>null</code> if it failed to resolve it.
-     */
-    private ResourceValue resolveValue(String type, String name, String value,
-            boolean isFrameworkValue) {
-        if (value == null) {
-            return null;
-        }
-
-        // get the ResourceValue referenced by this value
-        ResourceValue resValue = findResValue(value, isFrameworkValue);
-
-        // if resValue is null, but value is not null, this means it was not a reference.
-        // we return the name/value wrapper in a ResourceValue. the isFramework flag doesn't
-        // matter.
-        if (resValue == null) {
-            return new ResourceValue(type, name, value, isFrameworkValue);
-        }
-
-        // we resolved a first reference, but we need to make sure this isn't a reference also.
-        return resolveResValue(resValue);
-    }
-
-    /**
-     * Returns the {@link ResourceValue} referenced by the value of <var>value</var>.
-     * <p/>
-     * This method ensures that it returns a {@link ResourceValue} object that does not
-     * reference another resource.
-     * If the resource cannot be resolved, it returns <code>null</code>.
-     * <p/>
-     * If a value that does not need to be resolved is given, the method will return the input
-     * value.
-     *
-     * @param value the value containing the reference to resolve.
-     * @return a {@link ResourceValue} object or <code>null</code>
-     */
-    public ResourceValue resolveResValue(ResourceValue value) {
-        if (value == null) {
-            return null;
-        }
-
-        // if the resource value is a style, we simply return it.
-        if (value instanceof StyleResourceValue) {
-            return value;
-        }
-
-        // else attempt to find another ResourceValue referenced by this one.
-        ResourceValue resolvedValue = findResValue(value.getValue(), value.isFramework());
-
-        // if the value did not reference anything, then we simply return the input value
-        if (resolvedValue == null) {
-            return value;
-        }
-
-        // otherwise, we attempt to resolve this new value as well
-        return resolveResValue(resolvedValue);
-    }
-
-    /**
-     * Searches for, and returns a {@link ResourceValue} by its reference.
-     * <p/>
-     * The reference format can be:
-     * <pre>@resType/resName</pre>
-     * <pre>@android:resType/resName</pre>
-     * <pre>@resType/android:resName</pre>
-     * <pre>?resType/resName</pre>
-     * <pre>?android:resType/resName</pre>
-     * <pre>?resType/android:resName</pre>
-     * Any other string format will return <code>null</code>.
-     * <p/>
-     * The actual format of a reference is <pre>@[namespace:]resType/resName</pre> but this method
-     * only support the android namespace.
-     *
-     * @param reference the resource reference to search for.
-     * @param forceFrameworkOnly if true all references are considered to be toward framework
-     *      resource even if the reference does not include the android: prefix.
-     * @return a {@link ResourceValue} or <code>null</code>.
-     */
-    ResourceValue findResValue(String reference, boolean forceFrameworkOnly) {
-        if (reference == null) {
-            return null;
-        }
-        if (reference.startsWith(BridgeConstants.PREFIX_THEME_REF)) {
-            // no theme? no need to go further!
-            if (mThemeValues == null) {
-                return null;
-            }
-
-            boolean frameworkOnly = false;
-
-            // eliminate the prefix from the string
-            if (reference.startsWith(BridgeConstants.PREFIX_ANDROID_THEME_REF)) {
-                frameworkOnly = true;
-                reference = reference.substring(BridgeConstants.PREFIX_ANDROID_THEME_REF.length());
-            } else {
-                reference = reference.substring(BridgeConstants.PREFIX_THEME_REF.length());
-            }
-
-            // at this point, value can contain type/name (drawable/foo for instance).
-            // split it to make sure.
-            String[] segments = reference.split("\\/");
-
-            // we look for the referenced item name.
-            String referenceName = null;
-
-            if (segments.length == 2) {
-                // there was a resType in the reference. If it's attr, we ignore it
-                // else, we assert for now.
-                if (BridgeConstants.RES_ATTR.equals(segments[0])) {
-                    referenceName = segments[1];
-                } else {
-                    // At this time, no support for ?type/name where type is not "attr"
-                    return null;
-                }
-            } else {
-                // it's just an item name.
-                referenceName = segments[0];
-            }
-
-            // now we look for android: in the referenceName in order to support format
-            // such as: ?attr/android:name
-            if (referenceName.startsWith(BridgeConstants.PREFIX_ANDROID)) {
-                frameworkOnly = true;
-                referenceName = referenceName.substring(BridgeConstants.PREFIX_ANDROID.length());
-            }
-
-            // Now look for the item in the theme, starting with the current one.
-            if (frameworkOnly) {
-                // FIXME for now we do the same as if it didn't specify android:
-                return findItemInStyle(mThemeValues, referenceName);
-            }
-
-            return findItemInStyle(mThemeValues, referenceName);
-        } else if (reference.startsWith(BridgeConstants.PREFIX_RESOURCE_REF)) {
-            boolean frameworkOnly = false;
-
-            // check for the specific null reference value.
-            if (BridgeConstants.REFERENCE_NULL.equals(reference)) {
-                return null;
-            }
-
-            // Eliminate the prefix from the string.
-            if (reference.startsWith(BridgeConstants.PREFIX_ANDROID_RESOURCE_REF)) {
-                frameworkOnly = true;
-                reference = reference.substring(
-                        BridgeConstants.PREFIX_ANDROID_RESOURCE_REF.length());
-            } else {
-                reference = reference.substring(BridgeConstants.PREFIX_RESOURCE_REF.length());
-            }
-
-            // at this point, value contains type/[android:]name (drawable/foo for instance)
-            String[] segments = reference.split("\\/");
-
-            // now we look for android: in the resource name in order to support format
-            // such as: @drawable/android:name
-            if (segments[1].startsWith(BridgeConstants.PREFIX_ANDROID)) {
-                frameworkOnly = true;
-                segments[1] = segments[1].substring(BridgeConstants.PREFIX_ANDROID.length());
-            }
-
-            return findResValue(segments[0], segments[1],
-                    forceFrameworkOnly ? true :frameworkOnly);
-        }
-
-        // Looks like the value didn't reference anything. Return null.
-        return null;
-    }
-
-    /**
-     * Searches for, and returns a {@link ResourceValue} by its name, and type.
-     * @param resType the type of the resource
-     * @param resName  the name of the resource
-     * @param frameworkOnly if <code>true</code>, the method does not search in the
-     * project resources
-     */
-    private ResourceValue findResValue(String resType, String resName, boolean frameworkOnly) {
-        // map of ResouceValue for the given type
-        Map<String, ResourceValue> typeMap;
-
-        // if allowed, search in the project resources first.
-        if (frameworkOnly == false) {
-            typeMap = mProjectResources.get(resType);
-            if (typeMap != null) {
-                ResourceValue item = typeMap.get(resName);
-                if (item != null) {
-                    return item;
-                }
-            }
-        }
-
-        // now search in the framework resources.
-        typeMap = mFrameworkResources.get(resType);
-        if (typeMap != null) {
-            ResourceValue item = typeMap.get(resName);
-            if (item != null) {
-                return item;
-            }
-
-            // if it was not found and the type is an id, it is possible that the ID was
-            // generated dynamically when compiling the framework resources.
-            // Look for it in the R map.
-            if (BridgeConstants.RES_ID.equals(resType)) {
-                if (Bridge.getResourceValue(resType, resName) != null) {
-                    return new ResourceValue(resType, resName, true);
-                }
-            }
-        }
-
-        // didn't find the resource anywhere.
-        // This is normal if the resource is an ID that is generated automatically.
-        // For other resources, we output a warning
-        if ("+id".equals(resType) == false && "+android:id".equals(resType) == false) { //$NON-NLS-1$ //$NON-NLS-2$
-            Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_RESOLVE,
-                    "Couldn't resolve resource @" +
-                    (frameworkOnly ? "android:" : "") + resType + "/" + resName,
-                    new ResourceValue(resType, resName, frameworkOnly));
-        }
-        return null;
-    }
-
-    /**
-     * Returns a framework resource by type and name. The returned resource is resolved.
-     * @param resourceType the type of the resource
-     * @param resourceName the name of the resource
-     */
-    public ResourceValue getFrameworkResource(String resourceType, String resourceName) {
-        return getResource(resourceType, resourceName, mFrameworkResources);
-    }
-
-    /**
-     * Returns a project resource by type and name. The returned resource is resolved.
-     * @param resourceType the type of the resource
-     * @param resourceName the name of the resource
-     */
-    public ResourceValue getProjectResource(String resourceType, String resourceName) {
-        return getResource(resourceType, resourceName, mProjectResources);
-    }
-
-    ResourceValue getResource(String resourceType, String resourceName,
-            Map<String, Map<String, ResourceValue>> resourceRepository) {
-        Map<String, ResourceValue> typeMap = resourceRepository.get(resourceType);
-        if (typeMap != null) {
-            ResourceValue item = typeMap.get(resourceName);
-            if (item != null) {
-                item = resolveResValue(item);
-                return item;
-            }
-        }
-
-        // didn't find the resource anywhere.
-        return null;
-
-    }
-
-    /**
-     * Returns the {@link ResourceValue} matching a given name in a given style. If the
-     * item is not directly available in the style, the method looks in its parent style.
-     * @param style the style to search in
-     * @param itemName the name of the item to search for.
-     * @return the {@link ResourceValue} object or <code>null</code>
-     */
-    public ResourceValue findItemInStyle(StyleResourceValue style, String itemName) {
-        ResourceValue item = style.findValue(itemName);
-
-        // if we didn't find it, we look in the parent style (if applicable)
-        if (item == null && mStyleInheritanceMap != null) {
-            StyleResourceValue parentStyle = mStyleInheritanceMap.get(style);
-            if (parentStyle != null) {
-                return findItemInStyle(parentStyle, itemName);
-            }
-        }
-
-        return item;
-    }
-
-    /**
      * The input int[] attrs is one of com.android.internal.R.styleable fields where the name
      * of the field is the style being referenced and the array contains one index per attribute.
      * <p/>
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
index e95d295b..61f47ba 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
@@ -19,8 +19,8 @@
 import com.android.ide.common.rendering.api.IProjectCallback;
 import com.android.ide.common.rendering.api.LayoutLog;
 import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.ide.common.resources.ResourceResolver;
 import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.BridgeConstants;
 
 import org.kxml2.io.KXmlParser;
 import org.xmlpull.v1.XmlPullParser;
@@ -155,14 +155,14 @@
 
             String[] layoutInfo = Bridge.resolveResourceValue(resource);
             if (layoutInfo != null) {
-                value = bridgeContext.getFrameworkResource(BridgeConstants.RES_LAYOUT,
-                        layoutInfo[0]);
+                value = bridgeContext.getResolver().getFrameworkResource(
+                        ResourceResolver.RES_LAYOUT, layoutInfo[0]);
             } else {
                 layoutInfo = mProjectCallback.resolveResourceValue(resource);
 
                 if (layoutInfo != null) {
-                    value = bridgeContext.getProjectResource(BridgeConstants.RES_LAYOUT,
-                            layoutInfo[0]);
+                    value = bridgeContext.getResolver().getProjectResource(
+                            ResourceResolver.RES_LAYOUT, layoutInfo[0]);
                 }
             }
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
index 23d81a2..3af6a1b 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
@@ -104,7 +104,7 @@
 
         if (resourceInfo != null) {
             platformResFlag_out[0] = true;
-            return mContext.getFrameworkResource(resourceInfo[1], resourceInfo[0]);
+            return mContext.getResolver().getFrameworkResource(resourceInfo[1], resourceInfo[0]);
         }
 
         // didn't find a match in the framework? look in the project.
@@ -113,7 +113,7 @@
 
             if (resourceInfo != null) {
                 platformResFlag_out[0] = false;
-                return mContext.getProjectResource(resourceInfo[1], resourceInfo[0]);
+                return mContext.getResolver().getProjectResource(resourceInfo[1], resourceInfo[0]);
             }
         }
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
index 84bb4d1..b166da5 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
@@ -19,6 +19,7 @@
 import com.android.ide.common.rendering.api.LayoutLog;
 import com.android.ide.common.rendering.api.ResourceValue;
 import com.android.ide.common.rendering.api.StyleResourceValue;
+import com.android.ide.common.resources.ResourceResolver;
 import com.android.internal.util.XmlUtils;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.BridgeConstants;
@@ -633,11 +634,11 @@
             // 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(BridgeConstants.RES_ID, idName, defValue);
+                return mContext.getFrameworkResourceValue(ResourceResolver.RES_ID, idName, defValue);
             }
 
             // look for idName in the project R class.
-            return mContext.getProjectResourceValue(BridgeConstants.RES_ID, idName, defValue);
+            return mContext.getProjectResourceValue(ResourceResolver.RES_ID, idName, defValue);
         }
 
         // not a direct id valid reference? resolve it
@@ -682,7 +683,7 @@
 
         ResourceValue value = mResourceData[index];
         String stringValue = value.getValue();
-        if (stringValue == null || BridgeConstants.REFERENCE_NULL.equals(stringValue)) {
+        if (stringValue == null || ResourceResolver.REFERENCE_NULL.equals(stringValue)) {
             return null;
         }
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index 443d881..8422d48 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -102,7 +102,7 @@
     }
 
     public void setInsets(IWindow window, int touchable, Rect contentInsets,
-            Rect visibleInsets) {
+            Rect visibleInsets, Region touchableRegion) {
         // pass for now.
     }
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlPullAttributes.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlPullAttributes.java
index ba45217..45d8e26 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlPullAttributes.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlPullAttributes.java
@@ -17,6 +17,7 @@
 package com.android.layoutlib.bridge.android;
 
 import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.ide.common.resources.ResourceResolver;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.BridgeConstants;
 
@@ -57,7 +58,7 @@
         String ns = mParser.getAttributeNamespace(index);
 
         if (BridgeConstants.NS_RESOURCES.equals(ns)) {
-            Integer v = Bridge.getResourceValue(BridgeConstants.RES_ATTR, name);
+            Integer v = Bridge.getResourceValue(ResourceResolver.RES_ATTR, name);
             if (v != null) {
                 return v.intValue();
             }
@@ -68,7 +69,7 @@
         // this is not an attribute in the android namespace, we query the customviewloader, if
         // the namespaces match.
         if (mContext.getProjectCallback().getNamespace().equals(ns)) {
-            Integer v = mContext.getProjectCallback().getResourceValue(BridgeConstants.RES_ATTR,
+            Integer v = mContext.getProjectCallback().getResourceValue(ResourceResolver.RES_ATTR,
                     name);
             if (v != null) {
                 return v.intValue();
@@ -102,8 +103,9 @@
 
     private int resolveResourceValue(String value, int defaultValue) {
         // now look for this particular value
-        ResourceValue resource = mContext.resolveResValue(
-                mContext.findResValue(value, mPlatformFile));
+        ResourceResolver resolver = mContext.getResolver();
+        ResourceValue resource = resolver.resolveResValue(
+                resolver.findResValue(value, mPlatformFile));
 
         if (resource != null) {
             Integer id = null;
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 2439791..a227d0c 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
@@ -38,9 +38,10 @@
 import com.android.ide.common.rendering.api.ViewInfo;
 import com.android.ide.common.rendering.api.Params.RenderingMode;
 import com.android.ide.common.rendering.api.Result.Status;
+import com.android.ide.common.resources.ResourceResolver;
+import com.android.ide.common.resources.ResourceResolver.IFrameworkResourceIdProvider;
 import com.android.internal.util.XmlUtils;
 import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.BridgeConstants;
 import com.android.layoutlib.bridge.android.BridgeContext;
 import com.android.layoutlib.bridge.android.BridgeInflater;
 import com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes;
@@ -73,8 +74,6 @@
 import java.awt.Graphics2D;
 import java.awt.image.BufferedImage;
 import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
@@ -106,7 +105,6 @@
     private BridgeContext mContext;
     private BridgeXmlBlockParser mBlockParser;
     private BridgeInflater mInflater;
-    private StyleResourceValue mCurrentTheme;
     private int mScreenOffset;
     private ResourceValue mWindowBackground;
     private FrameLayout mViewRoot;
@@ -170,18 +168,23 @@
         metrics.xdpi = mParams.getXdpi();
         metrics.ydpi = mParams.getYdpi();
 
-        // find the current theme and compute the style inheritance map
-        Map<StyleResourceValue, StyleResourceValue> styleParentMap =
-            new HashMap<StyleResourceValue, StyleResourceValue>();
+        // create the resource resolver
+        ResourceResolver resolver = ResourceResolver.create(
+                new IFrameworkResourceIdProvider() {
+                    public Integer getId(String resType, String resName) {
+                        return Bridge.getResourceValue(resType, resName);
+                    }
+                },
+                mParams.getProjectResources(),
+                mParams.getFrameworkResources(),
+                mParams.getThemeName(),
+                mParams.isProjectTheme(),
+                mParams.getLog());
 
-        mCurrentTheme = computeStyleMaps(mParams.getThemeName(), mParams.isProjectTheme(),
-                mParams.getProjectResources().get(BridgeConstants.RES_STYLE),
-                mParams.getFrameworkResources().get(BridgeConstants.RES_STYLE), styleParentMap);
 
         // build the context
-        mContext = new BridgeContext(mParams.getProjectKey(), metrics, mCurrentTheme,
-                mParams.getProjectResources(), mParams.getFrameworkResources(),
-                styleParentMap, mParams.getProjectCallback());
+        mContext = new BridgeContext(mParams.getProjectKey(), metrics, resolver,
+                mParams.getProjectCallback());
 
         // set the current rendering context
         sCurrentContext = mContext;
@@ -193,12 +196,12 @@
         // get the screen offset and window-background resource
         mWindowBackground = null;
         mScreenOffset = 0;
-        if (mCurrentTheme != null && mParams.isBgColorOverridden() == false) {
-            mWindowBackground = mContext.findItemInStyle(mCurrentTheme, "windowBackground");
-            mWindowBackground = mContext.resolveResValue(mWindowBackground);
+        StyleResourceValue theme = resolver.getTheme();
+        if (theme != null && mParams.isBgColorOverridden() == false) {
+            mWindowBackground = resolver.findItemInTheme("windowBackground");
+            mWindowBackground = resolver.resolveResValue(mWindowBackground);
 
-            mScreenOffset = getScreenOffset(mParams.getFrameworkResources(), mCurrentTheme,
-                    mContext);
+            mScreenOffset = getScreenOffset(resolver, metrics);
         }
 
         // build the inflater and parser.
@@ -499,18 +502,18 @@
         ResourceValue animationResource = null;
         int animationId = 0;
         if (isFrameworkAnimation) {
-            animationResource = mContext.getFrameworkResource(BridgeConstants.RES_ANIMATOR,
-                    animationName);
+            animationResource = mContext.getResolver().getFrameworkResource(
+                    ResourceResolver.RES_ANIMATOR, animationName);
             if (animationResource != null) {
-                animationId = Bridge.getResourceValue(BridgeConstants.RES_ANIMATOR,
+                animationId = Bridge.getResourceValue(ResourceResolver.RES_ANIMATOR,
                         animationName);
             }
         } else {
-            animationResource = mContext.getProjectResource(BridgeConstants.RES_ANIMATOR,
-                    animationName);
+            animationResource = mContext.getResolver().getProjectResource(
+                    ResourceResolver.RES_ANIMATOR, animationName);
             if (animationResource != null) {
                 animationId = mContext.getProjectCallback().getResourceValue(
-                        BridgeConstants.RES_ANIMATOR, animationName);
+                        ResourceResolver.RES_ANIMATOR, animationName);
             }
         }
 
@@ -905,182 +908,21 @@
         }
     }
 
-
-    /**
-     * Compute style information from the given list of style for the project and framework.
-     * @param themeName the name of the current theme.  In order to differentiate project and
-     * platform themes sharing the same name, all project themes must be prepended with
-     * a '*' character.
-     * @param isProjectTheme Is this a project theme
-     * @param inProjectStyleMap the project style map
-     * @param inFrameworkStyleMap the framework style map
-     * @param outInheritanceMap the map of style inheritance. This is filled by the method
-     * @return the {@link StyleResourceValue} matching <var>themeName</var>
-     */
-    private StyleResourceValue computeStyleMaps(
-            String themeName, boolean isProjectTheme, Map<String,
-            ResourceValue> inProjectStyleMap, Map<String, ResourceValue> inFrameworkStyleMap,
-            Map<StyleResourceValue, StyleResourceValue> outInheritanceMap) {
-
-        if (inProjectStyleMap != null && inFrameworkStyleMap != null) {
-            // first, get the theme
-            ResourceValue theme = null;
-
-            // project theme names have been prepended with a *
-            if (isProjectTheme) {
-                theme = inProjectStyleMap.get(themeName);
-            } else {
-                theme = inFrameworkStyleMap.get(themeName);
-            }
-
-            if (theme instanceof StyleResourceValue) {
-                // compute the inheritance map for both the project and framework styles
-                computeStyleInheritance(inProjectStyleMap.values(), inProjectStyleMap,
-                        inFrameworkStyleMap, outInheritanceMap);
-
-                // Compute the style inheritance for the framework styles/themes.
-                // Since, for those, the style parent values do not contain 'android:'
-                // we want to force looking in the framework style only to avoid using
-                // similarly named styles from the project.
-                // To do this, we pass null in lieu of the project style map.
-                computeStyleInheritance(inFrameworkStyleMap.values(), null /*inProjectStyleMap */,
-                        inFrameworkStyleMap, outInheritanceMap);
-
-                return (StyleResourceValue)theme;
-            }
-        }
-
-        return null;
-    }
-
-    /**
-     * Compute the parent style for all the styles in a given list.
-     * @param styles the styles for which we compute the parent.
-     * @param inProjectStyleMap the map of project styles.
-     * @param inFrameworkStyleMap the map of framework styles.
-     * @param outInheritanceMap the map of style inheritance. This is filled by the method.
-     */
-    private void computeStyleInheritance(Collection<ResourceValue> styles,
-            Map<String, ResourceValue> inProjectStyleMap,
-            Map<String, ResourceValue> inFrameworkStyleMap,
-            Map<StyleResourceValue, StyleResourceValue> outInheritanceMap) {
-        for (ResourceValue value : styles) {
-            if (value instanceof StyleResourceValue) {
-                StyleResourceValue style = (StyleResourceValue)value;
-                StyleResourceValue parentStyle = null;
-
-                // first look for a specified parent.
-                String parentName = style.getParentStyle();
-
-                // no specified parent? try to infer it from the name of the style.
-                if (parentName == null) {
-                    parentName = getParentName(value.getName());
-                }
-
-                if (parentName != null) {
-                    parentStyle = getStyle(parentName, inProjectStyleMap, inFrameworkStyleMap);
-
-                    if (parentStyle != null) {
-                        outInheritanceMap.put(style, parentStyle);
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Searches for and returns the {@link StyleResourceValue} from a given name.
-     * <p/>The format of the name can be:
-     * <ul>
-     * <li>[android:]&lt;name&gt;</li>
-     * <li>[android:]style/&lt;name&gt;</li>
-     * <li>@[android:]style/&lt;name&gt;</li>
-     * </ul>
-     * @param parentName the name of the style.
-     * @param inProjectStyleMap the project style map. Can be <code>null</code>
-     * @param inFrameworkStyleMap the framework style map.
-     * @return The matching {@link StyleResourceValue} object or <code>null</code> if not found.
-     */
-    private StyleResourceValue getStyle(String parentName,
-            Map<String, ResourceValue> inProjectStyleMap,
-            Map<String, ResourceValue> inFrameworkStyleMap) {
-        boolean frameworkOnly = false;
-
-        String name = parentName;
-
-        // remove the useless @ if it's there
-        if (name.startsWith(BridgeConstants.PREFIX_RESOURCE_REF)) {
-            name = name.substring(BridgeConstants.PREFIX_RESOURCE_REF.length());
-        }
-
-        // check for framework identifier.
-        if (name.startsWith(BridgeConstants.PREFIX_ANDROID)) {
-            frameworkOnly = true;
-            name = name.substring(BridgeConstants.PREFIX_ANDROID.length());
-        }
-
-        // at this point we could have the format <type>/<name>. we want only the name as long as
-        // the type is style.
-        if (name.startsWith(BridgeConstants.REFERENCE_STYLE)) {
-            name = name.substring(BridgeConstants.REFERENCE_STYLE.length());
-        } else if (name.indexOf('/') != -1) {
-            return null;
-        }
-
-        ResourceValue parent = null;
-
-        // if allowed, search in the project resources.
-        if (frameworkOnly == false && inProjectStyleMap != null) {
-            parent = inProjectStyleMap.get(name);
-        }
-
-        // if not found, then look in the framework resources.
-        if (parent == null) {
-            parent = inFrameworkStyleMap.get(name);
-        }
-
-        // make sure the result is the proper class type and return it.
-        if (parent instanceof StyleResourceValue) {
-            return (StyleResourceValue)parent;
-        }
-
-        assert false;
-        mParams.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE,
-                String.format("Unable to resolve parent style name: %s", parentName),
-                null /*data*/);
-
-        return null;
-    }
-
-    /**
-     * Computes the name of the parent style, or <code>null</code> if the style is a root style.
-     */
-    private String getParentName(String styleName) {
-        int index = styleName.lastIndexOf('.');
-        if (index != -1) {
-            return styleName.substring(0, index);
-        }
-
-        return null;
-    }
-
     /**
      * Returns the top screen offset. This depends on whether the current theme defines the user
      * of the title and status bars.
-     * @param frameworkResources The framework resources
-     * @param currentTheme The current theme
-     * @param context The context
+     * @param resolver The {@link ResourceResolver}
+     * @param metrics The display metrics
      * @return the pixel height offset
      */
-    private int getScreenOffset(Map<String, Map<String, ResourceValue>> frameworkResources,
-            StyleResourceValue currentTheme, BridgeContext context) {
+    private int getScreenOffset(ResourceResolver resolver, DisplayMetrics metrics) {
         int offset = 0;
 
         // get the title bar flag from the current theme.
-        ResourceValue value = context.findItemInStyle(currentTheme, "windowNoTitle");
+        ResourceValue value = resolver.findItemInTheme("windowNoTitle");
 
         // because it may reference something else, we resolve it.
-        value = context.resolveResValue(value);
+        value = resolver.resolveResValue(value);
 
         // if there's a value and it's true (default is false)
         if (value == null || value.getValue() == null ||
@@ -1089,17 +931,17 @@
             int defaultOffset = DEFAULT_TITLE_BAR_HEIGHT;
 
             // get value from the theme.
-            value = context.findItemInStyle(currentTheme, "windowTitleSize");
+            value = resolver.findItemInTheme("windowTitleSize");
 
             // resolve it
-            value = context.resolveResValue(value);
+            value = resolver.resolveResValue(value);
 
             if (value != null) {
                 // get the numerical value, if available
                 TypedValue typedValue = ResourceHelper.getValue(value.getValue());
                 if (typedValue != null) {
                     // compute the pixel value based on the display metrics
-                    defaultOffset = (int)typedValue.getDimension(context.getResources().mMetrics);
+                    defaultOffset = (int)typedValue.getDimension(metrics);
                 }
             }
 
@@ -1107,10 +949,10 @@
         }
 
         // get the fullscreen flag from the current theme.
-        value = context.findItemInStyle(currentTheme, "windowFullscreen");
+        value = resolver.findItemInTheme("windowFullscreen");
 
         // because it may reference something else, we resolve it.
-        value = context.resolveResValue(value);
+        value = resolver.resolveResValue(value);
 
         if (value == null || value.getValue() == null ||
                 XmlUtils.convertValueToBoolean(value.getValue(), false /* defValue */) == false) {
@@ -1118,16 +960,13 @@
             // default value
             int defaultOffset = DEFAULT_STATUS_BAR_HEIGHT;
 
-            // get the real value, first the list of Dimensions from the framework map
-            Map<String, ResourceValue> dimens = frameworkResources.get(BridgeConstants.RES_DIMEN);
-
-            // now get the value
-            value = dimens.get("status_bar_height");
+            // get the real value
+            value = resolver.getFrameworkResource(ResourceResolver.RES_DIMEN, "status_bar_height");
             if (value != null) {
                 TypedValue typedValue = ResourceHelper.getValue(value.getValue());
                 if (typedValue != null) {
                     // compute the pixel value based on the display metrics
-                    defaultOffset = (int)typedValue.getDimension(context.getResources().mMetrics);
+                    defaultOffset = (int)typedValue.getDimension(metrics);
                 }
             }
 
@@ -1136,7 +975,6 @@
         }
 
         return offset;
-
     }
 
     /**