Merge "Remove unneeded #include <sys/resource.h>"
diff --git a/Android.mk b/Android.mk
index 358bcc6..d4d9a33 100644
--- a/Android.mk
+++ b/Android.mk
@@ -382,8 +382,12 @@
 		            resources/samples/AccessibilityService "Accessibility Service" \
 		-samplecode $(sample_dir)/AccelerometerPlay \
 		            resources/samples/AccelerometerPlay "Accelerometer Play" \
-	  -samplecode $(sample_dir)/ApiDemos \
+		-samplecode $(sample_dir)/ApiDemos \
 		            resources/samples/ApiDemos "API Demos" \
+		-samplecode $(sample_dir)/Support4Demos \
+		            resources/samples/Support4Demos "API 4+ Support Demos" \
+		-samplecode $(sample_dir)/Support13Demos \
+		            resources/samples/Support13Demos "API 13+ Support Demos" \
 		-samplecode $(sample_dir)/BackupRestore \
 		            resources/samples/BackupRestore "Backup and Restore" \
 		-samplecode $(sample_dir)/BluetoothChat \
diff --git a/api/current.txt b/api/current.txt
index 7c9c851..51c9348 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -218,6 +218,7 @@
     field public static final int alertDialogIcon = 16843605; // 0x1010355
     field public static final int alertDialogStyle = 16842845; // 0x101005d
     field public static final int alertDialogTheme = 16843529; // 0x1010309
+    field public static final int alignmentMode = 16843642; // 0x101037a
     field public static final int allContactsName = 16843468; // 0x10102cc
     field public static final int allowBackup = 16843392; // 0x1010280
     field public static final int allowClearUserData = 16842757; // 0x1010005
@@ -627,6 +628,8 @@
     field public static final int listDividerAlertDialog = 16843525; // 0x1010305
     field public static final int listPopupWindowStyle = 16843519; // 0x10102ff
     field public static final int listPreferredItemHeight = 16842829; // 0x101004d
+    field public static final int listPreferredItemHeightLarge = 16843670; // 0x1010396
+    field public static final int listPreferredItemHeightSmall = 16843671; // 0x1010397
     field public static final int listSelector = 16843003; // 0x10100fb
     field public static final int listSeparatorTextViewStyle = 16843272; // 0x1010208
     field public static final int listViewStyle = 16842868; // 0x1010074
@@ -636,7 +639,6 @@
     field public static final int loopViews = 16843527; // 0x1010307
     field public static final int manageSpaceActivity = 16842756; // 0x1010004
     field public static final int mapViewStyle = 16842890; // 0x101008a
-    field public static final int marginsIncludedInAlignment = 16843642; // 0x101037a
     field public static final int marqueeRepeatLimit = 16843293; // 0x101021d
     field public static final int max = 16843062; // 0x1010136
     field public static final int maxDate = 16843584; // 0x1010340
@@ -1374,6 +1376,7 @@
     field public static final int config_longAnimTime = 17694722; // 0x10e0002
     field public static final int config_mediumAnimTime = 17694721; // 0x10e0001
     field public static final int config_shortAnimTime = 17694720; // 0x10e0000
+    field public static final int status_bar_notification_info_maxnum = 17694723; // 0x10e0003
   }
 
   public static final class R.interpolator {
@@ -1460,6 +1463,7 @@
     field public static final int search_go = 17039372; // 0x104000c
     field public static final int selectAll = 17039373; // 0x104000d
     field public static final int selectTextMode = 17039382; // 0x1040016
+    field public static final int status_bar_notification_info_overflow = 17039383; // 0x1040017
     field public static final int unknownName = 17039374; // 0x104000e
     field public static final int untitled = 17039375; // 0x104000f
     field public static final int yes = 17039379; // 0x1040013
@@ -1632,6 +1636,7 @@
     field public static final int Widget_Holo_AutoCompleteTextView = 16973968; // 0x1030090
     field public static final int Widget_Holo_Button = 16973963; // 0x103008b
     field public static final int Widget_Holo_Button_Borderless = 16974050; // 0x10300e2
+    field public static final int Widget_Holo_Button_Borderless_Small = 16974107; // 0x103011b
     field public static final int Widget_Holo_Button_Inset = 16973965; // 0x103008d
     field public static final int Widget_Holo_Button_Small = 16973964; // 0x103008c
     field public static final int Widget_Holo_Button_Toggle = 16973966; // 0x103008e
@@ -1658,6 +1663,7 @@
     field public static final int Widget_Holo_Light_ActionMode = 16974047; // 0x10300df
     field public static final int Widget_Holo_Light_AutoCompleteTextView = 16974011; // 0x10300bb
     field public static final int Widget_Holo_Light_Button = 16974006; // 0x10300b6
+    field public static final int Widget_Holo_Light_Button_Borderless_Small = 16974108; // 0x103011c
     field public static final int Widget_Holo_Light_Button_Inset = 16974008; // 0x10300b8
     field public static final int Widget_Holo_Light_Button_Small = 16974007; // 0x10300b7
     field public static final int Widget_Holo_Light_Button_Toggle = 16974009; // 0x10300b9
@@ -2448,7 +2454,7 @@
     field public static final int RESULT_OK = -1; // 0xffffffff
   }
 
-  public class ActivityGroup extends android.app.Activity {
+  public deprecated class ActivityGroup extends android.app.Activity {
     ctor public ActivityGroup();
     ctor public ActivityGroup(boolean);
     method public android.app.Activity getCurrentActivity();
@@ -3237,7 +3243,7 @@
     method public abstract void onLoaderReset(android.content.Loader<D>);
   }
 
-  public class LocalActivityManager {
+  public deprecated class LocalActivityManager {
     ctor public LocalActivityManager(android.app.Activity, boolean);
     method public android.view.Window destroyActivity(java.lang.String, boolean);
     method public void dispatchCreate(android.os.Bundle);
@@ -3520,7 +3526,7 @@
     field public static final int START_STICKY_COMPATIBILITY = 0; // 0x0
   }
 
-  public class TabActivity extends android.app.ActivityGroup {
+  public deprecated class TabActivity extends android.app.ActivityGroup {
     ctor public TabActivity();
     method public android.widget.TabHost getTabHost();
     method public android.widget.TabWidget getTabWidget();
@@ -5804,6 +5810,7 @@
     method public abstract void setInstallerPackageName(java.lang.String, java.lang.String);
     field public static final int COMPONENT_ENABLED_STATE_DEFAULT = 0; // 0x0
     field public static final int COMPONENT_ENABLED_STATE_DISABLED = 2; // 0x2
+    field public static final int COMPONENT_ENABLED_STATE_DISABLED_USER = 3; // 0x3
     field public static final int COMPONENT_ENABLED_STATE_ENABLED = 1; // 0x1
     field public static final int DONT_KILL_APP = 1; // 0x1
     field public static final java.lang.String FEATURE_AUDIO_LOW_LATENCY = "android.hardware.audio.low_latency";
@@ -14002,6 +14009,7 @@
     field public static final int INTERFACE_TRANSACTION = 1598968902; // 0x5f4e5446
     field public static final int LAST_CALL_TRANSACTION = 16777215; // 0xffffff
     field public static final int PING_TRANSACTION = 1599098439; // 0x5f504e47
+    field public static final int TWEET_TRANSACTION = 1599362900; // 0x5f545754
   }
 
   public static abstract interface IBinder.DeathRecipient {
@@ -15262,6 +15270,8 @@
     field public static final java.lang.String DIRECTORY_PARAM_KEY = "directory";
     field public static final java.lang.String INCLUDE_PROFILE = "include_profile";
     field public static final java.lang.String LIMIT_PARAM_KEY = "limit";
+    field public static final java.lang.String PRIMARY_ACCOUNT_NAME = "name_for_primary_account";
+    field public static final java.lang.String PRIMARY_ACCOUNT_TYPE = "type_for_primary_account";
   }
 
   public static final class ContactsContract.AggregationExceptions implements android.provider.BaseColumns {
@@ -15604,6 +15614,15 @@
   protected static abstract interface ContactsContract.DataColumnsWithJoins implements android.provider.BaseColumns android.provider.ContactsContract.ContactNameColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.ContactStatusColumns android.provider.ContactsContract.ContactsColumns android.provider.ContactsContract.DataColumns android.provider.ContactsContract.RawContactsColumns android.provider.ContactsContract.StatusColumns {
   }
 
+  public static final class ContactsContract.DataUsageFeedback {
+    ctor public ContactsContract.DataUsageFeedback();
+    field public static final android.net.Uri FEEDBACK_URI;
+    field public static final java.lang.String USAGE_TYPE = "type";
+    field public static final java.lang.String USAGE_TYPE_CALL = "call";
+    field public static final java.lang.String USAGE_TYPE_LONG_TEXT = "long_text";
+    field public static final java.lang.String USAGE_TYPE_SHORT_TEXT = "short_text";
+  }
+
   public static final class ContactsContract.Directory implements android.provider.BaseColumns {
     method public static void notifyDirectoryChange(android.content.ContentResolver);
     field public static final java.lang.String ACCOUNT_NAME = "accountName";
@@ -16672,6 +16691,7 @@
     method public static android.renderscript.Element U8_4(android.renderscript.RenderScript);
     method public static android.renderscript.Element createPixel(android.renderscript.RenderScript, android.renderscript.Element.DataType, android.renderscript.Element.DataKind);
     method public static android.renderscript.Element createVector(android.renderscript.RenderScript, android.renderscript.Element.DataType, int);
+    method public boolean isCompatible(android.renderscript.Element);
     method public boolean isComplex();
   }
 
@@ -17370,9 +17390,12 @@
     enum_constant public static final android.renderscript.Type.CubemapFace NEGATIVE_X;
     enum_constant public static final android.renderscript.Type.CubemapFace NEGATIVE_Y;
     enum_constant public static final android.renderscript.Type.CubemapFace NEGATIVE_Z;
-    enum_constant public static final android.renderscript.Type.CubemapFace POSITVE_X;
-    enum_constant public static final android.renderscript.Type.CubemapFace POSITVE_Y;
-    enum_constant public static final android.renderscript.Type.CubemapFace POSITVE_Z;
+    enum_constant public static final android.renderscript.Type.CubemapFace POSITIVE_X;
+    enum_constant public static final android.renderscript.Type.CubemapFace POSITIVE_Y;
+    enum_constant public static final android.renderscript.Type.CubemapFace POSITIVE_Z;
+    enum_constant public static final deprecated android.renderscript.Type.CubemapFace POSITVE_X;
+    enum_constant public static final deprecated android.renderscript.Type.CubemapFace POSITVE_Y;
+    enum_constant public static final deprecated android.renderscript.Type.CubemapFace POSITVE_Z;
   }
 
 }
@@ -17586,6 +17609,7 @@
   }
 
   public final class SynthesisRequest {
+    ctor public SynthesisRequest(java.lang.String, android.os.Bundle);
     method public java.lang.String getCountry();
     method public java.lang.String getLanguage();
     method public android.os.Bundle getParams();
@@ -23713,7 +23737,8 @@
     method public boolean getSavePassword();
     method public synchronized java.lang.String getSerifFontFamily();
     method public synchronized java.lang.String getStandardFontFamily();
-    method public synchronized android.webkit.WebSettings.TextSize getTextSize();
+    method public deprecated synchronized android.webkit.WebSettings.TextSize getTextSize();
+    method public synchronized int getTextZoom();
     method public deprecated synchronized boolean getUseDoubleTree();
     method public deprecated boolean getUseWebViewBackgroundForOverscrollBackground();
     method public synchronized boolean getUseWideViewPort();
@@ -23763,7 +23788,8 @@
     method public synchronized void setStandardFontFamily(java.lang.String);
     method public synchronized void setSupportMultipleWindows(boolean);
     method public void setSupportZoom(boolean);
-    method public synchronized void setTextSize(android.webkit.WebSettings.TextSize);
+    method public deprecated synchronized void setTextSize(android.webkit.WebSettings.TextSize);
+    method public synchronized void setTextZoom(int);
     method public deprecated synchronized void setUseDoubleTree(boolean);
     method public deprecated void setUseWebViewBackgroundForOverscrollBackground(boolean);
     method public synchronized void setUseWideViewPort(boolean);
@@ -23802,7 +23828,7 @@
     enum_constant public static final android.webkit.WebSettings.RenderPriority NORMAL;
   }
 
-  public static final class WebSettings.TextSize extends java.lang.Enum {
+  public static final deprecated class WebSettings.TextSize extends java.lang.Enum {
     method public static android.webkit.WebSettings.TextSize valueOf(java.lang.String);
     method public static final android.webkit.WebSettings.TextSize[] values();
     enum_constant public static final android.webkit.WebSettings.TextSize LARGER;
@@ -24773,21 +24799,23 @@
     ctor public GridLayout(android.content.Context);
     ctor public GridLayout(android.content.Context, android.util.AttributeSet, int);
     ctor public GridLayout(android.content.Context, android.util.AttributeSet);
+    method public int getAlignmentMode();
     method public int getColumnCount();
-    method public boolean getMarginsIncludedInAlignment();
     method public int getOrientation();
     method public int getRowCount();
     method public boolean getUseDefaultMargins();
     method public boolean isColumnOrderPreserved();
     method public boolean isRowOrderPreserved();
     method protected void onLayout(boolean, int, int, int, int);
+    method public void setAlignmentMode(int);
     method public void setColumnCount(int);
     method public void setColumnOrderPreserved(boolean);
-    method public void setMarginsIncludedInAlignment(boolean);
     method public void setOrientation(int);
     method public void setRowCount(int);
     method public void setRowOrderPreserved(boolean);
     method public void setUseDefaultMargins(boolean);
+    field public static final int ALIGN_BOUNDS = 0; // 0x0
+    field public static final int ALIGN_MARGINS = 1; // 0x1
     field public static final android.widget.GridLayout.Alignment BASELINE;
     field public static final android.widget.GridLayout.Alignment BOTTOM;
     field public static final android.widget.GridLayout.Alignment CENTER;
@@ -24800,9 +24828,10 @@
     field public static final int VERTICAL = 1; // 0x1
   }
 
-  public static abstract interface GridLayout.Alignment {
-    method public abstract int getAlignmentValue(android.view.View, int);
-    method public abstract int getSizeInCell(android.view.View, int, int);
+  public static abstract class GridLayout.Alignment {
+    ctor public GridLayout.Alignment();
+    method public abstract int getAlignmentValue(android.view.View, int, int);
+    method public int getSizeInCell(android.view.View, int, int, int);
   }
 
   public static class GridLayout.Group {
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index b0e4a86..e433079 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -120,6 +120,11 @@
             return;
         }
 
+        if ("disable-user".equals(op)) {
+            runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER);
+            return;
+        }
+
         if ("setInstallLocation".equals(op)) {
             runSetInstallLocation();
             return;
@@ -970,6 +975,8 @@
                 return "enabled";
             case PackageManager.COMPONENT_ENABLED_STATE_DISABLED:
                 return "disabled";
+            case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER:
+                return "disabled-user";
         }
         return "unknown";
     }
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index cac06ec..3ec5edb 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -487,6 +487,12 @@
      * Create and return a new {@link Tab}.
      * This tab will not be included in the action bar until it is added.
      *
+     * <p>Very often tabs will be used to switch between {@link Fragment}
+     * objects.  Here is a typical implementation of such tabs:</p>
+     *
+     * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentTabs.java
+     *      complete}
+     *
      * @return A new Tab
      *
      * @see #addTab(Tab)
diff --git a/core/java/android/app/ActivityGroup.java b/core/java/android/app/ActivityGroup.java
index 5b04253..fbd78be 100644
--- a/core/java/android/app/ActivityGroup.java
+++ b/core/java/android/app/ActivityGroup.java
@@ -23,8 +23,13 @@
 import android.util.Log;
 
 /**
+ * @deprecated Use the new {@link Fragment} and {@link FragmentManager} APIs
+ * instead; these are also
+ * available on older platforms through the Android compatibility package.
+ *
  * A screen that contains and runs multiple embedded activities.
  */
+@Deprecated
 public class ActivityGroup extends Activity {
     private static final String TAG = "ActivityGroup";
     private static final String STATES_KEY = "android:states";
diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java
index e83d104..7a465c1 100644
--- a/core/java/android/app/AlertDialog.java
+++ b/core/java/android/app/AlertDialog.java
@@ -890,7 +890,7 @@
         public AlertDialog create() {
             final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, false);
             P.apply(dialog.mAlert);
-            dialog.setCancelable(P.mCancelable);
+            dialog.setCanceledOnTouchOutside(P.mCancelable);
             dialog.setOnCancelListener(P.mOnCancelListener);
             if (P.mOnKeyListener != null) {
                 dialog.setOnKeyListener(P.mOnKeyListener);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 20dc792..94a4afa 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -52,6 +52,8 @@
 import android.media.AudioManager;
 import android.net.ConnectivityManager;
 import android.net.IConnectivityManager;
+import android.net.INetworkPolicyManager;
+import android.net.NetworkPolicyManager;
 import android.net.ThrottleManager;
 import android.net.IThrottleManager;
 import android.net.Uri;
@@ -339,6 +341,14 @@
                     return new LocationManager(ILocationManager.Stub.asInterface(b));
                 }});
 
+        registerService(NETWORK_POLICY_SERVICE, new ServiceFetcher() {
+            @Override
+            public Object createService(ContextImpl ctx) {
+                return new NetworkPolicyManager(INetworkPolicyManager.Stub.asInterface(
+                        ServiceManager.getService(NETWORK_POLICY_SERVICE)));
+            }
+        });
+
         registerService(NOTIFICATION_SERVICE, new ServiceFetcher() {
                 public Object createService(ContextImpl ctx) {
                     final Context outerContext = ctx.getOuterContext();
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index b88e5cf..ad8d41f 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -23,6 +23,7 @@
 import android.database.Cursor;
 import android.database.CursorWrapper;
 import android.net.ConnectivityManager;
+import android.net.NetworkPolicyManager;
 import android.net.Uri;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
@@ -170,7 +171,6 @@
      */
     public final static int STATUS_FAILED = 1 << 4;
 
-
     /**
      * Value of COLUMN_ERROR_CODE when the download has completed with an error that doesn't fit
      * under any other error code.
@@ -226,6 +226,14 @@
     public final static int ERROR_FILE_ALREADY_EXISTS = 1009;
 
     /**
+     * Value of {@link #COLUMN_REASON} when the download has failed because of
+     * {@link NetworkPolicyManager} controls on the requesting application.
+     *
+     * @hide
+     */
+    public final static int ERROR_BLOCKED = 1010;
+
+    /**
      * Value of {@link #COLUMN_REASON} when the download is paused because some network error
      * occurred and the download manager is waiting before retrying the request.
      */
@@ -1304,6 +1312,9 @@
                 case Downloads.Impl.STATUS_FILE_ALREADY_EXISTS_ERROR:
                     return ERROR_FILE_ALREADY_EXISTS;
 
+                case Downloads.Impl.STATUS_BLOCKED:
+                    return ERROR_BLOCKED;
+
                 default:
                     return ERROR_UNKNOWN;
             }
diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java
index c958e1b..0a6b804 100644
--- a/core/java/android/app/LocalActivityManager.java
+++ b/core/java/android/app/LocalActivityManager.java
@@ -28,12 +28,17 @@
 import java.util.Map;
 
 /**
- * Helper class for managing multiple running embedded activities in the same
+ * @deprecated Use the new {@link Fragment} and {@link FragmentManager} APIs
+ * instead; these are also
+ * available on older platforms through the Android compatibility package.
+ *
+ * <p>Helper class for managing multiple running embedded activities in the same
  * process. This class is not normally used directly, but rather created for
  * you as part of the {@link android.app.ActivityGroup} implementation.
  *
  * @see ActivityGroup
  */
+@Deprecated
 public class LocalActivityManager {
     private static final String TAG = "LocalActivityManager";
     private static final boolean localLOGV = false;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index c9351af..170d2b5 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -929,15 +929,15 @@
             if (mContentInfo != null) {
                 contentView.setTextViewText(R.id.info, mContentInfo);
             } else if (mNumber > 0) {
-                if (mNumber > 999) {
-                    contentView.setTextViewText(R.id.info, "999+");
+                final int tooBig = mContext.getResources().getInteger(
+                        R.integer.status_bar_notification_info_maxnum);
+                if (mNumber > tooBig) {
+                    contentView.setTextViewText(R.id.info, mContext.getResources().getString(
+                                R.string.status_bar_notification_info_overflow));
                 } else {
                     NumberFormat f = NumberFormat.getIntegerInstance();
                     contentView.setTextViewText(R.id.info, f.format(mNumber));
                 }
-                contentView.setFloat(R.id.info, "setTextSize",
-                        mContext.getResources().getDimensionPixelSize(
-                            R.dimen.status_bar_content_number_size));
             } else {
                 contentView.setViewVisibility(R.id.info, View.GONE);
             }
diff --git a/core/java/android/app/TabActivity.java b/core/java/android/app/TabActivity.java
index 033fa0c..0fd0c2c 100644
--- a/core/java/android/app/TabActivity.java
+++ b/core/java/android/app/TabActivity.java
@@ -23,8 +23,34 @@
 import android.widget.TextView;
 
 /**
- * An activity that contains and runs multiple embedded activities or views.
+ * @deprecated New applications should use Fragments instead of this class;
+ * to continue to run on older devices, you can use the v4 support library
+ * which provides a version of the Fragment API that is compatible down to
+ * {@link android.os.Build.VERSION_CODES#DONUT}.
+ *
+ * <p>For apps developing against {@link android.os.Build.VERSION_CODES#HONEYCOMB}
+ * or later, tabs are typically presented in the UI using the new
+ * {@link ActionBar#newTab() ActionBar.newTab()} and
+ * related APIs for placing tabs within their action bar area.</p>
+ *
+ * <p>A replacement for TabActivity can also be implemented by directly using
+ * TabHost.  You will need to define a layout that correctly uses a TabHost
+ * with a TabWidget as well as an area in which to display your tab content.
+ * A typical example would be:</p>
+ *
+ * {@sample development/samples/Support4Demos/res/layout/fragment_tabs.xml complete}
+ *
+ * <p>The implementation needs to take over responsibility for switching
+ * the shown content when the user switches between tabs.
+ *
+ * {@sample development/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentTabs.java
+ *      complete}
+ *
+ * <p>Also see the <a href="{@docRoot}resources/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentTabsPager.html">
+ * Fragment Tabs Pager</a> sample for an example of using the support library's ViewPager to
+ * allow the user to swipe the content to switch between tabs.</p>
  */
+@Deprecated
 public class TabActivity extends ActivityGroup {
     private TabHost mTabHost;
     private String mDefaultTab = null;
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index c0a1d8e..454cb31 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -417,6 +417,12 @@
     public boolean enabled = true;
 
     /**
+     * For convenient access to the current enabled setting of this app.
+     * @hide
+     */
+    public int enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+
+    /**
      * For convenient access to package's install location.
      * @hide
      */
@@ -508,6 +514,7 @@
         uid = orig.uid;
         targetSdkVersion = orig.targetSdkVersion;
         enabled = orig.enabled;
+        enabledSetting = orig.enabledSetting;
         installLocation = orig.installLocation;
         manageSpaceActivityName = orig.manageSpaceActivityName;
         descriptionRes = orig.descriptionRes;
@@ -544,6 +551,7 @@
         dest.writeInt(uid);
         dest.writeInt(targetSdkVersion);
         dest.writeInt(enabled ? 1 : 0);
+        dest.writeInt(enabledSetting);
         dest.writeInt(installLocation);
         dest.writeString(manageSpaceActivityName);
         dest.writeString(backupAgentName);
@@ -581,6 +589,7 @@
         uid = source.readInt();
         targetSdkVersion = source.readInt();
         enabled = source.readInt() != 0;
+        enabledSetting = source.readInt();
         installLocation = source.readInt();
         manageSpaceActivityName = source.readString();
         backupAgentName = source.readString();
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 1cd8ec0..dd684cd 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -224,11 +224,41 @@
      */
     public static final int SIGNATURE_UNKNOWN_PACKAGE = -4;
 
+    /**
+     * Flag for {@link #setApplicationEnabledSetting(String, int, int)}
+     * and {@link #setComponentEnabledSetting(ComponentName, int, int)}: This
+     * component or application is in its default enabled state (as specified
+     * in its manifest).
+     */
     public static final int COMPONENT_ENABLED_STATE_DEFAULT = 0;
+
+    /**
+     * Flag for {@link #setApplicationEnabledSetting(String, int, int)}
+     * and {@link #setComponentEnabledSetting(ComponentName, int, int)}: This
+     * component or application has been explictily enabled, regardless of
+     * what it has specified in its manifest.
+     */
     public static final int COMPONENT_ENABLED_STATE_ENABLED = 1;
+
+    /**
+     * Flag for {@link #setApplicationEnabledSetting(String, int, int)}
+     * and {@link #setComponentEnabledSetting(ComponentName, int, int)}: This
+     * component or application has been explicitly disabled, regardless of
+     * what it has specified in its manifest.
+     */
     public static final int COMPONENT_ENABLED_STATE_DISABLED = 2;
 
     /**
+     * Flag for {@link #setApplicationEnabledSetting(String, int, int)} only: The
+     * user has explicitly disabled the application, regardless of what it has
+     * specified in its manifest.  Because this is due to the user's request,
+     * they may re-enable it if desired through the appropriate system UI.  This
+     * option currently <strong>can not</strong> be used with
+     * {@link #setComponentEnabledSetting(ComponentName, int, int)}.
+     */
+    public static final int COMPONENT_ENABLED_STATE_DISABLED_USER = 3;
+
+    /**
      * Flag parameter for {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} to
      * indicate that this package should be installed as forward locked, i.e. only the app itself
      * should have access to its code and non-resource assets.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 31ad6e9..e927f6c 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3128,9 +3128,11 @@
         }
         if (p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
             ai.enabled = true;
-        } else if (p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED) {
+        } else if (p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+                || p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
             ai.enabled = false;
         }
+        ai.enabledSetting = p.mSetEnabled;
         return ai;
     }
 
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 9bd45d3..a00f790 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -19,6 +19,7 @@
 import android.content.pm.ActivityInfo;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.LocaleUtil;
 
 import java.util.Locale;
 
@@ -277,21 +278,6 @@
     public int compatSmallestScreenWidthDp;
 
     /**
-     * @hide Do not use. Implementation not finished.
-     */
-    public static final int TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE = -1;
-
-    /**
-     * @hide Do not use. Implementation not finished.
-     */
-    public static final int TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE = 0;
-
-    /**
-     * @hide Do not use. Implementation not finished.
-     */
-    public static final int TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE = 1;
-
-    /**
      * @hide The text layout direction associated to the current Locale
      */
     public int textLayoutDirection;
@@ -359,8 +345,8 @@
             sb.append(" (no locale)");
         }
         switch (textLayoutDirection) {
-            case TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE: sb.append(" ?layoutdir"); break;
-            case TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE: sb.append(" rtl"); break;
+            case LocaleUtil.TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE: sb.append(" ?layoutdir"); break;
+            case LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE: sb.append(" rtl"); break;
             default: sb.append(" layoutdir="); sb.append(textLayoutDirection); break;
         }
         if (smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
@@ -483,7 +469,7 @@
         screenWidthDp = compatScreenWidthDp = SCREEN_WIDTH_DP_UNDEFINED;
         screenHeightDp = compatScreenHeightDp = SCREEN_HEIGHT_DP_UNDEFINED;
         smallestScreenWidthDp = compatSmallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
-        textLayoutDirection = TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE;
+        textLayoutDirection = LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE;
         seq = 0;
     }
 
@@ -519,7 +505,7 @@
             changed |= ActivityInfo.CONFIG_LOCALE;
             locale = delta.locale != null
                     ? (Locale) delta.locale.clone() : null;
-            textLayoutDirection = getLayoutDirectionFromLocale(locale);
+            textLayoutDirection = LocaleUtil.getLayoutDirectionFromLocale(locale);
         }
         if (delta.userSetLocale && (!userSetLocale || ((changed & ActivityInfo.CONFIG_LOCALE) != 0)))
         {
@@ -609,31 +595,6 @@
     }
 
     /**
-     * Return the layout direction for a given Locale
-     * @param locale the Locale for which we want the layout direction. Can be null.
-     * @return the layout direction. This may be one of:
-     * {@link #TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE} or
-     * {@link #TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE} or
-     * {@link #TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE}.
-     *
-     * @hide
-     */
-    public static int getLayoutDirectionFromLocale(Locale locale) {
-        if (locale == null || locale.equals(Locale.ROOT)) return TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE;
-        // Be careful: this code will need to be changed when vertical scripts will be supported
-        // OR if ICU4C is updated to have the "likelySubtags" file
-        switch(Character.getDirectionality(locale.getDisplayName(locale).charAt(0))) {
-            case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
-                return TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE;
-            case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
-            case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
-                return TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE;
-            default:
-                return TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE;
-        }
-    }
-
-    /**
      * Return a bit mask of the differences between this Configuration
      * object and the given one.  Does not change the values of either.  Any
      * undefined fields in <var>delta</var> are ignored.
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 1df3108..338e6c8 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -216,7 +216,9 @@
      *     {@link #getNumberOfCameras()}-1.
      * @return a new Camera object, connected, locked and ready for use.
      * @throws RuntimeException if connection to the camera service fails (for
-     *     example, if the camera is in use by another process).
+     *     example, if the camera is in use by another process or device policy
+     *     manager has disabled the camera).
+     * @see android.app.admin.DevicePolicyManager#getCameraDisabled(android.content.ComponentName)
      */
     public static Camera open(int cameraId) {
         return new Camera(cameraId);
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
index 5df2343..2b9c082 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -81,4 +81,13 @@
 
     /* Clears default preferences and permissions for the package */
     void clearDefaults(String packageName);
+
+    /* Sets the current primary USB function. */
+    void setPrimaryFunction(String functions);
+
+    /* Sets the default primary USB function. */
+    void setDefaultFunction(String functions);
+
+    /* Sets the file path for USB mass storage backing file. */
+    void setMassStorageBackingFile(String path);
 }
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 5994c98..a828a23 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -22,12 +22,9 @@
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
+import android.os.SystemProperties;
 import android.util.Log;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
 import java.util.HashMap;
 
 /**
@@ -50,7 +47,7 @@
      * This is a sticky broadcast for clients that includes USB connected/disconnected state,
      * <ul>
      * <li> {@link #USB_CONNECTED} boolean indicating whether USB is connected or disconnected.
-     * <li> {@link #USB_CONFIGURATION} integer containing current USB configuration
+     * <li> {@link #USB_CONFIGURED} boolean indicating whether USB is configured.
      * currently zero if not configured, one for configured.
      * <li> {@link #USB_FUNCTION_MASS_STORAGE} boolean extra indicating whether the
      * mass storage function is enabled
@@ -128,12 +125,12 @@
     public static final String USB_CONNECTED = "connected";
 
     /**
-     * Integer extra containing currently set USB configuration.
+     * Boolean extra indicating whether USB is configured.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast.
      *
      * {@hide}
      */
-    public static final String USB_CONFIGURATION = "configuration";
+    public static final String USB_CONFIGURED = "configured";
 
     /**
      * Name of the USB mass storage USB function.
@@ -388,21 +385,14 @@
         }
     }
 
-    private static File getFunctionEnableFile(String function) {
-        return new File("/sys/class/usb_composite/" + function + "/enable");
-    }
-
-    /**
-     * Returns true if the specified USB function is supported by the kernel.
-     * Note that a USB function maybe supported but disabled.
-     *
-     * @param function name of the USB function
-     * @return true if the USB function is supported.
-     *
-     * {@hide}
-     */
-    public static boolean isFunctionSupported(String function) {
-        return getFunctionEnableFile(function).exists();
+    private static boolean propertyContainsFunction(String property, String function) {
+        String functions = SystemProperties.get(property, "");
+        int index = functions.indexOf(function);
+        if (index < 0) return false;
+        if (index > 0 && functions.charAt(index - 1) != ',') return false;
+        int charAfter = index + function.length();
+        if (charAfter < functions.length() && functions.charAt(charAfter) != ',') return false;
+        return true;
     }
 
     /**
@@ -413,30 +403,52 @@
      *
      * {@hide}
      */
-    public static boolean isFunctionEnabled(String function) {
+    public boolean isFunctionEnabled(String function) {
+        return propertyContainsFunction("sys.usb.config", function);
+    }
+
+    /**
+     * Sets the primary USB function.
+     *
+     * @param function name of the USB function
+     *
+     * {@hide}
+     */
+    public void setPrimaryFunction(String function) {
         try {
-            FileInputStream stream = new FileInputStream(getFunctionEnableFile(function));
-            boolean enabled = (stream.read() == '1');
-            stream.close();
-            return enabled;
-        } catch (IOException e) {
-            return false;
+            mService.setPrimaryFunction(function);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in setPrimaryFunction", e);
         }
     }
 
     /**
-     * Enables or disables a USB function.
+     * Sets the default primary USB function.
+     *
+     * @param function name of the USB function
      *
      * {@hide}
      */
-    public static boolean setFunctionEnabled(String function, boolean enable) {
+    public void setDefaultFunction(String function) {
         try {
-            FileOutputStream stream = new FileOutputStream(getFunctionEnableFile(function));
-            stream.write(enable ? '1' : '0');
-            stream.close();
-            return true;
-        } catch (IOException e) {
-            return false;
+            mService.setDefaultFunction(function);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in setDefaultFunction", e);
+        }
+    }
+
+    /**
+     * Sets the file path for USB mass storage backing file.
+     *
+     * @param path backing file path
+     *
+     * {@hide}
+     */
+    public void setMassStorageBackingFile(String path) {
+        try {
+            mService.setMassStorageBackingFile(path);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in setDefaultFunction", e);
         }
     }
 }
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 3025462..2242e9e 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -19,7 +19,6 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.os.Binder;
-import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 
@@ -758,43 +757,4 @@
         } catch (RemoteException e) {
         }
     }
-
-    /**
-     * Protect a socket from routing changes. This method is limited to VPN
-     * applications, and it is always hidden to avoid direct use.
-     * @hide
-     */
-    public void protectVpn(ParcelFileDescriptor socket) {
-        try {
-            mService.protectVpn(socket);
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
-     * Prepare for a VPN application. This method is limited to VpnDialogs,
-     * and it is always hidden to avoid direct use.
-     * @hide
-     */
-    public String prepareVpn(String packageName) {
-        try {
-            return mService.prepareVpn(packageName);
-        } catch (RemoteException e) {
-            return null;
-        }
-    }
-
-    /**
-     * Configure a TUN interface and return its file descriptor. Parameters
-     * are encoded and opaque to this class. This method is limited to VPN
-     * applications, and it is always hidden to avoid direct use.
-     * @hide
-     */
-    public ParcelFileDescriptor establishVpn(Bundle config) {
-        try {
-            return mService.establishVpn(config);
-        } catch (RemoteException e) {
-            return null;
-        }
-    }
 }
diff --git a/core/java/android/net/DhcpStateMachine.java b/core/java/android/net/DhcpStateMachine.java
index eaf087f..c49c019 100644
--- a/core/java/android/net/DhcpStateMachine.java
+++ b/core/java/android/net/DhcpStateMachine.java
@@ -66,6 +66,9 @@
     private static final int DHCP_RENEW = 0;
     private static final String ACTION_DHCP_RENEW = "android.net.wifi.DHCP_RENEW";
 
+    //Used for sanity check on setting up renewal
+    private static final int MIN_RENEWAL_TIME_SECS = 5 * 60;  // 5 minutes
+
     private enum DhcpAction {
         START,
         RENEW
@@ -331,13 +334,21 @@
 
         if (success) {
             Log.d(TAG, "DHCP succeeded on " + mInterfaceName);
-            //Do it a bit earlier than half the lease duration time
-            //to beat the native DHCP client and avoid extra packets
-            //48% for one hour lease time = 29 minutes
-            mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
-                    SystemClock.elapsedRealtime() +
-                    dhcpInfoInternal.leaseDuration * 480, //in milliseconds
-                    mDhcpRenewalIntent);
+           long leaseDuration = dhcpInfoInternal.leaseDuration; //int to long conversion
+
+           //Sanity check for renewal
+           //TODO: would be good to notify the user that his network configuration is
+           //bad and that the device cannot renew below MIN_RENEWAL_TIME_SECS
+           if (leaseDuration < MIN_RENEWAL_TIME_SECS) {
+               leaseDuration = MIN_RENEWAL_TIME_SECS;
+           }
+           //Do it a bit earlier than half the lease duration time
+           //to beat the native DHCP client and avoid extra packets
+           //48% for one hour lease time = 29 minutes
+           mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                   SystemClock.elapsedRealtime() +
+                   leaseDuration * 480, //in milliseconds
+                   mDhcpRenewalIntent);
 
             mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, dhcpInfoInternal)
                 .sendToTarget();
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 7f3775d..fba16e1 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -20,10 +20,11 @@
 import android.net.NetworkInfo;
 import android.net.NetworkState;
 import android.net.ProxyProperties;
-import android.os.Bundle;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 
+import com.android.internal.net.VpnConfig;
+
 /**
  * Interface that answers queries about, and allows changing, the
  * state of network connectivity.
@@ -102,5 +103,5 @@
 
     String prepareVpn(String packageName);
 
-    ParcelFileDescriptor establishVpn(in Bundle config);
+    ParcelFileDescriptor establishVpn(in VpnConfig config);
 }
diff --git a/core/java/android/net/INetworkPolicyListener.aidl b/core/java/android/net/INetworkPolicyListener.aidl
index 9230151..a45ec54 100644
--- a/core/java/android/net/INetworkPolicyListener.aidl
+++ b/core/java/android/net/INetworkPolicyListener.aidl
@@ -19,6 +19,7 @@
 /** {@hide} */
 oneway interface INetworkPolicyListener {
 
-    void onRulesChanged(int uid, int uidRules);
+    void onUidRulesChanged(int uid, int uidRules);
+    void onMeteredIfacesChanged(in String[] meteredIfaces);
 
 }
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index 288112a..ae9aa05 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -18,18 +18,19 @@
 
 import android.net.NetworkStats;
 import android.net.NetworkStatsHistory;
+import android.net.NetworkTemplate;
 
 /** {@hide} */
 interface INetworkStatsService {
 
     /** Return historical stats for traffic that matches template. */
-    NetworkStatsHistory getHistoryForNetwork(int networkTemplate);
+    NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template);
     /** Return historical stats for specific UID traffic that matches template. */
-    NetworkStatsHistory getHistoryForUid(int uid, int networkTemplate);
+    NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int tag);
 
     /** Return usage summary for traffic that matches template. */
-    NetworkStats getSummaryForNetwork(long start, long end, int networkTemplate, String subscriberId);
+    NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end);
     /** Return usage summary per UID for traffic that matches template. */
-    NetworkStats getSummaryForAllUid(long start, long end, int networkTemplate);
+    NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end, boolean includeTags);
 
 }
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index 770f152..f3c863f 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -69,10 +69,6 @@
     private boolean mPrivateDnsRouteSet = false;
     private boolean mDefaultRouteSet = false;
 
-    // DEFAULT and HIPRI are the same connection.  If we're one of these we need to check if
-    // the other is also disconnected before we reset sockets
-    private boolean mIsDefaultOrHipri = false;
-
     private Handler mHandler;
     private AsyncChannel mDataConnectionTrackerAc;
     private Messenger mMessenger;
@@ -87,12 +83,6 @@
                 TelephonyManager.getDefault().getNetworkType(), tag,
                 TelephonyManager.getDefault().getNetworkTypeName());
         mApnType = networkTypeToApnType(netType);
-        if (netType == ConnectivityManager.TYPE_MOBILE ||
-                netType == ConnectivityManager.TYPE_MOBILE_HIPRI) {
-            mIsDefaultOrHipri = true;
-        }
-
-        mPhoneService = null;
     }
 
     /**
@@ -180,8 +170,6 @@
     }
 
     private class MobileDataStateReceiver extends BroadcastReceiver {
-        IConnectivityManager mConnectivityManager;
-
         @Override
         public void onReceive(Context context, Intent intent) {
             if (intent.getAction().equals(TelephonyIntents.
@@ -218,35 +206,6 @@
                             }
 
                             setDetailedState(DetailedState.DISCONNECTED, reason, apnName);
-                            boolean doReset = true;
-                            if (mIsDefaultOrHipri == true) {
-                                // both default and hipri must go down before we reset
-                                int typeToCheck = (Phone.APN_TYPE_DEFAULT.equals(mApnType) ?
-                                    ConnectivityManager.TYPE_MOBILE_HIPRI :
-                                    ConnectivityManager.TYPE_MOBILE);
-                                if (mConnectivityManager == null) {
-                                    IBinder b = ServiceManager.getService(
-                                            Context.CONNECTIVITY_SERVICE);
-                                    mConnectivityManager = IConnectivityManager.Stub.asInterface(b);
-                                }
-                                try {
-                                    if (mConnectivityManager != null) {
-                                        NetworkInfo info = mConnectivityManager.getNetworkInfo(
-                                                typeToCheck);
-                                        if (info.isConnected() == true) {
-                                            doReset = false;
-                                        }
-                                    }
-                                } catch (RemoteException e) {
-                                    // just go ahead with the reset
-                                    loge("Exception trying to contact ConnService: " + e);
-                                }
-                            }
-                            if (doReset && mLinkProperties != null) {
-                                String iface = mLinkProperties.getInterfaceName();
-                                if (iface != null) NetworkUtils.resetConnections(iface);
-                            }
-                            // TODO - check this
                             // can't do this here - ConnectivityService needs it to clear stuff
                             // it's ok though - just leave it to be refreshed next time
                             // we connect.
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
new file mode 100644
index 0000000..ccef122
--- /dev/null
+++ b/core/java/android/net/NetworkIdentity.java
@@ -0,0 +1,122 @@
+/*
+ * 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 android.net;
+
+import static android.net.ConnectivityManager.isNetworkTypeMobile;
+
+import android.content.Context;
+import android.telephony.TelephonyManager;
+
+import com.android.internal.util.Objects;
+
+/**
+ * Network definition that includes strong identity. Analogous to combining
+ * {@link NetworkInfo} and an IMSI.
+ *
+ * @hide
+ */
+public class NetworkIdentity {
+    final int mType;
+    final int mSubType;
+    final String mSubscriberId;
+    final boolean mRoaming;
+
+    public NetworkIdentity(int type, int subType, String subscriberId, boolean roaming) {
+        this.mType = type;
+        this.mSubType = subType;
+        this.mSubscriberId = subscriberId;
+        this.mRoaming = roaming;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(mType, mSubType, mSubscriberId);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof NetworkIdentity) {
+            final NetworkIdentity ident = (NetworkIdentity) obj;
+            return mType == ident.mType && mSubType == ident.mSubType
+                    && Objects.equal(mSubscriberId, ident.mSubscriberId)
+                    && mRoaming == ident.mRoaming;
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        final String typeName = ConnectivityManager.getNetworkTypeName(mType);
+        final String subTypeName;
+        if (ConnectivityManager.isNetworkTypeMobile(mType)) {
+            subTypeName = TelephonyManager.getNetworkTypeName(mSubType);
+        } else {
+            subTypeName = Integer.toString(mSubType);
+        }
+
+        final String scrubSubscriberId = mSubscriberId != null ? "valid" : "null";
+        final String roaming = mRoaming ? ", ROAMING" : "";
+        return "[type=" + typeName + ", subType=" + subTypeName + ", subscriberId="
+                + scrubSubscriberId + roaming + "]";
+    }
+
+    public int getType() {
+        return mType;
+    }
+
+    public int getSubType() {
+        return mSubType;
+    }
+
+    public String getSubscriberId() {
+        return mSubscriberId;
+    }
+
+    public boolean getRoaming() {
+        return mRoaming;
+    }
+
+    /**
+     * Build a {@link NetworkIdentity} from the given {@link NetworkState},
+     * assuming that any mobile networks are using the current IMSI.
+     */
+    public static NetworkIdentity buildNetworkIdentity(Context context, NetworkState state) {
+        final int type = state.networkInfo.getType();
+        final int subType = state.networkInfo.getSubtype();
+
+        // TODO: consider moving subscriberId over to LinkCapabilities, so it
+        // comes from an authoritative source.
+
+        final String subscriberId;
+        final boolean roaming;
+        if (isNetworkTypeMobile(type)) {
+            final TelephonyManager telephony = (TelephonyManager) context.getSystemService(
+                    Context.TELEPHONY_SERVICE);
+            roaming = telephony.isNetworkRoaming();
+            if (state.subscriberId != null) {
+                subscriberId = state.subscriberId;
+            } else {
+                subscriberId = telephony.getSubscriberId();
+            }
+        } else {
+            subscriberId = null;
+            roaming = false;
+        }
+        return new NetworkIdentity(type, subType, subscriberId, roaming);
+    }
+
+}
diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java
index 1899281..52cab30 100644
--- a/core/java/android/net/NetworkPolicy.java
+++ b/core/java/android/net/NetworkPolicy.java
@@ -16,37 +16,38 @@
 
 package android.net;
 
+import static com.android.internal.util.Preconditions.checkNotNull;
+
 import android.os.Parcel;
 import android.os.Parcelable;
 
 /**
- * Policy for a specific network, including usage cycle and limits to be
- * enforced.
+ * Policy for networks matching a {@link NetworkTemplate}, including usage cycle
+ * and limits to be enforced.
  *
  * @hide
  */
 public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
-    public final int networkTemplate;
-    public final String subscriberId;
+    public static final long WARNING_DISABLED = -1;
+    public static final long LIMIT_DISABLED = -1;
+
+    public final NetworkTemplate template;
     public int cycleDay;
     public long warningBytes;
     public long limitBytes;
 
-    public static final long WARNING_DISABLED = -1;
-    public static final long LIMIT_DISABLED = -1;
+    // TODO: teach how to snooze limit for current cycle
 
-    public NetworkPolicy(int networkTemplate, String subscriberId, int cycleDay, long warningBytes,
-            long limitBytes) {
-        this.networkTemplate = networkTemplate;
-        this.subscriberId = subscriberId;
+    public NetworkPolicy(
+            NetworkTemplate template, int cycleDay, long warningBytes, long limitBytes) {
+        this.template = checkNotNull(template, "missing NetworkTemplate");
         this.cycleDay = cycleDay;
         this.warningBytes = warningBytes;
         this.limitBytes = limitBytes;
     }
 
     public NetworkPolicy(Parcel in) {
-        networkTemplate = in.readInt();
-        subscriberId = in.readString();
+        template = in.readParcelable(null);
         cycleDay = in.readInt();
         warningBytes = in.readLong();
         limitBytes = in.readLong();
@@ -54,8 +55,7 @@
 
     /** {@inheritDoc} */
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(networkTemplate);
-        dest.writeString(subscriberId);
+        dest.writeParcelable(template, flags);
         dest.writeInt(cycleDay);
         dest.writeLong(warningBytes);
         dest.writeLong(limitBytes);
@@ -81,8 +81,8 @@
 
     @Override
     public String toString() {
-        return "NetworkPolicy: networkTemplate=" + networkTemplate + ", cycleDay=" + cycleDay
-                + ", warningBytes=" + warningBytes + ", limitBytes=" + limitBytes;
+        return "NetworkPolicy[" + template + "]: cycleDay=" + cycleDay + ", warningBytes="
+                + warningBytes + ", limitBytes=" + limitBytes;
     }
 
     public static final Creator<NetworkPolicy> CREATOR = new Creator<NetworkPolicy>() {
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index e9d65e6..91af16d 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -19,6 +19,7 @@
 import static android.text.format.Time.MONTH_DAY;
 
 import android.content.Context;
+import android.content.Intent;
 import android.os.RemoteException;
 import android.text.format.Time;
 
@@ -33,13 +34,35 @@
 
     /** No specific network policy, use system default. */
     public static final int POLICY_NONE = 0x0;
-    /** Reject network usage on paid networks when application in background. */
-    public static final int POLICY_REJECT_PAID_BACKGROUND = 0x1;
+    /** Reject network usage on metered networks when application in background. */
+    public static final int POLICY_REJECT_METERED_BACKGROUND = 0x1;
 
     /** All network traffic should be allowed. */
     public static final int RULE_ALLOW_ALL = 0x0;
-    /** Reject traffic on paid networks. */
-    public static final int RULE_REJECT_PAID = 0x1;
+    /** Reject traffic on metered networks. */
+    public static final int RULE_REJECT_METERED = 0x1;
+
+    /**
+     * {@link Intent} action launched when user selects {@link NetworkPolicy}
+     * warning notification.
+     */
+    public static final String ACTION_DATA_USAGE_WARNING =
+            "android.intent.action.DATA_USAGE_WARNING";
+
+    /**
+     * {@link Intent} action launched when user selects {@link NetworkPolicy}
+     * limit notification.
+     */
+    public static final String ACTION_DATA_USAGE_LIMIT =
+            "android.intent.action.DATA_USAGE_LIMIT";
+
+    /**
+     * {@link Intent} extra included in {@link #ACTION_DATA_USAGE_WARNING} and
+     * {@link #ACTION_DATA_USAGE_LIMIT} to indicate which
+     * {@link NetworkTemplate} rule it applies to.
+     */
+    public static final String EXTRA_NETWORK_TEMPLATE =
+            "android.intent.extra.NETWORK_TEMPLATE";
 
     private INetworkPolicyManager mService;
 
@@ -75,7 +98,7 @@
      * Set policy flags for specific UID.
      *
      * @param policy {@link #POLICY_NONE} or combination of flags like
-     *            {@link #POLICY_REJECT_PAID_BACKGROUND}.
+     *            {@link #POLICY_REJECT_METERED_BACKGROUND}.
      */
     public void setUidPolicy(int uid, int policy) {
         try {
@@ -92,6 +115,20 @@
         }
     }
 
+    public void registerListener(INetworkPolicyListener listener) {
+        try {
+            mService.registerListener(listener);
+        } catch (RemoteException e) {
+        }
+    }
+
+    public void unregisterListener(INetworkPolicyListener listener) {
+        try {
+            mService.unregisterListener(listener);
+        } catch (RemoteException e) {
+        }
+    }
+
     /**
      * Compute the last cycle boundary for the given {@link NetworkPolicy}. For
      * example, if cycle day is 20th, and today is June 15th, it will return May
@@ -180,8 +217,8 @@
     /** {@hide} */
     public static void dumpPolicy(PrintWriter fout, int policy) {
         fout.write("[");
-        if ((policy & POLICY_REJECT_PAID_BACKGROUND) != 0) {
-            fout.write("REJECT_PAID_BACKGROUND");
+        if ((policy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
+            fout.write("REJECT_METERED_BACKGROUND");
         }
         fout.write("]");
     }
@@ -189,8 +226,8 @@
     /** {@hide} */
     public static void dumpRules(PrintWriter fout, int rules) {
         fout.write("[");
-        if ((rules & RULE_REJECT_PAID) != 0) {
-            fout.write("REJECT_PAID");
+        if ((rules & RULE_REJECT_METERED) != 0) {
+            fout.write("REJECT_METERED");
         }
         fout.write("]");
     }
diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java
index 749039a..704111b 100644
--- a/core/java/android/net/NetworkState.java
+++ b/core/java/android/net/NetworkState.java
@@ -29,18 +29,27 @@
     public final NetworkInfo networkInfo;
     public final LinkProperties linkProperties;
     public final LinkCapabilities linkCapabilities;
+    /** Currently only used by testing. */
+    public final String subscriberId;
 
     public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties,
             LinkCapabilities linkCapabilities) {
+        this(networkInfo, linkProperties, linkCapabilities, null);
+    }
+
+    public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties,
+            LinkCapabilities linkCapabilities, String subscriberId) {
         this.networkInfo = networkInfo;
         this.linkProperties = linkProperties;
         this.linkCapabilities = linkCapabilities;
+        this.subscriberId = subscriberId;
     }
 
     public NetworkState(Parcel in) {
         networkInfo = in.readParcelable(null);
         linkProperties = in.readParcelable(null);
         linkCapabilities = in.readParcelable(null);
+        subscriberId = in.readString();
     }
 
     /** {@inheritDoc} */
@@ -53,6 +62,7 @@
         out.writeParcelable(networkInfo, flags);
         out.writeParcelable(linkProperties, flags);
         out.writeParcelable(linkCapabilities, flags);
+        out.writeString(subscriberId);
     }
 
     public static final Creator<NetworkState> CREATOR = new Creator<NetworkState>() {
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 60f740e..9d40c42 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -40,9 +40,8 @@
     public static final String IFACE_ALL = null;
     /** {@link #uid} value when UID details unavailable. */
     public static final int UID_ALL = -1;
-
-    // NOTE: data should only be accounted for once in this structure; if data
-    // is broken out, the summarized version should not be included.
+    /** {@link #tag} value for without tag. */
+    public static final int TAG_NONE = 0;
 
     /**
      * {@link SystemClock#elapsedRealtime()} timestamp when this data was
@@ -52,16 +51,16 @@
     public int size;
     public String[] iface;
     public int[] uid;
+    public int[] tag;
     public long[] rx;
     public long[] tx;
 
-    // TODO: add fg/bg stats once reported by kernel
-
     public NetworkStats(long elapsedRealtime, int initialSize) {
         this.elapsedRealtime = elapsedRealtime;
         this.size = 0;
         this.iface = new String[initialSize];
         this.uid = new int[initialSize];
+        this.tag = new int[initialSize];
         this.rx = new long[initialSize];
         this.tx = new long[initialSize];
     }
@@ -71,21 +70,27 @@
         size = parcel.readInt();
         iface = parcel.createStringArray();
         uid = parcel.createIntArray();
+        tag = parcel.createIntArray();
         rx = parcel.createLongArray();
         tx = parcel.createLongArray();
     }
 
-    public NetworkStats addEntry(String iface, int uid, long rx, long tx) {
+    /**
+     * Add new stats entry with given values.
+     */
+    public NetworkStats addEntry(String iface, int uid, int tag, long rx, long tx) {
         if (size >= this.iface.length) {
             final int newLength = Math.max(this.iface.length, 10) * 3 / 2;
             this.iface = Arrays.copyOf(this.iface, newLength);
             this.uid = Arrays.copyOf(this.uid, newLength);
+            this.tag = Arrays.copyOf(this.tag, newLength);
             this.rx = Arrays.copyOf(this.rx, newLength);
             this.tx = Arrays.copyOf(this.tx, newLength);
         }
 
         this.iface[size] = iface;
         this.uid[size] = uid;
+        this.tag[size] = tag;
         this.rx[size] = rx;
         this.tx[size] = tx;
         size++;
@@ -93,17 +98,29 @@
         return this;
     }
 
-    @Deprecated
-    public int length() {
-        return size;
+    /**
+     * Combine given values with an existing row, or create a new row if
+     * {@link #findIndex(String, int, int)} is unable to find match. Can also be
+     * used to subtract values from existing rows.
+     */
+    public NetworkStats combineEntry(String iface, int uid, int tag, long rx, long tx) {
+        final int i = findIndex(iface, uid, tag);
+        if (i == -1) {
+            // only create new entry when positive contribution
+            addEntry(iface, uid, tag, rx, tx);
+        } else {
+            this.rx[i] += rx;
+            this.tx[i] += tx;
+        }
+        return this;
     }
 
     /**
      * Find first stats index that matches the requested parameters.
      */
-    public int findIndex(String iface, int uid) {
+    public int findIndex(String iface, int uid, int tag) {
         for (int i = 0; i < size; i++) {
-            if (equal(iface, this.iface[i]) && uid == this.uid[i]) {
+            if (equal(iface, this.iface[i]) && uid == this.uid[i] && tag == this.tag[i]) {
                 return i;
             }
         }
@@ -186,12 +203,13 @@
         for (int i = 0; i < size; i++) {
             final String iface = this.iface[i];
             final int uid = this.uid[i];
+            final int tag = this.tag[i];
 
             // find remote row that matches, and subtract
-            final int j = value.findIndex(iface, uid);
+            final int j = value.findIndex(iface, uid, tag);
             if (j == -1) {
                 // newly appearing row, return entire value
-                result.addEntry(iface, uid, this.rx[i], this.tx[i]);
+                result.addEntry(iface, uid, tag, this.rx[i], this.tx[i]);
             } else {
                 // existing row, subtract remote value
                 long rx = this.rx[i] - value.rx[j];
@@ -203,7 +221,7 @@
                     rx = Math.max(0, rx);
                     tx = Math.max(0, tx);
                 }
-                result.addEntry(iface, uid, rx, tx);
+                result.addEntry(iface, uid, tag, rx, tx);
             }
         }
 
@@ -221,6 +239,7 @@
             pw.print(prefix);
             pw.print("  iface="); pw.print(iface[i]);
             pw.print(" uid="); pw.print(uid[i]);
+            pw.print(" tag="); pw.print(tag[i]);
             pw.print(" rx="); pw.print(rx[i]);
             pw.print(" tx="); pw.println(tx[i]);
         }
@@ -244,6 +263,7 @@
         dest.writeInt(size);
         dest.writeStringArray(iface);
         dest.writeIntArray(uid);
+        dest.writeIntArray(tag);
         dest.writeLongArray(rx);
         dest.writeLongArray(tx);
     }
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index 5fa8e21..ff6e220 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -40,10 +40,9 @@
  * @hide
  */
 public class NetworkStatsHistory implements Parcelable {
-    private static final int VERSION_CURRENT = 1;
+    private static final int VERSION_INIT = 1;
 
-    // TODO: teach about zigzag encoding to use less disk space
-    // TODO: teach how to convert between bucket sizes
+    // TODO: teach about varint encoding to use less disk space
 
     public final long bucketDuration;
 
@@ -83,7 +82,7 @@
     public NetworkStatsHistory(DataInputStream in) throws IOException {
         final int version = in.readInt();
         switch (version) {
-            case VERSION_CURRENT: {
+            case VERSION_INIT: {
                 bucketDuration = in.readLong();
                 bucketStart = readLongArray(in);
                 rx = readLongArray(in);
@@ -98,7 +97,7 @@
     }
 
     public void writeToStream(DataOutputStream out) throws IOException {
-        out.writeInt(VERSION_CURRENT);
+        out.writeInt(VERSION_INIT);
         out.writeLong(bucketDuration);
         writeLongArray(out, bucketStart, bucketCount);
         writeLongArray(out, rx, bucketCount);
@@ -115,6 +114,11 @@
      * distribute across internal buckets, creating new buckets as needed.
      */
     public void recordData(long start, long end, long rx, long tx) {
+        if (rx < 0 || tx < 0) {
+            throw new IllegalArgumentException(
+                    "tried recording negative data: rx=" + rx + ", tx=" + tx);
+        }
+
         // create any buckets needed by this range
         ensureBuckets(start, end);
 
diff --git a/core/java/android/net/NetworkTemplate.aidl b/core/java/android/net/NetworkTemplate.aidl
new file mode 100644
index 0000000..3d37488
--- /dev/null
+++ b/core/java/android/net/NetworkTemplate.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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 android.net;
+
+parcelable NetworkTemplate;
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
new file mode 100644
index 0000000..9381f1d
--- /dev/null
+++ b/core/java/android/net/NetworkTemplate.java
@@ -0,0 +1,217 @@
+/*
+ * 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 android.net;
+
+import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.ConnectivityManager.TYPE_WIMAX;
+import static android.net.ConnectivityManager.isNetworkTypeMobile;
+import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G;
+import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G;
+import static android.telephony.TelephonyManager.NETWORK_CLASS_4_G;
+import static android.telephony.TelephonyManager.NETWORK_CLASS_UNKNOWN;
+import static android.telephony.TelephonyManager.getNetworkClass;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Objects;
+
+/**
+ * Template definition used to generically match {@link NetworkIdentity},
+ * usually when collecting statistics.
+ *
+ * @hide
+ */
+public class NetworkTemplate implements Parcelable {
+
+    /**
+     * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style
+     * networks together. Only uses statistics for requested IMSI.
+     */
+    public static final int MATCH_MOBILE_ALL = 1;
+
+    /**
+     * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style
+     * networks together that roughly meet a "3G" definition, or lower. Only
+     * uses statistics for requested IMSI.
+     */
+    public static final int MATCH_MOBILE_3G_LOWER = 2;
+
+    /**
+     * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style
+     * networks together that meet a "4G" definition. Only uses statistics for
+     * requested IMSI.
+     */
+    public static final int MATCH_MOBILE_4G = 3;
+
+    /**
+     * Template to combine all {@link ConnectivityManager#TYPE_WIFI} style
+     * networks together.
+     */
+    public static final int MATCH_WIFI = 4;
+
+    final int mMatchRule;
+    final String mSubscriberId;
+
+    public NetworkTemplate(int matchRule, String subscriberId) {
+        this.mMatchRule = matchRule;
+        this.mSubscriberId = subscriberId;
+    }
+
+    public NetworkTemplate(Parcel in) {
+        mMatchRule = in.readInt();
+        mSubscriberId = in.readString();
+    }
+
+    /** {@inheritDoc} */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mMatchRule);
+        dest.writeString(mSubscriberId);
+    }
+
+    /** {@inheritDoc} */
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public String toString() {
+        final String scrubSubscriberId = mSubscriberId != null ? "valid" : "null";
+        return "NetworkTemplate: matchRule=" + getMatchRuleName(mMatchRule) + ", subscriberId="
+                + scrubSubscriberId;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(mMatchRule, mSubscriberId);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof NetworkTemplate) {
+            final NetworkTemplate other = (NetworkTemplate) obj;
+            return mMatchRule == other.mMatchRule
+                    && Objects.equal(mSubscriberId, other.mSubscriberId);
+        }
+        return false;
+    }
+
+    public int getMatchRule() {
+        return mMatchRule;
+    }
+
+    public String getSubscriberId() {
+        return mSubscriberId;
+    }
+
+    /**
+     * Test if this network matches the given template and IMEI.
+     */
+    public boolean matches(NetworkIdentity ident) {
+        switch (mMatchRule) {
+            case MATCH_MOBILE_ALL:
+                return matchesMobile(ident);
+            case MATCH_MOBILE_3G_LOWER:
+                return matchesMobile3gLower(ident);
+            case MATCH_MOBILE_4G:
+                return matchesMobile4g(ident);
+            case MATCH_WIFI:
+                return matchesWifi(ident);
+            default:
+                throw new IllegalArgumentException("unknown network template");
+        }
+    }
+
+    /**
+     * Check if mobile network with matching IMEI. Also matches
+     * {@link #TYPE_WIMAX}.
+     */
+    private boolean matchesMobile(NetworkIdentity ident) {
+        if (isNetworkTypeMobile(ident.mType) && Objects.equal(mSubscriberId, ident.mSubscriberId)) {
+            return true;
+        } else if (ident.mType == TYPE_WIMAX) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Check if mobile network classified 3G or lower with matching IMEI.
+     */
+    private boolean matchesMobile3gLower(NetworkIdentity ident) {
+        if (isNetworkTypeMobile(ident.mType) && Objects.equal(mSubscriberId, ident.mSubscriberId)) {
+            switch (getNetworkClass(ident.mSubType)) {
+                case NETWORK_CLASS_UNKNOWN:
+                case NETWORK_CLASS_2_G:
+                case NETWORK_CLASS_3_G:
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Check if mobile network classified 4G with matching IMEI. Also matches
+     * {@link #TYPE_WIMAX}.
+     */
+    private boolean matchesMobile4g(NetworkIdentity ident) {
+        if (isNetworkTypeMobile(ident.mType) && Objects.equal(mSubscriberId, ident.mSubscriberId)) {
+            switch (getNetworkClass(ident.mSubType)) {
+                case NETWORK_CLASS_4_G:
+                    return true;
+            }
+        } else if (ident.mType == TYPE_WIMAX) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Check if matches Wi-Fi network template.
+     */
+    private boolean matchesWifi(NetworkIdentity ident) {
+        if (ident.mType == TYPE_WIFI) {
+            return true;
+        }
+        return false;
+    }
+
+    public static String getMatchRuleName(int matchRule) {
+        switch (matchRule) {
+            case MATCH_MOBILE_3G_LOWER:
+                return "MOBILE_3G_LOWER";
+            case MATCH_MOBILE_4G:
+                return "MOBILE_4G";
+            case MATCH_MOBILE_ALL:
+                return "MOBILE_ALL";
+            case MATCH_WIFI:
+                return "WIFI";
+            default:
+                return "UNKNOWN";
+        }
+    }
+
+    public static final Creator<NetworkTemplate> CREATOR = new Creator<NetworkTemplate>() {
+        public NetworkTemplate createFromParcel(Parcel in) {
+            return new NetworkTemplate(in);
+        }
+
+        public NetworkTemplate[] newArray(int size) {
+            return new NetworkTemplate[size];
+        }
+    };
+}
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index 3725fa6..cb47193 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -42,38 +42,12 @@
     public final static int UNSUPPORTED = -1;
 
     /**
-     * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style
-     * networks together. Only uses statistics for requested IMSI.
+     * Special UID value used when collecting {@link NetworkStatsHistory} for
+     * removed applications.
      *
      * @hide
      */
-    public static final int TEMPLATE_MOBILE_ALL = 1;
-
-    /**
-     * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style
-     * networks together that roughly meet a "3G" definition, or lower. Only
-     * uses statistics for requested IMSI.
-     *
-     * @hide
-     */
-    public static final int TEMPLATE_MOBILE_3G_LOWER = 2;
-
-    /**
-     * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style
-     * networks together that meet a "4G" definition. Only uses statistics for
-     * requested IMSI.
-     *
-     * @hide
-     */
-    public static final int TEMPLATE_MOBILE_4G = 3;
-
-    /**
-     * Template to combine all {@link ConnectivityManager#TYPE_WIFI} style
-     * networks together.
-     *
-     * @hide
-     */
-    public static final int TEMPLATE_WIFI = 4;
+    public static final int UID_REMOVED = -4;
 
     /**
      * Snapshot of {@link NetworkStats} when the currently active profiling
@@ -182,17 +156,6 @@
         }
     }
 
-    /** {@hide} */
-    public static boolean isNetworkTemplateMobile(int networkTemplate) {
-        switch (networkTemplate) {
-            case TEMPLATE_MOBILE_3G_LOWER:
-            case TEMPLATE_MOBILE_4G:
-            case TEMPLATE_MOBILE_ALL:
-                return true;
-        }
-        return false;
-    }
-
     /**
      * Get the total number of packets transmitted through the mobile interface.
      *
diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java
index 8876354..81defd6 100644
--- a/core/java/android/os/IBinder.java
+++ b/core/java/android/os/IBinder.java
@@ -110,6 +110,24 @@
     int INTERFACE_TRANSACTION   = ('_'<<24)|('N'<<16)|('T'<<8)|'F';
 
     /**
+     * IBinder protocol transaction code: send a tweet to the target
+     * object.  The data in the parcel is intended to be delivered to
+     * a shared messaging service associated with the object; it can be
+     * anything, as long as it is not more than 130 UTF-8 characters to
+     * conservatively fit within common messaging services.  As part of
+     * {@link Build.VERSION_CODES#HONEYCOMB_MR2}, all Binder objects are
+     * expected to support this protocol for fully integrated tweeting
+     * across the platform.  To support older code, the default implementation
+     * logs the tweet to the main log as a simple emulation of broadcasting
+     * it publicly over the Internet.
+     * 
+     * <p>Also, upon completing the dispatch, the object must make a cup
+     * of tea, return it to the caller, and exclaim "jolly good message
+     * old boy!".
+     */
+    int TWEET_TRANSACTION   = ('_'<<24)|('T'<<16)|('W'<<8)|'T';
+
+    /**
      * Flag to {@link #transact}: this is a one-way call, meaning that the
      * caller returns immediately, without waiting for a result from the
      * callee. Applies only if the caller and callee are in different
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index f17a6f2..b97ec19 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -59,6 +59,11 @@
     void setInterfaceConfig(String iface, in InterfaceConfiguration cfg);
 
     /**
+     * Clear all IP addresses on the specified interface
+     */
+    void clearInterfaceAddresses(String iface);
+
+    /**
      * Retrieves the network routes currently configured on the specified
      * interface
      */
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index b6d1594..74a376d 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -29,6 +29,7 @@
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.AbsSavedState;
+import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -956,6 +957,17 @@
             context.startActivity(mIntent);
         }
     }
+
+    /**
+     * Allows a Preference to intercept key events without having focus.
+     * For example, SeekBarPreference uses this to intercept +/- to adjust
+     * the progress.
+     * @return True if the Preference handled the key. Returns false by default.
+     * @hide
+     */
+    public boolean onKey(View v, int keyCode, KeyEvent event) {
+        return false;
+    }
     
     /**
      * Returns the {@link android.content.Context} of this Preference. 
diff --git a/core/java/android/preference/PreferenceFragment.java b/core/java/android/preference/PreferenceFragment.java
index 488919c..f6ba7f7 100644
--- a/core/java/android/preference/PreferenceFragment.java
+++ b/core/java/android/preference/PreferenceFragment.java
@@ -20,13 +20,14 @@
 import android.app.Fragment;
 import android.content.Intent;
 import android.content.SharedPreferences;
-import android.content.res.Configuration;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.View.OnKeyListener;
 import android.widget.ListView;
 
 /**
@@ -350,6 +351,22 @@
                     "Your content must have a ListView whose id attribute is " +
                     "'android.R.id.list'");
         }
+        mList.setOnKeyListener(mListOnKeyListener);
         mHandler.post(mRequestFocus);
     }
+
+    private OnKeyListener mListOnKeyListener = new OnKeyListener() {
+
+        @Override
+        public boolean onKey(View v, int keyCode, KeyEvent event) {
+            Object selectedItem = mList.getSelectedItem();
+            if (selectedItem instanceof Preference) {
+                View selectedView = mList.getSelectedView();
+                return ((Preference)selectedItem).onKey(
+                        selectedView, keyCode, event);
+            }
+            return false;
+        }
+
+    };
 }
diff --git a/core/java/android/preference/SeekBarDialogPreference.java b/core/java/android/preference/SeekBarDialogPreference.java
new file mode 100644
index 0000000..0e89b16
--- /dev/null
+++ b/core/java/android/preference/SeekBarDialogPreference.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2007 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 android.preference;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.preference.DialogPreference;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.SeekBar;
+
+/**
+ * @hide
+ */
+public class SeekBarDialogPreference extends DialogPreference {
+    private static final String TAG = "SeekBarDialogPreference";
+
+    private Drawable mMyIcon;
+
+    public SeekBarDialogPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        setDialogLayoutResource(com.android.internal.R.layout.seekbar_dialog);
+        createActionButtons();
+
+        // Steal the XML dialogIcon attribute's value
+        mMyIcon = getDialogIcon();
+        setDialogIcon(null);
+    }
+
+    // Allow subclasses to override the action buttons
+    public void createActionButtons() {
+        setPositiveButtonText(android.R.string.ok);
+        setNegativeButtonText(android.R.string.cancel);
+    }
+
+    @Override
+    protected void onBindDialogView(View view) {
+        super.onBindDialogView(view);
+
+        final ImageView iconView = (ImageView) view.findViewById(android.R.id.icon);
+        if (mMyIcon != null) {
+            iconView.setImageDrawable(mMyIcon);
+        } else {
+            iconView.setVisibility(View.GONE);
+        }
+    }
+
+    protected static SeekBar getSeekBar(View dialogView) {
+        return (SeekBar) dialogView.findViewById(com.android.internal.R.id.seekbar);
+    }
+}
diff --git a/core/java/android/preference/SeekBarPreference.java b/core/java/android/preference/SeekBarPreference.java
index 037fb41..b8919c2 100644
--- a/core/java/android/preference/SeekBarPreference.java
+++ b/core/java/android/preference/SeekBarPreference.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 The Android Open Source Project
+ * 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.
@@ -17,51 +17,226 @@
 package android.preference;
 
 import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.preference.DialogPreference;
+import android.content.res.TypedArray;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.util.AttributeSet;
+import android.view.KeyEvent;
 import android.view.View;
-import android.widget.ImageView;
 import android.widget.SeekBar;
+import android.widget.SeekBar.OnSeekBarChangeListener;
 
 /**
  * @hide
  */
-public class SeekBarPreference extends DialogPreference {
-    private static final String TAG = "SeekBarPreference";
+public class SeekBarPreference extends Preference
+        implements OnSeekBarChangeListener {
 
-    private Drawable mMyIcon;
+    private int mProgress;
+    private int mMax;
+    private boolean mTrackingTouch;
 
-    public SeekBarPreference(Context context, AttributeSet attrs) {
-        super(context, attrs);
-
-        setDialogLayoutResource(com.android.internal.R.layout.seekbar_dialog);
-        createActionButtons();
-
-        // Steal the XML dialogIcon attribute's value
-        mMyIcon = getDialogIcon();
-        setDialogIcon(null);
+    public SeekBarPreference(
+            Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        TypedArray a = context.obtainStyledAttributes(attrs,
+                com.android.internal.R.styleable.ProgressBar, defStyle, 0);
+        setMax(a.getInt(com.android.internal.R.styleable.ProgressBar_max, mMax));
+        a.recycle();
+        setLayoutResource(com.android.internal.R.layout.preference_widget_seekbar);
     }
 
-    // Allow subclasses to override the action buttons
-    public void createActionButtons() {
-        setPositiveButtonText(android.R.string.ok);
-        setNegativeButtonText(android.R.string.cancel);
+    public SeekBarPreference(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public SeekBarPreference(Context context) {
+        this(context, null);
     }
 
     @Override
-    protected void onBindDialogView(View view) {
-        super.onBindDialogView(view);
+    protected void onBindView(View view) {
+        super.onBindView(view);
+        SeekBar seekBar = (SeekBar) view.findViewById(
+                com.android.internal.R.id.seekbar);
+        seekBar.setOnSeekBarChangeListener(this);
+        seekBar.setMax(mMax);
+        seekBar.setProgress(mProgress);
+        seekBar.setEnabled(isEnabled());
+    }
 
-        final ImageView iconView = (ImageView) view.findViewById(android.R.id.icon);
-        if (mMyIcon != null) {
-            iconView.setImageDrawable(mMyIcon);
-        } else {
-            iconView.setVisibility(View.GONE);
+    @Override
+    public CharSequence getSummary() {
+        return null;
+    }
+
+    @Override
+    protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
+        setProgress(restoreValue ? getPersistedInt(mProgress)
+                : (Integer) defaultValue);
+    }
+
+    @Override
+    public boolean onKey(View v, int keyCode, KeyEvent event) {
+        if (event.getAction() != KeyEvent.ACTION_UP) {
+            if (keyCode == KeyEvent.KEYCODE_PLUS
+                    || keyCode == KeyEvent.KEYCODE_EQUALS) {
+                setProgress(getProgress() + 1);
+                return true;
+            }
+            if (keyCode == KeyEvent.KEYCODE_MINUS) {
+                setProgress(getProgress() - 1);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void setMax(int max) {
+        if (max != mMax) {
+            mMax = max;
+            notifyChanged();
         }
     }
 
-    protected static SeekBar getSeekBar(View dialogView) {
-        return (SeekBar) dialogView.findViewById(com.android.internal.R.id.seekbar);
+    public void setProgress(int progress) {
+        setProgress(progress, true);
+    }
+
+    private void setProgress(int progress, boolean notifyChanged) {
+        if (progress > mMax) {
+            progress = mMax;
+        }
+        if (progress < 0) {
+            progress = 0;
+        }
+        if (progress != mProgress) {
+            mProgress = progress;
+            persistInt(progress);
+            if (notifyChanged) {
+                notifyChanged();
+            }
+        }
+    }
+
+    public int getProgress() {
+        return mProgress;
+    }
+
+    /**
+     * Persist the seekBar's progress value if callChangeListener
+     * returns true, otherwise set the seekBar's progress to the stored value
+     */
+    void syncProgress(SeekBar seekBar) {
+        int progress = seekBar.getProgress();
+        if (progress != mProgress) {
+            if (callChangeListener(progress)) {
+                setProgress(progress, false);
+            } else {
+                seekBar.setProgress(mProgress);
+            }
+        }
+    }
+
+    @Override
+    public void onProgressChanged(
+            SeekBar seekBar, int progress, boolean fromUser) {
+        if (fromUser && !mTrackingTouch) {
+            syncProgress(seekBar);
+        }
+    }
+
+    @Override
+    public void onStartTrackingTouch(SeekBar seekBar) {
+        mTrackingTouch = true;
+    }
+
+    @Override
+    public void onStopTrackingTouch(SeekBar seekBar) {
+        mTrackingTouch = false;
+        if (seekBar.getProgress() != mProgress) {
+            syncProgress(seekBar);
+        }
+    }
+
+    @Override
+    protected Parcelable onSaveInstanceState() {
+        /*
+         * Suppose a client uses this preference type without persisting. We
+         * must save the instance state so it is able to, for example, survive
+         * orientation changes.
+         */
+
+        final Parcelable superState = super.onSaveInstanceState();
+        if (isPersistent()) {
+            // No need to save instance state since it's persistent
+            return superState;
+        }
+
+        // Save the instance state
+        final SavedState myState = new SavedState(superState);
+        myState.progress = mProgress;
+        myState.max = mMax;
+        return myState;
+    }
+
+    @Override
+    protected void onRestoreInstanceState(Parcelable state) {
+        if (!state.getClass().equals(SavedState.class)) {
+            // Didn't save state for us in onSaveInstanceState
+            super.onRestoreInstanceState(state);
+            return;
+        }
+
+        // Restore the instance state
+        SavedState myState = (SavedState) state;
+        super.onRestoreInstanceState(myState.getSuperState());
+        mProgress = myState.progress;
+        mMax = myState.max;
+        notifyChanged();
+    }
+
+    /**
+     * SavedState, a subclass of {@link BaseSavedState}, will store the state
+     * of MyPreference, a subclass of Preference.
+     * <p>
+     * It is important to always call through to super methods.
+     */
+    private static class SavedState extends BaseSavedState {
+        int progress;
+        int max;
+
+        public SavedState(Parcel source) {
+            super(source);
+
+            // Restore the click counter
+            progress = source.readInt();
+            max = source.readInt();
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+
+            // Save the click counter
+            dest.writeInt(progress);
+            dest.writeInt(max);
+        }
+
+        public SavedState(Parcelable superState) {
+            super(superState);
+        }
+
+        @SuppressWarnings("unused")
+        public static final Parcelable.Creator<SavedState> CREATOR =
+                new Parcelable.Creator<SavedState>() {
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in);
+            }
+
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
     }
 }
diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java
index 3b12780..b48e8ce 100644
--- a/core/java/android/preference/VolumePreference.java
+++ b/core/java/android/preference/VolumePreference.java
@@ -38,19 +38,19 @@
 /**
  * @hide
  */
-public class VolumePreference extends SeekBarPreference implements 
+public class VolumePreference extends SeekBarDialogPreference implements
         PreferenceManager.OnActivityStopListener, View.OnKeyListener {
 
     private static final String TAG = "VolumePreference";
-    
+
     private int mStreamType;
 
     /** May be null if the dialog isn't visible. */
     private SeekBarVolumizer mSeekBarVolumizer;
-    
+
     public VolumePreference(Context context, AttributeSet attrs) {
         super(context, attrs);
-        
+
         TypedArray a = context.obtainStyledAttributes(attrs,
                 com.android.internal.R.styleable.VolumePreference, 0, 0);
         mStreamType = a.getInt(android.R.styleable.VolumePreference_streamType, 0);
@@ -64,7 +64,7 @@
     @Override
     protected void onBindDialogView(View view) {
         super.onBindDialogView(view);
-    
+
         final SeekBar seekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
         mSeekBarVolumizer = new SeekBarVolumizer(getContext(), seekBar, mStreamType);
 
@@ -105,7 +105,7 @@
     @Override
     protected void onDialogClosed(boolean positiveResult) {
         super.onDialogClosed(positiveResult);
-        
+
         if (!positiveResult && mSeekBarVolumizer != null) {
             mSeekBarVolumizer.revertVolume();
         }
@@ -222,16 +222,16 @@
 
         private Context mContext;
         private Handler mHandler = new Handler();
-    
+
         private AudioManager mAudioManager;
         private int mStreamType;
-        private int mOriginalStreamVolume; 
+        private int mOriginalStreamVolume;
         private Ringtone mRingtone;
-    
+
         private int mLastProgress = -1;
         private SeekBar mSeekBar;
         private int mVolumeBeforeMute = -1;
-        
+
         private ContentObserver mVolumeObserver = new ContentObserver(mHandler) {
             @Override
             public void onChange(boolean selfChange) {
@@ -263,7 +263,7 @@
             mOriginalStreamVolume = mAudioManager.getStreamVolume(mStreamType);
             seekBar.setProgress(mOriginalStreamVolume);
             seekBar.setOnSeekBarChangeListener(this);
-            
+
             mContext.getContentResolver().registerContentObserver(
                     System.getUriFor(System.VOLUME_SETTINGS[mStreamType]),
                     false, mVolumeObserver);
@@ -290,17 +290,17 @@
             mContext.getContentResolver().unregisterContentObserver(mVolumeObserver);
             mSeekBar.setOnSeekBarChangeListener(null);
         }
-        
+
         public void revertVolume() {
             mAudioManager.setStreamVolume(mStreamType, mOriginalStreamVolume, 0);
         }
-        
+
         public void onProgressChanged(SeekBar seekBar, int progress,
                 boolean fromTouch) {
             if (!fromTouch) {
                 return;
             }
-    
+
             postSetVolume(progress);
         }
 
@@ -310,7 +310,7 @@
             mHandler.removeCallbacks(this);
             mHandler.post(this);
         }
-    
+
         public void onStartTrackingTouch(SeekBar seekBar) {
         }
 
@@ -319,7 +319,7 @@
                 startSample();
             }
         }
-        
+
         public void run() {
             mAudioManager.setStreamVolume(mStreamType, mLastProgress, 0);
         }
@@ -334,7 +334,7 @@
                 mRingtone.play();
             }
         }
-    
+
         public void stopSample() {
             if (mRingtone != null) {
                 mRingtone.stop();
@@ -344,7 +344,7 @@
         public SeekBar getSeekBar() {
             return mSeekBar;
         }
-        
+
         public void changeVolumeBy(int amount) {
             mSeekBar.incrementProgressBy(amount);
             if (!isSamplePlaying()) {
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index 3db1827..4368e31 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -476,7 +476,96 @@
      }
 
     /**
-     * Fields and helpers for interacting with Calendars.
+     * Constants and helpers for the Calendars table, which contains details for
+     * individual calendars. <h3>Operations</h3> All operations can be done
+     * either as an app or as a sync adapter. To perform an operation as a sync
+     * adapter {@link #CALLER_IS_SYNCADAPTER} should be set to true and
+     * {@link #ACCOUNT_NAME} and {@link #ACCOUNT_TYPE} must be set in the Uri
+     * parameters. See
+     * {@link Uri.Builder#appendQueryParameter(java.lang.String, java.lang.String)}
+     * for details on adding parameters. Sync adapters have write access to more
+     * columns but are restricted to a single account at a time. Calendars are
+     * designed to be primarily managed by a sync adapter and inserting new
+     * calendars should be done as a sync adapter. For the most part, apps
+     * should only update calendars (such as changing the color or display
+     * name). If a local calendar is required an app can do so by inserting as a
+     * sync adapter and using an {@link #ACCOUNT_TYPE} of
+     * {@link #ACCOUNT_TYPE_LOCAL} .
+     * <dl>
+     * <dt><b>Insert</b></dt>
+     * <dd>When inserting a new calendar the following fields must be included:
+     * <ul>
+     * <li>{@link #ACCOUNT_NAME}</li>
+     * <li>{@link #ACCOUNT_TYPE}</li>
+     * <li>{@link #NAME}</li>
+     * <li>{@link #CALENDAR_DISPLAY_NAME}</li>
+     * <li>{@link #CALENDAR_COLOR}</li>
+     * <li>{@link #CALENDAR_ACCESS_LEVEL}</li>
+     * <li>{@link #OWNER_ACCOUNT}</li>
+     * </ul>
+     * The following fields are not required when inserting a Calendar but are
+     * generally a good idea to include:
+     * <ul>
+     * <li>{@link #SYNC_EVENTS} set to 1</li>
+     * <li>{@link #CALENDAR_TIME_ZONE}</li>
+     * <li>{@link #ALLOWED_REMINDERS}</li>
+     * </ul>
+     * <dt><b>Update</b></dt>
+     * <dd>To perform an update on a calendar the {@link #_ID} of the calendar
+     * should be provided either as an appended id to the Uri (
+     * {@link ContentUris#withAppendedId}) or as the first selection item--the
+     * selection should start with "_id=?" and the first selectionArg should be
+     * the _id of the calendar. Calendars may also be updated using a selection
+     * without the id. In general, the {@link #ACCOUNT_NAME} and
+     * {@link #ACCOUNT_TYPE} should not be changed after a calendar is created
+     * as this can cause issues for sync adapters.
+     * <dt><b>Delete</b></dt>
+     * <dd>Calendars can be deleted either by the {@link #_ID} as an appended id
+     * on the Uri or using any standard selection. Deleting a calendar should
+     * generally be handled by a sync adapter as it will remove the calendar
+     * from the database and all associated data (aka events).</dd>
+     * <dt><b>Query</b></dt>
+     * <dd>Querying the Calendars table will get you all information about a set
+     * of calendars. There will be one row returned for each calendar that
+     * matches the query selection, or at most a single row if the {@link #_ID}
+     * is appended to the Uri.</dd>
+     * </dl>
+     * <h3>Calendar Columns</h3> The following Calendar columns are writable by
+     * both an app and a sync adapter.
+     * <ul>
+     * <li>{@link #NAME}</li>
+     * <li>{@link #CALENDAR_DISPLAY_NAME}</li>
+     * <li>{@link #CALENDAR_COLOR}</li>
+     * <li>{@link #VISIBLE}</li>
+     * <li>{@link #SYNC_EVENTS}</li>
+     * </ul>
+     * The following Calendars columns are writable only by a sync adapter
+     * <ul>
+     * <li>{@link #ACCOUNT_NAME}</li>
+     * <li>{@link #ACCOUNT_TYPE}</li>
+     * <li>{@link #_SYNC_ID}</li>
+     * <li>{@link #DIRTY}</li>
+     * <li>{@link #OWNER_ACCOUNT}</li>
+     * <li>{@link #MAX_REMINDERS}</li>
+     * <li>{@link #ALLOWED_REMINDERS}</li>
+     * <li>{@link #CAN_MODIFY_TIME_ZONE}</li>
+     * <li>{@link #CAN_ORGANIZER_RESPOND}</li>
+     * <li>{@link #CAN_PARTIALLY_UPDATE}</li>
+     * <li>{@link #CALENDAR_LOCATION}</li>
+     * <li>{@link #CALENDAR_TIME_ZONE}</li>
+     * <li>{@link #CALENDAR_ACCESS_LEVEL}</li>
+     * <li>{@link #DELETED}</li>
+     * <li>{@link #CAL_SYNC1}</li>
+     * <li>{@link #CAL_SYNC2}</li>
+     * <li>{@link #CAL_SYNC3}</li>
+     * <li>{@link #CAL_SYNC4}</li>
+     * <li>{@link #CAL_SYNC5}</li>
+     * <li>{@link #CAL_SYNC6}</li>
+     * <li>{@link #CAL_SYNC7}</li>
+     * <li>{@link #CAL_SYNC8}</li>
+     * <li>{@link #CAL_SYNC9}</li>
+     * <li>{@link #CAL_SYNC10}</li>
+     * </ul>
      */
     public static class Calendars implements BaseColumns, SyncColumns, CalendarsColumns {
         private static final String WHERE_DELETE_FOR_ACCOUNT = Calendars.ACCOUNT_NAME + "=?"
@@ -569,6 +658,7 @@
             DIRTY,
             OWNER_ACCOUNT,
             MAX_REMINDERS,
+            ALLOWED_REMINDERS,
             CAN_MODIFY_TIME_ZONE,
             CAN_ORGANIZER_RESPOND,
             CAN_PARTIALLY_UPDATE,
@@ -648,7 +738,21 @@
     }
 
     /**
-     * Fields and helpers for interacting with Attendees.
+     * Fields and helpers for interacting with Attendees. Each row of this table
+     * represents a single attendee or guest of an event. Calling
+     * {@link #query(ContentResolver, long)} will return a list of attendees for
+     * the event with the given eventId. Both apps and sync adapters may write
+     * to this table. There are six writable fields and all of them except
+     * {@link #ATTENDEE_NAME} must be included when inserting a new attendee.
+     * They are:
+     * <ul>
+     * <li>{@link #EVENT_ID}</li>
+     * <li>{@link #ATTENDEE_NAME}</li>
+     * <li>{@link #ATTENDEE_EMAIL}</li>
+     * <li>{@link #ATTENDEE_RELATIONSHIP}</li>
+     * <li>{@link #ATTENDEE_TYPE}</li>
+     * <li>{@link #ATTENDEE_STATUS}</li>
+     * </ul>
      */
     public static final class Attendees implements BaseColumns, AttendeesColumns, EventsColumns {
 
@@ -1238,7 +1342,106 @@
     }
 
     /**
-     * Fields and helpers for interacting with Events.
+     * Constants and helpers for the Events table, which contains details for
+     * individual events. <h3>Operations</h3> All operations can be done either
+     * as an app or as a sync adapter. To perform an operation as a sync adapter
+     * {@link #CALLER_IS_SYNCADAPTER} should be set to true and
+     * {@link #ACCOUNT_NAME} and {@link #ACCOUNT_TYPE} must be set in the Uri
+     * parameters. See
+     * {@link Uri.Builder#appendQueryParameter(java.lang.String, java.lang.String)}
+     * for details on adding parameters. Sync adapters have write access to more
+     * columns but are restricted to a single account at a time.
+     * <dl>
+     * <dt><b>Insert</b></dt>
+     * <dd>When inserting a new event the following fields must be included:
+     * <ul>
+     * <li>dtstart</li>
+     * <li>dtend -or- a (rrule or rdate) and a duration</li>
+     * <li>a calendar_id</li>
+     * </ul>
+     * There are also further requirements when inserting or updating an event.
+     * See the section on Writing to Events.</dd>
+     * <dt><b>Update</b></dt>
+     * <dd>To perform an update of an Event the {@link Events#_ID} of the event
+     * should be provided either as an appended id to the Uri (
+     * {@link ContentUris#withAppendedId}) or as the first selection item--the
+     * selection should start with "_id=?" and the first selectionArg should be
+     * the _id of the event. Updates may also be done using a selection and no
+     * id. Updating an event must respect the same rules as inserting and is
+     * further restricted in the fields that can be written. See the section on
+     * Writing to Events.</dd>
+     * <dt><b>Delete</b></dt>
+     * <dd>Events can be deleted either by the {@link Events#_ID} as an appended
+     * id on the Uri or using any standard selection. If an appended id is used
+     * a selection is not allowed. There are two versions of delete: as an app
+     * and as a sync adapter. An app delete will set the deleted column on an
+     * event and remove all instances of that event. A sync adapter delete will
+     * remove the event from the database and all associated data.</dd>
+     * <dt><b>Query</b></dt>
+     * <dd>Querying the Events table will get you all information about a set of
+     * events except their reminders, attendees, and extended properties. There
+     * will be one row returned for each event that matches the query selection,
+     * or at most a single row if the {@link Events#_ID} is appended to the Uri.
+     * Recurring events will only return a single row regardless of the number
+     * of times that event repeats.</dd>
+     * </dl>
+     * <h3>Writing to Events</h3> There are further restrictions on all Updates
+     * and Inserts in the Events table:
+     * <ul>
+     * <li>If allDay is set to 1 eventTimezone must be {@link Time#TIMEZONE_UTC}
+     * and the time must correspond to a midnight boundary.</li>
+     * <li>Exceptions are not allowed to recur. If rrule or rdate is not empty,
+     * original_id and original_sync_id must be empty.</li>
+     * <li>In general a calendar_id should not be modified after insertion. This
+     * is not explicitly forbidden but many sync adapters will not behave in an
+     * expected way if the calendar_id is modified.</li>
+     * </ul>
+     * The following Events columns are writable by both an app and a sync
+     * adapter.
+     * <ul>
+     * <li>{@link #CALENDAR_ID}</li>
+     * <li>{@link #ORGANIZER}</li>
+     * <li>{@link #TITLE}</li>
+     * <li>{@link #EVENT_LOCATION}</li>
+     * <li>{@link #DESCRIPTION}</li>
+     * <li>{@link #EVENT_COLOR}</li>
+     * <li>{@link #DTSTART}</li>
+     * <li>{@link #DTEND}</li>
+     * <li>{@link #EVENT_TIMEZONE}</li>
+     * <li>{@link #EVENT_END_TIMEZONE}</li>
+     * <li>{@link #DURATION}</li>
+     * <li>{@link #ALL_DAY}</li>
+     * <li>{@link #RRULE}</li>
+     * <li>{@link #RDATE}</li>
+     * <li>{@link #EXRULE}</li>
+     * <li>{@link #EXDATE}</li>
+     * <li>{@link #ORIGINAL_ID}</li>
+     * <li>{@link #ORIGINAL_SYNC_ID}</li>
+     * <li>{@link #ORIGINAL_INSTANCE_TIME}</li>
+     * <li>{@link #ORIGINAL_ALL_DAY}</li>
+     * <li>{@link #ACCESS_LEVEL}</li>
+     * <li>{@link #AVAILABILITY}</li>
+     * <li>{@link #GUESTS_CAN_MODIFY}</li>
+     * <li>{@link #GUESTS_CAN_INVITE_OTHERS}</li>
+     * <li>{@link #GUESTS_CAN_SEE_GUESTS}</li>
+     * </ul>
+     * The following Events columns are writable only by a sync adapter
+     * <ul>
+     * <li>{@link #DIRTY}</li>
+     * <li>{@link #_SYNC_ID}</li>
+     * <li>{@link #SYNC_DATA1}</li>
+     * <li>{@link #SYNC_DATA2}</li>
+     * <li>{@link #SYNC_DATA3}</li>
+     * <li>{@link #SYNC_DATA4}</li>
+     * <li>{@link #SYNC_DATA5}</li>
+     * <li>{@link #SYNC_DATA6}</li>
+     * <li>{@link #SYNC_DATA7}</li>
+     * <li>{@link #SYNC_DATA8}</li>
+     * <li>{@link #SYNC_DATA9}</li>
+     * <li>{@link #SYNC_DATA10}</li>
+     * </ul>
+     * The remaining columns are either updated by the provider only or are
+     * views into other tables and cannot be changed through the Events table.
      */
     public static final class Events implements BaseColumns, SyncColumns, EventsColumns,
             CalendarsColumns {
@@ -1350,7 +1553,8 @@
     /**
      * Fields and helpers for interacting with Instances. An instance is a
      * single occurrence of an event including time zone specific start and end
-     * days and minutes.
+     * days and minutes. The instances table is not writable and only provides a
+     * way to query event occurrences.
      */
     public static final class Instances implements BaseColumns, EventsColumns, CalendarsColumns {
 
@@ -1637,8 +1841,10 @@
 
     /**
      * A few Calendar globals are needed in the CalendarProvider for expanding
-     * the Instances table and these are all stored in the first (and only)
-     * row of the CalendarMetaData table.
+     * the Instances table and these are all stored in the first (and only) row
+     * of the CalendarMetaData table.
+     *
+     * @hide
      */
     protected interface CalendarMetaDataColumns {
         /**
@@ -1771,7 +1977,17 @@
     }
 
     /**
-     * Fields and helpers for accessing reminders for an event.
+     * Fields and helpers for accessing reminders for an event. Each row of this
+     * table represents a single reminder for an event. Calling
+     * {@link #query(ContentResolver, long)} will return a list of reminders for
+     * the event with the given eventId. Both apps and sync adapters may write
+     * to this table. There are three writable fields and all of them must be
+     * included when inserting a new reminder. They are:
+     * <ul>
+     * <li>{@link #EVENT_ID}</li>
+     * <li>{@link #MINUTES}</li>
+     * <li>{@link #METHOD}</li>
+     * </ul>
      */
     public static final class Reminders implements BaseColumns, RemindersColumns, EventsColumns {
         private static final String REMINDERS_WHERE = CalendarContract.Reminders.EVENT_ID + "=?";
@@ -1872,7 +2088,14 @@
 
     /**
      * Fields and helpers for accessing calendar alerts information. These
-     * fields are for tracking which alerts have been fired.
+     * fields are for tracking which alerts have been fired. Scheduled alarms
+     * will generate an intent using {@link #EVENT_REMINDER_ACTION}. Apps that
+     * receive this action may update the {@link #STATE} for the reminder when
+     * they have finished handling it. Apps that have their notifications
+     * disabled should not modify the table to ensure that they do not conflict
+     * with another app that is generating a notification. In general, apps
+     * should not need to write to this table directly except to update the
+     * state of a reminder.
      */
     public static final class CalendarAlerts implements BaseColumns,
             CalendarAlertsColumns, EventsColumns, CalendarsColumns {
@@ -2044,9 +2267,11 @@
 
         /**
          * Schedules an alarm intent with the system AlarmManager that will
-         * cause the Calendar provider to recheck alarms. This is used to wake
-         * the Calendar alarm handler when an alarm is expected or to do a
-         * periodic refresh of alarm data.
+         * notify listeners when a reminder should be fired. The provider will
+         * keep scheduled reminders up to date but apps may use this to
+         * implement snooze functionality without modifying the reminders table.
+         * Scheduled alarms will generate an intent using
+         * {@link #EVENT_REMINDER_ACTION}.
          *
          * @param context A context for referencing system resources
          * @param manager The AlarmManager to use or null
@@ -2136,7 +2361,13 @@
     /**
      * Fields for accessing the Extended Properties. This is a generic set of
      * name/value pairs for use by sync adapters or apps to add extra
-     * information to events.
+     * information to events. There are three writable columns and all three
+     * must be present when inserting a new value. They are:
+     * <ul>
+     * <li>{@link #EVENT_ID}</li>
+     * <li>{@link #NAME}</li>
+     * <li>{@link #VALUE}</li>
+     * </ul>
      */
    public static final class ExtendedProperties implements BaseColumns,
             ExtendedPropertiesColumns, EventsColumns {
@@ -2170,6 +2401,8 @@
 
     /**
      * Columns from the EventsRawTimes table
+     *
+     * @hide
      */
     protected interface EventsRawTimesColumns {
         /**
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 00e2998..b5a11ab 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -163,14 +163,12 @@
      * obtaining possible recipients, letting the provider know which account is selected during
      * the composition. The provider may use the "primary account" information to optimize
      * the search result.
-     * @hide
      */
     public static final String PRIMARY_ACCOUNT_NAME = "name_for_primary_account";
 
     /**
      * A query parameter specifing a primary account. This parameter should be used with
      * {@link #PRIMARY_ACCOUNT_NAME}. See the doc in {@link #PRIMARY_ACCOUNT_NAME}.
-     * @hide
      */
     public static final String PRIMARY_ACCOUNT_TYPE = "type_for_primary_account";
 
@@ -1298,6 +1296,15 @@
         public static final Uri CONTENT_VCARD_URI = Uri.withAppendedPath(CONTENT_URI,
                 "as_vcard");
 
+       /**
+        * Boolean parameter that may be used with {@link #CONTENT_VCARD_URI}
+        * and {@link #CONTENT_MULTI_VCARD_URI} to indicate that the returned
+        * vcard should not contain a photo.
+        *
+        * @hide
+        */
+        public static final String QUERY_PARAMETER_VCARD_NO_PHOTO = "nophoto";
+
         /**
          * Base {@link Uri} for referencing multiple {@link Contacts} entry,
          * created by appending {@link #LOOKUP_KEY} using
@@ -6308,7 +6315,6 @@
      * boolean successful = resolver.update(uri, new ContentValues(), null, null) > 0;
      * </pre>
      * </p>
-     * @hide
      */
     public static final class DataUsageFeedback {
 
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index 3c4bb79..ba4804d 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -17,6 +17,7 @@
 package android.provider;
 
 import android.app.DownloadManager;
+import android.net.NetworkPolicyManager;
 import android.net.Uri;
 
 /**
@@ -695,6 +696,14 @@
         public static final int STATUS_TOO_MANY_REDIRECTS = 497;
 
         /**
+         * This download has failed because requesting application has been
+         * blocked by {@link NetworkPolicyManager}.
+         *
+         * @hide
+         */
+        public static final int STATUS_BLOCKED = 498;
+
+        /**
          * This download is visible but only shows in the notifications
          * while it's in progress.
          */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 01e028e7..603edf0 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3800,6 +3800,8 @@
         public static final String NETSTATS_UID_BUCKET_DURATION = "netstats_uid_bucket_duration";
         /** {@hide} */
         public static final String NETSTATS_UID_MAX_HISTORY = "netstats_uid_max_history";
+        /** {@hide} */
+        public static final String NETSTATS_TAG_MAX_HISTORY = "netstats_tag_max_history";
 
         /**
          * @hide
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index 376e0bb..ae41876 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -127,7 +127,7 @@
          * <P>Type: TEXT</P>
          * <P> Note that this is NOT the voicemail media content data.
          */
-        public static final String SOURCE_DATA = "provider_data";
+        public static final String SOURCE_DATA = "source_data";
         /**
          * Whether the media content for this voicemail is available for
          * consumption.
diff --git a/core/java/android/speech/tts/SynthesisRequest.java b/core/java/android/speech/tts/SynthesisRequest.java
index ef1704c..6398d3d 100644
--- a/core/java/android/speech/tts/SynthesisRequest.java
+++ b/core/java/android/speech/tts/SynthesisRequest.java
@@ -42,7 +42,7 @@
     private int mSpeechRate;
     private int mPitch;
 
-    SynthesisRequest(String text, Bundle params) {
+    public SynthesisRequest(String text, Bundle params) {
         mText = text;
         // Makes a copy of params.
         mParams = new Bundle(params);
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 7d596df..40e9355 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -498,8 +498,7 @@
     private int initTts() {
         String defaultEngine = getDefaultEngine();
         String engine = defaultEngine;
-        if (!areDefaultsEnforced() && !TextUtils.isEmpty(mRequestedEngine)
-                && mEnginesHelper.isEngineEnabled(mRequestedEngine)) {
+        if (mEnginesHelper.isEngineInstalled(mRequestedEngine)) {
             engine = mRequestedEngine;
         }
 
@@ -1080,12 +1079,12 @@
     }
 
     /**
-     * Checks whether the user's settings should override settings requested by the calling
-     * application.
+     * Checks whether the user's settings should override settings requested
+     * by the calling application. As of the Ice cream sandwich release,
+     * user settings never forcibly override the app's settings.
      */
     public boolean areDefaultsEnforced() {
-        return Settings.Secure.getInt(mContext.getContentResolver(),
-                Settings.Secure.TTS_USE_DEFAULTS, Engine.USE_DEFAULTS) == 1;
+        return false;
     }
 
     /**
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 3eea6b7..7ea9373 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -191,11 +191,6 @@
     protected abstract void onSynthesizeText(SynthesisRequest request,
             SynthesisCallback callback);
 
-    private boolean areDefaultsEnforced() {
-        return getSecureSettingInt(Settings.Secure.TTS_USE_DEFAULTS,
-                TextToSpeech.Engine.USE_DEFAULTS) == 1;
-    }
-
     private int getDefaultSpeechRate() {
         return getSecureSettingInt(Settings.Secure.TTS_DEFAULT_RATE, Engine.DEFAULT_RATE);
     }
@@ -504,13 +499,9 @@
         }
 
         private void setRequestParams(SynthesisRequest request) {
-            if (areDefaultsEnforced()) {
-                request.setLanguage(getDefaultLanguage(), getDefaultCountry(), getDefaultVariant());
-                request.setSpeechRate(getDefaultSpeechRate());
-            } else {
-                request.setLanguage(getLanguage(), getCountry(), getVariant());
-                request.setSpeechRate(getSpeechRate());
-            }
+            request.setLanguage(getLanguage(), getCountry(), getVariant());
+            request.setSpeechRate(getSpeechRate());
+
             request.setPitch(getPitch());
         }
 
@@ -749,13 +740,6 @@
                 return TextToSpeech.ERROR;
             }
 
-            if (areDefaultsEnforced()) {
-                if (isDefault(lang, country, variant)) {
-                    return mDefaultAvailability;
-                } else {
-                    return TextToSpeech.LANG_NOT_SUPPORTED;
-                }
-            }
             return onIsLanguageAvailable(lang, country, variant);
         }
 
@@ -768,13 +752,6 @@
                 return TextToSpeech.ERROR;
             }
 
-            if (areDefaultsEnforced()) {
-                if (isDefault(lang, country, variant)) {
-                    return mDefaultAvailability;
-                } else {
-                    return TextToSpeech.LANG_NOT_SUPPORTED;
-                }
-            }
             return onLoadLanguage(lang, country, variant);
         }
 
diff --git a/core/java/android/speech/tts/TtsEngines.java b/core/java/android/speech/tts/TtsEngines.java
index 715894f..ed9e048 100644
--- a/core/java/android/speech/tts/TtsEngines.java
+++ b/core/java/android/speech/tts/TtsEngines.java
@@ -117,30 +117,10 @@
         return engines;
     }
 
-    /**
-     * Checks whether a given engine is enabled or not. Note that all system
-     * engines are enabled by default.
-     */
+    // TODO: Used only by the settings app. Remove once
+    // the settings UI change has been finalized.
     public boolean isEngineEnabled(String engine) {
-        // System engines are enabled by default always.
-        EngineInfo info = getEngineInfo(engine);
-        if (info == null) {
-            // The engine is not installed, and therefore cannot
-            // be enabled.
-            return false;
-        }
-
-        if (info.system) {
-            // All system engines are enabled by default.
-            return true;
-        }
-
-        for (String enabled : getUserEnabledEngines()) {
-            if (engine.equals(enabled)) {
-                return true;
-            }
-        }
-        return false;
+        return isEngineInstalled(engine);
     }
 
     private boolean isSystemEngine(ServiceInfo info) {
@@ -149,22 +129,14 @@
     }
 
     /**
-     * @return true if a given engine is installed on the system. Useful to deal
-     *         with cases where an engine has been uninstalled by the user or removed
-     *         for any other reason.
+     * @return true if a given engine is installed on the system.
      */
-    private boolean isEngineInstalled(String engine) {
+    public boolean isEngineInstalled(String engine) {
         if (engine == null) {
             return false;
         }
 
-        for (EngineInfo info : getEngines()) {
-            if (engine.equals(info.name)) {
-                return true;
-            }
-        }
-
-        return false;
+        return getEngineInfo(engine) != null;
     }
 
     private EngineInfo getEngineInfo(ResolveInfo resolve, PackageManager pm) {
@@ -185,17 +157,6 @@
         return null;
     }
 
-    // Note that in addition to this list, all engines that are a part
-    // of the system are enabled by default.
-    private String[] getUserEnabledEngines() {
-        String str = Settings.Secure.getString(mContext.getContentResolver(),
-                Settings.Secure.TTS_ENABLED_PLUGINS);
-        if (TextUtils.isEmpty(str)) {
-            return new String[0];
-        }
-        return str.split(" ");
-    }
-
     private static class EngineInfoComparator implements Comparator<EngineInfo> {
         private EngineInfoComparator() { }
 
diff --git a/core/java/android/util/FinitePool.java b/core/java/android/util/FinitePool.java
index 4ae21ad..b30f2bf 100644
--- a/core/java/android/util/FinitePool.java
+++ b/core/java/android/util/FinitePool.java
@@ -20,6 +20,8 @@
  * @hide
  */
 class FinitePool<T extends Poolable<T>> implements Pool<T> {
+    private static final String LOG_TAG = "FinitePool";
+
     /**
      * Factory used to create new pool objects
      */
@@ -77,15 +79,16 @@
     }
 
     public void release(T element) {
-        if (element.isPooled()) {
-            throw new IllegalArgumentException("Element already in the pool.");
+        if (!element.isPooled()) {
+            if (mInfinite || mPoolCount < mLimit) {
+                mPoolCount++;
+                element.setNextPoolable(mRoot);
+                element.setPooled(true);
+                mRoot = element;
+            }
+            mManager.onReleased(element);
+        } else {
+            Log.w(LOG_TAG, "Element is already in pool: " + element);
         }
-        if (mInfinite || mPoolCount < mLimit) {
-            mPoolCount++;
-            element.setNextPoolable(mRoot);
-            element.setPooled(true);
-            mRoot = element;
-        }
-        mManager.onReleased(element);
     }
 }
diff --git a/core/java/android/util/LocaleUtil.java b/core/java/android/util/LocaleUtil.java
new file mode 100644
index 0000000..74a930f
--- /dev/null
+++ b/core/java/android/util/LocaleUtil.java
@@ -0,0 +1,106 @@
+/*
+ * 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 android.util;
+
+import java.util.Locale;
+
+import libcore.icu.ICU;
+
+/**
+ * Various utilities for Locales
+ *
+ * @hide
+ */
+public class LocaleUtil {
+
+    private LocaleUtil() { /* cannot be instantiated */ }
+
+    /**
+     * @hide Do not use. Implementation not finished.
+     */
+    public static final int TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE = -1;
+
+    /**
+     * @hide Do not use. Implementation not finished.
+     */
+    public static final int TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE = 0;
+
+    /**
+     * @hide Do not use. Implementation not finished.
+     */
+    public static final int TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE = 1;
+
+    private static final char UNDERSCORE_CHAR = '_';
+
+    private static String ARAB_SCRIPT_SUBTAG = "Arab";
+    private static String HEBR_SCRIPT_SUBTAG = "Hebr";
+
+    /**
+     * Return the layout direction for a given Locale
+     *
+     * @param locale the Locale for which we want the layout direction. Can be null.
+     * @return the layout direction. This may be one of:
+     * {@link #TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE} or
+     * {@link #TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE} or
+     * {@link #TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE}.
+     *
+     * Be careful: this code will need to be changed when vertical scripts will be supported
+     *
+     * @hide
+     */
+    public static int getLayoutDirectionFromLocale(Locale locale) {
+        if (locale == null || locale.equals(Locale.ROOT)) {
+            return TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE;
+        }
+
+        final String scriptSubtag = ICU.getScript(ICU.addLikelySubtags(locale.toString()));
+        if (scriptSubtag == null) return getLayoutDirectionFromFirstChar(locale);
+
+        if (scriptSubtag.equalsIgnoreCase(ARAB_SCRIPT_SUBTAG) ||
+                scriptSubtag.equalsIgnoreCase(HEBR_SCRIPT_SUBTAG)) {
+            return TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE;
+        }
+        return TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE;
+    }
+
+    /**
+     * Fallback algorithm to detect the locale direction. Rely on the fist char of the
+     * localized locale name. This will not work if the localized locale name is in English
+     * (this is the case for ICU 4.4 and "Urdu" script)
+     *
+     * @param locale
+     * @return the layout direction. This may be one of:
+     * {@link #TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE} or
+     * {@link #TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE} or
+     * {@link #TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE}.
+     *
+     * Be careful: this code will need to be changed when vertical scripts will be supported
+     *
+     * @hide
+     */
+    private static int getLayoutDirectionFromFirstChar(Locale locale) {
+        switch(Character.getDirectionality(locale.getDisplayName(locale).charAt(0))) {
+            case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
+                return TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE;
+            case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
+            case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
+                return TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE;
+            default:
+                return TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE;
+        }
+    }
+}
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 383bfb3..5216c49 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -29,6 +29,7 @@
 import android.graphics.RectF;
 import android.graphics.Region;
 import android.graphics.Shader;
+import android.graphics.SurfaceTexture;
 import android.graphics.TemporaryBuffer;
 import android.text.GraphicsOperations;
 import android.text.SpannableString;
@@ -163,7 +164,7 @@
     static native int nCreateTextureLayer(int[] layerInfo);
     static native int nCreateLayer(int width, int height, boolean isOpaque, int[] layerInfo);
     static native void nResizeLayer(int layerId, int width, int height, int[] layerInfo);
-    static native void nUpdateTextureLayer(int layerId, int width, int height, int surface);
+    static native void nUpdateTextureLayer(int layerId, int width, int height, SurfaceTexture surface);
     static native void nDestroyLayer(int layerId);
     static native void nDestroyLayerDeferred(int layerId);
     static native boolean nCopyLayer(int layerId, int bitmap);
diff --git a/core/java/android/view/GLES20TextureLayer.java b/core/java/android/view/GLES20TextureLayer.java
index fcf421b..063eee7 100644
--- a/core/java/android/view/GLES20TextureLayer.java
+++ b/core/java/android/view/GLES20TextureLayer.java
@@ -70,7 +70,7 @@
         return mSurface;
     }
 
-    void update(int width, int height, int surface) {
-        GLES20Canvas.nUpdateTextureLayer(mLayer, width, height, surface);
+    void update(int width, int height) {
+        GLES20Canvas.nUpdateTextureLayer(mLayer, width, height, mSurface);
     }
 }
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 5944bd4..5ceb12a 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -194,7 +194,7 @@
      * 
      * @return A {@link SurfaceTexture}
      */
-    abstract SurfaceTexture createSuraceTexture(HardwareLayer layer);
+    abstract SurfaceTexture createSurfaceTexture(HardwareLayer layer);
 
     /**
      * Updates the specified layer.
@@ -202,10 +202,8 @@
      * @param layer The hardware layer to update
      * @param width The layer's width
      * @param height The layer's height
-     * @param surface The surface to update
      */
-    abstract void updateTextureLayer(HardwareLayer layer, int width, int height,
-            SurfaceTexture surface);
+    abstract void updateTextureLayer(HardwareLayer layer, int width, int height);
 
     /**
      * Copies the content of the specified layer into the specified bitmap.
@@ -815,14 +813,13 @@
         }
 
         @Override
-        SurfaceTexture createSuraceTexture(HardwareLayer layer) {
+        SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
             return ((GLES20TextureLayer) layer).getSurfaceTexture();
         }
 
         @Override
-        void updateTextureLayer(HardwareLayer layer, int width, int height,
-                SurfaceTexture surface) {
-            ((GLES20TextureLayer) layer).update(width, height, surface.mSurfaceTexture);
+        void updateTextureLayer(HardwareLayer layer, int width, int height) {
+            ((GLES20TextureLayer) layer).update(width, height);
         }
 
         @Override
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 4daa892..0421205 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -232,7 +232,7 @@
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         super.onSizeChanged(w, h, oldw, oldh);
         if (mSurface != null) {
-            nSetDefaultBufferSize(mSurface.mSurfaceTexture, getWidth(), getHeight());
+            nSetDefaultBufferSize(mSurface, getWidth(), getHeight());
             if (mListener != null) {
                 mListener.onSurfaceTextureSizeChanged(mSurface, getWidth(), getHeight());
             }
@@ -247,8 +247,8 @@
 
         if (mLayer == null) {
             mLayer = mAttachInfo.mHardwareRenderer.createHardwareLayer();
-            mSurface = mAttachInfo.mHardwareRenderer.createSuraceTexture(mLayer);
-            nSetDefaultBufferSize(mSurface.mSurfaceTexture, getWidth(), getHeight());
+            mSurface = mAttachInfo.mHardwareRenderer.createSurfaceTexture(mLayer);
+            nSetDefaultBufferSize(mSurface, getWidth(), getHeight());
 
             mUpdateListener = new SurfaceTexture.OnFrameAvailableListener() {
                 @Override
@@ -290,7 +290,7 @@
             return;
         }
 
-        mAttachInfo.mHardwareRenderer.updateTextureLayer(mLayer, getWidth(), getHeight(), mSurface);
+        mAttachInfo.mHardwareRenderer.updateTextureLayer(mLayer, getWidth(), getHeight());
 
         invalidate();
     }
@@ -306,6 +306,8 @@
      * <p><strong>Do not</strong> invoke this method from a drawing method
      * ({@link #onDraw(android.graphics.Canvas)} for instance).</p>
      * 
+     * <p>If an error occurs during the copy, an empty bitmap will be returned.</p>
+     * 
      * @return A valid {@link Bitmap.Config#ARGB_8888} bitmap, or null if the surface
      *         texture is not available or the width &lt;= 0 or the height &lt;= 0
      * 
@@ -328,6 +330,8 @@
      * <p><strong>Do not</strong> invoke this method from a drawing method
      * ({@link #onDraw(android.graphics.Canvas)} for instance).</p>
      * 
+     * <p>If an error occurs during the copy, an empty bitmap will be returned.</p>
+     * 
      * @param width The width of the bitmap to create
      * @param height The height of the bitmap to create
      * 
@@ -354,6 +358,8 @@
      * <p><strong>Do not</strong> invoke this method from a drawing method
      * ({@link #onDraw(android.graphics.Canvas)} for instance).</p>
      * 
+     * <p>If an error occurs, the bitmap is left unchanged.</p>
+     * 
      * @param bitmap The bitmap to copy the content of the surface texture into,
      *               cannot be null, all configurations are supported
      * 
@@ -447,5 +453,6 @@
         public void onSurfaceTextureDestroyed(SurfaceTexture surface);
     }
 
-    private static native void nSetDefaultBufferSize(int surfaceTexture, int width, int height);
+    private static native void nSetDefaultBufferSize(SurfaceTexture surfaceTexture,
+            int width, int height);
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 1dfb858..888f0c0 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import android.util.FloatProperty;
+import android.util.LocaleUtil;
 import android.util.Property;
 import com.android.internal.R;
 import com.android.internal.util.Predicate;
@@ -6088,7 +6089,11 @@
         /* Check if the VISIBLE bit has changed */
         if ((changed & INVISIBLE) != 0) {
             needGlobalAttributesUpdate(false);
-            invalidate(true);
+            /*
+             * If this view is becoming invisible, set the DRAWN flag so that
+             * the next invalidate() will not be skipped.
+             */
+            mPrivateFlags |= DRAWN;
 
             if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE) && hasFocus()) {
                 // root view becoming invisible shouldn't clear focus
@@ -8735,6 +8740,10 @@
         }
         jumpDrawablesToCurrentState();
         resolveLayoutDirection();
+        if (isFocused()) {
+            InputMethodManager imm = InputMethodManager.peekInstance();
+            imm.focusIn(this);
+        }
     }
 
     /**
@@ -8772,18 +8781,8 @@
      * @return true if a Locale is corresponding to a RTL script.
      */
     private static boolean isLayoutDirectionRtl(Locale locale) {
-        if (locale == null || locale.equals(Locale.ROOT)) return false;
-        // Be careful: this code will need to be changed when vertical scripts will be supported
-        // OR if ICU4C is updated to have the "likelySubtags" file
-        switch(Character.getDirectionality(locale.getDisplayName(locale).charAt(0))) {
-            case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
-                return false;
-            case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
-            case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
-                return true;
-            default:
-                return false;
-        }
+        return (LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE ==
+                LocaleUtil.getLayoutDirectionFromLocale(locale));
     }
 
     /**
@@ -11710,7 +11709,7 @@
 
     /**
      * Utility to return a default size. Uses the supplied size if the
-     * MeasureSpec imposed no contraints. Will get larger if allowed
+     * MeasureSpec imposed no constraints. Will get larger if allowed
      * by the MeasureSpec.
      *
      * @param size Default size for this view
@@ -11720,7 +11719,7 @@
     public static int getDefaultSize(int size, int measureSpec) {
         int result = size;
         int specMode = MeasureSpec.getMode(measureSpec);
-        int specSize =  MeasureSpec.getSize(measureSpec);
+        int specSize = MeasureSpec.getSize(measureSpec);
 
         switch (specMode) {
         case MeasureSpec.UNSPECIFIED:
diff --git a/core/java/android/view/ViewAncestor.java b/core/java/android/view/ViewAncestor.java
index 914973e..afbedaf 100644
--- a/core/java/android/view/ViewAncestor.java
+++ b/core/java/android/view/ViewAncestor.java
@@ -4407,7 +4407,7 @@
                 predicate.init(accessibilityId);
                 View root = ViewAncestor.this.mView;
                 View target = root.findViewByPredicate(predicate);
-                if (target != null) {
+                if (target != null && target.isShown()) {
                     info = target.createAccessibilityNodeInfo();
                 }
             } finally {
@@ -4439,7 +4439,7 @@
             try {
                 View root = ViewAncestor.this.mView;
                 View target = root.findViewById(viewId);
-                if (target != null) {
+                if (target != null && target.isShown()) {
                     info = target.createAccessibilityNodeInfo();
                 }
             } finally {
@@ -4479,14 +4479,14 @@
                 ArrayList<View> foundViews = mAttachInfo.mFocusablesTempList;
                 foundViews.clear();
 
-                View root = null;
+                View root;
                 if (accessibilityViewId != View.NO_ID) {
                     root = findViewByAccessibilityId(accessibilityViewId);
                 } else {
                     root = ViewAncestor.this.mView;
                 }
 
-                if (root == null) {
+                if (root == null || !root.isShown()) {
                     return;
                 }
 
@@ -4501,7 +4501,9 @@
                 final int viewCount = foundViews.size();
                 for (int i = 0; i < viewCount; i++) {
                     View foundView = foundViews.get(i);
-                    infos.add(foundView.createAccessibilityNodeInfo());
+                    if (foundView.isShown()) {
+                        infos.add(foundView.createAccessibilityNodeInfo());
+                    }
                  }
             } finally {
                 try {
@@ -4611,7 +4613,8 @@
                 return null;
             }
             mFindByAccessibilityIdPredicate.init(accessibilityId);
-            return root.findViewByPredicate(mFindByAccessibilityIdPredicate);
+            View foundView = root.findViewByPredicate(mFindByAccessibilityIdPredicate);
+            return (foundView != null && foundView.isShown()) ? foundView : null;
         }
 
         private final class FindByAccessibilitytIdPredicate implements Predicate<View> {
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 57ee8a0..a6bce75 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2023,10 +2023,11 @@
     @Override
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(info);
-
         for (int i = 0, count = mChildrenCount; i < count; i++) {
             View child = mChildren[i];
-            info.addChild(child);
+            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
+                info.addChild(child);
+            }
         }
     }
 
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 9eddf23..a3de285 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -349,7 +349,7 @@
             }
         }
         mPendingAnimations.clear();
-        mView.getHandler().removeCallbacks(mAnimationStarter);
+        mView.removeCallbacks(mAnimationStarter);
     }
 
     /**
@@ -705,7 +705,7 @@
 
         NameValuesHolder nameValuePair = new NameValuesHolder(constantName, startValue, byValue);
         mPendingAnimations.add(nameValuePair);
-        mView.getHandler().removeCallbacks(mAnimationStarter);
+        mView.removeCallbacks(mAnimationStarter);
         mView.post(mAnimationStarter);
     }
 
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index c361a4a..761007f 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -59,6 +59,7 @@
      * NORMAL is 100%
      * LARGER is 150%
      * LARGEST is 200%
+     * @deprecated Use {@link WebSettings#setTextZoom(int)} and {@link WebSettings#getTextZoom()} instead.
      */
     public enum TextSize {
         SMALLEST(50),
@@ -158,7 +159,7 @@
     // know what they are.
     private LayoutAlgorithm mLayoutAlgorithm = LayoutAlgorithm.NARROW_COLUMNS;
     private Context         mContext;
-    private TextSize        mTextSize = TextSize.NORMAL;
+    private int             mTextSize = 100;
     private String          mStandardFontFamily = "sans-serif";
     private String          mFixedFontFamily = "monospace";
     private String          mSansSerifFontFamily = "sans-serif";
@@ -709,26 +710,61 @@
     }
 
     /**
-     * Set the text size of the page.
-     * @param t A TextSize value for increasing or decreasing the text.
-     * @see WebSettings.TextSize
+     * Set the text zoom of the page in percent. Default is 100.
+     * @param textZoom A percent value for increasing or decreasing the text.
      */
-    public synchronized void setTextSize(TextSize t) {
-        if (WebView.mLogEvent && mTextSize != t ) {
-            EventLog.writeEvent(EventLogTags.BROWSER_TEXT_SIZE_CHANGE,
-                    mTextSize.value, t.value);
+    public synchronized void setTextZoom(int textZoom) {
+        if (mTextSize != textZoom) {
+            if (WebView.mLogEvent) {
+                EventLog.writeEvent(EventLogTags.BROWSER_TEXT_SIZE_CHANGE,
+                        mTextSize, textZoom);
+            }
+            mTextSize = textZoom;
+            postSync();
         }
-        mTextSize = t;
-        postSync();
     }
 
     /**
-     * Get the text size of the page.
+     * Get the text zoom of the page in percent.
+     * @return A percent value describing the text zoom.
+     * @see setTextSizeZoom
+     */
+    public synchronized int getTextZoom() {
+        return mTextSize;
+    }
+
+    /**
+     * Set the text size of the page.
+     * @param t A TextSize value for increasing or decreasing the text.
+     * @see WebSettings.TextSize
+     * @deprecated Use {@link #setTextZoom(int)} instead
+     */
+    public synchronized void setTextSize(TextSize t) {
+        setTextZoom(t.value);
+    }
+
+    /**
+     * Get the text size of the page. If the text size was previously specified
+     * in percent using {@link #setTextZoom(int)}, this will return
+     * the closest matching {@link TextSize}.
      * @return A TextSize enum value describing the text size.
      * @see WebSettings.TextSize
+     * @deprecated Use {@link #getTextZoom()} instead
      */
     public synchronized TextSize getTextSize() {
-        return mTextSize;
+        TextSize closestSize = null;
+        int smallestDelta = Integer.MAX_VALUE;
+        for (TextSize size : TextSize.values()) {
+            int delta = Math.abs(mTextSize - size.value);
+            if (delta == 0) {
+                return size;
+            }
+            if (delta < smallestDelta) {
+                smallestDelta = delta;
+                closestSize = size;
+            }
+        }
+        return closestSize != null ? closestSize : TextSize.NORMAL;
     }
 
     /**
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index bfab8a9..c56e6db 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -3062,6 +3062,13 @@
     }
 
     /**
+     * @hide
+     */
+    public int getPageBackgroundColor() {
+        return nativeGetBackgroundColor();
+    }
+
+    /**
      * Pause all layout, parsing, and JavaScript timers for all webviews. This
      * is a global requests, not restricted to just this webview. This can be
      * useful if the application has been paused.
@@ -9216,4 +9223,5 @@
      * @return True if the layer is successfully scrolled.
      */
     private native boolean  nativeScrollLayer(int layer, int newX, int newY);
+    private native int      nativeGetBackgroundColor();
 }
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index a730018..2410eb2 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -28,6 +28,7 @@
 import android.view.Gravity;
 import android.view.ViewDebug;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
 
 /**
  * <p>
@@ -214,6 +215,12 @@
     }
 
     @Override
+    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(info);
+        info.setChecked(mChecked);
+    }
+
+    @Override
     protected void onDraw(Canvas canvas) {
         super.onDraw(canvas);
 
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 092c2f7..4a514bf 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -38,8 +38,6 @@
 import java.util.List;
 import java.util.Map;
 
-import static android.view.View.MeasureSpec.EXACTLY;
-import static android.view.View.MeasureSpec.UNSPECIFIED;
 import static java.lang.Math.max;
 import static java.lang.Math.min;
 
@@ -135,11 +133,44 @@
      */
     public static final int UNDEFINED = Integer.MIN_VALUE;
 
+    /**
+     * This constant is an {@link #setAlignmentMode(int) alignmentMode}.
+     * When the {@code alignmentMode} is set to {@link #ALIGN_BOUNDS}, alignment
+     * is made between the edges of each component's raw
+     * view boundary: i.e. the area delimited by the component's:
+     * {@link android.view.View#getTop() top},
+     * {@link android.view.View#getLeft() left},
+     * {@link android.view.View#getBottom() bottom} and
+     * {@link android.view.View#getRight() right} properties.
+     * <p>
+     * For example, when {@code GridLayout} is in {@link #ALIGN_BOUNDS} mode,
+     * children that belong to a row group that uses {@link #TOP} alignment will
+     * all return the same value when their {@link android.view.View#getTop()}
+     * method is called.
+     *
+     * @see #setAlignmentMode(int)
+     */
+    public static final int ALIGN_BOUNDS = 0;
+
+    /**
+     * This constant is an {@link #setAlignmentMode(int) alignmentMode}.
+     * When the {@code alignmentMode} is set to {@link #ALIGN_MARGINS},
+     * the bounds of each view are extended outwards, according
+     * to their margins, before the edges of the resulting rectangle are aligned.
+     * <p>
+     * For example, when {@code GridLayout} is in {@link #ALIGN_MARGINS} mode,
+     * the quantity {@code top - layoutParams.topMargin} is the same for all children that
+     * belong to a row group that uses {@link #TOP} alignment.
+     *
+     * @see #setAlignmentMode(int)
+     */
+    public static final int ALIGN_MARGINS = 1;
+
     // Misc constants
 
     private static final String TAG = GridLayout.class.getName();
     private static final boolean DEBUG = false;
-    private static final Paint GRID_PAINT = new Paint();
+    private static Paint GRID_PAINT;
     private static final double GOLDEN_RATIO = (1 + Math.sqrt(5)) / 2;
     private static final int MIN = 0;
     private static final int PRF = 1;
@@ -151,7 +182,7 @@
     private static final int DEFAULT_COUNT = UNDEFINED;
     private static final boolean DEFAULT_USE_DEFAULT_MARGINS = false;
     private static final boolean DEFAULT_ORDER_PRESERVED = false;
-    private static final boolean DEFAULT_MARGINS_INCLUDED = true;
+    private static final int DEFAULT_ALIGNMENT_MODE = ALIGN_MARGINS;
     // todo remove this
     private static final int DEFAULT_CONTAINER_MARGIN = 20;
 
@@ -161,14 +192,17 @@
     private static final int ROW_COUNT = styleable.GridLayout_rowCount;
     private static final int COLUMN_COUNT = styleable.GridLayout_columnCount;
     private static final int USE_DEFAULT_MARGINS = styleable.GridLayout_useDefaultMargins;
-    private static final int MARGINS_INCLUDED = styleable.GridLayout_marginsIncludedInAlignment;
+    private static final int ALIGNMENT_MODE = styleable.GridLayout_alignmentMode;
     private static final int ROW_ORDER_PRESERVED = styleable.GridLayout_rowOrderPreserved;
     private static final int COLUMN_ORDER_PRESERVED = styleable.GridLayout_columnOrderPreserved;
 
     // Static initialization
 
     static {
-        GRID_PAINT.setColor(Color.argb(50, 255, 255, 255));
+        if (DEBUG) {
+            GRID_PAINT = new Paint();
+            GRID_PAINT.setColor(Color.argb(50, 255, 255, 255));
+        }
     }
 
     // Instance variables
@@ -178,7 +212,7 @@
     private boolean mLayoutParamsValid = false;
     private int mOrientation = DEFAULT_ORIENTATION;
     private boolean mUseDefaultMargins = DEFAULT_USE_DEFAULT_MARGINS;
-    private boolean mMarginsIncludedInAlignment = DEFAULT_MARGINS_INCLUDED;
+    private int mAlignmentMode = DEFAULT_ALIGNMENT_MODE;
     private int mDefaultGravity = Gravity.NO_GRAVITY;
 
     /* package */ boolean accommodateBothMinAndMax = false;
@@ -189,10 +223,7 @@
      * {@inheritDoc}
      */
     public GridLayout(Context context) {
-        super(context);
-        if (DEBUG) {
-            setWillNotDraw(false);
-        }
+        this(context, null, 0);
     }
 
     /**
@@ -200,6 +231,9 @@
      */
     public GridLayout(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
+        if (DEBUG) {
+            setWillNotDraw(false);
+        }
         processAttributes(context, attrs);
     }
 
@@ -207,18 +241,17 @@
      * {@inheritDoc}
      */
     public GridLayout(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        processAttributes(context, attrs);
+        this(context, attrs, 0);
     }
 
     private void processAttributes(Context context, AttributeSet attrs) {
         TypedArray a = context.obtainStyledAttributes(attrs, styleable.GridLayout);
         try {
-            setRowCount(a.getInteger(ROW_COUNT, DEFAULT_COUNT));
-            setColumnCount(a.getInteger(COLUMN_COUNT, DEFAULT_COUNT));
-            mOrientation = a.getInteger(ORIENTATION, DEFAULT_ORIENTATION);
+            setRowCount(a.getInt(ROW_COUNT, DEFAULT_COUNT));
+            setColumnCount(a.getInt(COLUMN_COUNT, DEFAULT_COUNT));
+            mOrientation = a.getInt(ORIENTATION, DEFAULT_ORIENTATION);
             mUseDefaultMargins = a.getBoolean(USE_DEFAULT_MARGINS, DEFAULT_USE_DEFAULT_MARGINS);
-            mMarginsIncludedInAlignment = a.getBoolean(MARGINS_INCLUDED, DEFAULT_MARGINS_INCLUDED);
+            mAlignmentMode = a.getInt(ALIGNMENT_MODE, DEFAULT_ALIGNMENT_MODE);
             setRowOrderPreserved(a.getBoolean(ROW_ORDER_PRESERVED, DEFAULT_ORDER_PRESERVED));
             setColumnOrderPreserved(a.getBoolean(COLUMN_ORDER_PRESERVED, DEFAULT_ORDER_PRESERVED));
         } finally {
@@ -348,15 +381,15 @@
      * When {@code false}, the default value of all margins is zero.
      * <p>
      * When setting to {@code true}, consider setting the value of the
-     * {@link #setMarginsIncludedInAlignment(boolean) marginsIncludedInAlignment}
-     * property to {@code false}.
+     * {@link #setAlignmentMode(int) alignmentMode}
+     * property to {@link #ALIGN_BOUNDS}.
      * <p>
      * The default value of this property is {@code false}.
      *
      * @param useDefaultMargins use {@code true} to make GridLayout allocate default margins
      *
      * @see #getUseDefaultMargins()
-     * @see #setMarginsIncludedInAlignment(boolean)
+     * @see #setAlignmentMode(int)
      *
      * @see MarginLayoutParams#leftMargin
      * @see MarginLayoutParams#topMargin
@@ -371,36 +404,38 @@
     }
 
     /**
-     * Returns whether GridLayout aligns the edges of the view or the edges
-     * of the larger rectangle created by extending the view by its associated
-     * margins.
+     * Returns the alignment mode.
      *
-     * @see #setMarginsIncludedInAlignment(boolean)
+     * @return the alignment mode; either {@link #ALIGN_BOUNDS} or {@link #ALIGN_MARGINS}
      *
-     * @return {@code true} if alignment is between edges including margins
+     * @see #ALIGN_BOUNDS
+     * @see #ALIGN_MARGINS
      *
-     * @attr ref android.R.styleable#GridLayout_marginsIncludedInAlignment
+     * @see #setAlignmentMode(int)
+     *
+     * @attr ref android.R.styleable#GridLayout_alignmentMode
      */
-    public boolean getMarginsIncludedInAlignment() {
-        return mMarginsIncludedInAlignment;
+    public int getAlignmentMode() {
+        return mAlignmentMode;
     }
 
     /**
-     * When {@code true}, the bounds of a view are extended outwards according to its
-     * margins before the edges of the resulting rectangle are aligned.
-     * When {@code false}, alignment occurs between the bounds of the view - i.e.
-     * {@link #LEFT} alignment means align the left edges of the view.
+     * Sets the alignment mode to be used for all of the alignments between the
+     * children of this container.
      * <p>
-     * The default value of this property is {@code true}.
+     * The default value of this property is {@link #ALIGN_MARGINS}.
      *
-     * @param marginsIncludedInAlignment {@code true} if alignment between edges includes margins
+     * @param alignmentMode either {@link #ALIGN_BOUNDS} or {@link #ALIGN_MARGINS}
      *
-     * @see #getMarginsIncludedInAlignment()
+     * @see #ALIGN_BOUNDS
+     * @see #ALIGN_MARGINS
      *
-     * @attr ref android.R.styleable#GridLayout_marginsIncludedInAlignment
+     * @see #getAlignmentMode()
+     *
+     * @attr ref android.R.styleable#GridLayout_alignmentMode
      */
-    public void setMarginsIncludedInAlignment(boolean marginsIncludedInAlignment) {
-        mMarginsIncludedInAlignment = marginsIncludedInAlignment;
+    public void setAlignmentMode(int alignmentMode) {
+        mAlignmentMode = alignmentMode;
         requestLayout();
     }
 
@@ -723,43 +758,6 @@
 
     // Measurement
 
-    private static int getChildMeasureSpec2(int spec, int padding, int childDimension) {
-        int resultSize;
-        int resultMode;
-
-        if (childDimension >= 0) {
-            resultSize = childDimension;
-            resultMode = EXACTLY;
-        } else {
-            /*
-            using the following lines would replicate the logic of ViewGroup.getChildMeasureSpec()
-
-            int specMode = MeasureSpec.getMode(spec);
-            int specSize = MeasureSpec.getSize(spec);
-            int size = Math.max(0, specSize - padding);
-
-            resultSize = size;
-            resultMode = (specMode == EXACTLY && childDimension == LayoutParams.WRAP_CONTENT) ?
-                    AT_MOST : specMode;
-            */
-            resultSize = 0;
-            resultMode = UNSPECIFIED;
-        }
-        return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
-    }
-
-    @Override
-    protected void measureChild(View child, int parentWidthSpec, int parentHeightSpec) {
-        ViewGroup.LayoutParams lp = child.getLayoutParams();
-
-        int childWidthMeasureSpec = getChildMeasureSpec2(parentWidthSpec,
-                mPaddingLeft + mPaddingRight, lp.width);
-        int childHeightMeasureSpec = getChildMeasureSpec2(parentHeightSpec,
-                mPaddingTop + mPaddingBottom, lp.height);
-
-        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
-    }
-
     @Override
     protected void onMeasure(int widthSpec, int heightSpec) {
         measureChildren(widthSpec, heightSpec);
@@ -782,7 +780,7 @@
 
     private int getMeasurementIncludingMargin(View c, boolean horizontal, int measurementType) {
         int result = getMeasurement(c, horizontal, measurementType);
-        if (mMarginsIncludedInAlignment) {
+        if (mAlignmentMode == ALIGN_MARGINS) {
             int leadingMargin = getMargin(c, true, horizontal);
             int trailingMargin = getMargin(c, false, horizontal);
             return result + leadingMargin + trailingMargin;
@@ -844,8 +842,8 @@
             int pWidth = getMeasurement(view, true, PRF);
             int pHeight = getMeasurement(view, false, PRF);
 
-            Alignment hAlignment = columnGroup.alignment;
-            Alignment vAlignment = rowGroup.alignment;
+            Alignment hAlign = columnGroup.alignment;
+            Alignment vAlign = rowGroup.alignment;
 
             int dx, dy;
 
@@ -853,22 +851,23 @@
             Bounds rowBounds = mVerticalAxis.getGroupBounds().getValue(i);
 
             // Gravity offsets: the location of the alignment group relative to its cell group.
-            int c2ax = protect(hAlignment.getAlignmentValue(null, cellWidth - colBounds.size()));
-            int c2ay = protect(vAlignment.getAlignmentValue(null, cellHeight - rowBounds.size()));
+            int type = PRF;
+            int c2ax = protect(hAlign.getAlignmentValue(null, cellWidth - colBounds.size(), type));
+            int c2ay = protect(vAlign.getAlignmentValue(null, cellHeight - rowBounds.size(), type));
 
-            if (mMarginsIncludedInAlignment) {
+            if (mAlignmentMode == ALIGN_MARGINS) {
                 int leftMargin = getMargin(view, true, true);
                 int topMargin = getMargin(view, true, false);
                 int rightMargin = getMargin(view, false, true);
                 int bottomMargin = getMargin(view, false, false);
 
                 // Same calculation as getMeasurementIncludingMargin()
-                int measuredWidth = leftMargin + pWidth + rightMargin;
-                int measuredHeight = topMargin + pHeight + bottomMargin;
+                int mWidth = leftMargin + pWidth + rightMargin;
+                int mHeight = topMargin + pHeight + bottomMargin;
 
                 // Alignment offsets: the location of the view relative to its alignment group.
-                int a2vx = colBounds.before - hAlignment.getAlignmentValue(view, measuredWidth);
-                int a2vy = rowBounds.before - vAlignment.getAlignmentValue(view, measuredHeight);
+                int a2vx = colBounds.before - hAlign.getAlignmentValue(view, mWidth, type);
+                int a2vy = rowBounds.before - vAlign.getAlignmentValue(view, mHeight, type);
 
                 dx = c2ax + a2vx + leftMargin;
                 dy = c2ay + a2vy + topMargin;
@@ -877,15 +876,15 @@
                 cellHeight -= topMargin + bottomMargin;
             } else {
                 // Alignment offsets: the location of the view relative to its alignment group.
-                int a2vx = colBounds.before - hAlignment.getAlignmentValue(view, pWidth);
-                int a2vy = rowBounds.before - vAlignment.getAlignmentValue(view, pHeight);
+                int a2vx = colBounds.before - hAlign.getAlignmentValue(view, pWidth, type);
+                int a2vy = rowBounds.before - vAlign.getAlignmentValue(view, pHeight, type);
 
                 dx = c2ax + a2vx;
                 dy = c2ay + a2vy;
             }
 
-            int width = hAlignment.getSizeInCell(view, pWidth, cellWidth);
-            int height = vAlignment.getSizeInCell(view, pHeight, cellHeight);
+            int width = hAlign.getSizeInCell(view, pWidth, cellWidth, type);
+            int height = vAlign.getSizeInCell(view, pHeight, cellHeight, type);
 
             int cx = paddingLeft + x1 + dx;
             int cy = paddingTop + y1 + dy;
@@ -1003,7 +1002,7 @@
 
                 int size = getMeasurementIncludingMargin(c, horizontal, PRF);
                 // todo test this works correctly when the returned value is UNDEFINED
-                int before = g.alignment.getAlignmentValue(c, size);
+                int before = g.alignment.getAlignmentValue(c, size, PRF);
                 bounds.include(before, size - before);
             }
         }
@@ -1107,9 +1106,6 @@
             return result;
         }
 
-        /*
-        Topological sort.
-         */
         private Arc[] topologicalSort(final Arc[] arcs, int start) {
         // todo ensure the <start> vertex is added in edge cases
             final List<Arc> result = new ArrayList<Arc>();
@@ -1358,7 +1354,7 @@
         private int getLocationIncludingMargin(View view, boolean leading, int index) {
             int location = locations[index];
             int margin;
-            if (!mMarginsIncludedInAlignment) {
+            if (mAlignmentMode != ALIGN_MARGINS) {
                 margin = (leading ? leadingMargins : trailingMargins)[index];
             } else {
                 margin = 0;
@@ -1370,7 +1366,7 @@
             Arrays.fill(a, MIN_VALUE);
             a[0] = 0;
             solve(getArcs(), a);
-            if (!mMarginsIncludedInAlignment) {
+            if (mAlignmentMode != ALIGN_MARGINS) {
                 addMargins();
             }
         }
@@ -1459,6 +1455,7 @@
             spanSizes = null;
             leadingMargins = null;
             trailingMargins = null;
+            arcs = null;
             minima = null;
             weights = null;
             locations = null;
@@ -1750,16 +1747,16 @@
         private void init(Context context, AttributeSet attrs, int defaultGravity) {
             TypedArray a = context.obtainStyledAttributes(attrs, styleable.GridLayout_Layout);
             try {
-                int gravity = a.getInteger(GRAVITY, defaultGravity);
+                int gravity = a.getInt(GRAVITY, defaultGravity);
 
-                int column = a.getInteger(COLUMN, DEFAULT_COLUMN);
-                int columnSpan = a.getInteger(COLUMN_SPAN, DEFAULT_SPAN_SIZE);
+                int column = a.getInt(COLUMN, DEFAULT_COLUMN);
+                int columnSpan = a.getInt(COLUMN_SPAN, DEFAULT_SPAN_SIZE);
                 Interval hSpan = new Interval(column, column + columnSpan);
                 this.columnGroup = new Group(hSpan, getColumnAlignment(gravity, width));
                 this.columnWeight = a.getFloat(COLUMN_WEIGHT, getDefaultWeight(width));
 
-                int row = a.getInteger(ROW, DEFAULT_ROW);
-                int rowSpan = a.getInteger(ROW_SPAN, DEFAULT_SPAN_SIZE);
+                int row = a.getInt(ROW, DEFAULT_ROW);
+                int rowSpan = a.getInt(ROW_SPAN, DEFAULT_SPAN_SIZE);
                 Interval vSpan = new Interval(row, row + rowSpan);
                 this.rowGroup = new Group(vSpan, getRowAlignment(gravity, height));
                 this.rowWeight = a.getFloat(ROW_WEIGHT, getDefaultWeight(height));
@@ -2156,57 +2153,63 @@
      * {@link Group#alignment alignment}. Overall placement of the view in the cell
      * group is specified by the two alignments which act along each axis independently.
      * <p>
-     * An Alignment implementation must define the {@link #getAlignmentValue(View, int)}
+     * An Alignment implementation must define {@link #getAlignmentValue(View, int, int)},
      * to return the appropriate value for the type of alignment being defined.
      * The enclosing algorithms position the children
-     * so that the values returned from the alignment
+     * so that the locations defined by the alignment values
      * are the same for all of the views in a group.
      * <p>
      *  The GridLayout class defines the most common alignments used in general layout:
      * {@link #TOP}, {@link #LEFT}, {@link #BOTTOM}, {@link #RIGHT}, {@link #CENTER}, {@link
      * #BASELINE} and {@link #FILL}.
      */
-    public static interface Alignment {
+    public static abstract class Alignment {
         /**
          * Returns an alignment value. In the case of vertical alignments the value
          * returned should indicate the distance from the top of the view to the
          * alignment location.
          * For horizontal alignments measurement is made from the left edge of the component.
          *
-         * @param view     the view to which this alignment should be applied
-         * @param viewSize the measured size of the view
-         * @return         the alignment value
+         * @param view              the view to which this alignment should be applied
+         * @param viewSize          the measured size of the view
+         * @param measurementType   The type of measurement that should be made. This feature
+         *                          is currently unused as GridLayout only supports one
+         *                          type of measurement: {@link View#measure(int, int)}.
+         *
+         * @return                  the alignment value
          */
-        public int getAlignmentValue(View view, int viewSize);
+        public abstract int getAlignmentValue(View view, int viewSize, int measurementType);
 
         /**
          * Returns the size of the view specified by this alignment.
          * In the case of vertical alignments this method should return a height; for
          * horizontal alignments this method should return the width.
+         * <p>
+         * The default implementation returns {@code viewSize}.
          *
-         * @param view     the view to which this alignment should be applied
-         * @param viewSize the measured size of the view
-         * @param cellSize the size of the cell into which this view will be placed
-         * @return         the aligned size
+         * @param view              the view to which this alignment should be applied
+         * @param viewSize          the measured size of the view
+         * @param cellSize          the size of the cell into which this view will be placed
+         * @param measurementType   The type of measurement that should be made. This feature
+         *                          is currently unused as GridLayout only supports one
+         *                          type of measurement: {@link View#measure(int, int)}.
+         *
+         * @return                  the aligned size
          */
-        public int getSizeInCell(View view, int viewSize, int cellSize);
-    }
-
-    private static abstract class AbstractAlignment implements Alignment {
-        public int getSizeInCell(View view, int viewSize, int cellSize) {
+        public int getSizeInCell(View view, int viewSize, int cellSize, int measurementType) {
             return viewSize;
         }
     }
 
-    private static final Alignment LEADING = new AbstractAlignment() {
-        public int getAlignmentValue(View view, int viewSize) {
+    private static final Alignment LEADING = new Alignment() {
+        public int getAlignmentValue(View view, int viewSize, int measurementType) {
             return 0;
         }
 
     };
 
-    private static final Alignment TRAILING = new AbstractAlignment() {
-        public int getAlignmentValue(View view, int viewSize) {
+    private static final Alignment TRAILING = new Alignment() {
+        public int getAlignmentValue(View view, int viewSize, int measurementType) {
             return viewSize;
         }
     };
@@ -2240,8 +2243,8 @@
      * This constant may be used in both {@link LayoutParams#rowGroup rowGroups} and {@link
      * LayoutParams#columnGroup columnGroups}.
      */
-    public static final Alignment CENTER = new AbstractAlignment() {
-        public int getAlignmentValue(View view, int viewSize) {
+    public static final Alignment CENTER = new Alignment() {
+        public int getAlignmentValue(View view, int viewSize, int measurementType) {
             return viewSize >> 1;
         }
     };
@@ -2253,8 +2256,8 @@
      *
      * @see View#getBaseline()
      */
-    public static final Alignment BASELINE = new AbstractAlignment() {
-        public int getAlignmentValue(View view, int height) {
+    public static final Alignment BASELINE = new Alignment() {
+        public int getAlignmentValue(View view, int viewSize, int measurementType) {
             if (view == null) {
                 return UNDEFINED;
             }
@@ -2274,12 +2277,13 @@
      * {@link LayoutParams#columnGroup columnGroups}.
      */
     public static final Alignment FILL = new Alignment() {
-        public int getAlignmentValue(View view, int viewSize) {
+        public int getAlignmentValue(View view, int viewSize, int measurementType) {
             return UNDEFINED;
         }
 
-        public int getSizeInCell(View view, int viewSize, int cellSize) {
+        @Override
+        public int getSizeInCell(View view, int viewSize, int cellSize, int measurementType) {
             return cellSize;
         }
     };
-}
\ No newline at end of file
+}
diff --git a/core/java/android/widget/Space.java b/core/java/android/widget/Space.java
index d98b937..d7b2ec2 100644
--- a/core/java/android/widget/Space.java
+++ b/core/java/android/widget/Space.java
@@ -72,4 +72,35 @@
     public void setLayoutParams(ViewGroup.LayoutParams params) {
         super.setLayoutParams(params);
     }
+
+    /**
+     * Compare to: {@link View#getDefaultSize(int, int)}
+     * If mode is AT_MOST, return the child size instead of the parent size
+     * (unless it is too big).
+     */
+    private static int getDefaultSize2(int size, int measureSpec) {
+        int result = size;
+        int specMode = MeasureSpec.getMode(measureSpec);
+        int specSize = MeasureSpec.getSize(measureSpec);
+
+        switch (specMode) {
+            case MeasureSpec.UNSPECIFIED:
+                result = size;
+                break;
+            case MeasureSpec.AT_MOST:
+                result = Math.min(size, specSize);
+                break;
+            case MeasureSpec.EXACTLY:
+                result = specSize;
+                break;
+        }
+        return result;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        setMeasuredDimension(
+                getDefaultSize2(getSuggestedMinimumWidth(), widthMeasureSpec),
+                getDefaultSize2(getSuggestedMinimumHeight(), heightMeasureSpec));
+    }
 }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 470a23d6..02c2b8f 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -8574,11 +8574,7 @@
                     final String originalText = mText.subSequence(spanStart, spanEnd).toString();
                     ((Editable) mText).replace(spanStart, spanEnd, suggestion);
 
-                    // Swap text content between actual text and Suggestion span
-                    String[] suggestions = suggestionInfo.suggestionSpan.getSuggestions();
-                    suggestions[suggestionInfo.suggestionIndex] = originalText;
-
-                    // Notify source IME of the suggestion pick
+                    // Notify source IME of the suggestion pick. Do this before swaping texts.
                     if (!TextUtils.isEmpty(
                             suggestionInfo.suggestionSpan.getNotificationTargetClassName())) {
                         InputMethodManager imm = InputMethodManager.peekInstance();
@@ -8586,6 +8582,10 @@
                                 suggestionInfo.suggestionIndex);
                     }
 
+                    // Swap text content between actual text and Suggestion span
+                    String[] suggestions = suggestionInfo.suggestionSpan.getSuggestions();
+                    suggestions[suggestionInfo.suggestionIndex] = originalText;
+
                     // Restore previous SuggestionSpans
                     final int lengthDifference = suggestion.length() - (spanEnd - spanStart);
                     for (int i = 0; i < length; i++) {
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 71a7a52..8d6caa1 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -575,9 +575,13 @@
         params.weight = 0.5f;
         button.setLayoutParams(params);
         View leftSpacer = mWindow.findViewById(R.id.leftSpacer);
-        leftSpacer.setVisibility(View.VISIBLE);
+        if (leftSpacer != null) {
+            leftSpacer.setVisibility(View.VISIBLE);
+        }
         View rightSpacer = mWindow.findViewById(R.id.rightSpacer);
-        rightSpacer.setVisibility(View.VISIBLE);
+        if (rightSpacer != null) {
+            rightSpacer.setVisibility(View.VISIBLE);
+        }
     }
 
     private void setBackground(LinearLayout topPanel, LinearLayout contentPanel,
diff --git a/core/java/com/android/internal/net/VpnConfig.aidl b/core/java/com/android/internal/net/VpnConfig.aidl
new file mode 100644
index 0000000..be1684c
--- /dev/null
+++ b/core/java/com/android/internal/net/VpnConfig.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.internal.net;
+
+parcelable VpnConfig;
diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java
new file mode 100644
index 0000000..773be5b
--- /dev/null
+++ b/core/java/com/android/internal/net/VpnConfig.java
@@ -0,0 +1,108 @@
+/*
+ * 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.internal.net;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+
+/**
+ * A simple container used to carry information in VpnBuilder, VpnDialogs,
+ * and com.android.server.connectivity.Vpn. Internal use only.
+ *
+ * @hide
+ */
+public class VpnConfig implements Parcelable {
+
+    public static final String ACTION_VPN_REVOKED = "android.net.vpn.action.REVOKED";
+
+    public static void enforceCallingPackage(String packageName) {
+        if (!"com.android.vpndialogs".equals(packageName)) {
+            throw new SecurityException("Unauthorized Caller");
+        }
+    }
+
+    public static Intent getIntentForConfirmation() {
+        Intent intent = new Intent();
+        intent.setClassName("com.android.vpndialogs", "com.android.vpndialogs.ConfirmDialog");
+        return intent;
+    }
+
+    public static PendingIntent getIntentForNotification(Context context, VpnConfig config) {
+        config.startTime = SystemClock.elapsedRealtime();
+        Intent intent = new Intent();
+        intent.setClassName("com.android.vpndialogs", "com.android.vpndialogs.ManageDialog");
+        intent.putExtra("config", config);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_HISTORY |
+                Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+        return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+    }
+
+    public String packageName;
+    public String sessionName;
+    public String interfaceName;
+    public String configureActivity;
+    public int mtu = -1;
+    public String addresses;
+    public String routes;
+    public String dnsServers;
+    public long startTime = -1;
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(packageName);
+        out.writeString(sessionName);
+        out.writeString(interfaceName);
+        out.writeString(configureActivity);
+        out.writeInt(mtu);
+        out.writeString(addresses);
+        out.writeString(routes);
+        out.writeString(dnsServers);
+        out.writeLong(startTime);
+    }
+
+    public static final Parcelable.Creator<VpnConfig> CREATOR =
+            new Parcelable.Creator<VpnConfig>() {
+        @Override
+        public VpnConfig createFromParcel(Parcel in) {
+            VpnConfig config = new VpnConfig();
+            config.packageName = in.readString();
+            config.sessionName = in.readString();
+            config.interfaceName = in.readString();
+            config.configureActivity = in.readString();
+            config.mtu = in.readInt();
+            config.addresses = in.readString();
+            config.routes = in.readString();
+            config.dnsServers = in.readString();
+            config.startTime = in.readLong();
+            return config;
+        }
+
+        @Override
+        public VpnConfig[] newArray(int size) {
+            return new VpnConfig[size];
+        }
+    };
+}
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 2ff0413..c11fc10 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -35,5 +35,6 @@
     void setImeWindowStatus(in IBinder token, int vis, int backDisposition);
     void setHardKeyboardStatus(boolean available, boolean enabled);
     void userActivity();
+    void toggleRecentApps();
 }
 
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 3f2b1ef..a9e5057 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -47,4 +47,5 @@
     void setSystemUiVisibility(int vis);
     void setHardKeyboardEnabled(boolean enabled);
     void userActivity();
+    void toggleRecentApps();
 }
diff --git a/core/java/com/android/internal/util/HanziToPinyin.java b/core/java/com/android/internal/util/HanziToPinyin.java
deleted file mode 100644
index 6a4adaa..0000000
--- a/core/java/com/android/internal/util/HanziToPinyin.java
+++ /dev/null
@@ -1,495 +0,0 @@
-/*
- * Copyright (C) 2009 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.internal.util;
-
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.text.Collator;
-import java.util.ArrayList;
-import java.util.Locale;
-
-/**
- * An object to convert Chinese character to its corresponding pinyin string.
- * For characters with multiple possible pinyin string, only one is selected
- * according to collator. Polyphone is not supported in this implementation.
- * This class is implemented to achieve the best runtime performance and minimum
- * runtime resources with tolerable sacrifice of accuracy. This implementation
- * highly depends on zh_CN ICU collation data and must be always synchronized with
- * ICU.
- */
-public class HanziToPinyin {
-    private static final String TAG = "HanziToPinyin";
-
-    private static final char[] UNIHANS = {
-            '\u5416', '\u54ce', '\u5b89', '\u80ae', '\u51f9', '\u516b', '\u63b0', '\u6273',
-            '\u90a6', '\u52f9', '\u9642', '\u5954', '\u4f3b', '\u7680', '\u782d', '\u706c',
-            '\u618b', '\u6c43', '\u51ab', '\u7676', '\u5cec', '\u5693', '\u5072', '\u53c2',
-            '\u4ed3', '\u64a1', '\u518a', '\u5d7e', '\u564c', '\u6260', '\u62c6', '\u8fbf',
-            '\u4f25', '\u6284', '\u8f66', '\u62bb', '\u9637', '\u5403', '\u5145', '\u62bd',
-            '\u51fa', '\u640b', '\u5ddb', '\u5205', '\u5439', '\u65fe', '\u8e14', '\u5472',
-            '\u4ece', '\u51d1', '\u7c97', '\u6c46', '\u5d14', '\u90a8', '\u6413', '\u5491',
-            '\u5446', '\u4e39', '\u5f53', '\u5200', '\u6074', '\u6265', '\u706f', '\u4efe',
-            '\u55f2', '\u6541', '\u5201', '\u7239', '\u4e01', '\u4e1f', '\u4e1c', '\u543a',
-            '\u5262', '\u8011', '\u5796', '\u5428', '\u591a', '\u59b8', '\u5940', '\u97a5',
-            '\u800c', '\u53d1', '\u5e06', '\u531a', '\u98de', '\u5206', '\u4e30', '\u8985',
-            '\u4ecf', '\u57ba', '\u7d11', '\u592b', '\u7324', '\u65ee', '\u4f85', '\u5e72',
-            '\u5188', '\u768b', '\u6208', '\u7ed9', '\u6839', '\u63ef', '\u55bc', '\u55f0',
-            '\u5de5', '\u52fe', '\u4f30', '\u9e39', '\u4e56', '\u5173', '\u5149', '\u5f52',
-            '\u4e28', '\u8b34', '\u5459', '\u598e', '\u548d', '\u4f44', '\u592f', '\u8320',
-            '\u8bc3', '\u9ed2', '\u62eb', '\u4ea8', '\u53ff', '\u9f41', '\u4e4e', '\u82b1',
-            '\u6000', '\u6b22', '\u5ddf', '\u7070', '\u660f', '\u5419', '\u4e0c', '\u52a0',
-            '\u620b', '\u6c5f', '\u827d', '\u9636', '\u5dfe', '\u5755', '\u5182', '\u4e29',
-            '\u51e5', '\u59e2', '\u5658', '\u519b', '\u5494', '\u5f00', '\u938e', '\u5ffc',
-            '\u5c3b', '\u533c', '\u808e', '\u52a5', '\u7a7a', '\u62a0', '\u625d', '\u5938',
-            '\u84af', '\u5bbd', '\u5321', '\u4e8f', '\u5764', '\u6269', '\u62c9', '\u4f86',
-            '\u5170', '\u5577', '\u635e', '\u4ec2', '\u96f7', '\u8137', '\u68f1', '\u695e',
-            '\u550e', '\u4fe9', '\u5afe', '\u826f', '\u8e7d', '\u57d3', '\u53b8', '\u62ce',
-            '\u6e9c', '\u9f99', '\u5a04', '\u565c', '\u5b6a', '\u62a1', '\u9831', '\u5988',
-            '\u57cb', '\u989f', '\u7264', '\u732b', '\u5445', '\u95e8', '\u6c13', '\u54aa',
-            '\u5b80', '\u55b5', '\u4e5c', '\u6c11', '\u540d', '\u8c2c', '\u6478', '\u725f',
-            '\u6bcd', '\u62cf', '\u8149', '\u56e1', '\u56d4', '\u5b6c', '\u8bb7', '\u5a1e',
-            '\u5ae9', '\u80fd', '\u92b0', '\u62c8', '\u5a18', '\u9e1f', '\u634f', '\u56dc',
-            '\u5b81', '\u599e', '\u519c', '\u7fba', '\u5974', '\u597b', '\u9ec1', '\u90cd',
-            '\u5662', '\u8bb4', '\u5991', '\u62cd', '\u7705', '\u6c78', '\u629b', '\u5478',
-            '\u55b7', '\u5309', '\u4e76', '\u7247', '\u527d', '\u6c15', '\u59d8', '\u4e52',
-            '\u948b', '\u5256', '\u4ec6', '\u4e03', '\u6390', '\u5343', '\u545b', '\u6084',
-            '\u5207', '\u4eb2', '\u9751', '\u5b86', '\u74d7', '\u533a', '\u5cd1', '\u7094',
-            '\u590b', '\u5465', '\u7a63', '\u835b', '\u60f9', '\u4eba', '\u6254', '\u65e5',
-            '\u620e', '\u53b9', '\u909a', '\u5827', '\u6875', '\u95f0', '\u633c', '\u4ee8',
-            '\u6be2', '\u4e09', '\u6852', '\u63bb', '\u8272', '\u68ee', '\u50e7', '\u6740',
-            '\u7b5b', '\u5c71', '\u4f24', '\u5f30', '\u5962', '\u7533', '\u5347', '\u5c38',
-            '\u53ce', '\u4e66', '\u5237', '\u8870', '\u95e9', '\u53cc', '\u8c01', '\u542e',
-            '\u8bf4', '\u53b6', '\u5fea', '\u51c1', '\u82cf', '\u72fb', '\u590a', '\u5b59',
-            '\u5506', '\u4ed6', '\u5b61', '\u574d', '\u6c64', '\u5932', '\u5fd1', '\u81af',
-            '\u5254', '\u5929', '\u65eb', '\u6017', '\u5385', '\u70b5', '\u5077', '\u51f8',
-            '\u6e4d', '\u63a8', '\u541e', '\u8bac', '\u52b8', '\u6b6a', '\u5f2f', '\u5c23',
-            '\u5371', '\u6637', '\u7fc1', '\u631d', '\u4e4c', '\u5915', '\u5477', '\u4ed9',
-            '\u4e61', '\u7071', '\u4e9b', '\u5fc3', '\u5174', '\u51f6', '\u4f11', '\u620c',
-            '\u5405', '\u75b6', '\u7025', '\u4e2b', '\u54bd', '\u592e', '\u5e7a', '\u503b',
-            '\u4e00', '\u4e5a', '\u5e94', '\u5537', '\u4f63', '\u4f18', '\u7ea1', '\u56e6',
-            '\u66f0', '\u8480', '\u5e00', '\u707d', '\u5142', '\u7242', '\u50ae', '\u556b',
-            '\u9c61', '\u600e', '\u66fd', '\u5412', '\u635a', '\u6cbe', '\u5f20', '\u4f4b',
-            '\u8707', '\u8d1e', '\u9eee', '\u4e4b', '\u4e2d', '\u5dde', '\u6731', '\u6293',
-            '\u62fd', '\u4e13', '\u5986', '\u96b9', '\u5b92', '\u5353', '\u4ed4', '\u5b97',
-            '\u90b9', '\u79df', '\u5297', '\u55fa', '\u5c0a', '\u6628',
-        };
-    private final static byte[][] PINYINS = {
-            {65, 00, 00, 00, 00, 00, }, {65, 73, 00, 00, 00, 00, },
-            {65, 78, 00, 00, 00, 00, }, {65, 78, 71, 00, 00, 00, },
-            {65, 79, 00, 00, 00, 00, }, {66, 65, 00, 00, 00, 00, },
-            {66, 65, 73, 00, 00, 00, }, {66, 65, 78, 00, 00, 00, },
-            {66, 65, 78, 71, 00, 00, }, {66, 65, 79, 00, 00, 00, },
-            {66, 69, 73, 00, 00, 00, }, {66, 69, 78, 00, 00, 00, },
-            {66, 69, 78, 71, 00, 00, }, {66, 73, 00, 00, 00, 00, },
-            {66, 73, 65, 78, 00, 00, }, {66, 73, 65, 79, 00, 00, },
-            {66, 73, 69, 00, 00, 00, }, {66, 73, 78, 00, 00, 00, },
-            {66, 73, 78, 71, 00, 00, }, {66, 79, 00, 00, 00, 00, },
-            {66, 85, 00, 00, 00, 00, }, {67, 65, 00, 00, 00, 00, },
-            {67, 65, 73, 00, 00, 00, }, {67, 65, 78, 00, 00, 00, },
-            {67, 65, 78, 71, 00, 00, }, {67, 65, 79, 00, 00, 00, },
-            {67, 69, 00, 00, 00, 00, }, {67, 69, 78, 00, 00, 00, },
-            {67, 69, 78, 71, 00, 00, }, {67, 72, 65, 00, 00, 00, },
-            {67, 72, 65, 73, 00, 00, }, {67, 72, 65, 78, 00, 00, },
-            {67, 72, 65, 78, 71, 00, }, {67, 72, 65, 79, 00, 00, },
-            {67, 72, 69, 00, 00, 00, }, {67, 72, 69, 78, 00, 00, },
-            {67, 72, 69, 78, 71, 00, }, {67, 72, 73, 00, 00, 00, },
-            {67, 72, 79, 78, 71, 00, }, {67, 72, 79, 85, 00, 00, },
-            {67, 72, 85, 00, 00, 00, }, {67, 72, 85, 65, 73, 00, },
-            {67, 72, 85, 65, 78, 00, }, {67, 72, 85, 65, 78, 71, },
-            {67, 72, 85, 73, 00, 00, }, {67, 72, 85, 78, 00, 00, },
-            {67, 72, 85, 79, 00, 00, }, {67, 73, 00, 00, 00, 00, },
-            {67, 79, 78, 71, 00, 00, }, {67, 79, 85, 00, 00, 00, },
-            {67, 85, 00, 00, 00, 00, }, {67, 85, 65, 78, 00, 00, },
-            {67, 85, 73, 00, 00, 00, }, {67, 85, 78, 00, 00, 00, },
-            {67, 85, 79, 00, 00, 00, }, {68, 65, 00, 00, 00, 00, },
-            {68, 65, 73, 00, 00, 00, }, {68, 65, 78, 00, 00, 00, },
-            {68, 65, 78, 71, 00, 00, }, {68, 65, 79, 00, 00, 00, },
-            {68, 69, 00, 00, 00, 00, }, {68, 69, 78, 00, 00, 00, },
-            {68, 69, 78, 71, 00, 00, }, {68, 73, 00, 00, 00, 00, },
-            {68, 73, 65, 00, 00, 00, }, {68, 73, 65, 78, 00, 00, },
-            {68, 73, 65, 79, 00, 00, }, {68, 73, 69, 00, 00, 00, },
-            {68, 73, 78, 71, 00, 00, }, {68, 73, 85, 00, 00, 00, },
-            {68, 79, 78, 71, 00, 00, }, {68, 79, 85, 00, 00, 00, },
-            {68, 85, 00, 00, 00, 00, }, {68, 85, 65, 78, 00, 00, },
-            {68, 85, 73, 00, 00, 00, }, {68, 85, 78, 00, 00, 00, },
-            {68, 85, 79, 00, 00, 00, }, {69, 00, 00, 00, 00, 00, },
-            {69, 78, 00, 00, 00, 00, }, {69, 78, 71, 00, 00, 00, },
-            {69, 82, 00, 00, 00, 00, }, {70, 65, 00, 00, 00, 00, },
-            {70, 65, 78, 00, 00, 00, }, {70, 65, 78, 71, 00, 00, },
-            {70, 69, 73, 00, 00, 00, }, {70, 69, 78, 00, 00, 00, },
-            {70, 69, 78, 71, 00, 00, }, {70, 73, 65, 79, 00, 00, },
-            {70, 79, 00, 00, 00, 00, }, {70, 85, 00, 00, 00, 00, },
-            {70, 79, 85, 00, 00, 00, }, {70, 85, 00, 00, 00, 00, },
-            {71, 85, 73, 00, 00, 00, }, {71, 65, 00, 00, 00, 00, },
-            {71, 65, 73, 00, 00, 00, }, {71, 65, 78, 00, 00, 00, },
-            {71, 65, 78, 71, 00, 00, }, {71, 65, 79, 00, 00, 00, },
-            {71, 69, 00, 00, 00, 00, }, {71, 69, 73, 00, 00, 00, },
-            {71, 69, 78, 00, 00, 00, }, {71, 69, 78, 71, 00, 00, },
-            {74, 73, 69, 00, 00, 00, }, {71, 69, 00, 00, 00, 00, },
-            {71, 79, 78, 71, 00, 00, }, {71, 79, 85, 00, 00, 00, },
-            {71, 85, 00, 00, 00, 00, }, {71, 85, 65, 00, 00, 00, },
-            {71, 85, 65, 73, 00, 00, }, {71, 85, 65, 78, 00, 00, },
-            {71, 85, 65, 78, 71, 00, }, {71, 85, 73, 00, 00, 00, },
-            {71, 85, 78, 00, 00, 00, }, {71, 85, 65, 78, 00, 00, },
-            {71, 85, 79, 00, 00, 00, }, {72, 65, 00, 00, 00, 00, },
-            {72, 65, 73, 00, 00, 00, }, {72, 65, 78, 00, 00, 00, },
-            {72, 65, 78, 71, 00, 00, }, {72, 65, 79, 00, 00, 00, },
-            {72, 69, 00, 00, 00, 00, }, {72, 69, 73, 00, 00, 00, },
-            {72, 69, 78, 00, 00, 00, }, {72, 69, 78, 71, 00, 00, },
-            {72, 79, 78, 71, 00, 00, }, {72, 79, 85, 00, 00, 00, },
-            {72, 85, 00, 00, 00, 00, }, {72, 85, 65, 00, 00, 00, },
-            {72, 85, 65, 73, 00, 00, }, {72, 85, 65, 78, 00, 00, },
-            {72, 85, 65, 78, 71, 00, }, {72, 85, 73, 00, 00, 00, },
-            {72, 85, 78, 00, 00, 00, }, {72, 85, 79, 00, 00, 00, },
-            {74, 73, 00, 00, 00, 00, }, {74, 73, 65, 00, 00, 00, },
-            {74, 73, 65, 78, 00, 00, }, {74, 73, 65, 78, 71, 00, },
-            {74, 73, 65, 79, 00, 00, }, {74, 73, 69, 00, 00, 00, },
-            {74, 73, 78, 00, 00, 00, }, {74, 73, 78, 71, 00, 00, },
-            {74, 73, 79, 78, 71, 00, }, {74, 73, 85, 00, 00, 00, },
-            {74, 85, 00, 00, 00, 00, }, {74, 85, 65, 78, 00, 00, },
-            {74, 85, 69, 00, 00, 00, }, {74, 85, 78, 00, 00, 00, },
-            {75, 65, 00, 00, 00, 00, }, {75, 65, 73, 00, 00, 00, },
-            {75, 65, 78, 00, 00, 00, }, {75, 65, 78, 71, 00, 00, },
-            {75, 65, 79, 00, 00, 00, }, {75, 69, 00, 00, 00, 00, },
-            {75, 69, 78, 00, 00, 00, }, {75, 69, 78, 71, 00, 00, },
-            {75, 79, 78, 71, 00, 00, }, {75, 79, 85, 00, 00, 00, },
-            {75, 85, 00, 00, 00, 00, }, {75, 85, 65, 00, 00, 00, },
-            {75, 85, 65, 73, 00, 00, }, {75, 85, 65, 78, 00, 00, },
-            {75, 85, 65, 78, 71, 00, }, {75, 85, 73, 00, 00, 00, },
-            {75, 85, 78, 00, 00, 00, }, {75, 85, 79, 00, 00, 00, },
-            {76, 65, 00, 00, 00, 00, }, {76, 65, 73, 00, 00, 00, },
-            {76, 65, 78, 00, 00, 00, }, {76, 65, 78, 71, 00, 00, },
-            {76, 65, 79, 00, 00, 00, }, {76, 69, 00, 00, 00, 00, },
-            {76, 69, 73, 00, 00, 00, }, {76, 73, 00, 00, 00, 00, },
-            {76, 73, 78, 71, 00, 00, }, {76, 69, 78, 71, 00, 00, },
-            {76, 73, 00, 00, 00, 00, }, {76, 73, 65, 00, 00, 00, },
-            {76, 73, 65, 78, 00, 00, }, {76, 73, 65, 78, 71, 00, },
-            {76, 73, 65, 79, 00, 00, }, {76, 73, 69, 00, 00, 00, },
-            {76, 73, 78, 00, 00, 00, }, {76, 73, 78, 71, 00, 00, },
-            {76, 73, 85, 00, 00, 00, }, {76, 79, 78, 71, 00, 00, },
-            {76, 79, 85, 00, 00, 00, }, {76, 85, 00, 00, 00, 00, },
-            {76, 85, 65, 78, 00, 00, }, {76, 85, 78, 00, 00, 00, },
-            {76, 85, 79, 00, 00, 00, }, {77, 65, 00, 00, 00, 00, },
-            {77, 65, 73, 00, 00, 00, }, {77, 65, 78, 00, 00, 00, },
-            {77, 65, 78, 71, 00, 00, }, {77, 65, 79, 00, 00, 00, },
-            {77, 69, 73, 00, 00, 00, }, {77, 69, 78, 00, 00, 00, },
-            {77, 69, 78, 71, 00, 00, }, {77, 73, 00, 00, 00, 00, },
-            {77, 73, 65, 78, 00, 00, }, {77, 73, 65, 79, 00, 00, },
-            {77, 73, 69, 00, 00, 00, }, {77, 73, 78, 00, 00, 00, },
-            {77, 73, 78, 71, 00, 00, }, {77, 73, 85, 00, 00, 00, },
-            {77, 79, 00, 00, 00, 00, }, {77, 79, 85, 00, 00, 00, },
-            {77, 85, 00, 00, 00, 00, }, {78, 65, 00, 00, 00, 00, },
-            {78, 65, 73, 00, 00, 00, }, {78, 65, 78, 00, 00, 00, },
-            {78, 65, 78, 71, 00, 00, }, {78, 65, 79, 00, 00, 00, },
-            {78, 69, 00, 00, 00, 00, }, {78, 69, 73, 00, 00, 00, },
-            {78, 69, 78, 00, 00, 00, }, {78, 69, 78, 71, 00, 00, },
-            {78, 73, 00, 00, 00, 00, }, {78, 73, 65, 78, 00, 00, },
-            {78, 73, 65, 78, 71, 00, }, {78, 73, 65, 79, 00, 00, },
-            {78, 73, 69, 00, 00, 00, }, {78, 73, 78, 00, 00, 00, },
-            {78, 73, 78, 71, 00, 00, }, {78, 73, 85, 00, 00, 00, },
-            {78, 79, 78, 71, 00, 00, }, {78, 79, 85, 00, 00, 00, },
-            {78, 85, 00, 00, 00, 00, }, {78, 85, 65, 78, 00, 00, },
-            {78, 85, 78, 00, 00, 00, }, {78, 85, 79, 00, 00, 00, },
-            {79, 00, 00, 00, 00, 00, }, {79, 85, 00, 00, 00, 00, },
-            {80, 65, 00, 00, 00, 00, }, {80, 65, 73, 00, 00, 00, },
-            {80, 65, 78, 00, 00, 00, }, {80, 65, 78, 71, 00, 00, },
-            {80, 65, 79, 00, 00, 00, }, {80, 69, 73, 00, 00, 00, },
-            {80, 69, 78, 00, 00, 00, }, {80, 69, 78, 71, 00, 00, },
-            {80, 73, 00, 00, 00, 00, }, {80, 73, 65, 78, 00, 00, },
-            {80, 73, 65, 79, 00, 00, }, {80, 73, 69, 00, 00, 00, },
-            {80, 73, 78, 00, 00, 00, }, {80, 73, 78, 71, 00, 00, },
-            {80, 79, 00, 00, 00, 00, }, {80, 79, 85, 00, 00, 00, },
-            {80, 85, 00, 00, 00, 00, }, {81, 73, 00, 00, 00, 00, },
-            {81, 73, 65, 00, 00, 00, }, {81, 73, 65, 78, 00, 00, },
-            {81, 73, 65, 78, 71, 00, }, {81, 73, 65, 79, 00, 00, },
-            {81, 73, 69, 00, 00, 00, }, {81, 73, 78, 00, 00, 00, },
-            {81, 73, 78, 71, 00, 00, }, {81, 73, 79, 78, 71, 00, },
-            {81, 73, 85, 00, 00, 00, }, {81, 85, 00, 00, 00, 00, },
-            {81, 85, 65, 78, 00, 00, }, {81, 85, 69, 00, 00, 00, },
-            {81, 85, 78, 00, 00, 00, }, {82, 65, 78, 00, 00, 00, },
-            {82, 65, 78, 71, 00, 00, }, {82, 65, 79, 00, 00, 00, },
-            {82, 69, 00, 00, 00, 00, }, {82, 69, 78, 00, 00, 00, },
-            {82, 69, 78, 71, 00, 00, }, {82, 73, 00, 00, 00, 00, },
-            {82, 79, 78, 71, 00, 00, }, {82, 79, 85, 00, 00, 00, },
-            {82, 85, 00, 00, 00, 00, }, {82, 85, 65, 78, 00, 00, },
-            {82, 85, 73, 00, 00, 00, }, {82, 85, 78, 00, 00, 00, },
-            {82, 85, 79, 00, 00, 00, }, {83, 65, 00, 00, 00, 00, },
-            {83, 65, 73, 00, 00, 00, }, {83, 65, 78, 00, 00, 00, },
-            {83, 65, 78, 71, 00, 00, }, {83, 65, 79, 00, 00, 00, },
-            {83, 69, 00, 00, 00, 00, }, {83, 69, 78, 00, 00, 00, },
-            {83, 69, 78, 71, 00, 00, }, {83, 72, 65, 00, 00, 00, },
-            {83, 72, 65, 73, 00, 00, }, {83, 72, 65, 78, 00, 00, },
-            {83, 72, 65, 78, 71, 00, }, {83, 72, 65, 79, 00, 00, },
-            {83, 72, 69, 00, 00, 00, }, {83, 72, 69, 78, 00, 00, },
-            {83, 72, 69, 78, 71, 00, }, {83, 72, 73, 00, 00, 00, },
-            {83, 72, 79, 85, 00, 00, }, {83, 72, 85, 00, 00, 00, },
-            {83, 72, 85, 65, 00, 00, }, {83, 72, 85, 65, 73, 00, },
-            {83, 72, 85, 65, 78, 00, }, {83, 72, 85, 65, 78, 71, },
-            {83, 72, 85, 73, 00, 00, }, {83, 72, 85, 78, 00, 00, },
-            {83, 72, 85, 79, 00, 00, }, {83, 73, 00, 00, 00, 00, },
-            {83, 79, 78, 71, 00, 00, }, {83, 79, 85, 00, 00, 00, },
-            {83, 85, 00, 00, 00, 00, }, {83, 85, 65, 78, 00, 00, },
-            {83, 85, 73, 00, 00, 00, }, {83, 85, 78, 00, 00, 00, },
-            {83, 85, 79, 00, 00, 00, }, {84, 65, 00, 00, 00, 00, },
-            {84, 65, 73, 00, 00, 00, }, {84, 65, 78, 00, 00, 00, },
-            {84, 65, 78, 71, 00, 00, }, {84, 65, 79, 00, 00, 00, },
-            {84, 69, 00, 00, 00, 00, }, {84, 69, 78, 71, 00, 00, },
-            {84, 73, 00, 00, 00, 00, }, {84, 73, 65, 78, 00, 00, },
-            {84, 73, 65, 79, 00, 00, }, {84, 73, 69, 00, 00, 00, },
-            {84, 73, 78, 71, 00, 00, }, {84, 79, 78, 71, 00, 00, },
-            {84, 79, 85, 00, 00, 00, }, {84, 85, 00, 00, 00, 00, },
-            {84, 85, 65, 78, 00, 00, }, {84, 85, 73, 00, 00, 00, },
-            {84, 85, 78, 00, 00, 00, }, {84, 85, 79, 00, 00, 00, },
-            {87, 65, 00, 00, 00, 00, }, {87, 65, 73, 00, 00, 00, },
-            {87, 65, 78, 00, 00, 00, }, {87, 65, 78, 71, 00, 00, },
-            {87, 69, 73, 00, 00, 00, }, {87, 69, 78, 00, 00, 00, },
-            {87, 69, 78, 71, 00, 00, }, {87, 79, 00, 00, 00, 00, },
-            {87, 85, 00, 00, 00, 00, }, {88, 73, 00, 00, 00, 00, },
-            {88, 73, 65, 00, 00, 00, }, {88, 73, 65, 78, 00, 00, },
-            {88, 73, 65, 78, 71, 00, }, {88, 73, 65, 79, 00, 00, },
-            {88, 73, 69, 00, 00, 00, }, {88, 73, 78, 00, 00, 00, },
-            {88, 73, 78, 71, 00, 00, }, {88, 73, 79, 78, 71, 00, },
-            {88, 73, 85, 00, 00, 00, }, {88, 85, 00, 00, 00, 00, },
-            {88, 85, 65, 78, 00, 00, }, {88, 85, 69, 00, 00, 00, },
-            {88, 85, 78, 00, 00, 00, }, {89, 65, 00, 00, 00, 00, },
-            {89, 65, 78, 00, 00, 00, }, {89, 65, 78, 71, 00, 00, },
-            {89, 65, 79, 00, 00, 00, }, {89, 69, 00, 00, 00, 00, },
-            {89, 73, 00, 00, 00, 00, }, {89, 73, 78, 00, 00, 00, },
-            {89, 73, 78, 71, 00, 00, }, {89, 79, 00, 00, 00, 00, },
-            {89, 79, 78, 71, 00, 00, }, {89, 79, 85, 00, 00, 00, },
-            {89, 85, 00, 00, 00, 00, }, {89, 85, 65, 78, 00, 00, },
-            {89, 85, 69, 00, 00, 00, }, {89, 85, 78, 00, 00, 00, },
-            {90, 65, 00, 00, 00, 00, }, {90, 65, 73, 00, 00, 00, },
-            {90, 65, 78, 00, 00, 00, }, {90, 65, 78, 71, 00, 00, },
-            {90, 65, 79, 00, 00, 00, }, {90, 69, 00, 00, 00, 00, },
-            {90, 69, 73, 00, 00, 00, }, {90, 69, 78, 00, 00, 00, },
-            {90, 69, 78, 71, 00, 00, }, {90, 72, 65, 00, 00, 00, },
-            {90, 72, 65, 73, 00, 00, }, {90, 72, 65, 78, 00, 00, },
-            {90, 72, 65, 78, 71, 00, }, {90, 72, 65, 79, 00, 00, },
-            {90, 72, 69, 00, 00, 00, }, {90, 72, 69, 78, 00, 00, },
-            {90, 72, 69, 78, 71, 00, }, {90, 72, 73, 00, 00, 00, },
-            {90, 72, 79, 78, 71, 00, }, {90, 72, 79, 85, 00, 00, },
-            {90, 72, 85, 00, 00, 00, }, {90, 72, 85, 65, 00, 00, },
-            {90, 72, 85, 65, 73, 00, }, {90, 72, 85, 65, 78, 00, },
-            {90, 72, 85, 65, 78, 71, }, {90, 72, 85, 73, 00, 00, },
-            {90, 72, 85, 78, 00, 00, }, {90, 72, 85, 79, 00, 00, },
-            {90, 73, 00, 00, 00, 00, }, {90, 79, 78, 71, 00, 00, },
-            {90, 79, 85, 00, 00, 00, }, {90, 85, 00, 00, 00, 00, },
-            {90, 85, 65, 78, 00, 00, }, {90, 85, 73, 00, 00, 00, },
-            {90, 85, 78, 00, 00, 00, }, {90, 85, 79, 00, 00, 00, },
-
-        };
-
-    /** First and last Chinese character with known Pinyin according to zh collation */
-    private static final String FIRST_PINYIN_UNIHAN =  "\u5416";
-    private static final String LAST_PINYIN_UNIHAN =  "\u5497";
-    /** The first Chinese character in Unicode block */
-    private static final char FIRST_UNIHAN = '\u3400';
-    private static final Collator COLLATOR = Collator.getInstance(Locale.CHINA);
-
-    private static HanziToPinyin sInstance;
-    private final boolean mHasChinaCollator;
-
-    public static class Token {
-        /**
-         * Separator between target string for each source char
-         */
-        public static final String SEPARATOR = " ";
-
-        public static final int LATIN = 1;
-        public static final int PINYIN = 2;
-        public static final int UNKNOWN = 3;
-
-        public Token() {
-        }
-
-        public Token(int type, String source, String target) {
-            this.type = type;
-            this.source = source;
-            this.target = target;
-        }
-        /**
-         * Type of this token, ASCII, PINYIN or UNKNOWN.
-         */
-        public int type;
-        /**
-         * Original string before translation.
-         */
-        public String source;
-        /**
-         * Translated string of source. For Han, target is corresponding Pinyin.
-         * Otherwise target is original string in source.
-         */
-        public String target;
-    }
-
-    protected HanziToPinyin(boolean hasChinaCollator) {
-        mHasChinaCollator = hasChinaCollator;
-    }
-
-    public static HanziToPinyin getInstance() {
-        synchronized(HanziToPinyin.class) {
-            if (sInstance != null) {
-                return sInstance;
-            }
-            // Check if zh_CN collation data is available
-            final Locale locale[] = Collator.getAvailableLocales();
-            for (int i = 0; i < locale.length; i++) {
-                if (locale[i].equals(Locale.CHINA)) {
-                    sInstance = new HanziToPinyin(true);
-                    return sInstance;
-                }
-            }
-            Log.w(TAG, "There is no Chinese collator, HanziToPinyin is disabled");
-            sInstance = new HanziToPinyin(false);
-            return sInstance;
-        }
-    }
-
-    private Token getToken(char character) {
-        Token token = new Token();
-        final String letter = Character.toString(character);
-        token.source = letter;
-        int offset = -1;
-        int cmp;
-        if (character < 256) {
-            token.type = Token.LATIN;
-            token.target = letter;
-            return token;
-        } else if (character < FIRST_UNIHAN) {
-            token.type = Token.UNKNOWN;
-            token.target = letter;
-            return token;
-        } else {
-            cmp = COLLATOR.compare(letter, FIRST_PINYIN_UNIHAN);
-            if (cmp < 0) {
-                token.type = Token.UNKNOWN;
-                token.target = letter;
-                return token;
-            } else if (cmp == 0) {
-                token.type = Token.PINYIN;
-                offset = 0;
-            } else {
-                cmp = COLLATOR.compare(letter, LAST_PINYIN_UNIHAN);
-                if (cmp > 0) {
-                    token.type = Token.UNKNOWN;
-                    token.target = letter;
-                    return token;
-                } else if (cmp == 0) {
-                    token.type = Token.PINYIN;
-                    offset = UNIHANS.length - 1;
-                }
-            }
-        }
-
-        token.type = Token.PINYIN;
-        if (offset < 0) {
-            int begin = 0;
-            int end = UNIHANS.length - 1;
-            while (begin <= end) {
-                offset = (begin + end) / 2;
-                final String unihan = Character.toString(UNIHANS[offset]);
-                cmp = COLLATOR.compare(letter, unihan);
-                if (cmp == 0) {
-                    break;
-                } else if (cmp > 0) {
-                    begin = offset + 1;
-                } else {
-                    end = offset - 1;
-                }
-            }
-        }
-        if (cmp < 0) {
-            offset--;
-        }
-        StringBuilder pinyin = new StringBuilder();
-        for (int j = 0; j < PINYINS[offset].length && PINYINS[offset][j] != 0; j++) {
-            pinyin.append((char)PINYINS[offset][j]);
-        }
-        token.target = pinyin.toString();
-        return token;
-    }
-
-    /**
-     * Convert the input to a array of tokens. The sequence of ASCII or Unknown
-     * characters without space will be put into a Token, One Hanzi character 
-     * which has pinyin will be treated as a Token.
-     * If these is no China collator, the empty token array is returned.
-     */
-    public ArrayList<Token> get(final String input) {
-        ArrayList<Token> tokens = new ArrayList<Token>();
-        if (!mHasChinaCollator || TextUtils.isEmpty(input)) {
-            // return empty tokens.
-            return tokens;
-        }
-        final int inputLength = input.length();
-        final StringBuilder sb = new StringBuilder();
-        int tokenType = Token.LATIN;
-        // Go through the input, create a new token when
-        // a. Token type changed
-        // b. Get the Pinyin of current charater.
-        // c. current character is space.
-        for (int i = 0; i < inputLength; i++) {
-            final char character = input.charAt(i);
-            if (character == ' ') {
-                if (sb.length() > 0) {
-                    addToken(sb, tokens, tokenType);
-                }
-            } else if (character < 256) {
-                if (tokenType != Token.LATIN && sb.length() > 0) {
-                    addToken(sb, tokens, tokenType);
-                }
-                tokenType = Token.LATIN;
-                sb.append(character);
-            } else if (character < FIRST_UNIHAN) {
-                if (tokenType != Token.UNKNOWN && sb.length() > 0) {
-                    addToken(sb, tokens, tokenType);
-                }
-                tokenType = Token.UNKNOWN;
-                sb.append(character);
-            } else {
-                Token t = getToken(character);
-                if (t.type == Token.PINYIN) {
-                    if (sb.length() > 0) {
-                        addToken(sb, tokens, tokenType);
-                    }
-                    tokens.add(t);
-                    tokenType = Token.PINYIN;
-                } else {
-                    if (tokenType != t.type && sb.length() > 0) {
-                        addToken(sb, tokens, tokenType);
-                    }
-                    tokenType = t.type;
-                    sb.append(character);
-                }
-            }
-        }
-        if (sb.length() > 0) {
-            addToken(sb, tokens, tokenType);
-        }
-        return tokens;
-    }
-
-    private void addToken(final StringBuilder sb, final ArrayList<Token> tokens,
-            final int tokenType) {
-        String str = sb.toString();
-        tokens.add(new Token(tokenType, str, str));
-        sb.setLength(0);
-    }
-
-}
diff --git a/core/java/com/android/internal/view/menu/ListMenuPresenter.java b/core/java/com/android/internal/view/menu/ListMenuPresenter.java
index f8d24a3..cc09927 100644
--- a/core/java/com/android/internal/view/menu/ListMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ListMenuPresenter.java
@@ -177,7 +177,9 @@
 
     public void restoreHierarchyState(Bundle inState) {
         SparseArray<Parcelable> viewStates = inState.getSparseParcelableArray(VIEWS_TAG);
-        ((View) mMenuView).restoreHierarchyState(viewStates);
+        if (viewStates != null) {
+            ((View) mMenuView).restoreHierarchyState(viewStates);
+        }
     }
 
     private class MenuAdapter extends BaseAdapter {
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index 5767519..8db7e3c 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -17,6 +17,7 @@
 package com.android.internal.view.menu;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.util.DisplayMetrics;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
@@ -71,8 +72,9 @@
         mMenu = menu;
         mOverflowOnly = overflowOnly;
 
-        final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
-        mPopupMaxWidth = metrics.widthPixels / 2;
+        final Resources res = context.getResources();
+        mPopupMaxWidth = Math.max(res.getDisplayMetrics().widthPixels / 2,
+                res.getDimensionPixelSize(com.android.internal.R.dimen.config_prefDialogWidth));
 
         mAnchorView = anchorView;
 
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 9d8d361..290f90d 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -96,6 +96,8 @@
     private LinearLayout mTitleLayout;
     private TextView mTitleView;
     private TextView mSubtitleView;
+    private View mTitleUpView;
+
     private Spinner mSpinner;
     private LinearLayout mListNavLayout;
     private ScrollingTabContainerView mTabScrollView;
@@ -152,6 +154,16 @@
         }
     };
 
+    private final OnClickListener mUpClickListener = new OnClickListener() {
+        public void onClick(View v) {
+            Context context = getContext();
+            if (context instanceof Activity) {
+                Activity activity = (Activity) context;
+                activity.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, mLogoNavItem);
+            }
+        }
+    };
+
     public ActionBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
 
@@ -230,15 +242,7 @@
         a.recycle();
         
         mLogoNavItem = new ActionMenuItem(context, 0, android.R.id.home, 0, 0, mTitle);
-        mHomeLayout.setOnClickListener(new OnClickListener() {
-            public void onClick(View v) {
-                Context context = getContext();
-                if (context instanceof Activity) {
-                    Activity activity = (Activity) context;
-                    activity.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, mLogoNavItem);
-                }
-            }
-        });
+        mHomeLayout.setOnClickListener(mUpClickListener);
         mHomeLayout.setClickable(true);
         mHomeLayout.setFocusable(true);
     }
@@ -438,7 +442,8 @@
         }
 
         if ((flagsChanged & DISPLAY_RELAYOUT_MASK) != 0) {
-            final int vis = (options & ActionBar.DISPLAY_SHOW_HOME) != 0 ? VISIBLE : GONE;
+            final boolean showHome = (options & ActionBar.DISPLAY_SHOW_HOME) != 0;
+            final int vis = showHome ? VISIBLE : GONE;
             mHomeLayout.setVisibility(vis);
 
             if ((flagsChanged & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
@@ -458,6 +463,14 @@
                 }
             }
 
+            if ((flagsChanged &
+                    (ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME)) != 0) {
+                final boolean homeAsUp = (options & ActionBar.DISPLAY_HOME_AS_UP) != 0;
+                final boolean titleUp = homeAsUp && !showHome;
+                mTitleUpView.setVisibility(titleUp ? VISIBLE : GONE);
+                mTitleLayout.setEnabled(titleUp);
+            }
+
             if ((flagsChanged & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 && mCustomNavView != null) {
                 if ((options & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
                     addView(mCustomNavView);
@@ -641,6 +654,9 @@
         mTitleLayout = (LinearLayout) inflater.inflate(R.layout.action_bar_title_item, null);
         mTitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_title);
         mSubtitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_subtitle);
+        mTitleUpView = (View) mTitleLayout.findViewById(R.id.up);
+
+        mTitleLayout.setOnClickListener(mUpClickListener);
 
         if (mTitleStyleRes != 0) {
             mTitleView.setTextAppearance(mContext, mTitleStyleRes);
diff --git a/core/java/com/android/internal/widget/DialogTitle.java b/core/java/com/android/internal/widget/DialogTitle.java
index 125d2c5..cd165dc 100644
--- a/core/java/com/android/internal/widget/DialogTitle.java
+++ b/core/java/com/android/internal/widget/DialogTitle.java
@@ -54,15 +54,19 @@
                 if (ellipsisCount > 0) {
                     setSingleLine(false);
                     
-                    TypedArray a = mContext.obtainStyledAttributes(
-                            android.R.style.TextAppearance_Medium,
-                            android.R.styleable.TextAppearance);
+                    TypedArray a = mContext.obtainStyledAttributes(null,
+                            android.R.styleable.TextAppearance,
+                            android.R.attr.textAppearanceMedium,
+                            android.R.style.TextAppearance_Medium);
                     final int textSize = a.getDimensionPixelSize(
                             android.R.styleable.TextAppearance_textSize,
                             (int) (20 * getResources().getDisplayMetrics().density));
+                    final int textColor = a.getColor(
+                            android.R.styleable.TextAppearance_textColor, 0xffffffff);
 
                     // textSize is already expressed in pixels
                     setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
+                    setTextColor(textColor);
                     setMaxLines(2);
                     super.onMeasure(widthMeasureSpec, heightMeasureSpec);      
                 }
diff --git a/core/java/com/android/internal/widget/DigitalClock.java b/core/java/com/android/internal/widget/DigitalClock.java
index 0885b6e..ac0dc35 100644
--- a/core/java/com/android/internal/widget/DigitalClock.java
+++ b/core/java/com/android/internal/widget/DigitalClock.java
@@ -96,13 +96,13 @@
     };
 
     static class AmPm {
-        private TextView mAmPm;
+        private TextView mAmPmTextView;
         private String mAmString, mPmString;
 
         AmPm(View parent, Typeface tf) {
-            mAmPm = (TextView) parent.findViewById(R.id.am_pm);
-            if (tf != null) {
-                mAmPm.setTypeface(tf);
+            mAmPmTextView = (TextView) parent.findViewById(R.id.am_pm);
+            if (mAmPmTextView != null && tf != null) {
+                mAmPmTextView.setTypeface(tf);
             }
 
             String[] ampm = new DateFormatSymbols().getAmPmStrings();
@@ -111,11 +111,15 @@
         }
 
         void setShowAmPm(boolean show) {
-            mAmPm.setVisibility(show ? View.VISIBLE : View.GONE);
+            if (mAmPmTextView != null) {
+                mAmPmTextView.setVisibility(show ? View.VISIBLE : View.GONE);
+            }
         }
 
         void setIsMorning(boolean isMorning) {
-            mAmPm.setText(isMorning ? mAmString : mPmString);
+            if (mAmPmTextView != null) {
+                mAmPmTextView.setText(isMorning ? mAmString : mPmString);
+            }
         }
     }
 
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index bee8112..cbb110a 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -131,6 +131,7 @@
 
     private int mAspect;
     private final Matrix mArrowMatrix = new Matrix();
+    private final Matrix mCircleMatrix = new Matrix();
 
     /**
      * Represents a cell in the 3 X 3 matrix of the unlock pattern view.
@@ -281,9 +282,14 @@
         mBitmapArrowGreenUp = getBitmapFor(R.drawable.indicator_code_lock_drag_direction_green_up);
         mBitmapArrowRedUp = getBitmapFor(R.drawable.indicator_code_lock_drag_direction_red_up);
 
-        // we assume all bitmaps have the same size
-        mBitmapWidth = mBitmapBtnDefault.getWidth();
-        mBitmapHeight = mBitmapBtnDefault.getHeight();
+        // bitmaps have the size of the largest bitmap in this group
+        final Bitmap bitmaps[] = { mBitmapBtnDefault, mBitmapBtnTouched, mBitmapCircleDefault,
+                mBitmapCircleGreen, mBitmapCircleRed };
+
+        for (Bitmap bitmap : bitmaps) {
+            mBitmapWidth = Math.max(mBitmapWidth, bitmap.getWidth());
+            mBitmapHeight = Math.max(mBitmapHeight, bitmap.getHeight());
+        }
 
         // allow vibration pattern to be customized
         mVibePattern = loadVibratePattern(com.android.internal.R.array.config_virtualKeyVibePattern);
@@ -458,31 +464,40 @@
                 break;
             case MeasureSpec.EXACTLY:
             default:
-                result = specSize;
+                // use the specified size, if non-zero
+                result = specSize != 0 ? specSize : desired;
         }
         return result;
     }
 
     @Override
+    protected int getSuggestedMinimumWidth() {
+        // View should be large enough to contain 3 side-by-side target bitmaps
+        return 3 * mBitmapWidth;
+    }
+
+    @Override
+    protected int getSuggestedMinimumHeight() {
+        // View should be large enough to contain 3 side-by-side target bitmaps
+        return 3 * mBitmapWidth;
+    }
+
+    @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        final int minimumWidth = 3 * mBitmapCircleDefault.getWidth();
-        final int minimumHeight = 3 * mBitmapCircleDefault.getHeight();
+        final int minimumWidth = getSuggestedMinimumWidth();
+        final int minimumHeight = getSuggestedMinimumHeight();
         int viewWidth = resolveMeasured(widthMeasureSpec, minimumWidth);
         int viewHeight = resolveMeasured(heightMeasureSpec, minimumHeight);
 
-        int requestedWidth = MeasureSpec.getSize(widthMeasureSpec);
-        int requestedHeight = MeasureSpec.getSize(heightMeasureSpec);
         switch (mAspect) {
             case ASPECT_SQUARE:
-                viewWidth = viewHeight = Math.min(requestedWidth, requestedHeight);
+                viewWidth = viewHeight = Math.min(viewWidth, viewHeight);
                 break;
             case ASPECT_LOCK_WIDTH:
-                viewWidth = requestedWidth;
-                viewHeight = Math.min(requestedWidth, requestedHeight);
+                viewHeight = Math.min(viewWidth, viewHeight);
                 break;
             case ASPECT_LOCK_HEIGHT:
-                viewWidth = Math.min(requestedWidth, requestedHeight);
-                viewHeight = requestedHeight;
+                viewWidth = Math.min(viewWidth, viewHeight);
                 break;
         }
         // Log.v(TAG, "LockPatternView dimensions: " + viewWidth + "x" + viewHeight);
@@ -603,178 +618,20 @@
     }
 
     @Override
-    public boolean onTouchEvent(MotionEvent motionEvent) {
+    public boolean onTouchEvent(MotionEvent event) {
         if (!mInputEnabled || !isEnabled()) {
             return false;
         }
 
-        final float x = motionEvent.getX();
-        final float y = motionEvent.getY();
-        Cell hitCell;
-        switch(motionEvent.getAction()) {
+        switch(event.getAction()) {
             case MotionEvent.ACTION_DOWN:
-                resetPattern();
-                hitCell = detectAndAddHit(x, y);
-                if (hitCell != null && mOnPatternListener != null) {
-                    mPatternInProgress = true;
-                    mPatternDisplayMode = DisplayMode.Correct;
-                    mOnPatternListener.onPatternStart();
-                } else if (mOnPatternListener != null) {
-                    mPatternInProgress = false;
-                    mOnPatternListener.onPatternCleared();
-                }
-                if (hitCell != null) {
-                    final float startX = getCenterXForColumn(hitCell.column);
-                    final float startY = getCenterYForRow(hitCell.row);
-
-                    final float widthOffset = mSquareWidth / 2f;
-                    final float heightOffset = mSquareHeight / 2f;
-
-                    invalidate((int) (startX - widthOffset), (int) (startY - heightOffset),
-                            (int) (startX + widthOffset), (int) (startY + heightOffset));
-                }
-                mInProgressX = x;
-                mInProgressY = y;
-                if (PROFILE_DRAWING) {
-                    if (!mDrawingProfilingStarted) {
-                        Debug.startMethodTracing("LockPatternDrawing");
-                        mDrawingProfilingStarted = true;
-                    }
-                }
+                handleActionDown(event);
                 return true;
             case MotionEvent.ACTION_UP:
-                // report pattern detected
-                if (!mPattern.isEmpty() && mOnPatternListener != null) {
-                    mPatternInProgress = false;
-                    mOnPatternListener.onPatternDetected(mPattern);
-                    invalidate();
-                }
-                if (PROFILE_DRAWING) {
-                    if (mDrawingProfilingStarted) {
-                        Debug.stopMethodTracing();
-                        mDrawingProfilingStarted = false;
-                    }
-                }
+                handleActionUp(event);
                 return true;
             case MotionEvent.ACTION_MOVE:
-                final int patternSizePreHitDetect = mPattern.size();
-                hitCell = detectAndAddHit(x, y);
-                final int patternSize = mPattern.size();
-                if (hitCell != null && (mOnPatternListener != null) && (patternSize == 1)) {
-                    mPatternInProgress = true;
-                    mOnPatternListener.onPatternStart();
-                }
-                // note current x and y for rubber banding of in progress
-                // patterns
-                final float dx = Math.abs(x - mInProgressX);
-                final float dy = Math.abs(y - mInProgressY);
-                if (dx + dy > mSquareWidth * 0.01f) {
-                    float oldX = mInProgressX;
-                    float oldY = mInProgressY;
-
-                    mInProgressX = x;
-                    mInProgressY = y;
-
-                    if (mPatternInProgress && patternSize > 0) {
-                        final ArrayList<Cell> pattern = mPattern;
-                        final float radius = mSquareWidth * mDiameterFactor * 0.5f;
-
-                        final Cell lastCell = pattern.get(patternSize - 1);
-
-                        float startX = getCenterXForColumn(lastCell.column);
-                        float startY = getCenterYForRow(lastCell.row);
-
-                        float left;
-                        float top;
-                        float right;
-                        float bottom;
-
-                        final Rect invalidateRect = mInvalidate;
-
-                        if (startX < x) {
-                            left = startX;
-                            right = x;
-                        } else {
-                            left = x;
-                            right = startX;
-                        }
-
-                        if (startY < y) {
-                            top = startY;
-                            bottom = y;
-                        } else {
-                            top = y;
-                            bottom = startY;
-                        }
-
-                        // Invalidate between the pattern's last cell and the current location
-                        invalidateRect.set((int) (left - radius), (int) (top - radius),
-                                (int) (right + radius), (int) (bottom + radius));
-
-                        if (startX < oldX) {
-                            left = startX;
-                            right = oldX;
-                        } else {
-                            left = oldX;
-                            right = startX;
-                        }
-
-                        if (startY < oldY) {
-                            top = startY;
-                            bottom = oldY;
-                        } else {
-                            top = oldY;
-                            bottom = startY;
-                        }
-
-                        // Invalidate between the pattern's last cell and the previous location
-                        invalidateRect.union((int) (left - radius), (int) (top - radius),
-                                (int) (right + radius), (int) (bottom + radius));
-
-                        // Invalidate between the pattern's new cell and the pattern's previous cell
-                        if (hitCell != null) {
-                            startX = getCenterXForColumn(hitCell.column);
-                            startY = getCenterYForRow(hitCell.row);
-
-                            if (patternSize >= 2) {
-                                // (re-using hitcell for old cell)
-                                hitCell = pattern.get(patternSize - 1 - (patternSize - patternSizePreHitDetect));
-                                oldX = getCenterXForColumn(hitCell.column);
-                                oldY = getCenterYForRow(hitCell.row);
-
-                                if (startX < oldX) {
-                                    left = startX;
-                                    right = oldX;
-                                } else {
-                                    left = oldX;
-                                    right = startX;
-                                }
-
-                                if (startY < oldY) {
-                                    top = startY;
-                                    bottom = oldY;
-                                } else {
-                                    top = oldY;
-                                    bottom = startY;
-                                }
-                            } else {
-                                left = right = startX;
-                                top = bottom = startY;
-                            }
-
-                            final float widthOffset = mSquareWidth / 2f;
-                            final float heightOffset = mSquareHeight / 2f;
-
-                            invalidateRect.set((int) (left - widthOffset),
-                                    (int) (top - heightOffset), (int) (right + widthOffset),
-                                    (int) (bottom + heightOffset));
-                        }
-
-                        invalidate(invalidateRect);
-                    } else {
-                        invalidate();
-                    }
-                }
+                handleActionMove(event);
                 return true;
             case MotionEvent.ACTION_CANCEL:
                 resetPattern();
@@ -793,6 +650,181 @@
         return false;
     }
 
+    private void handleActionMove(MotionEvent event) {
+        // Handle all recent motion events so we don't skip any cells even when the device
+        // is busy...
+        final int historySize = event.getHistorySize();
+        for (int i = 0; i < historySize + 1; i++) {
+            final float x = i < historySize ? event.getHistoricalX(i) : event.getX();
+            final float y = i < historySize ? event.getHistoricalY(i) : event.getY();
+            final int patternSizePreHitDetect = mPattern.size();
+            Cell hitCell = detectAndAddHit(x, y);
+            final int patternSize = mPattern.size();
+            if (hitCell != null && (mOnPatternListener != null) && (patternSize == 1)) {
+                mPatternInProgress = true;
+                mOnPatternListener.onPatternStart();
+            }
+            // note current x and y for rubber banding of in progress patterns
+            final float dx = Math.abs(x - mInProgressX);
+            final float dy = Math.abs(y - mInProgressY);
+            if (dx + dy > mSquareWidth * 0.01f) {
+                float oldX = mInProgressX;
+                float oldY = mInProgressY;
+
+                mInProgressX = x;
+                mInProgressY = y;
+
+                if (mPatternInProgress && patternSize > 0) {
+                    final ArrayList<Cell> pattern = mPattern;
+                    final float radius = mSquareWidth * mDiameterFactor * 0.5f;
+
+                    final Cell lastCell = pattern.get(patternSize - 1);
+
+                    float startX = getCenterXForColumn(lastCell.column);
+                    float startY = getCenterYForRow(lastCell.row);
+
+                    float left;
+                    float top;
+                    float right;
+                    float bottom;
+
+                    final Rect invalidateRect = mInvalidate;
+
+                    if (startX < x) {
+                        left = startX;
+                        right = x;
+                    } else {
+                        left = x;
+                        right = startX;
+                    }
+
+                    if (startY < y) {
+                        top = startY;
+                        bottom = y;
+                    } else {
+                        top = y;
+                        bottom = startY;
+                    }
+
+                    // Invalidate between the pattern's last cell and the current location
+                    invalidateRect.set((int) (left - radius), (int) (top - radius),
+                            (int) (right + radius), (int) (bottom + radius));
+
+                    if (startX < oldX) {
+                        left = startX;
+                        right = oldX;
+                    } else {
+                        left = oldX;
+                        right = startX;
+                    }
+
+                    if (startY < oldY) {
+                        top = startY;
+                        bottom = oldY;
+                    } else {
+                        top = oldY;
+                        bottom = startY;
+                    }
+
+                    // Invalidate between the pattern's last cell and the previous location
+                    invalidateRect.union((int) (left - radius), (int) (top - radius),
+                            (int) (right + radius), (int) (bottom + radius));
+
+                    // Invalidate between the pattern's new cell and the pattern's previous cell
+                    if (hitCell != null) {
+                        startX = getCenterXForColumn(hitCell.column);
+                        startY = getCenterYForRow(hitCell.row);
+
+                        if (patternSize >= 2) {
+                            // (re-using hitcell for old cell)
+                            hitCell = pattern.get(patternSize - 1 - (patternSize - patternSizePreHitDetect));
+                            oldX = getCenterXForColumn(hitCell.column);
+                            oldY = getCenterYForRow(hitCell.row);
+
+                            if (startX < oldX) {
+                                left = startX;
+                                right = oldX;
+                            } else {
+                                left = oldX;
+                                right = startX;
+                            }
+
+                            if (startY < oldY) {
+                                top = startY;
+                                bottom = oldY;
+                            } else {
+                                top = oldY;
+                                bottom = startY;
+                            }
+                        } else {
+                            left = right = startX;
+                            top = bottom = startY;
+                        }
+
+                        final float widthOffset = mSquareWidth / 2f;
+                        final float heightOffset = mSquareHeight / 2f;
+
+                        invalidateRect.set((int) (left - widthOffset),
+                                (int) (top - heightOffset), (int) (right + widthOffset),
+                                (int) (bottom + heightOffset));
+                    }
+
+                    invalidate(invalidateRect);
+                } else {
+                    invalidate();
+                }
+            }
+        }
+    }
+
+    private void handleActionUp(MotionEvent event) {
+        // report pattern detected
+        if (!mPattern.isEmpty() && mOnPatternListener != null) {
+            mPatternInProgress = false;
+            mOnPatternListener.onPatternDetected(mPattern);
+            invalidate();
+        }
+        if (PROFILE_DRAWING) {
+            if (mDrawingProfilingStarted) {
+                Debug.stopMethodTracing();
+                mDrawingProfilingStarted = false;
+            }
+        }
+    }
+
+    private void handleActionDown(MotionEvent event) {
+        resetPattern();
+        final float x = event.getX();
+        final float y = event.getY();
+        final Cell hitCell = detectAndAddHit(x, y);
+        if (hitCell != null && mOnPatternListener != null) {
+            mPatternInProgress = true;
+            mPatternDisplayMode = DisplayMode.Correct;
+            mOnPatternListener.onPatternStart();
+        } else if (mOnPatternListener != null) {
+            mPatternInProgress = false;
+            mOnPatternListener.onPatternCleared();
+        }
+        if (hitCell != null) {
+            final float startX = getCenterXForColumn(hitCell.column);
+            final float startY = getCenterYForRow(hitCell.row);
+
+            final float widthOffset = mSquareWidth / 2f;
+            final float heightOffset = mSquareHeight / 2f;
+
+            invalidate((int) (startX - widthOffset), (int) (startY - heightOffset),
+                    (int) (startX + widthOffset), (int) (startY + heightOffset));
+        }
+        mInProgressX = x;
+        mInProgressY = y;
+        if (PROFILE_DRAWING) {
+            if (!mDrawingProfilingStarted) {
+                Debug.startMethodTracing("LockPatternDrawing");
+                mDrawingProfilingStarted = true;
+            }
+        }
+    }
+
     private float getCenterXForColumn(int column) {
         return mPaddingLeft + column * mSquareWidth + mSquareWidth / 2f;
     }
@@ -947,8 +979,8 @@
         // This assumes that the arrow image is drawn at 12:00 with it's top edge
         // coincident with the circle bitmap's top edge.
         Bitmap arrow = green ? mBitmapArrowGreenUp : mBitmapArrowRedUp;
-        final int cellWidth = mBitmapCircleDefault.getWidth();
-        final int cellHeight = mBitmapCircleDefault.getHeight();
+        final int cellWidth = mBitmapWidth;
+        final int cellHeight = mBitmapHeight;
 
         // the up arrow bitmap is at 12:00, so find the rotation from x axis and add 90 degrees.
         final float theta = (float) Math.atan2(
@@ -956,7 +988,12 @@
         final float angle = (float) Math.toDegrees(theta) + 90.0f;
 
         // compose matrix
+        float sx = Math.min(mSquareWidth / mBitmapWidth, 1.0f);
+        float sy = Math.min(mSquareHeight / mBitmapHeight, 1.0f);
         mArrowMatrix.setTranslate(leftX + offsetX, topY + offsetY); // transform to cell position
+        mArrowMatrix.preTranslate(mBitmapWidth/2, mBitmapHeight/2);
+        mArrowMatrix.preScale(sx, sy);
+        mArrowMatrix.preTranslate(-mBitmapWidth/2, -mBitmapHeight/2);
         mArrowMatrix.preRotate(angle, cellWidth / 2.0f, cellHeight / 2.0f);  // rotate about cell center
         mArrowMatrix.preTranslate((cellWidth - arrow.getWidth()) / 2.0f, 0.0f); // translate to 12:00 pos
         canvas.drawBitmap(arrow, mArrowMatrix, mPaint);
@@ -1002,8 +1039,17 @@
         int offsetX = (int) ((squareWidth - width) / 2f);
         int offsetY = (int) ((squareHeight - height) / 2f);
 
-        canvas.drawBitmap(outerCircle, leftX + offsetX, topY + offsetY, mPaint);
-        canvas.drawBitmap(innerCircle, leftX + offsetX, topY + offsetY, mPaint);
+        // Allow circles to shrink if the view is too small to hold them.
+        float sx = Math.min(mSquareWidth / mBitmapWidth, 1.0f);
+        float sy = Math.min(mSquareHeight / mBitmapHeight, 1.0f);
+
+        mCircleMatrix.setTranslate(leftX + offsetX, topY + offsetY);
+        mCircleMatrix.preTranslate(mBitmapWidth/2, mBitmapHeight/2);
+        mCircleMatrix.preScale(sx, sy);
+        mCircleMatrix.preTranslate(-mBitmapWidth/2, -mBitmapHeight/2);
+
+        canvas.drawBitmap(outerCircle, mCircleMatrix, mPaint);
+        canvas.drawBitmap(innerCircle, mCircleMatrix, mPaint);
     }
 
     @Override
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 7e82efb..e301e44 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -22,6 +22,7 @@
 #include "GraphicsJNI.h"
 #include <nativehelper/JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/android_graphics_SurfaceTexture.h>
 #include <utils/ResourceTypes.h>
 
 #include <gui/SurfaceTexture.h>
@@ -644,11 +645,13 @@
 }
 
 static void android_view_GLES20Canvas_updateTextureLayer(JNIEnv* env, jobject clazz,
-        Layer* layer, jint width, jint height, SurfaceTexture* surface) {
+        Layer* layer, jint width, jint height, jobject surface) {
     float transform[16];
-    surface->updateTexImage();
-    surface->getTransformMatrix(transform);
-    GLenum renderTarget = surface->getCurrentTextureTarget();
+    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, surface));
+
+    surfaceTexture->updateTexImage();
+    surfaceTexture->getTransformMatrix(transform);
+    GLenum renderTarget = surfaceTexture->getCurrentTextureTarget();
 
     LayerRenderer::updateTextureLayer(layer, width, height, renderTarget, transform);
 }
@@ -793,7 +796,8 @@
     { "nCreateLayer",            "(IIZ[I)I",   (void*) android_view_GLES20Canvas_createLayer },
     { "nResizeLayer",            "(III[I)V" ,  (void*) android_view_GLES20Canvas_resizeLayer },
     { "nCreateTextureLayer",     "([I)I",      (void*) android_view_GLES20Canvas_createTextureLayer },
-    { "nUpdateTextureLayer",     "(IIII)V",    (void*) android_view_GLES20Canvas_updateTextureLayer },
+    { "nUpdateTextureLayer",     "(IIILandroid/graphics/SurfaceTexture;)V",
+                                               (void*) android_view_GLES20Canvas_updateTextureLayer },
     { "nDestroyLayer",           "(I)V",       (void*) android_view_GLES20Canvas_destroyLayer },
     { "nDestroyLayerDeferred",   "(I)V",       (void*) android_view_GLES20Canvas_destroyLayerDeferred },
     { "nDrawLayer",              "(IIFFI)V",   (void*) android_view_GLES20Canvas_drawLayer },
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
index c5d86c8..b046b23 100644
--- a/core/jni/android_view_TextureView.cpp
+++ b/core/jni/android_view_TextureView.cpp
@@ -17,6 +17,7 @@
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/android_graphics_SurfaceTexture.h>
 
 #include <gui/SurfaceTexture.h>
 
@@ -27,10 +28,10 @@
 // ----------------------------------------------------------------------------
 
 static void android_view_TextureView_setDefaultBufferSize(JNIEnv* env, jobject,
-    jint surfaceTexture, jint width, jint height) {
+    jobject surface, jint width, jint height) {
 
-    sp<SurfaceTexture> surface = reinterpret_cast<SurfaceTexture*>(surfaceTexture);
-    surface->setDefaultBufferSize(width, height);
+    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, surface));
+    surfaceTexture->setDefaultBufferSize(width, height);
 }
 
 // ----------------------------------------------------------------------------
@@ -40,7 +41,8 @@
 const char* const kClassPathName = "android/view/TextureView";
 
 static JNINativeMethod gMethods[] = {
-    {   "nSetDefaultBufferSize", "(III)V", (void*) android_view_TextureView_setDefaultBufferSize }
+    {   "nSetDefaultBufferSize", "(Landroid/graphics/SurfaceTexture;II)V",
+            (void*) android_view_TextureView_setDefaultBufferSize }
 };
 
 int register_android_view_TextureView(JNIEnv* env) {
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index f777527..02974f9a 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -18,6 +18,7 @@
 #include "JNIHelp.h"
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/android_view_Surface.h>
+#include <android_runtime/android_graphics_SurfaceTexture.h>
 #include <utils/misc.h>
 
 #include <EGL/egl.h>
@@ -323,7 +324,7 @@
 }
 
 static jint jni_eglCreateWindowSurfaceTexture(JNIEnv *_env, jobject _this, jobject display,
-        jobject config, jint native_window, jintArray attrib_list) {
+        jobject config, jobject native_window, jintArray attrib_list) {
     if (display == NULL || config == NULL
         || !validAttribList(_env, attrib_list)) {
         jniThrowException(_env, "java/lang/IllegalArgumentException", NULL);
@@ -339,7 +340,7 @@
         return 0;
     }
     
-    sp<SurfaceTexture> surfaceTexture = reinterpret_cast<SurfaceTexture*>(native_window);
+    sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(_env, native_window));
 
     window = new SurfaceTextureClient(surfaceTexture);
     if (window == NULL)
@@ -540,7 +541,7 @@
 {"_eglCreatePbufferSurface","(" DISPLAY CONFIG "[I)I", (void*)jni_eglCreatePbufferSurface },
 {"_eglCreatePixmapSurface", "(" SURFACE DISPLAY CONFIG OBJECT "[I)V", (void*)jni_eglCreatePixmapSurface },
 {"_eglCreateWindowSurface", "(" DISPLAY CONFIG OBJECT "[I)I", (void*)jni_eglCreateWindowSurface },
-{"_eglCreateWindowSurfaceTexture", "(" DISPLAY CONFIG "I[I)I", (void*)jni_eglCreateWindowSurfaceTexture },
+{"_eglCreateWindowSurfaceTexture", "(" DISPLAY CONFIG OBJECT "[I)I", (void*)jni_eglCreateWindowSurfaceTexture },
 {"eglDestroyContext",      "(" DISPLAY CONTEXT ")Z", (void*)jni_eglDestroyContext },
 {"eglDestroySurface",      "(" DISPLAY SURFACE ")Z", (void*)jni_eglDestroySurface },
 {"eglMakeCurrent",         "(" DISPLAY SURFACE SURFACE CONTEXT")Z", (void*)jni_eglMakeCurrent },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index a8aff37..47902a8 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -91,6 +91,8 @@
     <protected-broadcast android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
     <protected-broadcast android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
 
+    <protected-broadcast android:name="android.net.vpn.action.REVOKED" />
+
     <protected-broadcast android:name="android.nfc.action.LLCP_LINK_STATE_CHANGED" />
     <protected-broadcast android:name="com.android.nfc_extras.action.RF_FIELD_ON_DETECTED" />
     <protected-broadcast android:name="com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED" />
diff --git a/core/res/res/drawable-hdpi/btn_code_lock_default_holo.png b/core/res/res/drawable-hdpi/btn_code_lock_default_holo.png
new file mode 100644
index 0000000..94d27cf
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_code_lock_default_holo.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_code_lock_touched_holo.png b/core/res/res/drawable-hdpi/btn_code_lock_touched_holo.png
new file mode 100644
index 0000000..94d27cf
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_code_lock_touched_holo.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_bottom_holo_dark.9.png b/core/res/res/drawable-hdpi/dialog_bottom_holo_dark.9.png
index 32c2c97..5225a81 100644
--- a/core/res/res/drawable-hdpi/dialog_bottom_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/dialog_bottom_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_bottom_holo_light.9.png b/core/res/res/drawable-hdpi/dialog_bottom_holo_light.9.png
index f1cba06..2e7e973 100644
--- a/core/res/res/drawable-hdpi/dialog_bottom_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/dialog_bottom_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_full_holo_dark.9.png b/core/res/res/drawable-hdpi/dialog_full_holo_dark.9.png
index 08b163a..4591627 100644
--- a/core/res/res/drawable-hdpi/dialog_full_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/dialog_full_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_full_holo_light.9.png b/core/res/res/drawable-hdpi/dialog_full_holo_light.9.png
index 77ec017..9cf1826 100644
--- a/core/res/res/drawable-hdpi/dialog_full_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/dialog_full_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_middle_holo_dark.9.png b/core/res/res/drawable-hdpi/dialog_middle_holo_dark.9.png
index 029f186..a47ef40 100644
--- a/core/res/res/drawable-hdpi/dialog_middle_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/dialog_middle_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_middle_holo_light.9.png b/core/res/res/drawable-hdpi/dialog_middle_holo_light.9.png
index ee1054ef..9b50c73 100644
--- a/core/res/res/drawable-hdpi/dialog_middle_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/dialog_middle_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_top_holo_dark.9.png b/core/res/res/drawable-hdpi/dialog_top_holo_dark.9.png
index acbd7cf..a0d36de 100644
--- a/core/res/res/drawable-hdpi/dialog_top_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/dialog_top_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_top_holo_light.9.png b/core/res/res/drawable-hdpi/dialog_top_holo_light.9.png
index b7ddbb4..805b9567 100644
--- a/core/res/res/drawable-hdpi/dialog_top_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/dialog_top_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lock_idle_alarm.png b/core/res/res/drawable-hdpi/ic_lock_idle_alarm.png
index 6b4f66d..3cadaff 100644
--- a/core/res/res/drawable-hdpi/ic_lock_idle_alarm.png
+++ b/core/res/res/drawable-hdpi/ic_lock_idle_alarm.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_emergencycall_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_emergencycall_normal.png
new file mode 100644
index 0000000..460495a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_emergencycall_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_emergencycall_pressed.png b/core/res/res/drawable-hdpi/ic_lockscreen_emergencycall_pressed.png
new file mode 100644
index 0000000..b0f7ae9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_emergencycall_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_forgotpassword_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_forgotpassword_normal.png
new file mode 100644
index 0000000..6402d3d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_forgotpassword_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_forgotpassword_pressed.png b/core/res/res/drawable-hdpi/ic_lockscreen_forgotpassword_pressed.png
new file mode 100644
index 0000000..83be046
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_forgotpassword_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_green_up_holo.png b/core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_green_up_holo.png
new file mode 100644
index 0000000..a686975
--- /dev/null
+++ b/core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_green_up_holo.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_red_up_holo.png b/core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_red_up_holo.png
new file mode 100644
index 0000000..92db8ef
--- /dev/null
+++ b/core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_red_up_holo.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/indicator_code_lock_point_area_default_holo.png b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_default_holo.png
new file mode 100644
index 0000000..237011c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_default_holo.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/indicator_code_lock_point_area_green_holo.png b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_green_holo.png
new file mode 100644
index 0000000..2418017
--- /dev/null
+++ b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_green_holo.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/indicator_code_lock_point_area_red_holo.png b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_red_holo.png
new file mode 100644
index 0000000..2120bad
--- /dev/null
+++ b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_red_holo.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_code_lock_default.png b/core/res/res/drawable-mdpi/btn_code_lock_default.png
old mode 100644
new mode 100755
index 45cc20d..f524317
--- a/core/res/res/drawable-mdpi/btn_code_lock_default.png
+++ b/core/res/res/drawable-mdpi/btn_code_lock_default.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_code_lock_default_holo.png b/core/res/res/drawable-mdpi/btn_code_lock_default_holo.png
new file mode 100644
index 0000000..7d11275
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_code_lock_default_holo.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_code_lock_touched.png b/core/res/res/drawable-mdpi/btn_code_lock_touched.png
old mode 100644
new mode 100755
index 45cc20d..5cd436c
--- a/core/res/res/drawable-mdpi/btn_code_lock_touched.png
+++ b/core/res/res/drawable-mdpi/btn_code_lock_touched.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_code_lock_touched_holo.png b/core/res/res/drawable-mdpi/btn_code_lock_touched_holo.png
new file mode 100644
index 0000000..7d11275
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_code_lock_touched_holo.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_bottom_holo_dark.9.png b/core/res/res/drawable-mdpi/dialog_bottom_holo_dark.9.png
index cc66804..a0bd4e3 100644
--- a/core/res/res/drawable-mdpi/dialog_bottom_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/dialog_bottom_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_bottom_holo_light.9.png b/core/res/res/drawable-mdpi/dialog_bottom_holo_light.9.png
index bc734c8..12abcd2 100644
--- a/core/res/res/drawable-mdpi/dialog_bottom_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/dialog_bottom_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_full_holo_dark.9.png b/core/res/res/drawable-mdpi/dialog_full_holo_dark.9.png
index 8603e93..adb8104 100644
--- a/core/res/res/drawable-mdpi/dialog_full_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/dialog_full_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_full_holo_light.9.png b/core/res/res/drawable-mdpi/dialog_full_holo_light.9.png
index 65a318c..d7c6bbf 100644
--- a/core/res/res/drawable-mdpi/dialog_full_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/dialog_full_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_middle_holo_dark.9.png b/core/res/res/drawable-mdpi/dialog_middle_holo_dark.9.png
index e39a472..42cfc52 100644
--- a/core/res/res/drawable-mdpi/dialog_middle_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/dialog_middle_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_middle_holo_light.9.png b/core/res/res/drawable-mdpi/dialog_middle_holo_light.9.png
index ec06c17d..9a08e15 100644
--- a/core/res/res/drawable-mdpi/dialog_middle_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/dialog_middle_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_top_holo_dark.9.png b/core/res/res/drawable-mdpi/dialog_top_holo_dark.9.png
index 32c49f2..5d86b2a 100644
--- a/core/res/res/drawable-mdpi/dialog_top_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/dialog_top_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_top_holo_light.9.png b/core/res/res/drawable-mdpi/dialog_top_holo_light.9.png
index 7a2bf8d..ad22f5b 100644
--- a/core/res/res/drawable-mdpi/dialog_top_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/dialog_top_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lock_idle_alarm.png b/core/res/res/drawable-mdpi/ic_lock_idle_alarm.png
index 97ac023..b5d3e09 100644
--- a/core/res/res/drawable-mdpi/ic_lock_idle_alarm.png
+++ b/core/res/res/drawable-mdpi/ic_lock_idle_alarm.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lock_idle_charging.png b/core/res/res/drawable-mdpi/ic_lock_idle_charging.png
old mode 100644
new mode 100755
index 4210db2..20d6320
--- a/core/res/res/drawable-mdpi/ic_lock_idle_charging.png
+++ b/core/res/res/drawable-mdpi/ic_lock_idle_charging.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lock_idle_lock.png b/core/res/res/drawable-mdpi/ic_lock_idle_lock.png
old mode 100644
new mode 100755
index 1060f5a..0206aee
--- a/core/res/res/drawable-mdpi/ic_lock_idle_lock.png
+++ b/core/res/res/drawable-mdpi/ic_lock_idle_lock.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lock_idle_low_battery.png b/core/res/res/drawable-mdpi/ic_lock_idle_low_battery.png
old mode 100644
new mode 100755
index 72e4afa..bb96782
--- a/core/res/res/drawable-mdpi/ic_lock_idle_low_battery.png
+++ b/core/res/res/drawable-mdpi/ic_lock_idle_low_battery.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_emergencycall_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_emergencycall_normal.png
new file mode 100644
index 0000000..cae795f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_emergencycall_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_emergencycall_pressed.png b/core/res/res/drawable-mdpi/ic_lockscreen_emergencycall_pressed.png
new file mode 100644
index 0000000..2867956
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_emergencycall_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_forgotpassword_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_forgotpassword_normal.png
new file mode 100644
index 0000000..a7e063a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_forgotpassword_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_forgotpassword_pressed.png b/core/res/res/drawable-mdpi/ic_lockscreen_forgotpassword_pressed.png
new file mode 100644
index 0000000..53af5a5
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_forgotpassword_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_green_up.png b/core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_green_up.png
index 0bc86c3..7ddeba5 100644
--- a/core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_green_up.png
+++ b/core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_green_up.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_green_up_holo.png b/core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_green_up_holo.png
new file mode 100644
index 0000000..89d209c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_green_up_holo.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_red_up.png b/core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_red_up.png
index 2ab4547..7201e58 100644
--- a/core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_red_up.png
+++ b/core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_red_up.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_red_up_holo.png b/core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_red_up_holo.png
new file mode 100644
index 0000000..1d4cb32
--- /dev/null
+++ b/core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_red_up_holo.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/indicator_code_lock_point_area_default_holo.png b/core/res/res/drawable-mdpi/indicator_code_lock_point_area_default_holo.png
new file mode 100644
index 0000000..a627cda
--- /dev/null
+++ b/core/res/res/drawable-mdpi/indicator_code_lock_point_area_default_holo.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/indicator_code_lock_point_area_green_holo.png b/core/res/res/drawable-mdpi/indicator_code_lock_point_area_green_holo.png
new file mode 100644
index 0000000..308624b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/indicator_code_lock_point_area_green_holo.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/indicator_code_lock_point_area_red_holo.png b/core/res/res/drawable-mdpi/indicator_code_lock_point_area_red_holo.png
new file mode 100644
index 0000000..6c451ec
--- /dev/null
+++ b/core/res/res/drawable-mdpi/indicator_code_lock_point_area_red_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lock_idle_alarm.png b/core/res/res/drawable-xhdpi/ic_lock_idle_alarm.png
new file mode 100644
index 0000000..2822a92
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lock_idle_alarm.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_emergencycall_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_emergencycall_normal.png
new file mode 100644
index 0000000..a61f7a5
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_emergencycall_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_emergencycall_pressed.png b/core/res/res/drawable-xhdpi/ic_lockscreen_emergencycall_pressed.png
new file mode 100644
index 0000000..dd5e481
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_emergencycall_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_forgotpassword_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_forgotpassword_normal.png
new file mode 100644
index 0000000..e4172ce
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_forgotpassword_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_forgotpassword_pressed.png b/core/res/res/drawable-xhdpi/ic_lockscreen_forgotpassword_pressed.png
new file mode 100644
index 0000000..e2c7621
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_forgotpassword_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/indicator_code_lock_point_area_default_holo.png b/core/res/res/drawable-xhdpi/indicator_code_lock_point_area_default_holo.png
new file mode 100644
index 0000000..d98a126
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/indicator_code_lock_point_area_default_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/indicator_code_lock_point_area_green_holo.png b/core/res/res/drawable-xhdpi/indicator_code_lock_point_area_green_holo.png
new file mode 100644
index 0000000..4491f02
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/indicator_code_lock_point_area_green_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/indicator_code_lock_point_area_red_holo.png b/core/res/res/drawable-xhdpi/indicator_code_lock_point_area_red_holo.png
new file mode 100644
index 0000000..6e91fbc
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/indicator_code_lock_point_area_red_holo.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/ic_lock_idle_alarm.png b/core/res/res/drawable-xlarge-hdpi/ic_lock_idle_alarm.png
new file mode 100644
index 0000000..29cd471
--- /dev/null
+++ b/core/res/res/drawable-xlarge-hdpi/ic_lock_idle_alarm.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/ic_lock_idle_charging.png b/core/res/res/drawable-xlarge-hdpi/ic_lock_idle_charging.png
new file mode 100644
index 0000000..211aa0b
--- /dev/null
+++ b/core/res/res/drawable-xlarge-hdpi/ic_lock_idle_charging.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/ic_lock_idle_lock.png b/core/res/res/drawable-xlarge-hdpi/ic_lock_idle_lock.png
new file mode 100644
index 0000000..683ba22
--- /dev/null
+++ b/core/res/res/drawable-xlarge-hdpi/ic_lock_idle_lock.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/ic_lock_idle_low_battery.png b/core/res/res/drawable-xlarge-hdpi/ic_lock_idle_low_battery.png
new file mode 100644
index 0000000..f4383f3
--- /dev/null
+++ b/core/res/res/drawable-xlarge-hdpi/ic_lock_idle_low_battery.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/btn_code_lock_default.png b/core/res/res/drawable-xlarge-mdpi/btn_code_lock_default.png
new file mode 100644
index 0000000..45cc20d
--- /dev/null
+++ b/core/res/res/drawable-xlarge-mdpi/btn_code_lock_default.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/btn_code_lock_touched.png b/core/res/res/drawable-xlarge-mdpi/btn_code_lock_touched.png
new file mode 100644
index 0000000..45cc20d
--- /dev/null
+++ b/core/res/res/drawable-xlarge-mdpi/btn_code_lock_touched.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/ic_lock_idle_alarm.png b/core/res/res/drawable-xlarge-mdpi/ic_lock_idle_alarm.png
new file mode 100644
index 0000000..97ac023
--- /dev/null
+++ b/core/res/res/drawable-xlarge-mdpi/ic_lock_idle_alarm.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/ic_lock_idle_charging.png b/core/res/res/drawable-xlarge-mdpi/ic_lock_idle_charging.png
new file mode 100644
index 0000000..4210db2
--- /dev/null
+++ b/core/res/res/drawable-xlarge-mdpi/ic_lock_idle_charging.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/ic_lock_idle_lock.png b/core/res/res/drawable-xlarge-mdpi/ic_lock_idle_lock.png
new file mode 100644
index 0000000..1060f5a
--- /dev/null
+++ b/core/res/res/drawable-xlarge-mdpi/ic_lock_idle_lock.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/ic_lock_idle_low_battery.png b/core/res/res/drawable-xlarge-mdpi/ic_lock_idle_low_battery.png
new file mode 100644
index 0000000..72e4afa
--- /dev/null
+++ b/core/res/res/drawable-xlarge-mdpi/ic_lock_idle_low_battery.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_drag_direction_green_up.png b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_drag_direction_green_up.png
new file mode 100644
index 0000000..0bc86c3
--- /dev/null
+++ b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_drag_direction_green_up.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_drag_direction_red_up.png b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_drag_direction_red_up.png
new file mode 100644
index 0000000..2ab4547
--- /dev/null
+++ b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_drag_direction_red_up.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_default.png b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_default.png
new file mode 100644
index 0000000..fe72d00
--- /dev/null
+++ b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_default.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_green.png b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_green.png
new file mode 100644
index 0000000..be666c6
--- /dev/null
+++ b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_green.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_red.png b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_red.png
new file mode 100644
index 0000000..9627197
--- /dev/null
+++ b/core/res/res/drawable-xlarge-mdpi/indicator_code_lock_point_area_red.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-xhdpi/indicator_code_lock_point_area_default.png b/core/res/res/drawable-xlarge-xhdpi/indicator_code_lock_point_area_default.png
new file mode 100644
index 0000000..6662eb1
--- /dev/null
+++ b/core/res/res/drawable-xlarge-xhdpi/indicator_code_lock_point_area_default.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-xhdpi/indicator_code_lock_point_area_green.png b/core/res/res/drawable-xlarge-xhdpi/indicator_code_lock_point_area_green.png
new file mode 100644
index 0000000..dce220a
--- /dev/null
+++ b/core/res/res/drawable-xlarge-xhdpi/indicator_code_lock_point_area_green.png
Binary files differ
diff --git a/core/res/res/drawable-xlarge-xhdpi/indicator_code_lock_point_area_red.png b/core/res/res/drawable-xlarge-xhdpi/indicator_code_lock_point_area_red.png
new file mode 100644
index 0000000..746a3ea
--- /dev/null
+++ b/core/res/res/drawable-xlarge-xhdpi/indicator_code_lock_point_area_red.png
Binary files differ
diff --git a/core/res/res/drawable/lockscreen_emergency_button.xml b/core/res/res/drawable/lockscreen_emergency_button.xml
new file mode 100644
index 0000000..4ec6a96
--- /dev/null
+++ b/core/res/res/drawable/lockscreen_emergency_button.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="true" android:drawable="@drawable/ic_lockscreen_emergencycall_normal" />
+    <item android:state_pressed="true" android:drawable="@drawable/ic_lockscreen_emergencycall_pressed" />
+    <item android:drawable="@drawable/ic_lockscreen_emergencycall_normal" />
+</selector>
diff --git a/core/res/res/drawable/lockscreen_forgot_password_button.xml b/core/res/res/drawable/lockscreen_forgot_password_button.xml
new file mode 100644
index 0000000..6c081bf
--- /dev/null
+++ b/core/res/res/drawable/lockscreen_forgot_password_button.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="true" android:drawable="@drawable/ic_lockscreen_forgotpassword_normal" />
+    <item android:state_pressed="true" android:drawable="@drawable/ic_lockscreen_forgotpassword_pressed" />
+    <item android:drawable="@drawable/ic_lockscreen_forgotpassword_normal" />
+</selector>
diff --git a/core/res/res/layout-sw600dp/keyguard_screen_status_land.xml b/core/res/res/layout-sw600dp/keyguard_screen_status_land.xml
index 0a485e2..302ee01 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_status_land.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_status_land.xml
@@ -56,7 +56,7 @@
             android:layout_height="wrap_content"
             android:singleLine="true"
             android:ellipsize="none"
-            android:textSize="98sp"
+            android:textSize="@dimen/keyguard_pattern_unlock_clock_font_size"
             android:textAppearance="?android:attr/textAppearanceMedium"
             android:textColor="@color/lockscreen_clock_background"
             android:layout_marginBottom="6dip"
@@ -67,7 +67,7 @@
             android:layout_height="wrap_content"
             android:singleLine="true"
             android:ellipsize="none"
-            android:textSize="98sp"
+            android:textSize="@dimen/keyguard_pattern_unlock_clock_font_size"
             android:textAppearance="?android:attr/textAppearanceMedium"
             android:textColor="@color/lockscreen_clock_foreground"
             android:layout_alignLeft="@id/timeDisplayBackground"
diff --git a/core/res/res/layout-sw600dp/keyguard_screen_status_port.xml b/core/res/res/layout-sw600dp/keyguard_screen_status_port.xml
index 346b21e..53fe902 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_status_port.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_status_port.xml
@@ -55,7 +55,7 @@
             android:layout_height="wrap_content"
             android:singleLine="true"
             android:ellipsize="none"
-            android:textSize="98sp"
+            android:textSize="@dimen/keyguard_pattern_unlock_clock_font_size"
             android:textAppearance="?android:attr/textAppearanceMedium"
             android:textColor="@color/lockscreen_clock_background"
             android:layout_marginBottom="6dip"
@@ -66,7 +66,7 @@
             android:layout_height="wrap_content"
             android:singleLine="true"
             android:ellipsize="none"
-            android:textSize="98sp"
+            android:textSize="@dimen/keyguard_pattern_unlock_clock_font_size"
             android:textAppearance="?android:attr/textAppearanceMedium"
             android:textColor="@color/lockscreen_clock_foreground"
             android:layout_marginBottom="6dip"
diff --git a/core/res/res/layout-sw600dp/keyguard_screen_unlock_landscape.xml b/core/res/res/layout-sw600dp/keyguard_screen_unlock_landscape.xml
index e3d7a3f..7ac41b5 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_unlock_landscape.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_unlock_landscape.xml
@@ -56,10 +56,8 @@
             android:layout_gravity="center_vertical"
         />
 
-        <!-- footer -->
-
-        <!-- option 1: a single emergency call button -->
-        <RelativeLayout android:id="@+id/footerNormal"
+        <!-- Emergency and forgot pattern buttons. -->
+        <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_below="@id/lockPattern"
@@ -68,43 +66,27 @@
             android:layout_marginTop="28dip"
             android:layout_marginLeft="28dip"
             android:layout_marginRight="28dip"
-            >
-            <Button android:id="@+id/emergencyCallAlone"
+            android:orientation="horizontal">
+
+            <Button android:id="@+id/forgotPatternButton"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:text="@string/lockscreen_emergency_call"
+                android:layout_gravity="center"
                 style="@style/Widget.Button.Transparent"
                 android:drawableLeft="@drawable/ic_emergency"
                 android:drawablePadding="8dip"
+                android:text="@string/lockscreen_forgot_pattern_button_text"
                 android:visibility="gone"
-                />
-        </RelativeLayout>
-
-        <!-- option 2: an emergency call button, and a 'forgot pattern?' button -->
-        <LinearLayout android:id="@+id/footerForgotPattern"
-            android:orientation="vertical"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_below="@id/footerNormal"
-            android:layout_alignLeft="@id/lockPattern"
-            android:layout_alignRight="@id/lockPattern"
-            android:layout_marginTop="28dip"
-            android:layout_marginLeft="28dip"
-            android:layout_marginRight="28dip">
-
-            <Button android:id="@+id/forgotPattern"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                style="@style/Widget.Button.Transparent"
             />
 
-            <Button android:id="@+id/emergencyCallTogether"
-                android:layout_width="match_parent"
+            <Button android:id="@+id/emergencyCallButton"
+                android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:text="@string/lockscreen_emergency_call"
+                android:layout_gravity="center"
                 style="@style/Widget.Button.Transparent"
                 android:drawableLeft="@drawable/ic_emergency"
                 android:drawablePadding="8dip"
+                android:text="@string/lockscreen_emergency_call"
                 android:visibility="gone"
             />
 
diff --git a/core/res/res/layout-sw600dp/keyguard_screen_unlock_portrait.xml b/core/res/res/layout-sw600dp/keyguard_screen_unlock_portrait.xml
index f35897e..1f6058f 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_unlock_portrait.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_unlock_portrait.xml
@@ -23,7 +23,7 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
-    <!-- top: status -->
+    <!-- top: status and emergency/forgot pattern buttons -->
     <LinearLayout
         android:layout_height="0dip"
         android:layout_weight="1"
@@ -36,53 +36,37 @@
             android:layout_marginTop="134dip"
             android:layout_marginLeft="266dip"/>
 
-        <!-- footer -->
-        <FrameLayout
+        <!-- Emergency and forgot pattern buttons. -->
+        <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_marginLeft="140dip"
-            >
+            android:orientation="horizontal"
+            android:gravity="center_horizontal">
 
-            <!-- option 1: a single emergency call button -->
-            <RelativeLayout android:id="@+id/footerNormal"
-                android:layout_width="match_parent"
+            <Button android:id="@+id/forgotPatternButton"
+                android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:gravity="left"
-                >
-                <Button android:id="@+id/emergencyCallAlone"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="@string/lockscreen_emergency_call"
-                    style="@style/Widget.Button.Transparent"
-                    android:drawableLeft="@drawable/ic_emergency"
-                    android:drawablePadding="8dip"
-                    android:visibility="gone"
-                    />
-            </RelativeLayout>
+                android:layout_gravity="center"
+                style="@style/Widget.Button.Transparent"
+                android:drawableLeft="@drawable/ic_emergency"
+                android:drawablePadding="8dip"
+                android:text="@string/lockscreen_forgot_pattern_button_text"
+                android:visibility="gone"
+            />
 
-            <!-- option 2: an emergency call button, and a 'forgot pattern?' button -->
-            <LinearLayout android:id="@+id/footerForgotPattern"
-                android:orientation="vertical"
-                android:layout_width="match_parent"
+            <Button android:id="@+id/emergencyCallButton"
+                android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:gravity="left"
-                >
-                <Button android:id="@+id/forgotPattern"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    style="@style/Widget.Button.Transparent"
-                    />
-                <Button android:id="@+id/emergencyCallTogether"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:text="@string/lockscreen_emergency_call"
-                    style="@style/Widget.Button.Transparent"
-                    android:drawableLeft="@drawable/ic_emergency"
-                    android:drawablePadding="8dip"
-                    android:visibility="gone"
-                    />
-            </LinearLayout>
-        </FrameLayout>
+                android:layout_gravity="center"
+                style="@style/Widget.Button.Transparent"
+                android:drawableLeft="@drawable/ic_emergency"
+                android:drawablePadding="8dip"
+                android:text="@string/lockscreen_emergency_call"
+                android:visibility="gone"
+            />
+
+        </LinearLayout>
+
     </LinearLayout>
 
     <!-- right side: lock pattern -->
diff --git a/core/res/res/layout/action_bar_title_item.xml b/core/res/res/layout/action_bar_title_item.xml
index d8b729d..e803b26 100644
--- a/core/res/res/layout/action_bar_title_item.xml
+++ b/core/res/res/layout/action_bar_title_item.xml
@@ -17,17 +17,32 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
-              android:orientation="vertical"
-              android:paddingRight="32dip" >
-    <TextView android:id="@+id/action_bar_title"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:singleLine="true"
-        android:ellipsize="end" />
-    <TextView android:id="@+id/action_bar_subtitle"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:singleLine="true"
-        android:ellipsize="end"
-        android:visibility="gone" />
+              android:orientation="horizontal"
+              android:paddingRight="16dip"
+              android:background="?android:attr/selectableItemBackground"
+              android:enabled="false">
+
+    <ImageView android:id="@android:id/up"
+               android:src="?android:attr/homeAsUpIndicator"
+               android:layout_gravity="center_vertical|left"
+               android:visibility="gone"
+               android:layout_width="wrap_content"
+               android:layout_height="wrap_content" />
+
+    <LinearLayout android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:layout_gravity="center_vertical|left"
+                  android:orientation="vertical">
+        <TextView android:id="@+id/action_bar_title"
+                  android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:singleLine="true"
+                  android:ellipsize="end" />
+        <TextView android:id="@+id/action_bar_subtitle"
+                  android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:singleLine="true"
+                  android:ellipsize="end"
+                  android:visibility="gone" />
+    </LinearLayout>
 </LinearLayout>
diff --git a/core/res/res/layout/alert_dialog_holo.xml b/core/res/res/layout/alert_dialog_holo.xml
index 8ee91ca..2185467 100644
--- a/core/res/res/layout/alert_dialog_holo.xml
+++ b/core/res/res/layout/alert_dialog_holo.xml
@@ -32,12 +32,10 @@
         android:orientation="vertical">
         <ImageView android:id="@+id/titleDividerTop"
             android:layout_width="match_parent"
-            android:layout_height="4dip"
+            android:layout_height="1dip"
             android:visibility="gone"
             android:scaleType="fitXY"
             android:gravity="fill_horizontal"
-            android:paddingLeft="16dip"
-            android:paddingRight="16dip"
             android:src="@android:drawable/divider_strong_holo" />
         <LinearLayout android:id="@+id/title_template"
             android:layout_width="match_parent"
@@ -45,15 +43,16 @@
             android:orientation="horizontal"
             android:gravity="center_vertical|left"
             android:minHeight="@dimen/alert_dialog_title_height"
-            android:layout_marginLeft="32dip"
-            android:layout_marginRight="32dip">
+            android:layout_marginLeft="16dip"
+            android:layout_marginRight="16dip">
             <ImageView android:id="@+id/icon"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:paddingRight="16dip"
+                android:paddingRight="8dip"
                 android:src="@null" />
             <com.android.internal.widget.DialogTitle android:id="@+id/alertTitle"
-                style="?android:attr/textAppearanceMedium"
+                style="?android:attr/textAppearanceLarge"
+                android:textColor="@android:color/holo_blue"
                 android:singleLine="true"
                 android:ellipsize="end"
                 android:layout_width="match_parent"
@@ -61,12 +60,10 @@
         </LinearLayout>
         <ImageView android:id="@+id/titleDivider"
             android:layout_width="match_parent"
-            android:layout_height="4dip"
+            android:layout_height="1dip"
             android:visibility="gone"
             android:scaleType="fitXY"
             android:gravity="fill_horizontal"
-            android:paddingLeft="16dip"
-            android:paddingRight="16dip"
             android:src="@android:drawable/divider_strong_holo" />
         <!-- If the client uses a customTitle, it will be added here. -->
     </LinearLayout>
@@ -79,17 +76,15 @@
         <ScrollView android:id="@+id/scrollView"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_marginLeft="16dip"
-            android:layout_marginRight="16dip"
-            android:paddingTop="32dip"
-            android:paddingBottom="32dip"
             android:clipToPadding="false">
             <TextView android:id="@+id/message"
                 style="?android:attr/textAppearanceMedium"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:paddingLeft="16dip"
-                android:paddingRight="16dip" />
+                android:paddingRight="16dip"
+                android:paddingTop="8dip"
+                android:paddingBottom="8dip"/>
         </ScrollView>
     </LinearLayout>
 
@@ -99,11 +94,7 @@
         android:layout_weight="1">
         <FrameLayout android:id="@+android:id/custom"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:paddingTop="8dip"
-            android:paddingBottom="8dip"
-            android:paddingLeft="32dip"
-            android:paddingRight="32dip" />
+            android:layout_height="wrap_content" />
     </FrameLayout>
 
     <LinearLayout android:id="@+id/buttonPanel"
@@ -113,27 +104,21 @@
         android:orientation="vertical"
         android:divider="?android:attr/dividerHorizontal"
         android:showDividers="beginning"
-        android:dividerPadding="16dip">
+        android:dividerPadding="0dip">
         <LinearLayout
             style="?android:attr/buttonBarStyle"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:orientation="horizontal"
-            android:paddingLeft="2dip"
-            android:paddingRight="2dip"
+            android:layoutDirection="locale"
             android:measureWithLargestChild="true">
-            <LinearLayout android:id="@+id/leftSpacer"
-                android:layout_weight="0.25"
-                android:layout_width="0dip"
-                android:layout_height="wrap_content"
-                android:orientation="horizontal"
-                android:visibility="gone" />
-            <Button android:id="@+id/button1"
+            <Button android:id="@+id/button2"
                 android:layout_width="0dip"
                 android:layout_gravity="left"
                 android:layout_weight="1"
                 android:maxLines="2"
                 style="?android:attr/buttonBarButtonStyle"
+                android:textSize="14sp"
                 android:minHeight="@dimen/alert_dialog_button_bar_height"
                 android:layout_height="wrap_content" />
             <Button android:id="@+id/button3"
@@ -142,22 +127,18 @@
                 android:layout_weight="1"
                 android:maxLines="2"
                 style="?android:attr/buttonBarButtonStyle"
+                android:textSize="14sp"
                 android:minHeight="@dimen/alert_dialog_button_bar_height"
                 android:layout_height="wrap_content" />
-            <Button android:id="@+id/button2"
+            <Button android:id="@+id/button1"
                 android:layout_width="0dip"
                 android:layout_gravity="right"
                 android:layout_weight="1"
                 android:maxLines="2"
                 android:minHeight="@dimen/alert_dialog_button_bar_height"
                 style="?android:attr/buttonBarButtonStyle"
+                android:textSize="14sp"
                 android:layout_height="wrap_content" />
-            <LinearLayout android:id="@+id/rightSpacer"
-                android:layout_width="0dip"
-                android:layout_weight="0.25"
-                android:layout_height="wrap_content"
-                android:orientation="horizontal"
-                android:visibility="gone" />
         </LinearLayout>
      </LinearLayout>
 </LinearLayout>
diff --git a/core/res/res/layout/dialog_custom_title_holo.xml b/core/res/res/layout/dialog_custom_title_holo.xml
index 74b6070..5261553 100644
--- a/core/res/res/layout/dialog_custom_title_holo.xml
+++ b/core/res/res/layout/dialog_custom_title_holo.xml
@@ -23,18 +23,16 @@
     android:fitsSystemWindows="true">
     <FrameLayout android:id="@android:id/title_container"
         android:layout_width="match_parent"
-        android:layout_height="60dip"
+        android:layout_height="@dimen/alert_dialog_title_height"
         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:layout_height="1dip"
             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"
diff --git a/core/res/res/layout/dialog_title_holo.xml b/core/res/res/layout/dialog_title_holo.xml
index 534dd8d..400ef60 100644
--- a/core/res/res/layout/dialog_title_holo.xml
+++ b/core/res/res/layout/dialog_title_holo.xml
@@ -26,17 +26,15 @@
     <TextView android:id="@android:id/title" style="?android:attr/windowTitleStyle"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:minHeight="60dip"
-        android:paddingLeft="32dip"
-        android:paddingRight="32dip"
+        android:minHeight="@android:dimen/alert_dialog_title_height"
+        android:paddingLeft="16dip"
+        android:paddingRight="16dip"
         android:gravity="center_vertical|left" />
     <ImageView android:id="@+id/titleDivider"
             android:layout_width="match_parent"
-            android:layout_height="4dip"
+            android:layout_height="1dip"
             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"
diff --git a/core/res/res/layout/dialog_title_icons_holo.xml b/core/res/res/layout/dialog_title_icons_holo.xml
index a3cd3af..f780ab0 100644
--- a/core/res/res/layout/dialog_title_icons_holo.xml
+++ b/core/res/res/layout/dialog_title_icons_holo.xml
@@ -28,16 +28,16 @@
         android:layout_height="wrap_content"
         android:orientation="horizontal"
         android:gravity="center_vertical"
-        android:minHeight="60dip"
-        android:paddingLeft="32dip"
-        android:paddingRight="32dip">
+        android:minHeight="@android:dimen/alert_dialog_title_height"
+        android:paddingLeft="16dip"
+        android:paddingRight="16dip">
         <ImageView android:id="@+id/left_icon"
             android:layout_width="32dip"
             android:layout_height="32dip"
             android:scaleType="fitCenter"
             android:layout_marginRight="8dip" />
         <TextView android:id="@android:id/title"
-		style="?android:attr/windowTitleStyle"
+            style="?android:attr/windowTitleStyle"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_weight="0" />
@@ -50,11 +50,9 @@
 
     <ImageView android:id="@+id/titleDivider"
             android:layout_width="match_parent"
-            android:layout_height="4dip"
+            android:layout_height="1dip"
             android:scaleType="fitXY"
             android:gravity="fill_horizontal"
-            android:paddingLeft="16dip"
-            android:paddingRight="16dip"
             android:src="@android:drawable/divider_strong_holo" />
 
     <FrameLayout
diff --git a/core/res/res/layout/keyguard_screen_status_land.xml b/core/res/res/layout/keyguard_screen_status_land.xml
index 259a3af..8a02e1f 100644
--- a/core/res/res/layout/keyguard_screen_status_land.xml
+++ b/core/res/res/layout/keyguard_screen_status_land.xml
@@ -133,16 +133,4 @@
         android:textAppearance="?android:attr/textAppearanceMedium"
         />
 
-    <TextView
-        android:id="@+id/propertyOf"
-        android:lineSpacingExtra="8dip"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:textAppearance="?android:attr/textAppearanceMedium"
-        android:textSize="17sp"
-        android:layout_marginTop="20dip"
-        android:singleLine="false"
-        android:textColor="@color/lockscreen_owner_info"
-        android:visibility="gone"
-        />
 </LinearLayout>
diff --git a/core/res/res/layout/keyguard_screen_status_port.xml b/core/res/res/layout/keyguard_screen_status_port.xml
index 680c073..1e87fb3 100644
--- a/core/res/res/layout/keyguard_screen_status_port.xml
+++ b/core/res/res/layout/keyguard_screen_status_port.xml
@@ -130,16 +130,4 @@
         android:textAppearance="?android:attr/textAppearanceMedium"
         />
 
-    <TextView
-        android:id="@+id/propertyOf"
-        android:lineSpacingExtra="8dip"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="20dip"
-        android:textAppearance="?android:attr/textAppearanceMedium"
-        android:textSize="17sp"
-        android:singleLine="false"
-        android:visibility="gone"
-        android:textColor="@color/lockscreen_owner_info"
-        />
 </LinearLayout>
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
index df29a4b..d45cc85 100644
--- a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
+++ b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
@@ -20,32 +20,130 @@
 <!-- This is the general lock screen which shows information about the
   state of the device, as well as instructions on how to get past it
   depending on the state of the device.-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="horizontal"
+    android:orientation="vertical"
+    android:rowCount="10"
     android:id="@+id/root"
     android:clipChildren="false">
 
-    <!-- left side -->
-    <RelativeLayout
-            android:layout_width="0dip"
-            android:layout_height="match_parent"
-            android:layout_weight="1.0"
-            android:layout_marginLeft="24dip"
-            android:gravity="left">
+    <!-- Column 0 -->
+    <Space android:height="20dip"/>
 
-        <TextView
+    <com.android.internal.widget.DigitalClock android:id="@+id/time"
+        android:layout_marginTop="56dip"
+        android:layout_marginBottom="8dip">
+
+       <!-- Because we can't have multi-tone fonts, we render two TextViews, one on
+        top of the other. Hence the redundant layout... -->
+        <TextView android:id="@+id/timeDisplayBackground"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:ellipsize="none"
+            android:textSize="72sp"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:layout_marginBottom="6dip"
+            android:textColor="@color/lockscreen_clock_background"
+            />
+
+        <TextView android:id="@+id/timeDisplayForeground"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:ellipsize="none"
+            android:textSize="72sp"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:layout_marginBottom="6dip"
+            android:textColor="@color/lockscreen_clock_foreground"
+            android:layout_alignLeft="@id/timeDisplayBackground"
+            android:layout_alignTop="@id/timeDisplayBackground"
+            />
+
+        <TextView android:id="@+id/am_pm"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_toRightOf="@id/timeDisplayBackground"
+            android:layout_alignBaseline="@id/timeDisplayBackground"
+            android:singleLine="true"
+            android:ellipsize="none"
+            android:textSize="22sp"
+            android:layout_marginLeft="8dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="@color/lockscreen_clock_am_pm"
+            android:visibility="gone"
+            />
+
+    </com.android.internal.widget.DigitalClock>
+
+    <TextView
+        android:id="@+id/date"
+        android:layout_below="@id/time"
+        android:layout_marginTop="6dip"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:layout_gravity="left"
+        />
+
+    <TextView
+        android:id="@+id/alarm_status"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textSize="18sp"
+        android:drawablePadding="4dip"
+        android:layout_marginTop="4dip"
+        android:layout_gravity="left"
+        />
+
+    <TextView
+        android:id="@+id/status1"
+        android:layout_marginTop="4dip"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:drawablePadding="4dip"
+        android:layout_gravity="left"
+        />
+
+    <TextView
+        android:id="@+id/status2"
+        android:layout_marginTop="4dip"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:drawablePadding="4dip"
+        android:layout_gravity="left"
+        />
+
+    <TextView
+        android:id="@+id/screenLocked"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:gravity="center"
+        android:layout_marginTop="4dip"
+        android:drawablePadding="4dip"
+        android:layout_gravity="left"
+        />
+
+    <Space android:height="20dip"/>
+
+    <LinearLayout android:orientation="horizontal" >
+
+         <TextView
             android:id="@+id/carrier"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_alignParentTop="true"
-            android:layout_marginTop="20dip"
             android:singleLine="true"
             android:ellipsize="marquee"
-            android:gravity="right|bottom"
+            android:layout_gravity="bottom|left"
             android:textAppearance="?android:attr/textAppearanceMedium"
-            />
+        />
+
+        <Button
+            android:id="@+id/emergencyCallButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:drawableLeft="@drawable/ic_emergency"
+            style="@style/Widget.Button.Transparent"
+            android:drawablePadding="8dip"
+            android:layout_marginRight="80dip"
+            android:visibility="gone"
+        />
 
         <!-- "emergency calls only" shown when sim is missing or PUKd -->
         <TextView
@@ -57,117 +155,20 @@
             android:text="@string/emergency_calls_only"
             android:textAppearance="?android:attr/textAppearanceSmall"
             android:textColor="@color/white"
-           />
+        />
+    </LinearLayout>
 
-        <com.android.internal.widget.DigitalClock android:id="@+id/time"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_below="@id/carrier"
-            android:layout_marginTop="56dip"
-            android:layout_marginBottom="8dip"
-            >
+    <Space android:height="20dip"/>
 
-           <!-- Because we can't have multi-tone fonts, we render two TextViews, one on
-            top of the other. Hence the redundant layout... -->
-            <TextView android:id="@+id/timeDisplayBackground"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:singleLine="true"
-                android:ellipsize="none"
-                android:textSize="72sp"
-                android:textAppearance="?android:attr/textAppearanceMedium"
-                android:layout_marginBottom="6dip"
-                android:textColor="@color/lockscreen_clock_background"
-                />
+    <!-- Column 1 -->
+    <Space android:width="20dip" android:layout_columnWeight="1" android:layout_rowSpan="10" />
 
-            <TextView android:id="@+id/timeDisplayForeground"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:singleLine="true"
-                android:ellipsize="none"
-                android:textSize="72sp"
-                android:textAppearance="?android:attr/textAppearanceMedium"
-                android:layout_marginBottom="6dip"
-                android:textColor="@color/lockscreen_clock_foreground"
-                android:layout_alignLeft="@id/timeDisplayBackground"
-                android:layout_alignTop="@id/timeDisplayBackground"
-                />
-
-            <TextView android:id="@+id/am_pm"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_toRightOf="@id/timeDisplayBackground"
-                android:layout_alignBaseline="@id/timeDisplayBackground"
-                android:singleLine="true"
-                android:ellipsize="none"
-                android:textSize="22sp"
-                android:layout_marginLeft="8dip"
-                android:textAppearance="?android:attr/textAppearanceMedium"
-                android:textColor="@color/lockscreen_clock_am_pm"
-                />
-
-        </com.android.internal.widget.DigitalClock>
-
-        <TextView
-            android:id="@+id/date"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_below="@id/time"
-            android:layout_marginTop="6dip"
-            android:textAppearance="?android:attr/textAppearanceMedium"
-            />
-
-        <!-- TODO: Redo layout when we release on phones -->
-        <TextView
-            android:id="@+id/alarm_status"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:textAppearance="?android:attr/textAppearanceMedium"
-            android:textSize="18sp"
-            android:drawablePadding="4dip"
-            android:layout_below="@id/date"
-            android:layout_marginTop="4dip"
-            android:layout_marginLeft="24dip"
-            />
-
-        <TextView
-            android:id="@+id/status1"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_below="@id/alarm_status"
-            android:layout_marginTop="6dip"
-            android:textAppearance="?android:attr/textAppearanceMedium"
-            android:drawablePadding="4dip"
-            />
-
-        <TextView
-            android:id="@+id/status2"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_below="@id/status1"
-            android:layout_marginTop="6dip"
-            android:textAppearance="?android:attr/textAppearanceMedium"
-            android:drawablePadding="4dip"
-            />
-
-        <TextView
-            android:id="@+id/screenLocked"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_below="@id/status2"
-            android:textAppearance="?android:attr/textAppearanceMedium"
-            android:gravity="center"
-            android:layout_marginTop="12dip"
-            android:drawablePadding="4dip"
-            />
-
-    </RelativeLayout>
-
-    <!-- right side -->
+    <!-- Column 2 -->
     <com.android.internal.widget.multiwaveview.MultiWaveView
         android:id="@+id/unlock_widget"
         android:layout_width="300dip"
         android:layout_height="match_parent"
+        android:layout_rowSpan="10"
 
         android:targetDrawables="@array/lockscreen_targets_when_silent"
         android:handleDrawable="@drawable/ic_lockscreen_handle"
@@ -178,21 +179,8 @@
         android:vibrationDuration="20"
         android:topChevronDrawable="@drawable/ic_lockscreen_chevron_up"
         android:feedbackCount="3"
-        android:horizontalOffset="60dip"
+        android:horizontalOffset="0dip"
         android:verticalOffset="0dip"
         />
 
-    <!-- emergency call button shown when sim is PUKd and tab_selector is
-         hidden -->
-    <Button
-        android:id="@+id/emergencyCallButton"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:drawableLeft="@drawable/ic_emergency"
-        style="@style/Widget.Button.Transparent"
-        android:drawablePadding="8dip"
-        android:layout_marginRight="80dip"
-        android:visibility="gone"
-        />
-
-</LinearLayout>
+</GridLayout>
diff --git a/core/res/res/layout/keyguard_screen_unlock_landscape.xml b/core/res/res/layout/keyguard_screen_unlock_landscape.xml
index c7b78c4..d52bc57 100644
--- a/core/res/res/layout/keyguard_screen_unlock_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_landscape.xml
@@ -21,198 +21,124 @@
      the user how to unlock their device, or make an emergency call.  This
      is the portrait layout.  -->
 
-<com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="horizontal"
+<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/root"
+    android:orientation="vertical"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    android:rowCount="9">
 
-    <!-- left side: instructions and emergency call button -->
-    <LinearLayout
-            android:orientation="vertical"
-            android:layout_width="0dip"
-            android:layout_height="match_parent"
-            android:layout_weight="1.0"
-            android:layout_marginLeft="24dip"
-            android:gravity="left"
-            >
+    <!-- Column 0: Time, date and status -->
+    <com.android.internal.widget.DigitalClock android:id="@+id/time"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="8dip"
+        android:layout_marginBottom="12dip"
+        android:layout_gravity="right">
 
-        <TextView
-            android:id="@+id/alarm_status"
+        <!-- Because we can't have multi-tone fonts, we render two TextViews, one on
+        top of the other. Hence the redundant layout... -->
+        <TextView android:id="@+id/timeDisplayBackground"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:textAppearance="?android:attr/textAppearanceMedium"
-            android:textSize="18sp"
-            android:drawablePadding="4dip"
-            />
-        <TextView
-            android:id="@+id/status1"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="16dip"
-            android:textAppearance="?android:attr/textAppearanceMedium"
-            />
-
-        <TextView
-            android:id="@+id/carrier"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:textAppearance="?android:attr/textAppearanceMedium"
-            android:textSize="17sp"
-            android:drawablePadding="4dip"
-            android:layout_marginTop="32dip"
             android:singleLine="true"
-            android:ellipsize="marquee"
-            android:gravity="right|bottom"
-            />
-
-        <com.android.internal.widget.DigitalClock android:id="@+id/time"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_alignParentTop="true"
-            android:layout_alignParentLeft="true"
-            android:layout_marginTop="8dip"
-            android:layout_marginBottom="8dip"
-            >
-
-            <!-- Because we can't have multi-tone fonts, we render two TextViews, one on
-            top of the other. Hence the redundant layout... -->
-            <TextView android:id="@+id/timeDisplayBackground"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:singleLine="true"
-                android:ellipsize="none"
-                android:textSize="72sp"
-                android:textAppearance="?android:attr/textAppearanceMedium"
-                android:layout_marginBottom="6dip"
-                android:textColor="@color/lockscreen_clock_background"
-                />
-
-            <TextView android:id="@+id/timeDisplayForeground"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:singleLine="true"
-                android:ellipsize="none"
-                android:textSize="72sp"
-                android:textAppearance="?android:attr/textAppearanceMedium"
-                android:layout_marginBottom="6dip"
-                android:layout_alignLeft="@id/timeDisplayBackground"
-                android:layout_alignTop="@id/timeDisplayBackground"
-                android:textColor="@color/lockscreen_clock_foreground"
-                />
-
-
-
-            <TextView android:id="@+id/am_pm"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_toRightOf="@id/timeDisplayBackground"
-                android:layout_alignBaseline="@id/timeDisplayBackground"
-                android:singleLine="true"
-                android:ellipsize="none"
-                android:textSize="22sp"
-                android:layout_marginLeft="8dip"
-                android:textAppearance="?android:attr/textAppearanceMedium"
-                android:textColor="@color/lockscreen_clock_am_pm"
-                />
-
-        </com.android.internal.widget.DigitalClock>
-
-        <TextView
-            android:id="@+id/date"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_below="@id/time"
+            android:ellipsize="none"
             android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textSize="@dimen/keyguard_pattern_unlock_clock_font_size"
+            android:layout_marginBottom="6dip"
+            android:textColor="@color/lockscreen_clock_background"
             />
 
-        <!-- used for instructions such as "draw pattern to unlock", the next alarm, and charging
-             status.  -->
-        <LinearLayout
-            android:orientation="horizontal"
+        <TextView android:id="@+id/timeDisplayForeground"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_marginTop="8dip"
-            android:gravity="center"
-            >
-            <TextView
-                android:id="@+id/statusSep"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginLeft="5dip"
-                android:layout_marginRight="5dip"
-                android:textAppearance="?android:attr/textAppearanceMedium"
-                android:textSize="17sp"
-                />
-            <TextView
-                android:id="@+id/status2"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_alignParentTop="true"
-                android:textAppearance="?android:attr/textAppearanceMedium"
-                android:textSize="17sp"
-                android:drawablePadding="4dip"
-                />
-        </LinearLayout>
-
-        <!-- fill space between header and button below -->
-        <View
-            android:layout_weight="1.0"
-            android:layout_width="match_parent"
-            android:layout_height="0dip"
+            android:singleLine="true"
+            android:ellipsize="none"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textSize="@dimen/keyguard_pattern_unlock_clock_font_size"
+            android:layout_marginBottom="6dip"
+            android:layout_alignLeft="@id/timeDisplayBackground"
+            android:layout_alignTop="@id/timeDisplayBackground"
+            android:textColor="@color/lockscreen_clock_foreground"
             />
 
-        <!-- footer -->
-        <FrameLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginBottom="16dip"
-            >
+    </com.android.internal.widget.DigitalClock>
 
-            <!-- option 1: a single emergency call button -->
-            <RelativeLayout android:id="@+id/footerNormal"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:gravity="left"
-                >
-                <Button android:id="@+id/emergencyCallAlone"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="@string/lockscreen_emergency_call"
-                    style="@style/Widget.Button.Transparent"
-                    android:drawableLeft="@drawable/ic_emergency"
-                    android:drawablePadding="8dip"
-                    />
-            </RelativeLayout>
+    <TextView
+        android:id="@+id/date"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textSize="@dimen/keyguard_pattern_unlock_status_line_font_size"
+        android:layout_gravity="right"
+        />
 
-            <!-- option 2: an emergency call button, and a 'forgot pattern?' button -->
-            <LinearLayout android:id="@+id/footerForgotPattern"
-                android:orientation="vertical"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:gravity="left"
-                >
-                <Button android:id="@+id/forgotPattern"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    style="@style/Widget.Button.Transparent"
-                    android:visibility="invisible"
-                    />
-                <Button android:id="@+id/emergencyCallTogether"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:text="@string/lockscreen_emergency_call"
-                    style="@style/Widget.Button.Transparent"
-                    android:drawableLeft="@drawable/ic_emergency"
-                    android:drawablePadding="8dip"
-                    />
-            </LinearLayout>
-        </FrameLayout>
-    </LinearLayout>
+    <TextView
+        android:id="@+id/alarm_status"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textSize="@dimen/keyguard_pattern_unlock_status_line_font_size"
+        android:layout_gravity="right"
+        android:drawablePadding="4dip"
+        />
 
-    <!-- right side: lock pattern -->
+    <TextView
+        android:id="@+id/status1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textSize="@dimen/keyguard_pattern_unlock_status_line_font_size"
+        android:layout_gravity="right"
+        />
+
+    <TextView
+        android:id="@+id/status2"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textSize="@dimen/keyguard_pattern_unlock_status_line_font_size"
+        android:layout_gravity="right"
+        android:drawablePadding="4dip"
+        android:visibility="gone"
+        />
+
+    <Space android:layout_rowWeight="1" android:layout_columnWeight="1" />
+
+    <TextView android:id="@+id/carrier"
+        android:layout_gravity="right"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textSize="@dimen/keyguard_pattern_unlock_status_line_font_size"
+        android:singleLine="true"
+        android:ellipsize="marquee"
+        />
+
+    <Button android:id="@+id/emergencyCallButton"
+        android:layout_gravity="right"
+        style="@*android:style/Widget.Button.Transparent"
+        android:textSize="@dimen/keyguard_pattern_unlock_status_line_font_size"
+        android:text="@string/lockscreen_emergency_call"
+        android:drawableLeft="@*android:drawable/lockscreen_emergency_button"
+        android:drawablePadding="0dip"
+    />
+
+    <Button android:id="@+id/forgotPatternButton"
+        android:layout_gravity="right"
+        style="@*android:style/Widget.Button.Transparent"
+        android:textSize="@dimen/keyguard_pattern_unlock_status_line_font_size"
+        android:text="@*android:string/lockscreen_forgot_pattern_button_text"
+        android:drawableLeft="@*android:drawable/lockscreen_forgot_password_button"
+        android:drawablePadding="0dip"
+    />
+
+    <!-- Column 1: lock pattern -->
     <com.android.internal.widget.LockPatternView android:id="@+id/lockPattern"
-         android:layout_width="wrap_content"
-         android:layout_height="wrap_content" />
+         android:layout_width="match_parent"
+         android:layout_height="match_parent"
+         android:layout_marginTop="8dip"
+         android:layout_marginRight="8dip"
+         android:layout_marginBottom="8dip"
+         android:layout_marginLeft="8dip"
+         android:layout_rowSpan="9"/>
 
-</com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
+</GridLayout>
diff --git a/core/res/res/layout/keyguard_screen_unlock_portrait.xml b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
index 15f2afb..4ffa3405 100644
--- a/core/res/res/layout/keyguard_screen_unlock_portrait.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
@@ -20,213 +20,147 @@
 <!-- This is the screen that shows the 9 circle unlock widget and instructs
      the user how to unlock their device, or make an emergency call.  This
      is the portrait layout.  -->
-<com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
+<GridLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:gravity="center_horizontal">
 
-    <RelativeLayout
-        android:layout_width="match_parent"
+
+    <com.android.internal.widget.DigitalClock android:id="@+id/time"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        >
-        <TextView
-            android:id="@+id/carrier"
+        android:layout_marginBottom="18dip"
+        android:layout_marginRight="-4dip"
+        android:layout_gravity="right">
+
+        <!-- Because we can't have multi-tone fonts, we render two TextViews, one on
+        top of the other. Hence the redundant layout... -->
+        <TextView android:id="@*android:id/timeDisplayBackground"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_alignParentTop="true"
-            android:layout_marginTop="6dip"
-            android:layout_alignParentRight="true"
-            android:layout_marginRight="8dip"
-            android:layout_toRightOf="@+id/time"
             android:singleLine="true"
-            android:ellipsize="marquee"
-            android:gravity="right|bottom"
+            android:ellipsize="none"
+            android:textSize="@*android:dimen/keyguard_pattern_unlock_clock_font_size"
             android:textAppearance="?android:attr/textAppearanceMedium"
+            android:layout_marginBottom="6dip"
+            android:textColor="@*android:color/lockscreen_clock_background"
             />
 
-        <com.android.internal.widget.DigitalClock android:id="@+id/time"
+        <TextView android:id="@*android:id/timeDisplayForeground"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_alignParentLeft="true"
-            android:layout_alignParentTop="true"
-            android:layout_marginTop="15dip"
-            android:layout_marginLeft="20dip"
-            android:layout_marginBottom="8dip"
-            >
+            android:singleLine="true"
+            android:ellipsize="none"
+            android:textSize="@*android:dimen/keyguard_pattern_unlock_clock_font_size"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:layout_marginBottom="6dip"
+            android:textColor="@color/lockscreen_clock_foreground"
+            />
 
-            <!-- Because we can't have multi-tone fonts, we render two TextViews, one on
-            top of the other. Hence the redundant layout... -->
-            <TextView android:id="@+id/timeDisplayBackground"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:singleLine="true"
-                android:ellipsize="none"
-                android:textSize="56sp"
-                android:textAppearance="?android:attr/textAppearanceMedium"
-                android:layout_marginBottom="6dip"
-                android:textColor="@color/lockscreen_clock_background"
-                />
+    </com.android.internal.widget.DigitalClock>
 
-            <TextView android:id="@+id/timeDisplayForeground"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:singleLine="true"
-                android:ellipsize="none"
-                android:textSize="56sp"
-                android:textAppearance="?android:attr/textAppearanceMedium"
-                android:layout_marginBottom="6dip"
-                android:textColor="@color/lockscreen_clock_foreground"
-                />
-
-            <TextView android:id="@+id/am_pm"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_toRightOf="@id/timeDisplayBackground"
-                android:layout_alignBaseline="@id/timeDisplayBackground"
-                android:singleLine="true"
-                android:ellipsize="none"
-                android:textSize="18sp"
-                android:layout_marginLeft="4dip"
-                android:textAppearance="?android:attr/textAppearanceMedium"
-                android:textColor="@color/lockscreen_clock_am_pm"
-                />
-
-        </com.android.internal.widget.DigitalClock>
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="right">
 
         <TextView
             android:id="@+id/date"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_below="@id/time"
-            android:layout_marginLeft="24dip"
             android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textSize="@*android:dimen/keyguard_pattern_unlock_status_line_font_size"
             />
 
-    </RelativeLayout>
-
-    <View
-        android:id="@+id/divider"
-        android:layout_width="match_parent"
-        android:layout_height="1dip"
-        android:layout_marginTop="8dip"
-        android:layout_marginBottom="8dip"
-        android:background="@android:drawable/divider_horizontal_dark"
-        />
-
-    <!-- used for instructions such as "draw pattern to unlock", the next alarm, and charging
-         status.  -->
-    <LinearLayout
-        android:orientation="horizontal"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="0dip"
-        android:layout_marginLeft="12dip"
-        android:gravity="left"
-        >
-        <!-- TODO: Redo layout when we release on phones -->
         <TextView
             android:id="@+id/alarm_status"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:layout_marginLeft="16dip"
             android:textAppearance="?android:attr/textAppearanceMedium"
-            android:textSize="18sp"
+            android:textSize="@*android:dimen/keyguard_pattern_unlock_status_line_font_size"
             android:drawablePadding="4dip"
             />
-        <TextView
-            android:id="@+id/status1"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:textAppearance="?android:attr/textAppearanceMedium"
-            android:textSize="18sp"
-            android:drawablePadding="4dip"
-            />
-        <TextView
-            android:id="@+id/statusSep"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginLeft="5dip"
-            android:layout_marginRight="5dip"
-            android:textAppearance="?android:attr/textAppearanceMedium"
-            android:textSize="18sp"
-            />
-        <TextView
-            android:id="@+id/status2"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_alignParentTop="true"
-            android:textAppearance="?android:attr/textAppearanceMedium"
-            android:textSize="18sp"
-            android:drawablePadding="4dip"
-            />
+
     </LinearLayout>
 
+
+    <TextView
+        android:id="@+id/status1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textSize="@*android:dimen/keyguard_pattern_unlock_status_line_font_size"
+        android:drawablePadding="4dip"
+        android:layout_gravity="right"
+        />
+
+    <TextView
+        android:id="@+id/status2"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textSize="@*android:dimen/keyguard_pattern_unlock_status_line_font_size"
+        android:drawablePadding="4dip"
+        android:layout_gravity="right"
+        android:visibility="gone"
+        />
+
     <com.android.internal.widget.LockPatternView
         android:id="@+id/lockPattern"
-        android:layout_width="match_parent"
-        android:layout_height="0dip"
-        android:layout_weight="1"
-        android:layout_marginTop="2dip"
-        android:aspect="@string/lock_pattern_view_aspect"
-         />
+        android:layout_width="300dip"
+        android:layout_height="300dip"
+        android:layout_rowWeight="1"
+        android:layout_marginTop="8dip"
+        android:layout_marginRight="8dip"
+        android:layout_marginBottom="4dip"
+        android:layout_marginLeft="8dip"
+     />
 
-    <!-- footer -->
-    <FrameLayout
+    <TextView
+        android:id="@+id/carrier"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        android:singleLine="true"
+        android:ellipsize="marquee"
+        android:textSize="@*android:dimen/keyguard_pattern_unlock_status_line_font_size"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+    />
+
+    <!-- Footer: an emergency call button and an initially hidden "Forgot pattern" button -->
+    <LinearLayout
+        android:orientation="horizontal"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        >
+        android:layout_gravity="center">
 
-        <!-- option 1: a single emergency call button -->
-        <RelativeLayout android:id="@+id/footerNormal"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            >
-            <Button android:id="@+id/emergencyCallAlone"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_centerInParent="true"
-                android:text="@string/lockscreen_emergency_call"
-                style="@style/Widget.Button.Transparent"
-                android:drawableLeft="@drawable/ic_emergency"
-                android:drawablePadding="8dip"
-                />
+        <Button android:id="@+id/emergencyCallButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_horizontal"
+            style="@style/Widget.Button.Transparent"
+            android:textSize="@dimen/keyguard_pattern_unlock_status_line_font_size"
+            android:text="@string/lockscreen_emergency_call"
+            android:drawableLeft="@drawable/lockscreen_emergency_button"
+            android:drawablePadding="0dip"
+        />
 
-        </RelativeLayout>
+        <Button android:id="@+id/forgotPatternButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_horizontal"
+            style="@style/Widget.Button.Transparent"
+            android:textSize="@dimen/keyguard_pattern_unlock_status_line_font_size"
+            android:text="@string/lockscreen_forgot_pattern_button_text"
+            android:drawableLeft="@drawable/lockscreen_forgot_password_button"
+            android:drawablePadding="0dip"
+        />
 
-        <!-- option 2: an emergency call button, and a 'forgot pattern?' button -->
-        <LinearLayout android:id="@+id/footerForgotPattern"
-            android:orientation="horizontal"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:gravity="center"
-            >
-            <Button android:id="@+id/emergencyCallTogether"
-                android:layout_width="0dip"
-                android:layout_height="match_parent"
-                android:layout_weight="1.0"
-                android:layout_marginTop="4dip"
-                android:layout_marginBottom="4dip"
-                android:layout_marginLeft="4dip"
-                android:layout_marginRight="2dip"
-                android:text="@string/lockscreen_emergency_call"
-                style="@style/Widget.Button.Transparent"
-                android:drawableLeft="@drawable/ic_emergency"
-                android:drawablePadding="8dip"
-                />
-            <Button android:id="@+id/forgotPattern"
-                android:layout_width="0dip"
-                android:layout_height="match_parent"
-                android:layout_weight="1.0"
-                android:layout_marginTop="4dip"
-                android:layout_marginBottom="4dip"
-                android:layout_marginLeft="2dip"
-                android:layout_marginRight="4dip"
-                style="@style/Widget.Button.Transparent"
-                android:visibility="invisible"
-                />
-        </LinearLayout>
+    </LinearLayout>
 
-    </FrameLayout>
-
-</com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
+</GridLayout>
diff --git a/core/res/res/layout/preference_widget_seekbar.xml b/core/res/res/layout/preference_widget_seekbar.xml
new file mode 100644
index 0000000..e4cf86d
--- /dev/null
+++ b/core/res/res/layout/preference_widget_seekbar.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- Layout for a Preference in a PreferenceActivity. The
+     Preference is able to place a specific widget for its particular
+     type in the "widget_frame" layout. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:gravity="center_vertical"
+    android:paddingRight="?android:attr/scrollbarSize">
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:gravity="center"
+        android:minWidth="@dimen/preference_icon_minWidth"
+        android:orientation="horizontal">
+        <ImageView
+            android:id="@+android:id/icon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:minWidth="48dp"
+            />
+    </LinearLayout>
+
+    <RelativeLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="16dip"
+        android:layout_marginRight="8dip"
+        android:layout_marginTop="6dip"
+        android:layout_marginBottom="6dip"
+        android:layout_weight="1">
+
+        <TextView android:id="@+android:id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal" />
+
+        <TextView android:id="@+android:id/summary"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@android:id/title"
+            android:layout_alignLeft="@android:id/title"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:textColor="?android:attr/textColorSecondary"
+            android:maxLines="4" />
+
+        <!-- Preference should place its actual preference widget here. -->
+        <LinearLayout android:id="@+android:id/widget_frame"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_below="@android:id/summary"
+            android:layout_alignLeft="@android:id/title"
+            android:minWidth="@dimen/preference_widget_width"
+            android:gravity="center"
+            android:orientation="vertical" />
+
+        <SeekBar android:id="@+android:id/seekbar"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_below="@android:id/summary"
+            android:layout_toRightOf="@android:id/widget_frame"
+            android:layout_alignParentRight="true" />
+
+    </RelativeLayout>
+
+</LinearLayout>
diff --git a/core/res/res/layout/select_dialog_holo.xml b/core/res/res/layout/select_dialog_holo.xml
index 7c95693..06a5d96 100644
--- a/core/res/res/layout/select_dialog_holo.xml
+++ b/core/res/res/layout/select_dialog_holo.xml
@@ -27,9 +27,6 @@
     android:id="@+android:id/select_dialog_listview"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:layout_marginTop="5dip"
-    android:paddingLeft="16dip"
-    android:paddingRight="16dip"
     android:cacheColorHint="@null"
     android:divider="?android:attr/listDividerAlertDialog"
     android:scrollbars="vertical"
diff --git a/core/res/res/layout/select_dialog_item_holo.xml b/core/res/res/layout/select_dialog_item_holo.xml
index 396092e..0c700cf 100644
--- a/core/res/res/layout/select_dialog_item_holo.xml
+++ b/core/res/res/layout/select_dialog_item_holo.xml
@@ -26,7 +26,7 @@
     android:id="@android:id/text1"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall"
     android:textAppearance="?android:attr/textAppearanceMedium"
     android:textColor="?android:attr/textColorAlertDialogListItem"
     android:gravity="center_vertical"
diff --git a/core/res/res/layout/select_dialog_multichoice_holo.xml b/core/res/res/layout/select_dialog_multichoice_holo.xml
index 8027035..683151c 100644
--- a/core/res/res/layout/select_dialog_multichoice_holo.xml
+++ b/core/res/res/layout/select_dialog_multichoice_holo.xml
@@ -18,7 +18,7 @@
     android:id="@android:id/text1"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall"
     android:textAppearance="?android:attr/textAppearanceMedium"
     android:textColor="?android:attr/textColorAlertDialogListItem"
     android:gravity="center_vertical"
diff --git a/core/res/res/layout/select_dialog_singlechoice_holo.xml b/core/res/res/layout/select_dialog_singlechoice_holo.xml
index cab519f..52782d0 100644
--- a/core/res/res/layout/select_dialog_singlechoice_holo.xml
+++ b/core/res/res/layout/select_dialog_singlechoice_holo.xml
@@ -18,7 +18,7 @@
     android:id="@android:id/text1"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall"
     android:textAppearance="?android:attr/textAppearanceMedium"
     android:textColor="?android:attr/textColorAlertDialogListItem"
     android:gravity="center_vertical"
diff --git a/core/res/res/layout/status_bar_latest_event_content.xml b/core/res/res/layout/status_bar_latest_event_content.xml
index 676c38b..0dc6741 100644
--- a/core/res/res/layout/status_bar_latest_event_content.xml
+++ b/core/res/res/layout/status_bar_latest_event_content.xml
@@ -1,4 +1,5 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/status_bar_latest_event_content"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     >
@@ -8,41 +9,9 @@
         android:background="@drawable/notify_panel_notification_icon_bg"
         android:scaleType="center"
         />
-    <LinearLayout
-        android:layout_width="0dp"
+    <include layout="@layout/status_bar_latest_event_content_large_icon" 
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical"
-        android:layout_weight="1"
-        android:orientation="vertical"
-        android:paddingLeft="16dp"
-        >
-        <TextView android:id="@+id/title"
-            android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:singleLine="true"
-            android:ellipsize="marquee"
-            android:fadingEdge="horizontal"
-            android:layout_marginBottom="-3dp"
-            />
-        <TextView android:id="@+id/text"
-            android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_weight="1"
-            android:layout_marginTop="-2dp"
-            android:singleLine="true"
-            android:ellipsize="marquee"
-            android:fadingEdge="horizontal"
-            />
-    </LinearLayout>
-    <TextView android:id="@+id/info"
-        android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:singleLine="true"
-        android:gravity="center_vertical"
-        android:paddingLeft="8dp"
+        android:layout_gravity="center"
         />
 </LinearLayout>
-
diff --git a/core/res/res/layout/status_bar_latest_event_content_large_icon.xml b/core/res/res/layout/status_bar_latest_event_content_large_icon.xml
index ebdaaa3..d937392 100644
--- a/core/res/res/layout/status_bar_latest_event_content_large_icon.xml
+++ b/core/res/res/layout/status_bar_latest_event_content_large_icon.xml
@@ -1,50 +1,65 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/status_bar_latest_event_content_large_icon"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center"
+    android:orientation="vertical"
+    android:paddingLeft="8dp"
+    android:paddingRight="8dp"
     >
-    <LinearLayout
-        android:layout_width="0dp"
+    <TextView android:id="@+id/title"
+        android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical"
-        android:layout_weight="1"
-        android:orientation="vertical"
-        android:paddingLeft="16dp"
+        android:singleLine="true"
+        android:ellipsize="marquee"
+        android:fadingEdge="horizontal"
+        />
+    <TextView android:id="@+id/text2"
+        android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="-2dp"
+        android:layout_marginBottom="-2dp"
+        android:singleLine="true"
+        android:fadingEdge="horizontal"
+        android:ellipsize="marquee"
+        android:visibility="gone"
+        android:alpha="0.7"
+        />
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:alpha="0.7"
         >
-        <TextView android:id="@+id/title"
-            android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:singleLine="true"
-            android:ellipsize="marquee"
-            android:fadingEdge="horizontal"
-            android:layout_marginBottom="-3dp"
-            />
         <TextView android:id="@+id/text"
             android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-            android:layout_width="match_parent"
+            android:layout_width="0dp"
             android:layout_height="wrap_content"
             android:layout_weight="1"
-            android:layout_marginTop="-2dp"
+            android:layout_gravity="center"
             android:singleLine="true"
             android:ellipsize="marquee"
             android:fadingEdge="horizontal"
             />
+        <TextView android:id="@+id/info"
+            android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:layout_weight="0"
+            android:singleLine="true"
+            android:gravity="center"
+            android:paddingLeft="8dp"
+            />
+        <ImageView android:id="@+id/icon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:layout_weight="0"
+            android:scaleType="center"
+            android:paddingLeft="8dp"
+            />
     </LinearLayout>
-    <TextView android:id="@+id/info"
-        android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:singleLine="true"
-        android:gravity="center_vertical"
-        android:paddingLeft="4dp"
-        android:paddingRight="4dp"
-        />
-    <ImageView android:id="@+id/icon"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="bottom"
-        android:layout_marginBottom="13dip"
-        android:scaleType="center"
-        />
 </LinearLayout>
-
diff --git a/core/res/res/values-de/donottranslate-cldr.xml b/core/res/res/values-de/donottranslate-cldr.xml
index fffcf26..6b4bf5c 100644
--- a/core/res/res/values-de/donottranslate-cldr.xml
+++ b/core/res/res/values-de/donottranslate-cldr.xml
@@ -31,7 +31,7 @@
     <string name="month_medium_february">Feb.</string>
     <string name="month_medium_march">Mär.</string>
     <string name="month_medium_april">Apr.</string>
-    <string name="month_medium_may">Mai.</string>
+    <string name="month_medium_may">Mai</string>
     <string name="month_medium_june">Jun.</string>
     <string name="month_medium_july">Jul.</string>
     <string name="month_medium_august">Aug.</string>
diff --git a/core/res/res/values-h720dp/dimens.xml b/core/res/res/values-h720dp/dimens.xml
index c09cb5b..37dee8e 100644
--- a/core/res/res/values-h720dp/dimens.xml
+++ b/core/res/res/values-h720dp/dimens.xml
@@ -17,8 +17,6 @@
 */
 -->
 <resources>
-    <!-- Dialog title height -->
-    <dimen name="alert_dialog_title_height">54dip</dimen>
     <!-- Dialog button bar height -->
     <dimen name="alert_dialog_button_bar_height">54dip</dimen>
     <!-- Preference fragment padding, bottom -->
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index f17a272..b87e99e 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -190,6 +190,8 @@
     <string name="permdesc_receiveSms" msgid="6298292335965966117">"Aplikaciji omogućuje primanje i obradu SMS poruka. Zlonamjerne aplikacije mogu pratiti vaše poruke ili ih izbrisati prije nego što ih vi vidite."</string>
     <string name="permlab_receiveMms" msgid="8894700916188083287">"primanje MMS-a"</string>
     <string name="permdesc_receiveMms" msgid="4563346832000174373">"Aplikaciji omogućuje primanje i obradu MMS poruka. Zlonamjerne aplikacije mogu pratiti vaše poruke ili ih izbrisati prije nego što ih vi vidite."</string>
+    <string name="permlab_receiveEmergencyBroadcast" msgid="1803477660846288089">"primanje hitnih odašiljanja"</string>
+    <string name="permdesc_receiveEmergencyBroadcast" msgid="7118393393716546131">"Omogućuje aplikaciji primanje i obradu poruka hitnih odašiljanja. Ta je dozvola dostupna samo aplikacijama sustava."</string>
     <string name="permlab_sendSms" msgid="5600830612147671529">"slanje SMS poruka"</string>
     <string name="permdesc_sendSms" msgid="1946540351763502120">"Aplikaciji omogućuje slanje SMS poruka. Zlonamjerne aplikacije mogu stvarati troškove slanjem poruka bez vaše potvrde."</string>
     <string name="permlab_readSms" msgid="4085333708122372256">"čitanje SMS-a ili MMS-a"</string>
diff --git a/core/res/res/values-land/dimens.xml b/core/res/res/values-land/dimens.xml
index dbaad13..b8ce9b4 100644
--- a/core/res/res/values-land/dimens.xml
+++ b/core/res/res/values-land/dimens.xml
@@ -32,4 +32,7 @@
     <!-- Default height of an action bar. -->
     <dimen name="action_bar_default_height">40dip</dimen>
 
+    <!-- Size of clock font in LockScreen. -->
+    <dimen name="keyguard_pattern_unlock_clock_font_size">80sp</dimen>
+
 </resources>
diff --git a/core/res/res/values-sw600dp/dimens.xml b/core/res/res/values-sw600dp/dimens.xml
index df1597c..150b6d4 100644
--- a/core/res/res/values-sw600dp/dimens.xml
+++ b/core/res/res/values-sw600dp/dimens.xml
@@ -24,5 +24,12 @@
     <dimen name="status_bar_icon_size">32dip</dimen>
     <!-- Size of the giant number (unread count) in the notifications -->
     <dimen name="status_bar_content_number_size">48sp</dimen>
+
+    <!-- Size of clock font in LockScreen. -->
+    <dimen name="keyguard_pattern_unlock_clock_font_size">98sp</dimen>
+
+    <!-- Size of status line font in LockScreen. -->
+    <dimen name="keyguard_pattern_unlock_status_line_font_size">14sp</dimen>
+
 </resources>
 
diff --git a/core/res/res/values-sw600dp/styles.xml b/core/res/res/values-sw600dp/styles.xml
index 7515c98..645db13 100644
--- a/core/res/res/values-sw600dp/styles.xml
+++ b/core/res/res/values-sw600dp/styles.xml
@@ -15,27 +15,6 @@
 -->
 
 <resources>
-    <!-- Status Bar Styles -->
-
-    <style name="TextAppearance.StatusBar">
-        <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
-    </style>
-    <style name="TextAppearance.StatusBar.Ticker">
-    </style>
-    <style name="TextAppearance.StatusBar.Title">
-        <item name="android:textStyle">bold</item>
-    </style>
-
-    <style name="TextAppearance.StatusBar.Icon">
-    </style>
-    <style name="TextAppearance.StatusBar.EventContent">
-        <item name="android:textColor">#ff999999</item>
-        <item name="android:textSize">14sp</item>
-    </style>
-    <style name="TextAppearance.StatusBar.EventContent.Title">
-        <item name="android:textColor">?android:attr/textColorPrimary</item>
-    </style>
-
     <style name="TextAppearance.Holo.Widget.TabWidget">
         <item name="android:textSize">18sp</item>
         <item name="android:textStyle">normal</item>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 5d357c5..a59af1a 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -202,9 +202,14 @@
 
         <!-- The preferred list item height. -->
         <attr name="listPreferredItemHeight" format="dimension" />
-        <!-- The drawable for the list divider. -->
+        <!-- A smaller, sleeker list item height. -->
+        <attr name="listPreferredItemHeightSmall" format="dimension" />
+        <!-- A larger, more robust list item height. -->
+        <attr name="listPreferredItemHeightLarge" format="dimension" />
         <!-- The list item height for search results. @hide -->
         <attr name="searchResultListItemHeight" format="dimension" />
+
+        <!-- The drawable for the list divider. -->
         <attr name="listDivider" format="reference" />
         <!-- The list divider used in alert dialogs. -->
         <attr name="listDividerAlertDialog" format="reference" />
@@ -1133,9 +1138,9 @@
              edge, a right gravity will clip the left edge, and neither will clip both edges. -->
         <flag name="clip_horizontal" value="0x08" />
         <!-- Push object to the beginning of its container, not changing its size. -->
-        <flag name="before" value="0x00800003" />
+        <flag name="start" value="0x00800003" />
         <!-- Push object to the end of its container, not changing its size. -->
-        <flag name="after" value="0x00800005" />
+        <flag name="end" value="0x00800005" />
     </attr>
 
     <!-- Controls whether links such as urls and email addresses are
@@ -1206,6 +1211,16 @@
         <enum name="vertical" value="1" />
     </attr>
 
+    <!-- Alignment constants. -->
+    <attr name="alignmentMode">
+        <!-- Align the bounds of the children.
+        See {@link android.widget.GridLayout#ALIGN_BOUNDS}. -->
+        <enum name="alignBounds" value="0" />
+        <!-- Align the margins of the children.
+        See {@link android.widget.GridLayout#ALIGN_MARGINS}. -->
+        <enum name="alignMargins" value="1" />
+    </attr>
+
     <!-- ========================== -->
     <!-- Key Codes                  -->
     <!-- ========================== -->
@@ -2541,12 +2556,12 @@
         The default value is false.
         See {@link android.widget.GridLayout#setUseDefaultMargins(boolean)}.-->
         <attr name="useDefaultMargins" format="boolean" />
-        <!-- When set to true, causes alignment to take place between the outer
-        boundary of a view, as defined by its margins. When set to false,
+        <!-- When set to alignMargins, causes alignment to take place between the outer
+        boundary of a view, as defined by its margins. When set to alignBounds,
         causes alignment to take place between the edges of the view.
-        The default is true.
-        See {@link android.widget.GridLayout#setMarginsIncludedInAlignment(boolean)}.-->
-        <attr name="marginsIncludedInAlignment" format="boolean" />
+        The default is alignMargins.
+        See {@link android.widget.GridLayout#setAlignmentMode(int)}.-->
+        <attr name="alignmentMode" />
         <!-- When set to true, forces row boundaries to appear in the same order
         as row indices.
         The default is false.
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 6529fe1..e76c0e5 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -148,5 +148,14 @@
 
     <color name="group_button_dialog_pressed_holo_light">#ffffffff</color>
     <color name="group_button_dialog_focused_holo_light">#4699cc00</color>
+
+    <!-- General purpose colors for Holo-themed elements -->
+    <eat-comment />
+
+    <!-- A Holo shade of blue -->
+    <color name="holo_blue">#ff6699ff</color>
+    <!-- A Holo shade of green -->
+    <color name="holo_green">#ff99cc00</color>
+
 </resources>
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 3b4798e..52b00c6 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -82,7 +82,7 @@
     <!-- The maximum width we would prefer dialogs to be.  0 if there is no
          maximum (let them grow as large as the screen).  Actual values are
          specified for -large and -xlarge configurations. -->
-    <dimen name="config_prefDialogWidth">0px</dimen>
+    <dimen name="config_prefDialogWidth">320dp</dimen>
     
     <!-- Whether dialogs should close automatically when the user touches outside
          of them.  This should not normally be modified. -->
@@ -389,9 +389,11 @@
     <!-- Control the behavior when the user long presses the power button.
             0 - Nothing
             1 - Recent apps dialog
-            2 - Recent apps activity in SystemUI
+            2 - Recent apps view in SystemUI
+         This needs to match the constants in
+         policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
     -->
-    <integer name="config_longPressOnHomeBehavior">1</integer>
+    <integer name="config_longPressOnHomeBehavior">2</integer>
 
     <!-- Array of light sensor LUX values to define our levels for auto backlight brightness support.
          The N entries of this array define N + 1 zones as follows:
@@ -633,4 +635,23 @@
 
     <!-- Set to true if the RSSI should always display CDMA signal strength even on EVDO -->
     <bool name="config_alwaysUseCdmaRssi">false</bool>
+
+
+    <!-- If this value is true, duplicate Source/Destination port fields
+         in WDP header of some carriers OMADM wap push are supported.
+         ex: MSGTYPE-TotalSegments-CurrentSegment
+             -SourcePortDestPort-SourcePortDestPort-OMADM PDU
+         If false, not supported. -->
+    <bool name="config_duplicate_port_omadm_wappush">false</bool>
+
+    <!-- Maximum numerical value that will be shown in a status bar
+         notification icon or in the notification itself. Will be replaced
+         with @string/status_bar_notification_info_overflow when shown in the
+         UI. -->
+    <integer name="status_bar_notification_info_maxnum">999</integer>
+
+    <!-- Path to an ISO image to be shared with via USB mass storage.
+         This is intended to allow packaging drivers or tools for installation on a PC. -->
+    <string translatable="false" name="config_isoImagePath"></string>
+
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index df22f15..20cb852 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -111,7 +111,7 @@
     <dimen name="search_view_text_min_width">160dip</dimen>
 
     <!-- Dialog title height -->
-    <dimen name="alert_dialog_title_height">48dip</dimen>
+    <dimen name="alert_dialog_title_height">64dip</dimen>
     <!-- Dialog button bar height -->
     <dimen name="alert_dialog_button_bar_height">48dip</dimen>
 
@@ -119,4 +119,14 @@
     <dimen name="action_bar_default_height">48dip</dimen>
     <!-- Vertical padding around action bar icons. -->
     <dimen name="action_bar_icon_vertical_padding">4dip</dimen>
+
+    <!-- Size of clock font in LockScreen. -->
+    <dimen name="keyguard_pattern_unlock_clock_font_size">80sp</dimen>
+
+    <!-- Size of status line font in LockScreen. -->
+    <dimen name="keyguard_pattern_unlock_status_line_font_size">14sp</dimen>
+
+    <!-- Size of right margin in LockScreen -->
+    <dimen name="keyguard_pattern_unlock_status_line_font_right_margin">20dip</dimen>
+
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 17b23da..e02496c 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1733,7 +1733,7 @@
   <public type="attr" name="columnCount" />
   <public type="attr" name="columnOrderPreserved" />
   <public type="attr" name="useDefaultMargins" />
-  <public type="attr" name="marginsIncludedInAlignment" />
+  <public type="attr" name="alignmentMode" />
 
   <public type="attr" name="layout_row" />
   <public type="attr" name="layout_rowSpan" />
@@ -1766,5 +1766,13 @@
   <public type="attr" name="feedbackCount" />
   <public type="attr" name="verticalOffset" />
   <public type="attr" name="horizontalOffset" />
+  <public type="attr" name="listPreferredItemHeightLarge" />
+  <public type="attr" name="listPreferredItemHeightSmall" />
+
+  <public type="style" name="Widget.Holo.Button.Borderless.Small" />
+  <public type="style" name="Widget.Holo.Light.Button.Borderless.Small" />
+
+  <public type="integer" name="status_bar_notification_info_maxnum" />
+  <public type="string" name="status_bar_notification_info_overflow" />
 
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 5e13282..b5f4084 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -339,10 +339,12 @@
     <!-- status message in phone options dialog for when airplane mode is off -->
     <string name="global_actions_airplane_mode_off_status">Airplane mode is OFF</string>
 
-    <!-- Text to use when the number in a notification info is too large (> 100).  Most likely does not need
-    to be translated.  We do this so, for example, if the user has tens of thousands of unread
-    emails, the whole notification isn't taken over by the number. [CHAR LIMIT=5] -->
-    <string name="status_bar_notification_info_overflow">100+</string>
+    <!-- Text to use when the number in a notification info is too large
+         (greater than status_bar_notification_info_maxnum, defined in
+         values/config.xml) and must be truncated. May need to be localized
+         for most appropriate textual indicator of "more than X".
+         [CHAR LIMIT=4] -->
+    <string name="status_bar_notification_info_overflow">999+</string>
 
     <!-- Displayed to the user to tell them that they have started up the phone in "safe mode" -->
     <string name="safeMode">Safe mode</string>
@@ -901,16 +903,16 @@
         contact (address) data stored on your phone. Malicious
         applications can use this to erase or modify your contact data.</string>
 
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <!-- Title of the read profile permission, listed so the user can decide whether to allow the application to read the user's personal profile data. [CHAR LIMIT=30] -->
     <string name="permlab_readProfile">read profile data</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <!-- Description of the read profile permission, listed so the user can decide whether to allow the application to read the user's personal profile data. [CHAR LIMIT=NONE] -->
     <string name="permdesc_readProfile" product="default">Allows an application to read all
         of your personal profile information. Malicious applications can use this to identify
         you and send your personal information to other people.</string>
 
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <!-- Title of the write profile permission, listed so the user can decide whether to allow the application to write to the user's personal profile data. [CHAR LIMIT=30] -->
     <string name="permlab_writeProfile">write profile data</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <!-- Description of the write profile permission, listed so the user can decide whether to allow the application to write to the user's personal profile data. [CHAR LIMIT=NONE] -->
     <string name="permdesc_writeProfile" product="default">Allows an application to modify
         your personal profile information. Malicious applications can use this to erase or
         modify your profile data.</string>
@@ -1790,6 +1792,9 @@
     <string name="lockscreen_missing_sim_instructions">Please insert a SIM card.</string>
     <!-- Shown in the lock screen to ask the user to insert a SIM card when sim is missing or not readable. -->
     <string name="lockscreen_missing_sim_instructions_long">The SIM card is missing or not readable. Please insert a SIM card.</string>
+    <!-- Shown in the lock screen to inform the user to SIM card is permanently disabled. -->
+    <string name="lockscreen_permanent_disabled_sim_instructions">Your SIM card is permanently disabled.\n
+    Please contact your wireless service provider to obtain another SIM card.</string>
 
     <!-- Shown in the lock screen when there is emergency calls only mode. -->
     <string name="emergency_calls_only" msgid="2485604591272668370">Emergency calls only</string>
@@ -2603,6 +2608,11 @@
     <!-- USB_STORAGE_ERROR dialog  ok button-->
     <string name="dlg_ok">OK</string>
 
+    <!-- USB_PREFERENCES: When the user connects the phone to a computer via USB, we show a notification asking if he wants to share files across.  This is the title -->
+    <string name="usb_preferences_notification_title">USB connected</string>
+    <!-- See USB_PREFERENCES. This is the message. -->
+    <string name="usb_preferece_notification_message">Select to configure USB file transfer.</string>
+
     <!-- External media format dialog strings -->
     <!-- This is the label for the activity, and should never be visible to the user. -->
     <!-- See EXTMEDIA_FORMAT.  EXTMEDIA_FORMAT_DIALOG:  After the user selects the notification, a dialog is shown asking if he wants to format the SD card.  This is the title. [CHAR LIMIT=20] -->
@@ -2774,11 +2784,13 @@
     <string name="l2tp_ipsec_crt_vpn_description">Certificate based L2TP/IPSec VPN</string>
 
     <!-- Ticker text to show when VPN is active. -->
-    <string name="vpn_ticker">Activating <xliff:g id="app">%s</xliff:g> VPN...</string>
+    <string name="vpn_ticker"><xliff:g id="app" example="FooVPN client">%s</xliff:g> is activating VPN...</string>
     <!-- The title of the notification when VPN is active. -->
-    <string name="vpn_title"><xliff:g id="app">%s</xliff:g> VPN is active</string>
+    <string name="vpn_title">VPN is activated by <xliff:g id="app" example="FooVPN client">%s</xliff:g></string>
     <!-- The text of the notification when VPN is active. -->
-    <string name="vpn_text">VPN is connected to <xliff:g id="profile">%s</xliff:g>. Tap to manage the network.</string>
+    <string name="vpn_text">Tap to manage the network.</string>
+    <!-- The text of the notification when VPN is active with a session name. -->
+    <string name="vpn_text_long">Connected to <xliff:g id="session" example="office">%s</xliff:g>. Tap to manage the network.</string>
 
     <!-- Localized strings for WebView -->
     <!-- Label for button in a WebView that will open a chooser to choose a file to upload -->
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 19b05c9..72a5797 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -227,15 +227,15 @@
     <style name="TextAppearance.StatusBar.Icon">
     </style>
     <style name="TextAppearance.StatusBar.EventContent">
-        <item name="android:textColor">#ff999999</item>
-        <item name="android:textSize">14sp</item>
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
+        <item name="android:textSize">13sp</item>
     </style>
     <style name="TextAppearance.StatusBar.EventContent.Title">
-        <item name="android:textColor">?android:attr/textColorPrimary</item>
+        <item name="android:textSize">16sp</item>
+        <item name="android:textStyle">bold</item>
     </style>
     <style name="TextAppearance.StatusBar.EventContent.Info">
-        <item name="android:textAppearance">?android:attr/textAppearanceLarge</item>
-        <item name="android:textColor">#ff272727</item>
+        <item name="android:textSize">13sp</item>
     </style>
 
     <style name="TextAppearance.Small.CalendarViewWeekDayView">
@@ -1321,7 +1321,8 @@
     </style>
 
     <style name="TextAppearance.Holo.DialogWindowTitle">
-        <item name="android:textSize">18sp</item>
+        <item name="android:textSize">22sp</item>
+        <item name="android:textColor">@android:color/holo_blue</item>
     </style>
 
     <style name="TextAppearance.Holo.CalendarViewWeekDayView" parent="TextAppearance.Small.CalendarViewWeekDayView">
@@ -1419,7 +1420,8 @@
     </style>
 
     <style name="TextAppearance.Holo.Light.DialogWindowTitle">
-        <item name="android:textSize">18sp</item>
+        <item name="android:textSize">22sp</item>
+        <item name="android:textColor">@android:color/holo_blue</item>
     </style>
 
     <style name="TextAppearance.Holo.Light.CalendarViewWeekDayView" parent="TextAppearance.Small.CalendarViewWeekDayView">
@@ -1448,6 +1450,12 @@
 
     <style name="Widget.Holo.Button.Borderless">
         <item name="android:background">?android:attr/selectableItemBackground</item>
+        <item name="android:paddingLeft">4dip</item>
+        <item name="android:paddingRight">4dip</item>
+    </style>
+
+    <style name="Widget.Holo.Button.Borderless.Small">
+        <item name="android:textSize">14sp</item>
     </style>
 
     <style name="Widget.Holo.Button.Small">
@@ -1488,6 +1496,7 @@
 
     <style name="Holo.ButtonBar.AlertDialog">
         <item name="android:background">@null</item>
+        <item name="android:dividerPadding">0dp</item>
     </style>
 
     <style name="Widget.Holo.TextView" parent="Widget.TextView">
@@ -1864,6 +1873,12 @@
 
     <style name="Widget.Holo.Light.Button.Borderless">
         <item name="android:background">?android:attr/selectableItemBackground</item>
+        <item name="android:paddingLeft">4dip</item>
+        <item name="android:paddingRight">4dip</item>
+    </style>
+
+    <style name="Widget.Holo.Light.Button.Borderless.Small">
+        <item name="android:textSize">14sp</item>
     </style>
 
     <style name="Widget.Holo.Light.Button.Small">
@@ -1891,6 +1906,7 @@
 
     <style name="Holo.Light.ButtonBar.AlertDialog">
         <item name="android:background">@null</item>
+        <item name="android:dividerPadding">0dp</item>
     </style>
 
     <style name="Holo.Light.SegmentedButton" parent="SegmentedButton">
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 5f77dc5..2ab2c04 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -95,7 +95,9 @@
 
         <!-- List attributes -->
         <item name="listPreferredItemHeight">64dip</item>
-        <item name="dropdownListPreferredItemHeight">64dip</item>
+        <item name="listPreferredItemHeightSmall">?android:attr/listPreferredItemHeight</item>
+        <item name="listPreferredItemHeightLarge">?android:attr/listPreferredItemHeight</item>
+        <item name="dropdownListPreferredItemHeight">?android:attr/listPreferredItemHeight</item>
 
         <!-- @hide -->
         <item name="searchResultListItemHeight">58dip</item>
@@ -861,7 +863,9 @@
 
         <!-- List attributes -->
         <item name="listPreferredItemHeight">64dip</item>
-        <item name="dropdownListPreferredItemHeight">48dip</item>
+        <item name="listPreferredItemHeightSmall">48dip</item>
+        <item name="listPreferredItemHeightLarge">80dip</item>
+        <item name="dropdownListPreferredItemHeight">?android:attr/listPreferredItemHeightSmall</item>
 
         <!-- @hide -->
         <item name="searchResultListItemHeight">58dip</item>
@@ -1150,7 +1154,9 @@
 
         <!-- List attributes -->
         <item name="listPreferredItemHeight">64dip</item>
-        <item name="dropdownListPreferredItemHeight">48dip</item>
+        <item name="listPreferredItemHeightSmall">48dip</item>
+        <item name="listPreferredItemHeightLarge">80dip</item>
+        <item name="dropdownListPreferredItemHeight">?android:attr/listPreferredItemHeightSmall</item>
 
         <!-- @hide -->
         <item name="searchResultListItemHeight">58dip</item>
@@ -1411,6 +1417,7 @@
         <item name="android:colorBackgroundCacheHint">@null</item>
 
         <item name="android:buttonBarStyle">@android:style/Holo.ButtonBar.AlertDialog</item>
+        <item name="borderlessButtonStyle">@android:style/Widget.Holo.Button.Borderless.Small</item>
         
         <item name="textAppearance">@android:style/TextAppearance.Holo</item>
         <item name="textAppearanceInverse">@android:style/TextAppearance.Holo.Inverse</item>
@@ -1420,7 +1427,7 @@
          a regular dialog. -->
     <style name="Theme.Holo.Dialog.MinWidth">
         <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
-        <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_major</item>
+        <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
     </style>
 
     <!-- Variation of Theme.Holo.Dialog that does not include a title bar. -->
@@ -1433,7 +1440,7 @@
          a regular dialog. -->
     <style name="Theme.Holo.Dialog.NoActionBar.MinWidth">
         <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
-        <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_major</item>
+        <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
     </style>
 
     <!-- Variation of Theme.Holo.Dialog that does not include a frame (or background).
@@ -1460,7 +1467,7 @@
         <item name="windowTitleStyle">@android:style/DialogWindowTitle.Holo</item>
         <item name="windowContentOverlay">@null</item>
         <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
-        <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_major</item>
+        <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
     </style>
 
     <!-- Theme for a window that will be displayed either full-screen on
@@ -1499,6 +1506,7 @@
         <item name="android:colorBackgroundCacheHint">@null</item>
 
         <item name="android:buttonBarStyle">@android:style/Holo.Light.ButtonBar.AlertDialog</item>
+        <item name="borderlessButtonStyle">@android:style/Widget.Holo.Light.Button.Borderless.Small</item>
 
         <item name="textAppearance">@android:style/TextAppearance.Holo.Light</item>
         <item name="textAppearanceInverse">@android:style/TextAppearance.Holo.Light.Inverse</item>
@@ -1508,7 +1516,7 @@
          a regular dialog. -->
     <style name="Theme.Holo.Light.Dialog.MinWidth">
         <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
-        <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_major</item>
+        <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
     </style>
 
     <!-- Variation of Theme.Holo.Light.Dialog that does not include a title bar. -->
@@ -1521,7 +1529,7 @@
          a regular dialog. -->
     <style name="Theme.Holo.Light.Dialog.NoActionBar.MinWidth">
         <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
-        <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_major</item>
+        <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
     </style>
 
     <!-- Theme for a window that will be displayed either full-screen on
@@ -1547,7 +1555,7 @@
         <item name="windowTitleStyle">@android:style/DialogWindowTitle.Holo.Light</item>
         <item name="windowContentOverlay">@null</item>
         <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
-        <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_major</item>
+        <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
     </style>
 
     <!-- Default holographic (dark) for windows that want to have the user's selected
diff --git a/core/tests/coretests/src/android/content/res/ConfigurationTest.java b/core/tests/coretests/src/android/content/res/ConfigurationTest.java
deleted file mode 100644
index 54a5e4e..0000000
--- a/core/tests/coretests/src/android/content/res/ConfigurationTest.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * 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 android.content.res;
-
-import java.util.Locale;
-
-import android.test.AndroidTestCase;
-import dalvik.annotation.TestLevel;
-import dalvik.annotation.TestTargetNew;
-
-public class ConfigurationTest extends AndroidTestCase {
-
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        method = "getLayoutDirectionFromLocale",
-        args = {Locale.class}
-    )
-    public void testGetLayoutDirectionFromLocale() {
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(null));
-
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(Locale.ENGLISH));
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(Locale.CANADA));
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(Locale.CANADA_FRENCH));
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(Locale.FRANCE));
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(Locale.FRENCH));
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(Locale.GERMAN));
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(Locale.GERMANY));
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(Locale.ITALIAN));
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(Locale.ITALY));
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(Locale.UK));
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(Locale.US));
-
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(Locale.ROOT));
-
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(Locale.CHINA));
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(Locale.CHINESE));
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(Locale.JAPAN));
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(Locale.JAPANESE));
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(Locale.KOREA));
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(Locale.KOREAN));
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(Locale.PRC));
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(Locale.SIMPLIFIED_CHINESE));
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(Locale.TAIWAN));
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(Locale.TRADITIONAL_CHINESE));
-
-        Locale locale = new Locale("ar");
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(locale));
-        locale = new Locale("ar", "AE");
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(locale));
-        locale = new Locale("ar", "BH");
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(locale));
-        locale = new Locale("ar", "DZ");
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(locale));
-        locale = new Locale("ar", "EG");
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(locale));
-        locale = new Locale("ar", "IQ");
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(locale));
-        locale = new Locale("ar", "JO");
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(locale));
-        locale = new Locale("ar", "KW");
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(locale));
-        locale = new Locale("ar", "LB");
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(locale));
-        locale = new Locale("ar", "LY");
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(locale));
-        locale = new Locale("ar", "MA");
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(locale));
-        locale = new Locale("ar", "OM");
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(locale));
-        locale = new Locale("ar", "QA");
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(locale));
-        locale = new Locale("ar", "SA");
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(locale));
-        locale = new Locale("ar", "SD");
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(locale));
-        locale = new Locale("ar", "SY");
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(locale));
-        locale = new Locale("ar", "TN");
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(locale));
-        locale = new Locale("ar", "YE");
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(locale));
-
-        locale = new Locale("fa");
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(locale));
-        locale = new Locale("fa", "AF");
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(locale));
-        locale = new Locale("fa", "IR");
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(locale));
-
-        locale = new Locale("iw");
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(locale));
-        locale = new Locale("iw", "IL");
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(locale));
-        locale = new Locale("he");
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(locale));
-        locale = new Locale("he", "IL");
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(locale));
-
-        // The following test will not pass until we are able to take care about the scrip subtag
-        // thru having the "likelySubTags" file into ICU4C
-//        locale = new Locale("pa_Arab");
-//        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-//            Configuration.getLayoutDirectionFromLocale(locale));
-//        locale = new Locale("pa_Arab", "PK");
-//        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-//            Configuration.getLayoutDirectionFromLocale(locale));
-
-        locale = new Locale("ps");
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(locale));
-        locale = new Locale("ps", "AF");
-        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-            Configuration.getLayoutDirectionFromLocale(locale));
-
-        // The following test will not work as the localized display name would be "Urdu" with ICU 4.4
-        // We will need ICU 4.6 to get the correct localized display name
-//        locale = new Locale("ur");
-//        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-//            Configuration.getLayoutDirectionFromLocale(locale));
-//        locale = new Locale("ur", "IN");
-//        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-//            Configuration.getLayoutDirectionFromLocale(locale));
-//        locale = new Locale("ur", "PK");
-//        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-//            Configuration.getLayoutDirectionFromLocale(locale));
-
-        // The following test will not pass until we are able to take care about the scrip subtag
-        // thru having the "likelySubTags" file into ICU4C
-//        locale = new Locale("uz_Arab");
-//        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-//            Configuration.getLayoutDirectionFromLocale(locale));
-//        locale = new Locale("uz_Arab", "AF");
-//        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
-//            Configuration.getLayoutDirectionFromLocale(locale));
-    }
-}
diff --git a/core/tests/coretests/src/android/net/NetworkStatsTest.java b/core/tests/coretests/src/android/net/NetworkStatsTest.java
index 5250a7c..3cb64c7 100644
--- a/core/tests/coretests/src/android/net/NetworkStatsTest.java
+++ b/core/tests/coretests/src/android/net/NetworkStatsTest.java
@@ -16,6 +16,8 @@
 
 package android.net;
 
+import static android.net.NetworkStats.TAG_NONE;
+
 import android.test.suitebuilder.annotation.SmallTest;
 
 import junit.framework.TestCase;
@@ -29,14 +31,14 @@
 
     public void testFindIndex() throws Exception {
         final NetworkStats stats = new NetworkStats(TEST_START, 3)
-                .addEntry(TEST_IFACE, 100, 1024, 0)
-                .addEntry(TEST_IFACE, 101, 0, 1024)
-                .addEntry(TEST_IFACE, 102, 1024, 1024);
+                .addEntry(TEST_IFACE, 100, TAG_NONE, 1024L, 0L)
+                .addEntry(TEST_IFACE, 101, TAG_NONE, 0L, 1024L)
+                .addEntry(TEST_IFACE, 102, TAG_NONE, 1024L, 1024L);
 
-        assertEquals(2, stats.findIndex(TEST_IFACE, 102));
-        assertEquals(2, stats.findIndex(TEST_IFACE, 102));
-        assertEquals(0, stats.findIndex(TEST_IFACE, 100));
-        assertEquals(-1, stats.findIndex(TEST_IFACE, 6));
+        assertEquals(2, stats.findIndex(TEST_IFACE, 102, TAG_NONE));
+        assertEquals(2, stats.findIndex(TEST_IFACE, 102, TAG_NONE));
+        assertEquals(0, stats.findIndex(TEST_IFACE, 100, TAG_NONE));
+        assertEquals(-1, stats.findIndex(TEST_IFACE, 6, TAG_NONE));
     }
 
     public void testAddEntryGrow() throws Exception {
@@ -45,15 +47,15 @@
         assertEquals(0, stats.size);
         assertEquals(2, stats.iface.length);
 
-        stats.addEntry(TEST_IFACE, TEST_UID, 1L, 2L);
-        stats.addEntry(TEST_IFACE, TEST_UID, 2L, 2L);
+        stats.addEntry(TEST_IFACE, TEST_UID, TAG_NONE, 1L, 2L);
+        stats.addEntry(TEST_IFACE, TEST_UID, TAG_NONE, 2L, 2L);
 
         assertEquals(2, stats.size);
         assertEquals(2, stats.iface.length);
 
-        stats.addEntry(TEST_IFACE, TEST_UID, 3L, 4L);
-        stats.addEntry(TEST_IFACE, TEST_UID, 4L, 4L);
-        stats.addEntry(TEST_IFACE, TEST_UID, 5L, 5L);
+        stats.addEntry(TEST_IFACE, TEST_UID, TAG_NONE, 3L, 4L);
+        stats.addEntry(TEST_IFACE, TEST_UID, TAG_NONE, 4L, 4L);
+        stats.addEntry(TEST_IFACE, TEST_UID, TAG_NONE, 5L, 5L);
 
         assertEquals(5, stats.size);
         assertTrue(stats.iface.length >= 5);
@@ -65,14 +67,31 @@
         assertEquals(5L, stats.rx[4]);
     }
 
+    public void testCombineExisting() throws Exception {
+        final NetworkStats stats = new NetworkStats(TEST_START, 10);
+
+        stats.addEntry(TEST_IFACE, 1001, TAG_NONE, 512L, 256L);
+        stats.addEntry(TEST_IFACE, 1001, 0xff, 128L, 128L);
+        stats.combineEntry(TEST_IFACE, 1001, TAG_NONE, -128L, -128L);
+
+        assertStatsEntry(stats, 0, TEST_IFACE, 1001, TAG_NONE, 384L, 128L);
+        assertStatsEntry(stats, 1, TEST_IFACE, 1001, 0xff, 128L, 128L);
+
+        // now try combining that should create row
+        stats.combineEntry(TEST_IFACE, 5005, TAG_NONE, 128L, 128L);
+        assertStatsEntry(stats, 2, TEST_IFACE, 5005, TAG_NONE, 128L, 128L);
+        stats.combineEntry(TEST_IFACE, 5005, TAG_NONE, 128L, 128L);
+        assertStatsEntry(stats, 2, TEST_IFACE, 5005, TAG_NONE, 256L, 256L);
+    }
+
     public void testSubtractIdenticalData() throws Exception {
         final NetworkStats before = new NetworkStats(TEST_START, 2)
-                .addEntry(TEST_IFACE, 100, 1024, 0)
-                .addEntry(TEST_IFACE, 101, 0, 1024);
+                .addEntry(TEST_IFACE, 100, TAG_NONE, 1024L, 0L)
+                .addEntry(TEST_IFACE, 101, TAG_NONE, 0L, 1024L);
 
         final NetworkStats after = new NetworkStats(TEST_START, 2)
-                .addEntry(TEST_IFACE, 100, 1024, 0)
-                .addEntry(TEST_IFACE, 101, 0, 1024);
+                .addEntry(TEST_IFACE, 100, TAG_NONE, 1024L, 0L)
+                .addEntry(TEST_IFACE, 101, TAG_NONE, 0L, 1024L);
 
         final NetworkStats result = after.subtract(before);
 
@@ -85,12 +104,12 @@
 
     public void testSubtractIdenticalRows() throws Exception {
         final NetworkStats before = new NetworkStats(TEST_START, 2)
-                .addEntry(TEST_IFACE, 100, 1024, 0)
-                .addEntry(TEST_IFACE, 101, 0, 1024);
+                .addEntry(TEST_IFACE, 100, TAG_NONE, 1024L, 0L)
+                .addEntry(TEST_IFACE, 101, TAG_NONE, 0L, 1024L);
 
         final NetworkStats after = new NetworkStats(TEST_START, 2)
-                .addEntry(TEST_IFACE, 100, 1025, 2)
-                .addEntry(TEST_IFACE, 101, 3, 1028);
+                .addEntry(TEST_IFACE, 100, TAG_NONE, 1025L, 2L)
+                .addEntry(TEST_IFACE, 101, TAG_NONE, 3L, 1028L);
 
         final NetworkStats result = after.subtract(before);
 
@@ -103,13 +122,13 @@
 
     public void testSubtractNewRows() throws Exception {
         final NetworkStats before = new NetworkStats(TEST_START, 2)
-                .addEntry(TEST_IFACE, 100, 1024, 0)
-                .addEntry(TEST_IFACE, 101, 0, 1024);
+                .addEntry(TEST_IFACE, 100, TAG_NONE, 1024L, 0L)
+                .addEntry(TEST_IFACE, 101, TAG_NONE, 0L, 1024L);
 
         final NetworkStats after = new NetworkStats(TEST_START, 3)
-                .addEntry(TEST_IFACE, 100, 1024, 0)
-                .addEntry(TEST_IFACE, 101, 0, 1024)
-                .addEntry(TEST_IFACE, 102, 1024, 1024);
+                .addEntry(TEST_IFACE, 100, TAG_NONE, 1024L, 0L)
+                .addEntry(TEST_IFACE, 101, TAG_NONE, 0L, 1024L)
+                .addEntry(TEST_IFACE, 102, TAG_NONE, 1024L, 1024L);
 
         final NetworkStats result = after.subtract(before);
 
@@ -122,4 +141,13 @@
         assertEquals(1024, result.tx[2]);
     }
 
+    private static void assertStatsEntry(
+            NetworkStats stats, int i, String iface, int uid, int tag, long rx, long tx) {
+        assertEquals(iface, stats.iface[i]);
+        assertEquals(uid, stats.uid[i]);
+        assertEquals(tag, stats.tag[i]);
+        assertEquals(rx, stats.rx[i]);
+        assertEquals(tx, stats.tx[i]);
+    }
+
 }
diff --git a/core/tests/coretests/src/android/util/LocaleUtilTest.java b/core/tests/coretests/src/android/util/LocaleUtilTest.java
new file mode 100644
index 0000000..203781f
--- /dev/null
+++ b/core/tests/coretests/src/android/util/LocaleUtilTest.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2007 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 android.util;
+
+import java.util.Locale;
+
+import android.test.AndroidTestCase;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+
+import static android.util.LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE;
+import static android.util.LocaleUtil.TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE;
+
+public class LocaleUtilTest extends AndroidTestCase {
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "getLayoutDirectionFromLocale",
+        args = {Locale.class}
+    )
+    public void testGetLayoutDirectionFromLocale() {
+        assertEquals(TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE,
+                LocaleUtil.getLayoutDirectionFromLocale(null));
+
+        assertEquals(TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(Locale.ENGLISH));
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(Locale.CANADA));
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(Locale.CANADA_FRENCH));
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(Locale.FRANCE));
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(Locale.FRENCH));
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(Locale.GERMAN));
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(Locale.GERMANY));
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(Locale.ITALIAN));
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(Locale.ITALY));
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(Locale.UK));
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(Locale.US));
+
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(Locale.ROOT));
+
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(Locale.CHINA));
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(Locale.CHINESE));
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(Locale.JAPAN));
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(Locale.JAPANESE));
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(Locale.KOREA));
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(Locale.KOREAN));
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(Locale.PRC));
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(Locale.SIMPLIFIED_CHINESE));
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(Locale.TAIWAN));
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(Locale.TRADITIONAL_CHINESE));
+
+        Locale locale = new Locale("ar");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+        locale = new Locale("ar", "AE");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+        locale = new Locale("ar", "BH");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+        locale = new Locale("ar", "DZ");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+        locale = new Locale("ar", "EG");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+        locale = new Locale("ar", "IQ");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+        locale = new Locale("ar", "JO");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+        locale = new Locale("ar", "KW");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+        locale = new Locale("ar", "LB");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+        locale = new Locale("ar", "LY");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+        locale = new Locale("ar", "MA");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+        locale = new Locale("ar", "OM");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+        locale = new Locale("ar", "QA");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+        locale = new Locale("ar", "SA");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+        locale = new Locale("ar", "SD");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+        locale = new Locale("ar", "SY");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+        locale = new Locale("ar", "TN");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+        locale = new Locale("ar", "YE");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+
+        locale = new Locale("fa");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+        locale = new Locale("fa", "AF");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+        locale = new Locale("fa", "IR");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+
+        locale = new Locale("iw");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+        locale = new Locale("iw", "IL");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+        locale = new Locale("he");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+        locale = new Locale("he", "IL");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+
+        locale = new Locale("pa_Arab");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+        locale = new Locale("pa_Arab", "PK");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+
+        locale = new Locale("ps");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+        locale = new Locale("ps", "AF");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+
+        locale = new Locale("ur");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+        locale = new Locale("ur", "IN");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+        locale = new Locale("ur", "PK");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+
+        locale = new Locale("uz_Arab");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+        locale = new Locale("uz_Arab", "AF");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+
+        // Locale without a real language
+        locale = new Locale("zz");
+        assertEquals(LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
+            LocaleUtil.getLayoutDirectionFromLocale(locale));
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/util/HanziToPinyinTest.java b/core/tests/coretests/src/com/android/internal/util/HanziToPinyinTest.java
deleted file mode 100644
index 36dee70..0000000
--- a/core/tests/coretests/src/com/android/internal/util/HanziToPinyinTest.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.
- * 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.internal.util;
-
-import java.text.Collator;
-import java.util.Arrays;
-import java.util.ArrayList;
-import java.util.Locale;
-
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
-
-import com.android.internal.util.HanziToPinyin;
-import com.android.internal.util.HanziToPinyin.Token;
-
-import junit.framework.TestCase;
-
-public class HanziToPinyinTest extends TestCase {
-    private final static String ONE_HANZI = "\u675C";
-    private final static String TWO_HANZI = "\u675C\u9D51";
-    private final static String ASSIC = "test";
-    private final static String ONE_UNKNOWN = "\uFF71";
-    private final static String MISC = "test\u675C   Test with space\uFF71\uFF71\u675C";
-
-    @SmallTest
-    public void testGetToken() throws Exception {
-        if (!Arrays.asList(Collator.getAvailableLocales()).contains(Locale.CHINA)) {
-            return;
-        }
-        ArrayList<Token> tokens = HanziToPinyin.getInstance().get(ONE_HANZI);
-        assertEquals(tokens.size(), 1);
-        assertEquals(tokens.get(0).type, Token.PINYIN);
-        assertTrue(tokens.get(0).target.equalsIgnoreCase("DU"));
-
-        tokens = HanziToPinyin.getInstance().get(TWO_HANZI);
-        assertEquals(tokens.size(), 2);
-        assertEquals(tokens.get(0).type, Token.PINYIN);
-        assertEquals(tokens.get(1).type, Token.PINYIN);
-        assertTrue(tokens.get(0).target.equalsIgnoreCase("DU"));
-        assertTrue(tokens.get(1).target.equalsIgnoreCase("JUAN"));
-
-        tokens = HanziToPinyin.getInstance().get(ASSIC);
-        assertEquals(tokens.size(), 1);
-        assertEquals(tokens.get(0).type, Token.LATIN);
-
-        tokens = HanziToPinyin.getInstance().get(ONE_UNKNOWN);
-        assertEquals(tokens.size(), 1);
-        assertEquals(tokens.get(0).type, Token.UNKNOWN);
-
-        tokens = HanziToPinyin.getInstance().get(MISC);
-        assertEquals(tokens.size(), 7);
-        assertEquals(tokens.get(0).type, Token.LATIN);
-        assertEquals(tokens.get(1).type, Token.PINYIN);
-        assertEquals(tokens.get(2).type, Token.LATIN);
-        assertEquals(tokens.get(3).type, Token.LATIN);
-        assertEquals(tokens.get(4).type, Token.LATIN);
-        assertEquals(tokens.get(5).type, Token.UNKNOWN);
-        assertEquals(tokens.get(6).type, Token.PINYIN);
-    }
-}
diff --git a/docs/html/resources/resources-data.js b/docs/html/resources/resources-data.js
index 77aee46..097d004 100644
--- a/docs/html/resources/resources-data.js
+++ b/docs/html/resources/resources-data.js
@@ -407,6 +407,26 @@
     }
   },
   {
+    tags: ['sample', 'layout', 'ui', 'fragment', 'loader', 'new'],
+    path: 'samples/Support4Demos/index.html',
+    title: {
+      en: 'API 4+ Support Demos'
+    },
+    description: {
+      en: 'A variety of small applications that demonstrate the use of the helper classes in the Android API 4+ Support Library (classes which work down to API level 4 or version 1.6 of the platform).'
+    }
+  },
+  {
+    tags: ['sample', 'layout', 'ui', 'new'],
+    path: 'samples/Support13Demos/index.html',
+    title: {
+      en: 'API 13+ Support Demos'
+    },
+    description: {
+      en: 'A variety of small applications that demonstrate the use of the helper classes in the Android API 13+ Support Library (classes which work down to API level 13 or version 3.2 of the platform).'
+    }
+  },
+  {
     tags: ['sample', 'data', 'newfeature', 'accountsync'],
     path: 'samples/BackupRestore/index.html',
     title: {
diff --git a/drm/common/IDrmManagerService.cpp b/drm/common/IDrmManagerService.cpp
index c37b4f8..458f1b6 100644
--- a/drm/common/IDrmManagerService.cpp
+++ b/drm/common/IDrmManagerService.cpp
@@ -37,7 +37,7 @@
 
 using namespace android;
 
-static void writeDecrptHandleToParcelData(
+static void writeDecryptHandleToParcelData(
         const DecryptHandle* handle, Parcel* data) {
     data->writeInt32(handle->decryptId);
     data->writeString8(handle->mimeType);
@@ -46,14 +46,14 @@
 
     int size = handle->copyControlVector.size();
     data->writeInt32(size);
-    for(int i = 0; i < size; i++) {
+    for (int i = 0; i < size; i++) {
         data->writeInt32(handle->copyControlVector.keyAt(i));
         data->writeInt32(handle->copyControlVector.valueAt(i));
     }
 
     size = handle->extendedData.size();
     data->writeInt32(size);
-    for(int i = 0; i < size; i++) {
+    for (int i = 0; i < size; i++) {
         data->writeString8(handle->extendedData.keyAt(i));
         data->writeString8(handle->extendedData.valueAt(i));
     }
@@ -77,14 +77,14 @@
     handle->status = data.readInt32();
 
     int size = data.readInt32();
-    for (int i = 0; i < size; i ++) {
+    for (int i = 0; i < size; i++) {
         DrmCopyControl key = (DrmCopyControl)data.readInt32();
         int value = data.readInt32();
         handle->copyControlVector.add(key, value);
     }
 
     size = data.readInt32();
-    for (int i = 0; i < size; i ++) {
+    for (int i = 0; i < size; i++) {
         String8 key = data.readString8();
         String8 value = data.readString8();
         handle->extendedData.add(key, value);
@@ -416,7 +416,7 @@
     data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
     data.writeInt32(uniqueId);
 
-    writeDecrptHandleToParcelData(decryptHandle, &data);
+    writeDecryptHandleToParcelData(decryptHandle, &data);
 
     data.writeInt32(action);
     data.writeInt32(static_cast< int>(reserve));
@@ -433,7 +433,7 @@
     data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
     data.writeInt32(uniqueId);
 
-    writeDecrptHandleToParcelData(decryptHandle, &data);
+    writeDecryptHandleToParcelData(decryptHandle, &data);
 
     data.writeInt32(playbackStatus);
     data.writeInt64(position);
@@ -646,7 +646,7 @@
     data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
     data.writeInt32(uniqueId);
 
-    writeDecrptHandleToParcelData(decryptHandle, &data);
+    writeDecryptHandleToParcelData(decryptHandle, &data);
 
     remote()->transact(CLOSE_DECRYPT_SESSION, data, &reply);
 
@@ -662,7 +662,7 @@
     data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
     data.writeInt32(uniqueId);
 
-    writeDecrptHandleToParcelData(decryptHandle, &data);
+    writeDecryptHandleToParcelData(decryptHandle, &data);
 
     data.writeInt32(decryptUnitId);
 
@@ -682,7 +682,7 @@
     data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
     data.writeInt32(uniqueId);
 
-    writeDecrptHandleToParcelData(decryptHandle, &data);
+    writeDecryptHandleToParcelData(decryptHandle, &data);
 
     data.writeInt32(decryptUnitId);
     data.writeInt32((*decBuffer)->length);
@@ -715,7 +715,7 @@
     data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
     data.writeInt32(uniqueId);
 
-    writeDecrptHandleToParcelData(decryptHandle, &data);
+    writeDecryptHandleToParcelData(decryptHandle, &data);
 
     data.writeInt32(decryptUnitId);
 
@@ -733,7 +733,7 @@
     data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
     data.writeInt32(uniqueId);
 
-    writeDecrptHandleToParcelData(decryptHandle, &data);
+    writeDecryptHandleToParcelData(decryptHandle, &data);
 
     data.writeInt32(numBytes);
     data.writeInt64(offset);
@@ -1244,7 +1244,7 @@
             = openDecryptSession(uniqueId, fd, data.readInt64(), data.readInt64());
 
         if (NULL != handle) {
-            writeDecrptHandleToParcelData(handle, reply);
+            writeDecryptHandleToParcelData(handle, reply);
             clearDecryptHandle(handle);
             delete handle; handle = NULL;
         }
@@ -1262,7 +1262,7 @@
         DecryptHandle* handle = openDecryptSession(uniqueId, uri.string());
 
         if (NULL != handle) {
-            writeDecrptHandleToParcelData(handle, reply);
+            writeDecryptHandleToParcelData(handle, reply);
 
             clearDecryptHandle(handle);
             delete handle; handle = NULL;
diff --git a/drm/java/android/drm/DrmInfoRequest.java b/drm/java/android/drm/DrmInfoRequest.java
index 2222ae8..1429fa5 100755
--- a/drm/java/android/drm/DrmInfoRequest.java
+++ b/drm/java/android/drm/DrmInfoRequest.java
@@ -32,16 +32,16 @@
      */
     public static final int TYPE_REGISTRATION_INFO = 1;
     /**
-    * Acquires information for unregistering the DRM server.
-    */
+     * Acquires information for unregistering the DRM server.
+     */
     public static final int TYPE_UNREGISTRATION_INFO = 2;
     /**
-    * Acquires rights information.
-    */
+     * Acquires rights information.
+     */
     public static final int TYPE_RIGHTS_ACQUISITION_INFO = 3;
     /**
-    * Acquires the progress of the rights acquisition.
-    */
+     * Acquires the progress of the rights acquisition.
+     */
     public static final int TYPE_RIGHTS_ACQUISITION_PROGRESS_INFO = 4;
 
     /**
diff --git a/drm/java/android/drm/DrmInfoStatus.java b/drm/java/android/drm/DrmInfoStatus.java
index b04694b..5c12ae3 100755
--- a/drm/java/android/drm/DrmInfoStatus.java
+++ b/drm/java/android/drm/DrmInfoStatus.java
@@ -31,20 +31,20 @@
     public static final int STATUS_ERROR = 2;
 
     /**
-    * The status of the communication.
-    */
+     * The status of the communication.
+     */
     public final int statusCode;
     /**
-    * The type of DRM information processed.
-    */
+     * The type of DRM information processed.
+     */
     public final int infoType;
     /**
-    * The MIME type of the content.
-    */
+     * The MIME type of the content.
+     */
     public final String mimeType;
     /**
-    * The processed data.
-    */
+     * The processed data.
+     */
     public final ProcessedData data;
 
     /**
diff --git a/drm/libdrmframework/include/PlugInManager.h b/drm/libdrmframework/include/PlugInManager.h
index 8029138..7bb143f 100644
--- a/drm/libdrmframework/include/PlugInManager.h
+++ b/drm/libdrmframework/include/PlugInManager.h
@@ -202,7 +202,7 @@
     Vector<String8> getPlugInPathList(const String8& rsDirPath) {
         Vector<String8> fileList;
         DIR* pDir = opendir(rsDirPath.string());
-        struct dirent* pEntry = new dirent();
+        struct dirent* pEntry;
 
         while (NULL != pDir && NULL != (pEntry = readdir(pDir))) {
             if (!isPlugIn(pEntry)) {
@@ -219,8 +219,6 @@
         if (NULL != pDir) {
             closedir(pDir);
         }
-        delete pEntry;
-        pEntry = NULL;
 
         return fileList;
     }
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index 0ffd201..6c7341f 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -66,11 +66,8 @@
 
     /**
      * This field is used by native code, do not access or modify.
-     * 
-     * @hide
      */
-    @SuppressWarnings({"UnusedDeclaration"})
-    public int mSurfaceTexture;
+    private int mSurfaceTexture;
 
     /**
      * Callback interface for being notified that a new stream frame is available.
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index a63abb9..eeab9b4 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -606,9 +606,9 @@
      */
     public void copy1DRangeFrom(int off, int count, Allocation data, int dataOff) {
         mRS.nAllocationData2D(getID(), off, 0,
-                              0, Type.CubemapFace.POSITVE_X.mID,
+                              0, Type.CubemapFace.POSITIVE_X.mID,
                               count, 1, data.getID(), dataOff, 0,
-                              0, Type.CubemapFace.POSITVE_X.mID);
+                              0, Type.CubemapFace.POSITIVE_X.mID);
     }
 
     private void validate2DRange(int xoff, int yoff, int w, int h) {
@@ -675,9 +675,9 @@
         mRS.validate();
         validate2DRange(xoff, yoff, w, h);
         mRS.nAllocationData2D(getID(), xoff, yoff,
-                              0, Type.CubemapFace.POSITVE_X.mID,
+                              0, Type.CubemapFace.POSITIVE_X.mID,
                               w, h, data.getID(), dataXoff, dataYoff,
-                              0, Type.CubemapFace.POSITVE_X.mID);
+                              0, Type.CubemapFace.POSITIVE_X.mID);
     }
 
     /**
@@ -1048,15 +1048,15 @@
         Allocation cubemap = Allocation.createTyped(rs, t, mips, usage);
 
         AllocationAdapter adapter = AllocationAdapter.create2D(rs, cubemap);
-        adapter.setFace(Type.CubemapFace.POSITVE_X);
+        adapter.setFace(Type.CubemapFace.POSITIVE_X);
         adapter.copyFrom(xpos);
         adapter.setFace(Type.CubemapFace.NEGATIVE_X);
         adapter.copyFrom(xneg);
-        adapter.setFace(Type.CubemapFace.POSITVE_Y);
+        adapter.setFace(Type.CubemapFace.POSITIVE_Y);
         adapter.copyFrom(ypos);
         adapter.setFace(Type.CubemapFace.NEGATIVE_Y);
         adapter.copyFrom(yneg);
-        adapter.setFace(Type.CubemapFace.POSITVE_Z);
+        adapter.setFace(Type.CubemapFace.POSITIVE_Z);
         adapter.copyFrom(zpos);
         adapter.setFace(Type.CubemapFace.NEGATIVE_Z);
         adapter.copyFrom(zneg);
diff --git a/graphics/java/android/renderscript/AllocationAdapter.java b/graphics/java/android/renderscript/AllocationAdapter.java
index 07a1f5d..61f2e1f 100644
--- a/graphics/java/android/renderscript/AllocationAdapter.java
+++ b/graphics/java/android/renderscript/AllocationAdapter.java
@@ -33,7 +33,7 @@
     private Allocation mAlloc;
 
     private int mSelectedLOD = 0;
-    private Type.CubemapFace mSelectedFace = Type.CubemapFace.POSITVE_X;
+    private Type.CubemapFace mSelectedFace = Type.CubemapFace.POSITIVE_X;
 
     AllocationAdapter(int id, RenderScript rs, Allocation alloc) {
         super(id, rs, null, alloc.mUsage);
diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java
index 0c1ad2a..5a72dbe 100644
--- a/graphics/java/android/renderscript/Element.java
+++ b/graphics/java/android/renderscript/Element.java
@@ -32,8 +32,8 @@
  * <p>Complex elements contain a list of sub-elements and names that
  * represents a structure of data. The fields can be accessed by name
  * from a script or shader. The memory layout is defined and ordered. Data
- * alignment is determinied by the most basic primitive type. i.e. a float4
- * vector will be alligned to sizeof(float) and not sizeof(float4).  The
+ * alignment is determined by the most basic primitive type. i.e. a float4
+ * vector will be aligned to sizeof(float) and not sizeof(float4). The
  * ordering of elements in memory will be the order in which they were added
  * with each component aligned as necessary. No re-ordering will be done.</p>
  *
@@ -584,6 +584,33 @@
     }
 
     /**
+     * Check if the current Element is compatible with another Element.
+     * Primitive Elements are compatible if they share the same underlying
+     * size and type (i.e. U8 is compatible with A_8). User-defined Elements
+     * must be equal in order to be compatible. This requires strict name
+     * equivalence for all sub-Elements (in addition to structural equivalence).
+     *
+     * @param e The Element to check compatibility with.
+     *
+     * @return boolean true if the Elements are compatible, otherwise false.
+     */
+    public boolean isCompatible(Element e) {
+        // Try strict BaseObj equality to start with.
+        if (this.equals(e)) {
+            return true;
+        }
+
+        // Ignore mKind because it is allowed to be different (user vs. pixel).
+        // We also ignore mNormalized because it can be different. The mType
+        // field must be non-null since we require name equivalence for
+        // user-created Elements.
+        return ((mSize == e.mSize) &&
+                (mType != null) &&
+                (mType == e.mType) &&
+                (mVectorSize == e.mVectorSize));
+    }
+
+    /**
      * Builder class for producing complex elements with matching field and name
      * pairs.  The builder starts empty.  The order in which elements are added
      * is retained for the layout in memory.
diff --git a/graphics/java/android/renderscript/Type.java b/graphics/java/android/renderscript/Type.java
index b39d2e4..f88af8b 100644
--- a/graphics/java/android/renderscript/Type.java
+++ b/graphics/java/android/renderscript/Type.java
@@ -46,12 +46,18 @@
     Element mElement;
 
     public enum CubemapFace {
-        POSITVE_X (0),
+        POSITIVE_X (0),
         NEGATIVE_X (1),
-        POSITVE_Y (2),
+        POSITIVE_Y (2),
         NEGATIVE_Y (3),
-        POSITVE_Z (4),
-        NEGATIVE_Z (5);
+        POSITIVE_Z (4),
+        NEGATIVE_Z (5),
+        @Deprecated
+        POSITVE_X (0),
+        @Deprecated
+        POSITVE_Y (2),
+        @Deprecated
+        POSITVE_Z (4);
 
         int mID;
         CubemapFace(int id) {
diff --git a/include/utils/BlobCache.h b/include/utils/BlobCache.h
index 8f76d72..dc45ff0 100644
--- a/include/utils/BlobCache.h
+++ b/include/utils/BlobCache.h
@@ -82,6 +82,9 @@
     BlobCache(const BlobCache&);
     void operator=(const BlobCache&);
 
+    // A random function helper to get around MinGW not having nrand48()
+    long int blob_random();
+
     // clean evicts a randomly chosen set of entries from the cache such that
     // the total size of all remaining entries is less than mMaxTotalSize/2.
     void clean();
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index a4c5b36..519b40e 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -590,7 +590,7 @@
 
 // This test verifies that the buffer format can be queried immediately after
 // it is set.
-TEST_F(SurfaceTextureClientTest, DISABLED_QueryFormatAfterSettingWorks) {
+TEST_F(SurfaceTextureClientTest, QueryFormatAfterSettingWorks) {
     sp<ANativeWindow> anw(mSTC);
     int fmts[] = {
         // RGBA_8888 should not come first, as it's the default
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index 50af3bb..f6cefa6 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -542,11 +542,7 @@
     EXPECT_TRUE(checkPixel(36, 22, 155,  29,   0, 255));
 }
 
-// XXX: This test is disabled because it it currently broken on all devices to
-// which I have access.  Some of the checkPixel calls are not correct because
-// I just copied them from the npot test above and haven't bothered to figure
-// out the correct values.
-TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromCpuFilledYV12BufferPow2) {
+TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferPow2) {
     const int texWidth = 64;
     const int texHeight = 64;
 
@@ -576,18 +572,18 @@
 
     drawTexture();
 
-    EXPECT_TRUE(checkPixel( 0,  0, 255, 127, 255, 255));
-    EXPECT_TRUE(checkPixel(63,  0,   0, 133,   0, 255));
+    EXPECT_TRUE(checkPixel( 0,  0,   0, 133,   0, 255));
+    EXPECT_TRUE(checkPixel(63,  0, 255, 127, 255, 255));
     EXPECT_TRUE(checkPixel(63, 63,   0, 133,   0, 255));
     EXPECT_TRUE(checkPixel( 0, 63, 255, 127, 255, 255));
 
-    EXPECT_TRUE(checkPixel(22, 19, 247,  70, 255, 255));
-    EXPECT_TRUE(checkPixel(45, 11, 209,  32, 235, 255));
-    EXPECT_TRUE(checkPixel(52, 12, 100, 255,  73, 255));
-    EXPECT_TRUE(checkPixel( 7, 32, 155,   0, 118, 255));
-    EXPECT_TRUE(checkPixel(31, 54, 148,  71, 110, 255));
-    EXPECT_TRUE(checkPixel(29, 28, 255, 127, 255, 255));
-    EXPECT_TRUE(checkPixel(36, 41, 155,  29,   0, 255));
+    EXPECT_TRUE(checkPixel(22, 19, 100, 255,  74, 255));
+    EXPECT_TRUE(checkPixel(45, 11, 100, 255,  74, 255));
+    EXPECT_TRUE(checkPixel(52, 12, 155,   0, 181, 255));
+    EXPECT_TRUE(checkPixel( 7, 32, 150, 237, 170, 255));
+    EXPECT_TRUE(checkPixel(31, 54,   0,  71, 117, 255));
+    EXPECT_TRUE(checkPixel(29, 28,   0, 133,   0, 255));
+    EXPECT_TRUE(checkPixel(36, 41, 100, 232, 255, 255));
 }
 
 TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) {
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 596781e..e64d8ac 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -74,7 +74,7 @@
 
 struct CacheLogger {
     CacheLogger() {
-        LOGD("Creating OpenGL renderer caches");
+        INIT_LOGD("Creating OpenGL renderer caches");
     }
 }; // struct CacheLogger
 
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 146e789..77e63d7 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -326,12 +326,17 @@
             return false;
         }
 
+        SkAutoLockPixels alp(*bitmap);
+
         GLuint texture;
         GLuint previousFbo;
 
         GLenum format;
         GLenum type;
 
+        GLenum error = GL_NO_ERROR;
+        bool status = false;
+
         switch (bitmap->config()) {
             case SkBitmap::kA8_Config:
                 format = GL_ALPHA;
@@ -352,10 +357,18 @@
                 break;
         }
 
+        float alpha = layer->alpha;
+        SkXfermode::Mode mode = layer->mode;
+
+        layer->mode = SkXfermode::kSrc_Mode;
+        layer->alpha = 255;
+        layer->fbo = fbo;
+
         glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);
         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
 
         glGenTextures(1, &texture);
+        if ((error = glGetError()) != GL_NO_ERROR) goto error;
 
         glActiveTexture(GL_TEXTURE0);
         glBindTexture(GL_TEXTURE_2D, texture);
@@ -368,39 +381,48 @@
 
         glTexImage2D(GL_TEXTURE_2D, 0, format, bitmap->width(), bitmap->height(),
                 0, format, type, NULL);
+        if ((error = glGetError()) != GL_NO_ERROR) goto error;
+
         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                 GL_TEXTURE_2D, texture, 0);
+        if ((error = glGetError()) != GL_NO_ERROR) goto error;
 
-        glBindTexture(GL_TEXTURE_2D, layer->texture);
+        {
+            LayerRenderer renderer(layer);
+            renderer.setViewport(bitmap->width(), bitmap->height());
+            renderer.OpenGLRenderer::prepareDirty(0.0f, 0.0f,
+                    bitmap->width(), bitmap->height(), !layer->blend);
+            if ((error = glGetError()) != GL_NO_ERROR) goto error;
 
-        float alpha = layer->alpha;
-        SkXfermode::Mode mode = layer->mode;
+            {
+                Rect bounds;
+                bounds.set(0.0f, 0.0f, bitmap->width(), bitmap->height());
+                renderer.drawTextureLayer(layer, bounds);
 
-        layer->mode = SkXfermode::kSrc_Mode;
-        layer->alpha = 255;
-        layer->fbo = fbo;
+                glReadPixels(0, 0, bitmap->width(), bitmap->height(), format,
+                        type, bitmap->getPixels());
 
-        LayerRenderer renderer(layer);
-        renderer.setViewport(bitmap->width(), bitmap->height());
-        renderer.OpenGLRenderer::prepareDirty(0.0f, 0.0f,
-                bitmap->width(), bitmap->height(), !layer->blend);
+                if ((error = glGetError()) != GL_NO_ERROR) goto error;
+            }
 
-        Rect bounds;
-        bounds.set(0.0f, 0.0f, bitmap->width(), bitmap->height());
-        renderer.drawTextureLayer(layer, bounds);
+            status = true;
+        }
 
-        SkAutoLockPixels alp(*bitmap);
-        glReadPixels(0, 0, bitmap->width(), bitmap->height(), format, type, bitmap->getPixels());
+error:
+#if DEBUG_OPENGL
+        if (error != GL_NO_ERROR) {
+            LOGD("GL error while copying layer into bitmap = 0x%x", error);
+        }
+#endif
 
         glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
-
         layer->mode = mode;
         layer->alpha = alpha;
         layer->fbo = 0;
         glDeleteTextures(1, &texture);
         caches.fboCache.put(fbo);
 
-        return true;
+        return status;
     }
     return false;
 }
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 5343a05..88774c6 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -151,7 +151,6 @@
     mSaveCount = 1;
 
     glViewport(0, 0, mWidth, mHeight);
-
     glDisable(GL_DITHER);
 
     glEnable(GL_SCISSOR_TEST);
diff --git a/libs/hwui/ShapeCache.h b/libs/hwui/ShapeCache.h
index b5cc29c..b048469 100644
--- a/libs/hwui/ShapeCache.h
+++ b/libs/hwui/ShapeCache.h
@@ -537,15 +537,16 @@
     const float pathWidth = fmax(bounds.width(), 1.0f);
     const float pathHeight = fmax(bounds.height(), 1.0f);
 
-    if (pathWidth > mMaxTextureSize || pathHeight > mMaxTextureSize) {
+    const float offset = fmax(paint->getStrokeWidth(), 1.0f) * 1.5f;
+
+    const uint32_t width = uint32_t(pathWidth + offset * 2.0 + 0.5);
+    const uint32_t height = uint32_t(pathHeight + offset * 2.0 + 0.5);
+
+    if (width > mMaxTextureSize || height > mMaxTextureSize) {
         LOGW("Shape %s too large to be rendered into a texture", mName);
         return NULL;
     }
 
-    const float offset = paint->getStrokeWidth() * 1.5f;
-    const uint32_t width = uint32_t(pathWidth + offset * 2.0 + 0.5);
-    const uint32_t height = uint32_t(pathHeight + offset * 2.0 + 0.5);
-
     const uint32_t size = width * height;
     // Don't even try to cache a bitmap that's bigger than the cache
     if (size < mMaxSize) {
diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk
index 9fabf8d..d9cc6b6 100644
--- a/libs/rs/Android.mk
+++ b/libs/rs/Android.mk
@@ -119,6 +119,7 @@
 	driver/rsdBcc.cpp \
 	driver/rsdCore.cpp \
 	driver/rsdFrameBuffer.cpp \
+	driver/rsdFrameBufferObj.cpp \
 	driver/rsdGL.cpp \
 	driver/rsdMesh.cpp \
 	driver/rsdMeshObj.cpp \
diff --git a/libs/rs/driver/rsdAllocation.cpp b/libs/rs/driver/rsdAllocation.cpp
index 8bfc185..01a0cf6 100644
--- a/libs/rs/driver/rsdAllocation.cpp
+++ b/libs/rs/driver/rsdAllocation.cpp
@@ -19,6 +19,7 @@
 #include "rsdBcc.h"
 #include "rsdRuntime.h"
 #include "rsdAllocation.h"
+#include "rsdFrameBufferObj.h"
 
 #include "rsAllocation.h"
 
@@ -244,6 +245,9 @@
     if (alloc->mHal.state.usageFlags & ~RS_ALLOCATION_USAGE_SCRIPT) {
         drv->uploadDeferred = true;
     }
+
+    drv->readBackFBO = NULL;
+
     return true;
 }
 
@@ -269,6 +273,10 @@
         free(drv->mallocPtr);
         drv->mallocPtr = NULL;
     }
+    if (drv->readBackFBO != NULL) {
+        delete drv->readBackFBO;
+        drv->readBackFBO = NULL;
+    }
     free(drv);
     alloc->mHal.drv = NULL;
 }
@@ -292,13 +300,52 @@
     }
 }
 
+static void rsdAllocationSyncFromFBO(const Context *rsc, const Allocation *alloc) {
+    if (!alloc->getIsScript()) {
+        return; // nothing to sync
+    }
+
+    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+    RsdFrameBufferObj *lastFbo = dc->gl.currentFrameBuffer;
+
+    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
+    if (!drv->textureID && !drv->renderTargetID) {
+        return; // nothing was rendered here yet, so nothing to sync
+    }
+    if (drv->readBackFBO == NULL) {
+        drv->readBackFBO = new RsdFrameBufferObj();
+        drv->readBackFBO->setColorTarget(drv, 0);
+        drv->readBackFBO->setDimensions(alloc->getType()->getDimX(),
+                                        alloc->getType()->getDimY());
+    }
+
+    // Bind the framebuffer object so we can read back from it
+    drv->readBackFBO->setActive(rsc);
+
+    // Do the readback
+    glReadPixels(0, 0, alloc->getType()->getDimX(), alloc->getType()->getDimY(),
+                 drv->glFormat, drv->glType, alloc->getPtr());
+
+    // Revert framebuffer to its original
+    lastFbo->setActive(rsc);
+}
 
 
 void rsdAllocationSyncAll(const Context *rsc, const Allocation *alloc,
                          RsAllocationUsageType src) {
     DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
 
-    if (!drv->uploadDeferred) {
+    if (src == RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET) {
+        if(!alloc->getIsRenderTarget()) {
+            rsc->setError(RS_ERROR_FATAL_DRIVER,
+                          "Attempting to sync allocation from render target, "
+                          "for non-render target allocation");
+        } else if (alloc->getType()->getElement()->getKind() != RS_KIND_PIXEL_RGBA) {
+            rsc->setError(RS_ERROR_FATAL_DRIVER, "Cannot only sync from RGBA"
+                                                 "render target");
+        } else {
+            rsdAllocationSyncFromFBO(rsc, alloc);
+        }
         return;
     }
 
@@ -382,7 +429,40 @@
                                const android::renderscript::Allocation *dstAlloc,
                                uint32_t dstXoff, uint32_t dstLod, uint32_t count,
                                const android::renderscript::Allocation *srcAlloc,
-                               uint32_t srcXoff, uint32_t srcLod){
+                               uint32_t srcXoff, uint32_t srcLod) {
+}
+
+uint8_t *getOffsetPtr(const android::renderscript::Allocation *alloc,
+                      uint32_t xoff, uint32_t yoff, uint32_t lod,
+                      RsAllocationCubemapFace face) {
+    uint8_t *ptr = static_cast<uint8_t *>(alloc->getPtr());
+    ptr += alloc->getType()->getLODOffset(lod, xoff, yoff);
+
+    if (face != 0) {
+        uint32_t totalSizeBytes = alloc->getType()->getSizeBytes();
+        uint32_t faceOffset = totalSizeBytes / 6;
+        ptr += faceOffset * (uint32_t)face;
+    }
+    return ptr;
+}
+
+
+void rsdAllocationData2D_alloc_script(const android::renderscript::Context *rsc,
+                                      const android::renderscript::Allocation *dstAlloc,
+                                      uint32_t dstXoff, uint32_t dstYoff, uint32_t dstLod,
+                                      RsAllocationCubemapFace dstFace, uint32_t w, uint32_t h,
+                                      const android::renderscript::Allocation *srcAlloc,
+                                      uint32_t srcXoff, uint32_t srcYoff, uint32_t srcLod,
+                                      RsAllocationCubemapFace srcFace) {
+    uint32_t elementSize = dstAlloc->getType()->getElementSizeBytes();
+    for (uint32_t i = 0; i < h; i ++) {
+        uint8_t *dstPtr = getOffsetPtr(dstAlloc, dstXoff, dstYoff + i, dstLod, dstFace);
+        uint8_t *srcPtr = getOffsetPtr(srcAlloc, srcXoff, srcYoff + i, srcLod, srcFace);
+        memcpy(dstPtr, srcPtr, w * elementSize);
+
+        LOGE("COPIED dstXoff(%u), dstYoff(%u), dstLod(%u), dstFace(%u), w(%u), h(%u), srcXoff(%u), srcYoff(%u), srcLod(%u), srcFace(%u)",
+             dstXoff, dstYoff, dstLod, dstFace, w, h, srcXoff, srcYoff, srcLod, srcFace);
+    }
 }
 
 void rsdAllocationData2D_alloc(const android::renderscript::Context *rsc,
@@ -392,6 +472,14 @@
                                const android::renderscript::Allocation *srcAlloc,
                                uint32_t srcXoff, uint32_t srcYoff, uint32_t srcLod,
                                RsAllocationCubemapFace srcFace) {
+    if (!dstAlloc->getIsScript() && !srcAlloc->getIsScript()) {
+        rsc->setError(RS_ERROR_FATAL_DRIVER, "Non-script allocation copies not "
+                                             "yet implemented.");
+        return;
+    }
+    rsdAllocationData2D_alloc_script(rsc, dstAlloc, dstXoff, dstYoff,
+                                     dstLod, dstFace, w, h, srcAlloc,
+                                     srcXoff, srcYoff, srcLod, srcFace);
 }
 
 void rsdAllocationData3D_alloc(const android::renderscript::Context *rsc,
diff --git a/libs/rs/driver/rsdAllocation.h b/libs/rs/driver/rsdAllocation.h
index 7555c4a..4fc4419 100644
--- a/libs/rs/driver/rsdAllocation.h
+++ b/libs/rs/driver/rsdAllocation.h
@@ -23,6 +23,8 @@
 #include <GLES/gl.h>
 #include <GLES2/gl2.h>
 
+class RsdFrameBufferObj;
+
 struct DrvAllocation {
     // Is this a legal structure to be used as a texture source.
     // Initially this will require 1D or 2D and color data
@@ -42,8 +44,9 @@
     GLenum glType;
     GLenum glFormat;
 
-
     bool uploadDeferred;
+
+    RsdFrameBufferObj * readBackFBO;
 };
 
 GLenum rsdTypeToGLType(RsDataType t);
diff --git a/libs/rs/driver/rsdFrameBuffer.cpp b/libs/rs/driver/rsdFrameBuffer.cpp
index ce72b5d..8c1b12d 100644
--- a/libs/rs/driver/rsdFrameBuffer.cpp
+++ b/libs/rs/driver/rsdFrameBuffer.cpp
@@ -17,6 +17,7 @@
 
 #include "rsdCore.h"
 #include "rsdFrameBuffer.h"
+#include "rsdFrameBufferObj.h"
 #include "rsdAllocation.h"
 
 #include "rsContext.h"
@@ -28,133 +29,70 @@
 using namespace android;
 using namespace android::renderscript;
 
-struct DrvFrameBuffer {
-    GLuint mFBOId;
-};
-
-void checkError(const Context *rsc) {
-    GLenum status;
-    status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
-    switch (status) {
-    case GL_FRAMEBUFFER_COMPLETE:
-        break;
-    case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
-        rsc->setError(RS_ERROR_BAD_VALUE,
-                      "Unable to set up render Target: RFRAMEBUFFER_INCOMPLETE_ATTACHMENT");
-        break;
-    case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
-        rsc->setError(RS_ERROR_BAD_VALUE,
-                      "Unable to set up render Target: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
-        break;
-    case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
-        rsc->setError(RS_ERROR_BAD_VALUE,
-                      "Unable to set up render Target: GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
-        break;
-    case GL_FRAMEBUFFER_UNSUPPORTED:
-        rsc->setError(RS_ERROR_BAD_VALUE,
-                      "Unable to set up render Target: GL_FRAMEBUFFER_UNSUPPORTED");
-        break;
-    }
-}
-
-
 void setDepthAttachment(const Context *rsc, const FBOCache *fb) {
-    if (fb->mHal.state.depthTarget.get() != NULL) {
-        DrvAllocation *drv = (DrvAllocation *)fb->mHal.state.depthTarget->mHal.drv;
+    RsdFrameBufferObj *fbo = (RsdFrameBufferObj*)fb->mHal.drv;
 
-        if (drv->textureID) {
-            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
-                                   GL_TEXTURE_2D, drv->textureID, 0);
-        } else {
-            glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
-                                      GL_RENDERBUFFER, drv->renderTargetID);
+    DrvAllocation *depth = NULL;
+    if (fb->mHal.state.depthTarget.get() != NULL) {
+        depth = (DrvAllocation *)fb->mHal.state.depthTarget->mHal.drv;
+
+        if (depth->uploadDeferred) {
+            rsdAllocationSyncAll(rsc, fb->mHal.state.depthTarget.get(),
+                                 RS_ALLOCATION_USAGE_SCRIPT);
         }
-    } else {
-        // Reset last attachment
-        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
-        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
     }
+    fbo->setDepthTarget(depth);
 }
 
 void setColorAttachment(const Context *rsc, const FBOCache *fb) {
+    RsdFrameBufferObj *fbo = (RsdFrameBufferObj*)fb->mHal.drv;
     // Now attach color targets
     for (uint32_t i = 0; i < fb->mHal.state.colorTargetsCount; i ++) {
-        uint32_t texID = 0;
+        DrvAllocation *color = NULL;
         if (fb->mHal.state.colorTargets[i].get() != NULL) {
-            DrvAllocation *drv = (DrvAllocation *)fb->mHal.state.colorTargets[i]->mHal.drv;
+            color = (DrvAllocation *)fb->mHal.state.colorTargets[i]->mHal.drv;
 
-            if (drv->textureID) {
-                glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
-                                       GL_TEXTURE_2D, drv->textureID, 0);
-            } else {
-                glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
-                                          GL_RENDERBUFFER, drv->renderTargetID);
+            if (color->uploadDeferred) {
+                rsdAllocationSyncAll(rsc, fb->mHal.state.colorTargets[i].get(),
+                                     RS_ALLOCATION_USAGE_SCRIPT);
             }
-        } else {
-            // Reset last attachment
-            glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
-                                      GL_RENDERBUFFER, 0);
-            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
-                                   GL_TEXTURE_2D, 0, 0);
         }
+        fbo->setColorTarget(color, i);
     }
 }
 
-bool renderToFramebuffer(const FBOCache *fb) {
-    if (fb->mHal.state.depthTarget.get() != NULL) {
-        return false;
-    }
-
-    for (uint32_t i = 0; i < fb->mHal.state.colorTargetsCount; i ++) {
-        if (fb->mHal.state.colorTargets[i].get() != NULL) {
-            return false;
-        }
-    }
-    return true;
-}
-
-
 bool rsdFrameBufferInit(const Context *rsc, const FBOCache *fb) {
-    DrvFrameBuffer *drv = (DrvFrameBuffer *)calloc(1, sizeof(DrvFrameBuffer));
-    if (drv == NULL) {
+    RsdFrameBufferObj *fbo = new RsdFrameBufferObj();
+    if (fbo == NULL) {
         return false;
     }
-    fb->mHal.drv = drv;
-    drv->mFBOId = 0;
+    fb->mHal.drv = fbo;
+
+    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+    dc->gl.currentFrameBuffer = fbo;
 
     return true;
 }
 
 void rsdFrameBufferSetActive(const Context *rsc, const FBOCache *fb) {
-    DrvFrameBuffer *drv = (DrvFrameBuffer *)fb->mHal.drv;
+    setDepthAttachment(rsc, fb);
+    setColorAttachment(rsc, fb);
 
-    bool framebuffer = renderToFramebuffer(fb);
-    if (!framebuffer) {
-        if(drv->mFBOId == 0) {
-            glGenFramebuffers(1, &drv->mFBOId);
-        }
-        glBindFramebuffer(GL_FRAMEBUFFER, drv->mFBOId);
-
-        setDepthAttachment(rsc, fb);
-        setColorAttachment(rsc, fb);
-
-        glViewport(0, 0, fb->mHal.state.colorTargets[0]->getType()->getDimX(),
-                         fb->mHal.state.colorTargets[0]->getType()->getDimY());
-
-        checkError(rsc);
-    } else {
-        glBindFramebuffer(GL_FRAMEBUFFER, 0);
-        glViewport(0, 0, rsc->getWidth(), rsc->getHeight());
+    RsdFrameBufferObj *fbo = (RsdFrameBufferObj *)fb->mHal.drv;
+    if (fb->mHal.state.colorTargets[0].get()) {
+        fbo->setDimensions(fb->mHal.state.colorTargets[0]->getType()->getDimX(),
+                           fb->mHal.state.colorTargets[0]->getType()->getDimY());
+    } else if (fb->mHal.state.depthTarget.get()) {
+        fbo->setDimensions(fb->mHal.state.depthTarget->getType()->getDimX(),
+                           fb->mHal.state.depthTarget->getType()->getDimY());
     }
+
+    fbo->setActive(rsc);
 }
 
 void rsdFrameBufferDestroy(const Context *rsc, const FBOCache *fb) {
-    DrvFrameBuffer *drv = (DrvFrameBuffer *)fb->mHal.drv;
-    if(drv->mFBOId != 0) {
-        glDeleteFramebuffers(1, &drv->mFBOId);
-    }
-
-    free(fb->mHal.drv);
+    RsdFrameBufferObj *fbo = (RsdFrameBufferObj *)fb->mHal.drv;
+    delete fbo;
     fb->mHal.drv = NULL;
 }
 
diff --git a/libs/rs/driver/rsdFrameBufferObj.cpp b/libs/rs/driver/rsdFrameBufferObj.cpp
new file mode 100644
index 0000000..145bf34
--- /dev/null
+++ b/libs/rs/driver/rsdFrameBufferObj.cpp
@@ -0,0 +1,143 @@
+/*
+ * 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 "rsdFrameBufferObj.h"
+#include "rsdAllocation.h"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+RsdFrameBufferObj::RsdFrameBufferObj() {
+    mFBOId = 0;
+    mWidth = 0;
+    mHeight = 0;
+    mColorTargetsCount = 1;
+    mColorTargets = new DrvAllocation*[mColorTargetsCount];
+    for (uint32_t i = 0; i < mColorTargetsCount; i ++) {
+        mColorTargets[i] = 0;
+    }
+    mDepthTarget = NULL;
+    mDirty = true;
+}
+
+RsdFrameBufferObj::~RsdFrameBufferObj() {
+    if(mFBOId != 0) {
+        glDeleteFramebuffers(1, &mFBOId);
+    }
+    delete [] mColorTargets;
+}
+
+void RsdFrameBufferObj::checkError(const Context *rsc) {
+    GLenum status;
+    status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+    switch (status) {
+    case GL_FRAMEBUFFER_COMPLETE:
+        break;
+    case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
+        rsc->setError(RS_ERROR_BAD_VALUE,
+                      "Unable to set up render Target: RFRAMEBUFFER_INCOMPLETE_ATTACHMENT");
+        break;
+    case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
+        rsc->setError(RS_ERROR_BAD_VALUE,
+                      "Unable to set up render Target: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
+        break;
+    case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
+        rsc->setError(RS_ERROR_BAD_VALUE,
+                      "Unable to set up render Target: GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
+        break;
+    case GL_FRAMEBUFFER_UNSUPPORTED:
+        rsc->setError(RS_ERROR_BAD_VALUE,
+                      "Unable to set up render Target: GL_FRAMEBUFFER_UNSUPPORTED");
+        break;
+    }
+}
+
+
+void RsdFrameBufferObj::setDepthAttachment() {
+    if (mDepthTarget != NULL) {
+        if (mDepthTarget->textureID) {
+            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+                                   GL_TEXTURE_2D, mDepthTarget->textureID, 0);
+        } else {
+            glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+                                      GL_RENDERBUFFER, mDepthTarget->renderTargetID);
+        }
+    } else {
+        // Reset last attachment
+        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
+        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
+    }
+}
+
+void RsdFrameBufferObj::setColorAttachment() {
+    // Now attach color targets
+    for (uint32_t i = 0; i < mColorTargetsCount; i ++) {
+        if (mColorTargets[i] != NULL) {
+            if (mColorTargets[i]->textureID) {
+                glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
+                                       GL_TEXTURE_2D, mColorTargets[i]->textureID, 0);
+            } else {
+                glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
+                                          GL_RENDERBUFFER, mColorTargets[i]->renderTargetID);
+            }
+        } else {
+            // Reset last attachment
+            glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
+                                      GL_RENDERBUFFER, 0);
+            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
+                                   GL_TEXTURE_2D, 0, 0);
+        }
+    }
+}
+
+bool RsdFrameBufferObj::renderToFramebuffer() {
+    if (mDepthTarget != NULL) {
+        return false;
+    }
+
+    for (uint32_t i = 0; i < mColorTargetsCount; i ++) {
+        if (mColorTargets[i] != NULL) {
+            return false;
+        }
+    }
+    return true;
+}
+
+void RsdFrameBufferObj::setActive(const Context *rsc) {
+    bool framebuffer = renderToFramebuffer();
+    if (!framebuffer) {
+        if(mFBOId == 0) {
+            glGenFramebuffers(1, &mFBOId);
+        }
+        glBindFramebuffer(GL_FRAMEBUFFER, mFBOId);
+
+        if (mDirty) {
+            setDepthAttachment();
+            setColorAttachment();
+            mDirty = false;
+        }
+
+        glViewport(0, 0, mWidth, mHeight);
+        checkError(rsc);
+    } else {
+        glBindFramebuffer(GL_FRAMEBUFFER, 0);
+        glViewport(0, 0, rsc->getWidth(), rsc->getHeight());
+    }
+}
diff --git a/libs/rs/driver/rsdFrameBufferObj.h b/libs/rs/driver/rsdFrameBufferObj.h
new file mode 100644
index 0000000..c6e7deb
--- /dev/null
+++ b/libs/rs/driver/rsdFrameBufferObj.h
@@ -0,0 +1,59 @@
+/*
+ * 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 _RSD_FRAMEBUFFER_OBJ_H_
+#define _RSD_FRAMEBUFFER_OBJ_H_
+
+#include <rsContext.h>
+
+class DrvAllocation;
+
+class RsdFrameBufferObj {
+public:
+    RsdFrameBufferObj();
+    ~RsdFrameBufferObj();
+
+    void setActive(const android::renderscript::Context *rsc);
+    void setColorTarget(DrvAllocation *color, uint32_t index) {
+        mColorTargets[index] = color;
+        mDirty = true;
+    }
+    void setDepthTarget(DrvAllocation *depth) {
+        mDepthTarget = depth;
+        mDirty = true;
+    }
+    void setDimensions(uint32_t width, uint32_t height) {
+        mWidth = width;
+        mHeight = height;
+    }
+protected:
+    uint32_t mFBOId;
+    DrvAllocation **mColorTargets;
+    uint32_t mColorTargetsCount;
+    DrvAllocation *mDepthTarget;
+
+    uint32_t mWidth;
+    uint32_t mHeight;
+
+    bool mDirty;
+
+    bool renderToFramebuffer();
+    void checkError(const android::renderscript::Context *rsc);
+    void setColorAttachment();
+    void setDepthAttachment();
+};
+
+#endif //_RSD_FRAMEBUFFER_STATE_H_
diff --git a/libs/rs/driver/rsdGL.cpp b/libs/rs/driver/rsdGL.cpp
index a70589b..3ff03b4 100644
--- a/libs/rs/driver/rsdGL.cpp
+++ b/libs/rs/driver/rsdGL.cpp
@@ -39,6 +39,7 @@
 #include "rsContext.h"
 #include "rsdShaderCache.h"
 #include "rsdVertexArray.h"
+#include "rsdFrameBufferObj.h"
 
 using namespace android;
 using namespace android::renderscript;
@@ -294,6 +295,7 @@
     dc->gl.shaderCache = new RsdShaderCache();
     dc->gl.vertexArrayState = new RsdVertexArrayState();
     dc->gl.vertexArrayState->init(dc->gl.gl.maxVertexAttribs);
+    dc->gl.currentFrameBuffer = NULL;
 
     LOGV("initGLThread end %p", rsc);
     return true;
diff --git a/libs/rs/driver/rsdGL.h b/libs/rs/driver/rsdGL.h
index 01c8438..0d5b7e7 100644
--- a/libs/rs/driver/rsdGL.h
+++ b/libs/rs/driver/rsdGL.h
@@ -22,6 +22,7 @@
 
 class RsdShaderCache;
 class RsdVertexArrayState;
+class RsdFrameBufferObj;
 
 typedef void (* InvokeFunc_t)(void);
 typedef void (*WorkerCallback_t)(void *usr, uint32_t idx);
@@ -68,6 +69,7 @@
     uint32_t height;
     RsdShaderCache *shaderCache;
     RsdVertexArrayState *vertexArrayState;
+    RsdFrameBufferObj *currentFrameBuffer;
 } RsdGL;
 
 
diff --git a/libs/rs/driver/rsdMeshObj.cpp b/libs/rs/driver/rsdMeshObj.cpp
index c220ac1..4315c0d 100644
--- a/libs/rs/driver/rsdMeshObj.cpp
+++ b/libs/rs/driver/rsdMeshObj.cpp
@@ -138,7 +138,10 @@
 
     for (uint32_t ct=0; ct < mRSMesh->mHal.state.vertexBuffersCount; ct++) {
         const Allocation *alloc = mRSMesh->mHal.state.vertexBuffers[ct].get();
-        rsdAllocationSyncAll(rsc, alloc, RS_ALLOCATION_USAGE_SCRIPT);
+        DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
+        if (drv->uploadDeferred) {
+            rsdAllocationSyncAll(rsc, alloc, RS_ALLOCATION_USAGE_SCRIPT);
+        }
     }
 
     // update attributes with either buffer information or data ptr based on their current state
@@ -163,7 +166,9 @@
     const Allocation *idxAlloc = prim->mIndexBuffer.get();
     if (idxAlloc) {
         DrvAllocation *drvAlloc = (DrvAllocation *)idxAlloc->mHal.drv;
-        rsdAllocationSyncAll(rsc, idxAlloc, RS_ALLOCATION_USAGE_SCRIPT);
+        if (drvAlloc->uploadDeferred) {
+            rsdAllocationSyncAll(rsc, idxAlloc, RS_ALLOCATION_USAGE_SCRIPT);
+        }
 
         if (drvAlloc->bufferID) {
             glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, drvAlloc->bufferID);
diff --git a/libs/rs/driver/rsdRuntimeStubs.cpp b/libs/rs/driver/rsdRuntimeStubs.cpp
index bd8b3c3..25302aa 100644
--- a/libs/rs/driver/rsdRuntimeStubs.cpp
+++ b/libs/rs/driver/rsdRuntimeStubs.cpp
@@ -95,6 +95,8 @@
                                      Allocation *srcAlloc,
                                      uint32_t srcOff, uint32_t srcMip) {
     GET_TLS();
+    rsrAllocationCopy1DRange(rsc, dstAlloc, dstOff, dstMip, count,
+                             srcAlloc, srcOff, srcMip);
 }
 
 static void SC_AllocationCopy2DRange(Allocation *dstAlloc,
@@ -105,6 +107,11 @@
                                      uint32_t srcXoff, uint32_t srcYoff,
                                      uint32_t srcMip, uint32_t srcFace) {
     GET_TLS();
+    rsrAllocationCopy2DRange(rsc, dstAlloc,
+                             dstXoff, dstYoff, dstMip, dstFace,
+                             width, height,
+                             srcAlloc,
+                             srcXoff, srcYoff, srcMip, srcFace);
 }
 
 
diff --git a/libs/rs/rsFBOCache.cpp b/libs/rs/rsFBOCache.cpp
index 6960ef2..c5c64c2 100644
--- a/libs/rs/rsFBOCache.cpp
+++ b/libs/rs/rsFBOCache.cpp
@@ -80,16 +80,6 @@
         return;
     }
 
-    if (mHal.state.depthTarget.get() != NULL) {
-        mHal.state.depthTarget->syncAll(rsc, RS_ALLOCATION_USAGE_SCRIPT);
-    }
-
-    for (uint32_t i = 0; i < mHal.state.colorTargetsCount; i ++) {
-        if (mHal.state.colorTargets[i].get() != NULL) {
-            mHal.state.colorTargets[i]->syncAll(rsc, RS_ALLOCATION_USAGE_SCRIPT);
-        }
-    }
-
     rsc->mHal.funcs.framebuffer.setActive(rsc, this);
 
     mDirty = false;
diff --git a/libs/utils/BlobCache.cpp b/libs/utils/BlobCache.cpp
index 1298fa7..590576a 100644
--- a/libs/utils/BlobCache.cpp
+++ b/libs/utils/BlobCache.cpp
@@ -31,9 +31,13 @@
         mMaxTotalSize(maxTotalSize),
         mTotalSize(0) {
     nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+#ifdef _WIN32
+    srand(now);
+#else
     mRandState[0] = (now >> 0) & 0xFFFF;
     mRandState[1] = (now >> 16) & 0xFFFF;
     mRandState[2] = (now >> 32) & 0xFFFF;
+#endif
     LOGV("initializing random seed using %lld", now);
 }
 
@@ -148,11 +152,19 @@
     return valueBlobSize;
 }
 
+long int BlobCache::blob_random() {
+#ifdef _WIN32
+    return rand();
+#else
+    return nrand48(mRandState);
+#endif
+}
+
 void BlobCache::clean() {
     // Remove a random cache entry until the total cache size gets below half
     // the maximum total cache size.
     while (mTotalSize > mMaxTotalSize / 2) {
-        size_t i = size_t(nrand48(mRandState) % (mCacheEntries.size()));
+        size_t i = size_t(blob_random() % (mCacheEntries.size()));
         const CacheEntry& entry(mCacheEntries[i]);
         mTotalSize -= entry.getKey()->getSize() + entry.getValue()->getSize();
         mCacheEntries.removeAt(i);
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index c9e0f6f..4e271c7 100644
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -92,13 +92,18 @@
     };
     private static final String ID_WHERE = Files.FileColumns._ID + "=?";
     private static final String PATH_WHERE = Files.FileColumns.DATA + "=?";
-    private static final String PARENT_WHERE = Files.FileColumns.PARENT + "=?";
-    private static final String PARENT_FORMAT_WHERE = PARENT_WHERE + " AND "
+
+    private static final String STORAGE_WHERE = Files.FileColumns.STORAGE_ID + "=?";
+    private static final String FORMAT_WHERE = Files.FileColumns.PARENT + "=?";
+    private static final String PARENT_WHERE = Files.FileColumns.FORMAT + "=?";
+    private static final String STORAGE_FORMAT_WHERE = STORAGE_WHERE + " AND "
                                             + Files.FileColumns.FORMAT + "=?";
-    private static final String PARENT_STORAGE_WHERE = PARENT_WHERE + " AND "
-                                            + Files.FileColumns.STORAGE_ID + "=?";
-    private static final String PARENT_STORAGE_FORMAT_WHERE = PARENT_STORAGE_WHERE + " AND "
-                                            + Files.FileColumns.FORMAT + "=?";
+    private static final String STORAGE_PARENT_WHERE = STORAGE_WHERE + " AND "
+                                            + Files.FileColumns.PARENT + "=?";
+    private static final String FORMAT_PARENT_WHERE = FORMAT_WHERE + " AND "
+                                            + Files.FileColumns.PARENT + "=?";
+    private static final String STORAGE_FORMAT_PARENT_WHERE = STORAGE_FORMAT_WHERE + " AND "
+                                            + Files.FileColumns.PARENT + "=?";
 
     private final MediaScanner mMediaScanner;
 
@@ -249,26 +254,67 @@
     }
 
     private Cursor createObjectQuery(int storageID, int format, int parent) throws RemoteException {
-        if (storageID != 0) {
-            if (format != 0) {
-                return mMediaProvider.query(mObjectsUri, ID_PROJECTION,
-                        PARENT_STORAGE_FORMAT_WHERE,
-                        new String[] { Integer.toString(parent), Integer.toString(storageID),
-                                Integer.toString(format) }, null);
+        if (storageID == 0xFFFFFFFF) {
+            // query all stores
+            if (format == 0) {
+                // query all formats
+                if (parent == 0) {
+                    // query all objects
+                    return mMediaProvider.query(mObjectsUri, ID_PROJECTION, null, null, null);
+                }
+                if (parent == 0xFFFFFFFF) {
+                    // all objects in root of store
+                    parent = 0;
+                }
+                return mMediaProvider.query(mObjectsUri, ID_PROJECTION, PARENT_WHERE,
+                        new String[] { Integer.toString(parent) }, null);
             } else {
-                return mMediaProvider.query(mObjectsUri, ID_PROJECTION,
-                        PARENT_STORAGE_WHERE, new String[]
-                                { Integer.toString(parent), Integer.toString(storageID) }, null);
+                // query specific format
+                if (parent == 0) {
+                    // query all objects
+                    return mMediaProvider.query(mObjectsUri, ID_PROJECTION, FORMAT_WHERE,
+                            new String[] { Integer.toString(format) }, null);
+                }
+                if (parent == 0xFFFFFFFF) {
+                    // all objects in root of store
+                    parent = 0;
+                }
+                return mMediaProvider.query(mObjectsUri, ID_PROJECTION, FORMAT_PARENT_WHERE,
+                        new String[] { Integer.toString(format), Integer.toString(parent) }, null);
             }
         } else {
-            if (format != 0) {
-                return mMediaProvider.query(mObjectsUri, ID_PROJECTION,
-                            PARENT_FORMAT_WHERE,
-                            new String[] { Integer.toString(parent), Integer.toString(format) },
-                             null);
+            // query specific store
+            if (format == 0) {
+                // query all formats
+                if (parent == 0) {
+                    // query all objects
+                    return mMediaProvider.query(mObjectsUri, ID_PROJECTION, STORAGE_WHERE,
+                            new String[] { Integer.toString(storageID) }, null);
+                }
+                if (parent == 0xFFFFFFFF) {
+                    // all objects in root of store
+                    parent = 0;
+                }
+                return mMediaProvider.query(mObjectsUri, ID_PROJECTION, STORAGE_PARENT_WHERE,
+                        new String[] { Integer.toString(storageID), Integer.toString(parent) },
+                        null);
             } else {
-                return mMediaProvider.query(mObjectsUri, ID_PROJECTION,
-                            PARENT_WHERE, new String[] { Integer.toString(parent) }, null);
+                // query specific format
+                if (parent == 0) {
+                    // query all objects
+                    return mMediaProvider.query(mObjectsUri, ID_PROJECTION, STORAGE_FORMAT_WHERE,
+                            new String[] {  Integer.toString(storageID), Integer.toString(format) },
+                            null);
+                }
+                if (parent == 0xFFFFFFFF) {
+                    // all objects in root of store
+                    parent = 0;
+                }
+                return mMediaProvider.query(mObjectsUri, ID_PROJECTION, STORAGE_FORMAT_PARENT_WHERE,
+                        new String[] { Integer.toString(storageID),
+                                       Integer.toString(format),
+                                       Integer.toString(parent) },
+                        null);
             }
         }
     }
diff --git a/media/libeffects/factory/EffectsFactory.c b/media/libeffects/factory/EffectsFactory.c
index b0e8585..a3e76d9 100644
--- a/media/libeffects/factory/EffectsFactory.c
+++ b/media/libeffects/factory/EffectsFactory.c
@@ -257,7 +257,7 @@
     }
 
     // create effect in library
-    l->desc->create_effect(uuid, sessionId, ioId, &itfe);
+    ret = l->desc->create_effect(uuid, sessionId, ioId, &itfe);
     if (ret != 0) {
         LOGW("EffectCreate() library %s: could not create fx %s, error %d", l->name, d->name, ret);
         goto exit;
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 9ad1d4a..58f6699 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -1974,7 +1974,17 @@
     int64_t previousPausedDurationUs = 0;
     int64_t timestampUs = 0;
     int64_t cttsDeltaTimeUs = 0;
+    bool hasBFrames = false;
 
+#if 1
+    // XXX: Samsung's video encoder's output buffer timestamp
+    // is not correct. see bug 4724339
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("rw.media.record.hasb", value, NULL) &&
+        (!strcasecmp(value, "true") || !strcasecmp(value, "1"))) {
+        hasBFrames = true;
+    }
+#endif
     if (mIsAudio) {
         prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0);
     } else {
@@ -2117,7 +2127,7 @@
 
         timestampUs -= previousPausedDurationUs;
         CHECK(timestampUs >= 0);
-        if (!mIsAudio) {
+        if (!mIsAudio && hasBFrames) {
             /*
              * Composition time: timestampUs
              * Decoding time: decodingTimeUs
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 4a8fd3e..9ec73c4 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -533,12 +533,10 @@
     MtpStorageID storageID = mRequest.getParameter(1);      // 0xFFFFFFFF for all storage
     MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
     MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
-                                                            // 0x00000000 for all objects?
+                                                            // 0x00000000 for all objects
 
     if (!hasStorage(storageID))
         return MTP_RESPONSE_INVALID_STORAGE_ID;
-    if (parent == 0xFFFFFFFF)
-        parent = 0;
 
     MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
     mData.putAUInt32(handles);
@@ -552,11 +550,9 @@
     MtpStorageID storageID = mRequest.getParameter(1);      // 0xFFFFFFFF for all storage
     MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
     MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
-                                                            // 0x00000000 for all objects?
+                                                            // 0x00000000 for all objects
     if (!hasStorage(storageID))
         return MTP_RESPONSE_INVALID_STORAGE_ID;
-    if (parent == 0xFFFFFFFF)
-        parent = 0;
 
     int count = mDatabase->getNumObjects(storageID, format, parent);
     if (count >= 0) {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
index d6e1346..f3a91c5 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
@@ -1,57 +1,54 @@
 /*
  * Copyright (C) 2008 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
+ * 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
+ * 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.
+ * 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.mediaframeworktest;
 
 /**
- * 
- * This class has the names of the all the activity name and variables 
- * in the instrumentation test.
+ *
+ * This class has the names of the all the activity name and variables in the
+ * instrumentation test.
  *
  */
 public class MediaNames {
-    //A directory to hold all kinds of media files
+    // A directory to hold all kinds of media files
     public static final String MEDIA_SAMPLE_POOL = "/sdcard/media_api/samples/";
-    //Audio files
-    public static final String MP3CBR = "/sdcard/media_api/music/MP3_256kbps_2ch.mp3";
-    public static final String MP3VBR = "/sdcard/media_api/music/MP3_256kbps_2ch_VBR.mp3";
+    // Audio files
+    public static final String MP3CBR = "/sdcard/media_api/music/MP3_48KHz_128kbps_s_1_17_CBR.mp3";
+    public static final String MP3VBR = "/sdcard/media_api/music/MP3_48KHz_128kbps_s_1_17_VBR.mp3";
+    public static final String MP3ABR = "/sdcard/media_api/music/MP3_48KHz_128kbps_s_1_17_ABR.mp3";
     public static final String SHORTMP3 = "/sdcard/media_api/music/SHORTMP3.mp3";
     public static final String MIDI = "/sdcard/media_api/music/ants.mid";
-    public static final String WMA9 = "/sdcard/media_api/music/WMA9.wma";
-    public static final String WMA10 = "/sdcard/media_api/music/WMA10.wma";
     public static final String WAV = "/sdcard/media_api/music/rings_2ch.wav";
     public static final String AMR = "/sdcard/media_api/music/test_amr_ietf.amr";
-    public static final String OGG = "/sdcard/media_api/music/Revelation.ogg";
     public static final String SINE_200_1000 = "/sdcard/media_api/music/sine_200+1000Hz_44K_mo.wav";
-  
+    // public static final String OGG =
+    // "/sdcard/media_api/music/Revelation.ogg";
+
     public static final int MP3CBR_LENGTH = 71000;
     public static final int MP3VBR_LENGTH = 71000;
     public static final int SHORTMP3_LENGTH = 286;
     public static final int MIDI_LENGTH = 17000;
-    public static final int WMA9_LENGTH = 126559;
-    public static final int WMA10_LENGTH = 126559;
     public static final int AMR_LENGTH = 37000;
-    public static final int OGG_LENGTH = 4000;
     public static final int SEEK_TIME = 10000;
-  
+
     public static final long PAUSE_WAIT_TIME = 3000;
     public static final long WAIT_TIME = 2000;
     public static final long WAIT_SNAPSHOT_TIME = 5000;
 
-    //local video
+    // local video
     public static final String VIDEO_MP4 = "/sdcard/media_api/video/MPEG4_320_AAC_64.mp4";
     public static final String VIDEO_SHORT_3GP = "/sdcard/media_api/video/short.3gp";
     public static final String VIDEO_LARGE_SIZE_3GP = "/sdcard/media_api/video/border_large.3gp";
@@ -59,185 +56,105 @@
     public static final String VIDEO_H263_AMR = "/sdcard/media_api/video/H263_56_AMRNB_6.3gp";
     public static final String VIDEO_H264_AAC = "/sdcard/media_api/video/H264_320_AAC_64.3gp";
     public static final String VIDEO_H264_AMR = "/sdcard/media_api/video/H264_320_AMRNB_6.3gp";
-    public static final String VIDEO_WMV = "/sdcard/media_api/video/bugs.wmv";
     public static final String VIDEO_HIGHRES_H263 = "/sdcard/media_api/video/H263_500_AMRNB_12.3gp";
     public static final String VIDEO_HIGHRES_MP4 = "/sdcard/media_api/video/H264_500_AAC_128.3gp";
-    
-    //Media Recorder
+    public static final String VIDEO_WEBM = "/sdcard/media_api/video/big-buck-bunny_trailer.webm";
+
+    // Media Recorder
     public static final String RECORDER_OUTPUT = "/sdcard/media_api/recorderOutput.amr";
 
-    //video thumbnail
+    // video thumbnail
     public static final String THUMBNAIL_OUTPUT = "/sdcard/media_api/videoThumbnail.png";
     public static final String GOLDEN_THUMBNAIL_OUTPUT = "/sdcard/media_api/goldenThumbnail.png";
-    public static final String GOLDEN_THUMBNAIL_OUTPUT_2 = "/sdcard/media_api/goldenThumbnail2.png";
-    
-    //Metadata Utility
-    public static final String[] THUMBNAIL_CAPTURE_TEST_FILES = {
-      "/sdcard/media_api/metadata/test.mp4",
-      "/sdcard/media_api/metadata/test1.3gp",
-      "/sdcard/media_api/metadata/test2.3gp",
-      "/sdcard/media_api/metadata/test3.3gp",
-      "/sdcard/media_api/metadata/test4.3gp",
-      "/sdcard/media_api/metadata/test5.3gp",
-      "/sdcard/media_api/metadata/test6.3gp",
-      "/sdcard/media_api/metadata/test7.3gp",
-      "/sdcard/media_api/metadata/test8.3gp",
-      "/sdcard/media_api/metadata/test9.3gp",
-      "/sdcard/media_api/metadata/test10.3gp",
-      "/sdcard/media_api/metadata/test11.3gp",
-      "/sdcard/media_api/metadata/test12.3gp",
-      "/sdcard/media_api/metadata/test13.3gp",
-      "/sdcard/media_api/metadata/test14.3gp",
-      "/sdcard/media_api/metadata/test15.3gp",
-      "/sdcard/media_api/metadata/test16.3gp",
-      "/sdcard/media_api/metadata/test17.3gp",
-      "/sdcard/media_api/metadata/test18.3gp",
-      "/sdcard/media_api/metadata/test19.3gp",
-      "/sdcard/media_api/metadata/test20.3gp",
-      "/sdcard/media_api/metadata/test21.3gp",
-      "/sdcard/media_api/metadata/test22.3gp",
-      "/sdcard/media_api/metadata/test23.3gp",
-      "/sdcard/media_api/metadata/test24.3gp",
-      "/sdcard/media_api/metadata/test25.3gp",
-      "/sdcard/media_api/metadata/test26.3gp",
-      "/sdcard/media_api/metadata/test27.3gp",
-      "/sdcard/media_api/metadata/test28.3gp",
-      "/sdcard/media_api/metadata/test29.3gp",
-      "/sdcard/media_api/metadata/test30.3gp",
-      "/sdcard/media_api/metadata/test31.3gp",
-      "/sdcard/media_api/metadata/test32.3gp",
-      "/sdcard/media_api/metadata/test33.3gp",
-      "/sdcard/media_api/metadata/test35.mp4",
-      "/sdcard/media_api/metadata/test36.m4v",
-      "/sdcard/media_api/metadata/test34.wmv",
-      "/sdcard/media_api/metadata/test_metadata.mp4",
-  };
 
-  public static final String[] METADATA_RETRIEVAL_TEST_FILES = {
-      // Raw AAC is not supported
-      // "/sdcard/media_api/test_raw.aac",
-      // "/sdcard/media_api/test_adts.aac",
-      // "/sdcard/media_api/test_adif.aac",
-      "/sdcard/media_api/metadata/test_metadata.mp4",
-      "/sdcard/media_api/metadata/WMA10.wma",
-      "/sdcard/media_api/metadata/Leadsol_out.wav",
-      "/sdcard/media_api/metadata/test_aac.mp4",
-      "/sdcard/media_api/metadata/test_amr.mp4",
-      "/sdcard/media_api/metadata/test_avc_amr.mp4",
-      "/sdcard/media_api/metadata/test_metadata.mp4",
-      "/sdcard/media_api/metadata/test_vbr.mp3",
-      "/sdcard/media_api/metadata/test_cbr.mp3",
-      "/sdcard/media_api/metadata/metadata_test1.mp3",
-      "/sdcard/media_api/metadata/test33.3gp",
-      "/sdcard/media_api/metadata/test35.mp4",
-      "/sdcard/media_api/metadata/test36.m4v",
-      "/sdcard/media_api/metadata/test_m4v_amr.mp4",
-      "/sdcard/media_api/metadata/test_h263_amr.mp4",
-      "/sdcard/media_api/metadata/test34.wmv",
-  };
-  
-  public static final String[] ALBUMART_TEST_FILES = {
-      "/sdcard/media_api/album_photo/test_22_16_mp3.mp3",
-      "/sdcard/media_api/album_photo/PD_256kbps_48khz_mono_CBR_MCA.mp3",
-      "/sdcard/media_api/album_photo/PD_256kbps_44.1khz_mono_CBR_DPA.mp3",
-      "/sdcard/media_api/album_photo/PD_192kbps_32khz_mono_CBR_DPA.mp3",
-      "/sdcard/media_api/album_photo/NIN_256kbps_48khz_mono_CBR_MCA.mp3",
-      "/sdcard/media_api/album_photo/NIN_256kbps_44.1khz_mono_CBR_MCA.mp3",
-      "/sdcard/media_api/album_photo/NIN_112kbps(96kbps)_48khz_stereo_VBR_MCA.mp3",
-      "/sdcard/media_api/album_photo/NIN_112kbps(96kbps)_44.1khz_stereo_VBR_MCA.mp3",
-      "/sdcard/media_api/album_photo/lightGreen1.mp3",
-      "/sdcard/media_api/album_photo/babyBlue2 1.mp3",
-      "/sdcard/media_api/album_photo/2-01 01 NIN_56kbps(64kbps)_32khz_stereo_VBR_MCA.mp3",
-      "/sdcard/media_api/album_photo/02_NIN_112kbps(80kbps)_32khz_stereo_VBR_MCA.mp3",
-      "/sdcard/media_api/album_photo/No_Woman_No_Cry_128K.wma",
-      "/sdcard/media_api/album_photo/Beethoven_2.wma",
-  };
+    /*
+     * Metadata Utility Test media files which contain meta data.
+     */
+    public static final String[] THUMBNAIL_METADATA_TEST_FILES = {
+        "/sdcard/media_api/video/H263_500_AMRNB_12.3gp",
+        "/sdcard/media_api/video/H263_56_AAC_24.3gp",
+        "/sdcard/media_api/video/H263_56_AMRNB_6.3gp",
+        "/sdcard/media_api/video/H264_320_AAC_64.3gp",
+        "/sdcard/media_api/video/H264_320_AMRNB_6.3gp",
+        "/sdcard/media_api/video/H264_500_AAC_128.3gp",
+        "/sdcard/media_api/video/H264_HVGA_500_NO_AUDIO.3gp",
+        "/sdcard/media_api/video/H264_QVGA_500_NO_AUDIO.3gp",
+        "/sdcard/media_api/video/MPEG4_320_AAC_64.mp4",
+        "/sdcard/media_api/video/border_large.3gp",
+        "/sdcard/media_api/videoeditor/H264_BP_800x480_15fps_512kbps_AACLC_24KHz_38Kbps_s_1_17.mp4",
+        "/sdcard/media_api/videoeditor/H264_MP_960x720_25fps_800kbps_AACLC_48Khz_192Kbps_s_1_17.mp4",
+        "/sdcard/media_api/videoeditor/MPEG4_SP_640x480_15fps_512kbps_AACLC_48khz_132kbps_s_0_26.mp4",
+        "/sdcard/media_api/videoeditor/MPEG4_SP_176x144_12fps_92kbps_AMRNB_8KHz_12.2kbps_m_0_27.3gp",
+        "/sdcard/media_api/videoeditor/MPEG4_SP_720x480_30fps_280kbps_AACLC_48kHz_161kbps_s_0_26.mp4"
+    };
 
-  //TEST_PATH_1: is a video and contains metadata for key "num-tracks"
-  // TEST_PATH_2: any valid media file.
-  // TEST_PATH_3: invalid media file
-  public static final String TEST_PATH_1 = "/sdcard/media_api/metadata/test.mp4";
-  public static final String TEST_PATH_3 = "/sdcard/media_api/data.txt";
-  public static final String TEST_PATH_4 = "somenonexistingpathname";
-  public static final String TEST_PATH_5 = "mem://012345";
-  
-  //Meta data expected result
-  //The expected tag result in the following order
-  //cd_track_number, album, artist, author, composer, date, genre
-  //title, years, duration
-  public static final String META_DATA_MP3 [][] = {
-      {"/sdcard/media_api/metaDataTestMedias/MP3/ID3V1_ID3V2.mp3", "1/10", "ID3V2.3 Album", "ID3V2.3 Artist",
-          "ID3V2.3 Lyricist", "ID3V2.3 Composer", null, "Blues",
-          "ID3V2.3 Title", "1234", "295", "1", null},
-      {"/sdcard/media_api/metaDataTestMedias/MP3/ID3V2.mp3", "1/10", "ID3V2.3 Album", "ID3V2.3 Artist",
-          "ID3V2.3 Lyricist", "ID3V2.3 Composer", null, "Blues", 
-          "ID3V2.3 Title", "1234", "287", "1", null},
-      {"/sdcard/media_api/metaDataTestMedias/MP3/ID3V1.mp3", "1", "test ID3V1 Album", "test ID3V1 Artist",
-          null, null, null, "255", "test ID3V1 Title", "1234", "231332", "1", null},
-      {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V1.mp3" , null, null, null,
-              null, null, null, null, null, null, "231330", "1", null},
-      //The corrupted TALB field in id3v2 would not switch to id3v1 tag automatically
-      {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TALB.mp3", "01", null, "ID3V2.3 Artist",
-          "ID3V2.3 Lyricist", "ID3V2.3 Composer", null, 
-          "Blues", "ID3V2.3 Title", "1234", "295", "1", null},
-      {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TCOM.mp3", "01", "ID3V2.3 Album", 
-           "ID3V2.3 Artist", "ID3V2.3 Lyricist", null, null, 
-           "Blues", "ID3V2.3 Title", "1234", "295", "1", null},
-      {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TCOM_2.mp3", "01", "ID3V2.3 Album", 
-           "ID3V2.3 Artist", null, null, null, "Blues", "ID3V2.3 Title", "1234", "295", "1", null},
-      {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TRCK.mp3", "dd", "ID3V2.3 Album", 
-           "ID3V2.3 Artist", "ID3V2.3 Lyricist", "ID3V2.3 Composer", null,
-           "Blues", "ID3V2.3 Title", "1234", "295", "1", null},
-      {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TRCK_2.mp3", "01", "ID3V2.3 Album", 
-           "ID3V2.3 Artist", null, null, null, null, "ID3V2.3 Title", null, "295", "1", null},
-      {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TYER.mp3", "01", "ID3V2.3 Album",
-           "ID3V2.3 Artist", null, null, null, null, "ID3V2.3 Title", "9999", "295", "1", null},
-      {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TYER_2.mp3", "01", "ID3V2.3 Album",
-           "ID3V2.3 Artist", "ID3V2.3 Lyricist", "ID3V2.3 Composer", null, 
-           "Blues", "ID3V2.3 Title", null, "295", "1", null},
-      {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TIT.mp3", null, null, null,
-          null, null, null, null, null, null, "295", "1", null}
-  };
+    public static final String[] ALBUMART_TEST_FILES = {
+        "/sdcard/media_api/music/MP3_48KHz_128kbps_s_1_17_ID3V1_ID3V2.mp3",
+        "/sdcard/media_api/music/MP3_48KHz_128kbps_s_1_17_ID3V2.mp3",
+        "/sdcard/media_api/music/MP3_48KHz_128kbps_s_1_17_ID3V1.mp3",
+    };
 
-  //output recorded video
+    // TEST_PATH_1: is a video and contains metadata for key "num-tracks"
+    // TEST_PATH_2: any valid media file.
+    // TEST_PATH_3: invalid media file
+    public static final String TEST_PATH_1 = "/sdcard/media_api/video/MPEG4_320_AAC_64.mp4";
+    public static final String TEST_PATH_3 = "/sdcard/media_api/data.txt";
+    public static final String TEST_PATH_4 = "somenonexistingpathname";
+    public static final String TEST_PATH_5 = "mem://012345";
 
-  public static final String RECORDED_HVGA_H263 = "/sdcard/HVGA_H263.3gp";
-  public static final String RECORDED_QVGA_H263 = "/sdcard/QVGA_H263.3gp";
-  public static final String RECORDED_SQVGA_H263 = "/sdcard/SQVGA_H263.3gp";
-  public static final String RECORDED_CIF_H263 = "/sdcard/CIF_H263.3gp";
-  public static final String RECORDED_QCIF_H263 = "/sdcard/QCIF_H263.3gp";
-  public static final String RECORDED_PORTRAIT_H263 = "/sdcard/QCIF_mp4.3gp";
-  
-  public static final String RECORDED_HVGA_MP4 = "/sdcard/HVGA_mp4.mp4";
-  public static final String RECORDED_QVGA_MP4 = "/sdcard/QVGA_mp4.mp4";
-  public static final String RECORDED_SQVGA_MP4 = "/sdcard/SQVGA_mp4.mp4";
-  public static final String RECORDED_CIF_MP4 = "/sdcard/CIF_mp4.mp4";
-  public static final String RECORDED_QCIF_MP4 = "/sdcard/QCIF_mp4.mp4";
-  
-  public static final String RECORDED_VIDEO_3GP = "/sdcard/temp.3gp";
-  
-  public static final String INVALD_VIDEO_PATH = "/sdcard/media_api/filepathdoesnotexist" +
-      "/filepathdoesnotexist/temp.3gp";
-  
- 
-  public static final long RECORDED_TIME = 5000;
-  public static final long VALID_VIDEO_DURATION = 2000;
+    // Meta data expected result
+    // The expected tag result in the following order
+    // cd_track_number, album, artist, author, composer, date, genre
+    // title, years, duration
+    public static final String META_DATA_MP3[][] = {
+        {"/sdcard/media_api/music/MP3_48KHz_128kbps_s_1_17_ID3V1_ID3V2.mp3", "2/34",
+         "Test ID3V2 Album", "Test ID3V2 Artist", null, "Test ID3V2 Composer",
+         null, "(1)Classic Rock", "Test ID3V2 Title ", null, "77640", "1", null},
+        {"/sdcard/media_api/music/MP3_48KHz_128kbps_s_1_17_ID3V2.mp3", "1/10",
+         "Test ID3V2 Album", "Test ID3V2 Artist", null, "Test ID3V2 Composer",
+         null, "(74)Acid Jazz", "Test ID3V2 Tag", null, "77640", "1", null},
+        {"/sdcard/media_api/music/MP3_48KHz_128kbps_s_1_17_ID3V1.mp3", "2",
+         "Test ID3V1 Album", "Test ID3V1 Artist", null, null, null, "(15)",
+         "Test ID3V1 Title", "2011", "77640", "1", null}
+    };
 
-  //Streaming test files
-  public static final byte [] STREAM_SERVER = new byte[] {(byte)75,(byte)17,(byte)48,(byte)204};
-  public static final String STREAM_H264_480_360_1411k = 
-      "http://75.17.48.204:10088/yslau/stress_media/h264_regular.mp4";
-  public static final String STREAM_WMV = 
-      "http://75.17.48.204:10088/yslau/stress_media/bugs.wmv";
-  public static final String STREAM_H263_176x144_325k = 
-      "http://75.17.48.204:10088/yslau/stress_media/h263_regular.3gp";
-  public static final String STREAM_H264_352x288_1536k = 
-      "http://75.17.48.204:10088/yslau/stress_media/h264_highBitRate.mp4";
-  public static final String STREAM_MP3= 
-      "http://75.17.48.204:10088/yslau/stress_media/mp3_regular.mp3";
-  public static final String STREAM_MPEG4_QVGA_128k = 
-      "http://75.17.48.204:10088/yslau/stress_media/mpeg4_qvga_24fps.3gp";
-  public static final int STREAM_H264_480_360_1411k_DURATION = 46000;
-  public static final int VIDEO_H263_AAC_DURATION = 501000;
-  public static final int VIDEO_H263_AMR_DURATION = 502000;
+    // output recorded video
+    public static final String RECORDED_HVGA_H263 = "/sdcard/HVGA_H263.3gp";
+    public static final String RECORDED_QVGA_H263 = "/sdcard/QVGA_H263.3gp";
+    public static final String RECORDED_SQVGA_H263 = "/sdcard/SQVGA_H263.3gp";
+    public static final String RECORDED_CIF_H263 = "/sdcard/CIF_H263.3gp";
+    public static final String RECORDED_QCIF_H263 = "/sdcard/QCIF_H263.3gp";
+    public static final String RECORDED_PORTRAIT_H263 = "/sdcard/QCIF_mp4.3gp";
+
+    public static final String RECORDED_HVGA_MP4 = "/sdcard/HVGA_mp4.mp4";
+    public static final String RECORDED_QVGA_MP4 = "/sdcard/QVGA_mp4.mp4";
+    public static final String RECORDED_SQVGA_MP4 = "/sdcard/SQVGA_mp4.mp4";
+    public static final String RECORDED_CIF_MP4 = "/sdcard/CIF_mp4.mp4";
+    public static final String RECORDED_QCIF_MP4 = "/sdcard/QCIF_mp4.mp4";
+
+    public static final String RECORDED_VIDEO_3GP = "/sdcard/temp.3gp";
+
+    public static final String INVALD_VIDEO_PATH =
+            "/sdcard/media_api/filepathdoesnotexist" + "/filepathdoesnotexist/temp.3gp";
+
+    public static final long RECORDED_TIME = 5000;
+    public static final long VALID_VIDEO_DURATION = 2000;
+
+    // Streaming test files
+    public static final byte[] STREAM_SERVER =
+            new byte[] {(byte) 75, (byte) 17, (byte) 48, (byte) 204};
+    public static final String STREAM_H264_480_360_1411k =
+            "http://75.17.48.204:10088/yslau/stress_media/h264_regular.mp4";
+    public static final String STREAM_WMV = "http://75.17.48.204:10088/yslau/stress_media/bugs.wmv";
+    public static final String STREAM_H263_176x144_325k =
+            "http://75.17.48.204:10088/yslau/stress_media/h263_regular.3gp";
+    public static final String STREAM_H264_352x288_1536k =
+            "http://75.17.48.204:10088/yslau/stress_media/h264_highBitRate.mp4";
+    public static final String STREAM_MP3 =
+            "http://75.17.48.204:10088/yslau/stress_media/mp3_regular.mp3";
+    public static final String STREAM_MPEG4_QVGA_128k =
+            "http://75.17.48.204:10088/yslau/stress_media/mpeg4_qvga_24fps.3gp";
+    public static final int STREAM_H264_480_360_1411k_DURATION = 46000;
+    public static final int VIDEO_H263_AAC_DURATION = 501000;
+    public static final int VIDEO_H263_AMR_DURATION = 502000;
 }
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java
index 00e0a52..380de9c 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java
@@ -41,10 +41,7 @@
     }
     
     public static enum MP3_TEST_FILE{
-        ID3V1V2, ID3V2, ID3V1,
-        CORRUPTED_ID3V1, CORRUPTED_ID3V2_TALB, CORRUPTED_ID3V2_TCOM,
-        CORRUPTED_ID3V2_TCOM_2, CORRUPTED_ID3V2_TRCK, CORRUPTED_D3V2_TRCK_2,
-        CORRUPTED_ID3V2_TYER, CORRUPTED_ID3V2_TYER_2, CORRUPTED_ID3V2_TIT
+        ID3V1V2, ID3V2, ID3V1
     }
     
     public static METADATA_EXPECTEDRESULT meta;
@@ -64,53 +61,7 @@
     public static void testID3V1Metadata() throws Exception {
         validateMetatData(mp3_test_file.ID3V1.ordinal(), MediaNames.META_DATA_MP3);
     }
-    
-    @MediumTest
-    public static void testCorruptedID3V1Metadata() throws Exception {
-        validateMetatData(mp3_test_file.CORRUPTED_ID3V1.ordinal(), MediaNames.META_DATA_MP3);
-    }
 
-    @MediumTest
-    public static void testCorrupted_ID3V2_TALBMetadata() throws Exception {
-        validateMetatData(mp3_test_file.CORRUPTED_ID3V2_TALB.ordinal(), MediaNames.META_DATA_MP3);
-    }
-    
-    @MediumTest
-    public static void testCorrupted_ID3V2_TCOMMetadata() throws Exception {
-        validateMetatData(mp3_test_file.CORRUPTED_ID3V2_TCOM.ordinal(), MediaNames.META_DATA_MP3);
-    }
-    
-    @MediumTest
-    public static void testCorrupted_ID3V2_TCOMM2etadata() throws Exception {
-        validateMetatData(mp3_test_file.CORRUPTED_ID3V2_TCOM_2.ordinal(), MediaNames.META_DATA_MP3);
-    }
-    
-    @MediumTest
-    public static void testCorrupted_ID3V2_TRCKMetadata() throws Exception {
-        validateMetatData(mp3_test_file.CORRUPTED_ID3V2_TRCK.ordinal(), MediaNames.META_DATA_MP3);
-    }
-    
-    @MediumTest
-    public static void testCorrupted_ID3V2_TRCK2Metadata() throws Exception {
-        validateMetatData(mp3_test_file.CORRUPTED_D3V2_TRCK_2.ordinal(), MediaNames.META_DATA_MP3);
-    }
-   
-    @MediumTest
-    public static void testCorrupted_ID3V2_TYERMetadata() throws Exception {
-        validateMetatData(mp3_test_file.CORRUPTED_ID3V2_TYER.ordinal(), MediaNames.META_DATA_MP3);
-    }
-    
-    @MediumTest
-    public static void testCorrupted_ID3V2_TYER2Metadata() throws Exception {
-        validateMetatData(mp3_test_file.CORRUPTED_ID3V2_TYER_2.ordinal(), MediaNames.META_DATA_MP3);
-    }
-    
-    @MediumTest
-    public static void testCorrupted_ID3V2_TITMetadata() throws Exception {
-        validateMetatData(mp3_test_file.CORRUPTED_ID3V2_TIT.ordinal(), MediaNames.META_DATA_MP3);
-    }
-   
-     
     private static void validateMetatData(int fileIndex, String meta_data_file[][]) {
         Log.v(TAG, "filePath = "+ meta_data_file[fileIndex][0]);
         if ((meta_data_file[fileIndex][0].endsWith("wma") && !MediaProfileReader.getWMAEnable()) ||
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
index 3a9564d..57d5368 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
@@ -84,15 +84,6 @@
       duratoinWithinTolerence = verifyDuration(duration, MediaNames.MIDI_LENGTH);
       assertTrue("MIDI getDuration", duratoinWithinTolerence);  
     }
-    
-    @MediumTest
-    public void testWMA9GetDuration() throws Exception {
-      if (isWMAEnable) {
-            int duration = CodecTest.getDuration(MediaNames.WMA9);
-            duratoinWithinTolerence = verifyDuration(duration, MediaNames.WMA9_LENGTH);
-            assertTrue("WMA9 getDuration", duratoinWithinTolerence);
-        }
-    }
 
     @MediumTest
     public void testAMRGetDuration() throws Exception {
@@ -127,15 +118,7 @@
       boolean currentPosition = CodecTest.getCurrentPosition(MediaNames.MIDI);  
       assertTrue("MIDI GetCurrentPosition", currentPosition);  
     }
-    
-    @LargeTest
-    public void testWMA9GetCurrentPosition() throws Exception {
-        if (isWMAEnable) {
-            boolean currentPosition = CodecTest.getCurrentPosition(MediaNames.WMA9);
-            assertTrue("WMA9 GetCurrentPosition", currentPosition);
-        }
-    }
-    
+
     @LargeTest
     public void testAMRGetCurrentPosition() throws Exception {
       boolean currentPosition = CodecTest.getCurrentPosition(MediaNames.AMR);  
@@ -166,15 +149,7 @@
       boolean isPaused = CodecTest.pause(MediaNames.MIDI);  
       assertTrue("MIDI Pause", isPaused);  
     }
-   
-    @LargeTest
-    public void testWMA9Pause() throws Exception {
-        if (isWMAEnable) {
-            boolean isPaused = CodecTest.pause(MediaNames.WMA9);
-            assertTrue("WMA9 Pause", isPaused);
-        }
-    }
-  
+
     @LargeTest
     public void testAMRPause() throws Exception {
       boolean isPaused = CodecTest.pause(MediaNames.AMR);  
@@ -239,15 +214,7 @@
       boolean isLoop = CodecTest.setLooping(MediaNames.MIDI);  
       assertTrue("MIDI setLooping", isLoop);  
     }
-    
-    @LargeTest
-    public void testWMA9SetLooping() throws Exception {
-      if (isWMAEnable) {
-        boolean isLoop = CodecTest.setLooping(MediaNames.WMA9);
-        assertTrue("WMA9 setLooping", isLoop);
-      }
-    }
-    
+
     @LargeTest
     public void testAMRSetLooping() throws Exception {
       boolean isLoop = CodecTest.setLooping(MediaNames.AMR);  
@@ -279,15 +246,7 @@
       boolean isLoop = CodecTest.seekTo(MediaNames.MIDI);  
       assertTrue("MIDI seekTo", isLoop);  
     }
-    
-    @LargeTest
-    public void testWMA9SeekTo() throws Exception {
-        if (isWMAEnable) {
-            boolean isLoop = CodecTest.seekTo(MediaNames.WMA9);
-            assertTrue("WMA9 seekTo", isLoop);
-        }
-    }
-    
+
     @LargeTest
     public void testAMRSeekTo() throws Exception {
       boolean isLoop = CodecTest.seekTo(MediaNames.AMR);  
@@ -320,15 +279,6 @@
       boolean isEnd = CodecTest.seekToEnd(MediaNames.MIDI);  
       assertTrue("MIDI seekToEnd", isEnd);  
     }
-
-    @Suppress
-    @LargeTest
-    public void testWMA9SeekToEnd() throws Exception {
-        if (isWMAEnable) {
-            boolean isEnd = CodecTest.seekToEnd(MediaNames.WMA9);
-            assertTrue("WMA9 seekToEnd", isEnd);
-        }
-    }
     
     @LargeTest
     public void testAMRSeekToEnd() throws Exception {
@@ -393,17 +343,13 @@
       boolean isSeek = CodecTest.videoSeekTo(MediaNames.VIDEO_H264_AMR);
       assertTrue("H264AMR SeekTo", isSeek);         
     }
-   
+
     @LargeTest
-    public void testVideoWMVSeekTo() throws Exception {
-        Log.v(TAG, "wmv not enable");
-        if (isWMVEnable) {
-            Log.v(TAG, "wmv enable");
-            boolean isSeek = CodecTest.videoSeekTo(MediaNames.VIDEO_WMV);
-            assertTrue("WMV SeekTo", isSeek);
-        }
+    public void testVideoWebmSeekTo() throws Exception {
+      boolean isSeek = CodecTest.videoSeekTo(MediaNames.VIDEO_WEBM);
+      assertTrue("WEBM SeekTo", isSeek);
     }
-    
+
     @LargeTest
     public void testSoundRecord() throws Exception {
       boolean isRecordered = CodecTest.mediaRecorderRecord(MediaNames.RECORDER_OUTPUT);
@@ -412,7 +358,7 @@
   
     @LargeTest
     public void testGetThumbnail() throws Exception {
-      boolean getThumbnail = CodecTest.getThumbnail(MediaNames.VIDEO_H264_AAC, MediaNames.GOLDEN_THUMBNAIL_OUTPUT_2);
+      boolean getThumbnail = CodecTest.getThumbnail(MediaNames.VIDEO_H264_AAC, MediaNames.GOLDEN_THUMBNAIL_OUTPUT);
       assertTrue("Get Thumbnail", getThumbnail);         
     }
     
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
index 3b5b9a3..b396223 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
@@ -356,26 +356,6 @@
         assertTrue("H264 playback memory test", memoryResult);
     }
 
-    // Test case 3: Capture the memory usage after each 20 WMV playback
-    @LargeTest
-    public void testWMVVideoPlaybackMemoryUsage() throws Exception {
-        boolean memoryResult = false;
-        if (MediaProfileReader.getWMVEnable()){
-            mStartPid = getMediaserverPid();
-            File wmvMemoryOut = new File(MEDIA_MEMORY_OUTPUT);
-            Writer output = new BufferedWriter(new FileWriter(wmvMemoryOut, true));
-            output.write("WMV video playback only\n");
-            for (int i = 0; i < NUM_STRESS_LOOP; i++) {
-                mediaStressPlayback(MediaNames.VIDEO_WMV);
-                getMemoryWriteToLog(output, i);
-            }
-            output.write("\n");
-            memoryResult = validateMemoryResult(mStartPid, mStartMemory, output, DECODER_LIMIT);
-            output.close();
-            assertTrue("wmv playback memory test", memoryResult);
-        }
-    }
-
     // Test case 4: Capture the memory usage after every 20 video only recorded
     @LargeTest
     public void testH263RecordVideoOnlyMemoryUsage() throws Exception {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java
index a66db05..8eb75f3 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java
@@ -76,29 +76,29 @@
         boolean hasFailed = false;
         Log.v(TAG, "Thumbnail processing starts");
         long startedAt = System.currentTimeMillis();
-        for(int i = 0, n = MediaNames.THUMBNAIL_CAPTURE_TEST_FILES.length; i < n; ++i) {
+        for(int i = 0, n = MediaNames.THUMBNAIL_METADATA_TEST_FILES.length; i < n; ++i) {
             try {
-                Log.v(TAG, "File " + i + ": " + MediaNames.THUMBNAIL_CAPTURE_TEST_FILES[i]);
-                if ((MediaNames.THUMBNAIL_CAPTURE_TEST_FILES[i].endsWith(".wma") && !supportWMA) ||
-                    (MediaNames.THUMBNAIL_CAPTURE_TEST_FILES[i].endsWith(".wmv") && !supportWMV)
+                Log.v(TAG, "File " + i + ": " + MediaNames.THUMBNAIL_METADATA_TEST_FILES[i]);
+                if ((MediaNames.THUMBNAIL_METADATA_TEST_FILES[i].endsWith(".wma") && !supportWMA) ||
+                    (MediaNames.THUMBNAIL_METADATA_TEST_FILES[i].endsWith(".wmv") && !supportWMV)
                    ) {
                     Log.v(TAG, "windows media is not supported and thus we will skip the test for this file");
                     continue;
                 }
-                retriever.setDataSource(MediaNames.THUMBNAIL_CAPTURE_TEST_FILES[i]);
+                retriever.setDataSource(MediaNames.THUMBNAIL_METADATA_TEST_FILES[i]);
                 Bitmap bitmap = retriever.getFrameAtTime(-1);
                 assertTrue(bitmap != null);
                 try {
-                    java.io.OutputStream stream = new FileOutputStream(MediaNames.THUMBNAIL_CAPTURE_TEST_FILES[i] + ".jpg");
+                    java.io.OutputStream stream = new FileOutputStream(MediaNames.THUMBNAIL_METADATA_TEST_FILES[i] + ".jpg");
                     bitmap.compress(Bitmap.CompressFormat.JPEG, 75, stream);
                     stream.close();
                 } catch (Exception e) {
-                    Log.e(TAG, "Fails to convert the bitmap to a JPEG file for " + MediaNames.THUMBNAIL_CAPTURE_TEST_FILES[i]);
+                    Log.e(TAG, "Fails to convert the bitmap to a JPEG file for " + MediaNames.THUMBNAIL_METADATA_TEST_FILES[i]);
                     hasFailed = true;
                     Log.e(TAG, e.toString());
                 }
             } catch(Exception e) {
-                Log.e(TAG, "Fails to setDataSource for file " + MediaNames.THUMBNAIL_CAPTURE_TEST_FILES[i]);
+                Log.e(TAG, "Fails to setDataSource for file " + MediaNames.THUMBNAIL_METADATA_TEST_FILES[i]);
                 hasFailed = true;
             }
             Thread.yield();  // Don't be evil
@@ -106,7 +106,7 @@
         long endedAt = System.currentTimeMillis();
         retriever.release();
         assertTrue(!hasFailed);
-        Log.v(TAG, "Average processing time per thumbnail: " + (endedAt - startedAt)/MediaNames.THUMBNAIL_CAPTURE_TEST_FILES.length + " ms");
+        Log.v(TAG, "Average processing time per thumbnail: " + (endedAt - startedAt)/MediaNames.THUMBNAIL_METADATA_TEST_FILES.length + " ms");
     }
     
     @LargeTest
@@ -115,19 +115,19 @@
         boolean supportWMV = MediaProfileReader.getWMVEnable();
         boolean hasFailed = false;
         MediaMetadataRetriever retriever = new MediaMetadataRetriever();
-        for(int i = 0, n = MediaNames.METADATA_RETRIEVAL_TEST_FILES.length; i < n; ++i) {
+        for(int i = 0, n = MediaNames.THUMBNAIL_METADATA_TEST_FILES.length; i < n; ++i) {
             try {
-                Log.v(TAG, "File " + i + ": " + MediaNames.METADATA_RETRIEVAL_TEST_FILES[i]);
-                if ((MediaNames.METADATA_RETRIEVAL_TEST_FILES[i].endsWith(".wma") && !supportWMA) ||
-                    (MediaNames.METADATA_RETRIEVAL_TEST_FILES[i].endsWith(".wmv") && !supportWMV)
+                Log.v(TAG, "File " + i + ": " + MediaNames.THUMBNAIL_METADATA_TEST_FILES[i]);
+                if ((MediaNames.THUMBNAIL_METADATA_TEST_FILES[i].endsWith(".wma") && !supportWMA) ||
+                    (MediaNames.THUMBNAIL_METADATA_TEST_FILES[i].endsWith(".wmv") && !supportWMV)
                    ) {
                     Log.v(TAG, "windows media is not supported and thus we will skip the test for this file");
                     continue;
                 }
-                retriever.setDataSource(MediaNames.METADATA_RETRIEVAL_TEST_FILES[i]);
+                retriever.setDataSource(MediaNames.THUMBNAIL_METADATA_TEST_FILES[i]);
                 extractAllSupportedMetadataValues(retriever);
             } catch(Exception e) {
-                Log.e(TAG, "Fails to setDataSource for file " + MediaNames.METADATA_RETRIEVAL_TEST_FILES[i]);
+                Log.e(TAG, "Fails to setDataSource for file " + MediaNames.THUMBNAIL_METADATA_TEST_FILES[i]);
                 hasFailed = true;
             }
             Thread.yield();  // Don't be evil
@@ -239,45 +239,6 @@
         assertTrue(!hasFailed);
     }
 
-    @MediumTest
-    public static void testIntendedUsage() {
-        // By default, capture frame and retrieve metadata
-        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
-        boolean hasFailed = false;
-        retriever.setDataSource(MediaNames.TEST_PATH_1);
-        assertTrue(retriever.getFrameAtTime(-1) != null);
-        assertTrue(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS) != null);
-
-        // Do not capture frame or retrieve metadata
-        retriever.setDataSource(MediaNames.TEST_PATH_1);
-        if (retriever.getFrameAtTime(-1) != null) {
-            Log.e(TAG, "No frame expected, but is available");
-            hasFailed = true;
-        }
-        if (retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS) != null) {
-            Log.e(TAG, "No num track metadata expected, but is available");
-            hasFailed = true;
-        }
-
-        // Capture frame only
-        retriever.setDataSource(MediaNames.TEST_PATH_1);
-        assertTrue(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS) == null);
-
-        // Retriever metadata only
-        retriever.setDataSource(MediaNames.TEST_PATH_1);
-        if (retriever.getFrameAtTime(-1) != null) {
-            Log.e(TAG, "No frame expected, but is available");
-            hasFailed = true;
-        }
-
-        // Capture frame and retrieve metadata
-        retriever.setDataSource(MediaNames.TEST_PATH_1);
-        assertTrue(retriever.getFrameAtTime(-1) != null);
-        assertTrue(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS) != null);
-        retriever.release();
-        assertTrue(!hasFailed);
-    }
-
     // TODO:
     // Encode and test for the correct mix of metadata elements on a per-file basis?
     // We should be able to compare the actual returned metadata with the expected metadata
diff --git a/media/tests/contents/media_api/goldenThumbnail.png b/media/tests/contents/media_api/goldenThumbnail.png
new file mode 100755
index 0000000..3bb6ed2
--- /dev/null
+++ b/media/tests/contents/media_api/goldenThumbnail.png
Binary files differ
diff --git a/media/tests/contents/media_api/music/MP3_48KHz_128kbps_s_1_17.mp3 b/media/tests/contents/media_api/music/MP3_48KHz_128kbps_s_1_17.mp3
new file mode 100755
index 0000000..e0d6a17
--- /dev/null
+++ b/media/tests/contents/media_api/music/MP3_48KHz_128kbps_s_1_17.mp3
Binary files differ
diff --git a/media/tests/contents/media_api/music/MP3_48KHz_128kbps_s_1_17_ABR.mp3 b/media/tests/contents/media_api/music/MP3_48KHz_128kbps_s_1_17_ABR.mp3
new file mode 100644
index 0000000..12f7193
--- /dev/null
+++ b/media/tests/contents/media_api/music/MP3_48KHz_128kbps_s_1_17_ABR.mp3
Binary files differ
diff --git a/media/tests/contents/media_api/music/MP3_48KHz_128kbps_s_1_17_CBR.mp3 b/media/tests/contents/media_api/music/MP3_48KHz_128kbps_s_1_17_CBR.mp3
new file mode 100644
index 0000000..12f7193
--- /dev/null
+++ b/media/tests/contents/media_api/music/MP3_48KHz_128kbps_s_1_17_CBR.mp3
Binary files differ
diff --git a/media/tests/contents/media_api/music/MP3_48KHz_128kbps_s_1_17_ID3V1.mp3 b/media/tests/contents/media_api/music/MP3_48KHz_128kbps_s_1_17_ID3V1.mp3
new file mode 100644
index 0000000..29d332b
--- /dev/null
+++ b/media/tests/contents/media_api/music/MP3_48KHz_128kbps_s_1_17_ID3V1.mp3
Binary files differ
diff --git a/media/tests/contents/media_api/music/MP3_48KHz_128kbps_s_1_17_ID3V1_ID3V2.mp3 b/media/tests/contents/media_api/music/MP3_48KHz_128kbps_s_1_17_ID3V1_ID3V2.mp3
new file mode 100644
index 0000000..ea52638
--- /dev/null
+++ b/media/tests/contents/media_api/music/MP3_48KHz_128kbps_s_1_17_ID3V1_ID3V2.mp3
Binary files differ
diff --git a/media/tests/contents/media_api/music/MP3_48KHz_128kbps_s_1_17_ID3V2.mp3 b/media/tests/contents/media_api/music/MP3_48KHz_128kbps_s_1_17_ID3V2.mp3
new file mode 100644
index 0000000..024039c
--- /dev/null
+++ b/media/tests/contents/media_api/music/MP3_48KHz_128kbps_s_1_17_ID3V2.mp3
Binary files differ
diff --git a/media/tests/contents/media_api/music/MP3_48KHz_128kbps_s_1_17_VBR.mp3 b/media/tests/contents/media_api/music/MP3_48KHz_128kbps_s_1_17_VBR.mp3
new file mode 100644
index 0000000..12f7193
--- /dev/null
+++ b/media/tests/contents/media_api/music/MP3_48KHz_128kbps_s_1_17_VBR.mp3
Binary files differ
diff --git a/media/tests/contents/media_api/music/SHORTMP3.mp3 b/media/tests/contents/media_api/music/SHORTMP3.mp3
new file mode 100755
index 0000000..8b51b5d
--- /dev/null
+++ b/media/tests/contents/media_api/music/SHORTMP3.mp3
Binary files differ
diff --git a/media/tests/contents/media_api/music/ants.mid b/media/tests/contents/media_api/music/ants.mid
new file mode 100755
index 0000000..d4ead53
--- /dev/null
+++ b/media/tests/contents/media_api/music/ants.mid
Binary files differ
diff --git a/media/tests/contents/media_api/music/bzk_chic.wav b/media/tests/contents/media_api/music/bzk_chic.wav
new file mode 100755
index 0000000..bab1a6b
--- /dev/null
+++ b/media/tests/contents/media_api/music/bzk_chic.wav
Binary files differ
diff --git a/media/tests/contents/media_api/music/sine_200+1000Hz_44K_mo.wav b/media/tests/contents/media_api/music/sine_200+1000Hz_44K_mo.wav
new file mode 100755
index 0000000..312b6fb
--- /dev/null
+++ b/media/tests/contents/media_api/music/sine_200+1000Hz_44K_mo.wav
Binary files differ
diff --git a/media/tests/contents/media_api/music/test_amr_ietf.amr b/media/tests/contents/media_api/music/test_amr_ietf.amr
new file mode 100755
index 0000000..540794c
--- /dev/null
+++ b/media/tests/contents/media_api/music/test_amr_ietf.amr
Binary files differ
diff --git a/media/tests/contents/media_api/video/big-buck-bunny_trailer.webm b/media/tests/contents/media_api/video/big-buck-bunny_trailer.webm
new file mode 100755
index 0000000..6a17395
--- /dev/null
+++ b/media/tests/contents/media_api/video/big-buck-bunny_trailer.webm
Binary files differ
diff --git a/opengl/java/com/google/android/gles_jni/EGLImpl.java b/opengl/java/com/google/android/gles_jni/EGLImpl.java
index f162d40..51d6ca8 100644
--- a/opengl/java/com/google/android/gles_jni/EGLImpl.java
+++ b/opengl/java/com/google/android/gles_jni/EGLImpl.java
@@ -85,7 +85,7 @@
             eglSurfaceId = _eglCreateWindowSurface(display, config, sur, attrib_list);
         } else if (native_window instanceof SurfaceTexture) {
             eglSurfaceId = _eglCreateWindowSurfaceTexture(display, config,
-                    ((SurfaceTexture) native_window).mSurfaceTexture, attrib_list);
+                    (SurfaceTexture) native_window, attrib_list);
         } else {
             throw new java.lang.UnsupportedOperationException(
                 "eglCreateWindowSurface() can only be called with an instance of " +
@@ -143,7 +143,7 @@
     private native int _eglCreatePbufferSurface(EGLDisplay display, EGLConfig config, int[] attrib_list);
     private native void _eglCreatePixmapSurface(EGLSurface sur, EGLDisplay display, EGLConfig config, Object native_pixmap, int[] attrib_list);
     private native int _eglCreateWindowSurface(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list);
-    private native int _eglCreateWindowSurfaceTexture(EGLDisplay display, EGLConfig config, int native_window, int[] attrib_list);
+    private native int _eglCreateWindowSurfaceTexture(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list);
     private native int _eglGetDisplay(Object native_display);
     private native int _eglGetCurrentContext();
     private native int _eglGetCurrentDisplay();
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index bbe146d6..6d8eab6 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -25,6 +25,10 @@
             android:exported="true"
             />
 
+        <activity android:name=".usb.UsbPreferenceActivity"
+             android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+             android:excludeFromRecents="true">
+        </activity>
         <activity android:name=".usb.UsbStorageActivity"
                 android:excludeFromRecents="true">
         </activity>
@@ -33,13 +37,6 @@
                 android:excludeFromRecents="true">
         </activity>
 
-        <activity android:name=".recent.RecentApplicationsActivity"
-            android:theme="@android:style/Theme.NoTitleBar"
-            android:excludeFromRecents="true"
-            android:launchMode="singleInstance"
-            android:exported="true">
-        </activity>
-
         <!-- started from UsbDeviceSettingsManager -->
         <activity android:name=".usb.UsbConfirmActivity"
             android:exported="true"
diff --git a/packages/SystemUI/res/drawable-hdpi/compat_mode_help_diagram.png b/packages/SystemUI/res/drawable-hdpi/compat_mode_help_diagram.png
new file mode 100644
index 0000000..944b1f0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/compat_mode_help_diagram.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/compat_mode_help_divider_bottom.9.png b/packages/SystemUI/res/drawable-hdpi/compat_mode_help_divider_bottom.9.png
new file mode 100644
index 0000000..2e11928
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/compat_mode_help_divider_bottom.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/compat_mode_help_divider_top.9.png b/packages/SystemUI/res/drawable-hdpi/compat_mode_help_divider_top.9.png
new file mode 100644
index 0000000..58a78b7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/compat_mode_help_divider_top.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/compat_mode_help_icon.png b/packages/SystemUI/res/drawable-hdpi/compat_mode_help_icon.png
new file mode 100644
index 0000000..46bb891
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/compat_mode_help_icon.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/compat_mode_help_top_divider.9.png b/packages/SystemUI/res/drawable-hdpi/compat_mode_help_top_divider.9.png
new file mode 100644
index 0000000..03a5639
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/compat_mode_help_top_divider.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.png
index 87a67c9..23aabce 100644
--- a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.png
+++ b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.png
new file mode 100644
index 0000000..0b0765b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-hdpi/app_icon.png b/packages/SystemUI/res/drawable-large-hdpi/app_icon.png
deleted file mode 100644
index aedf7e7..0000000
--- a/packages/SystemUI/res/drawable-large-hdpi/app_icon.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-hdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-large-hdpi/recents_bg_protect_tile.png
deleted file mode 100644
index a57c27a..0000000
--- a/packages/SystemUI/res/drawable-large-hdpi/recents_bg_protect_tile.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-mdpi/app_icon.png b/packages/SystemUI/res/drawable-large-mdpi/app_icon.png
deleted file mode 100644
index 50a8ac8..0000000
--- a/packages/SystemUI/res/drawable-large-mdpi/app_icon.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-mdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-large-mdpi/recents_bg_protect_tile.png
deleted file mode 100644
index 87c7be6..0000000
--- a/packages/SystemUI/res/drawable-large-mdpi/recents_bg_protect_tile.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-mdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-large-mdpi/recents_blue_glow.9.png
deleted file mode 100644
index 4f4ae78..0000000
--- a/packages/SystemUI/res/drawable-large-mdpi/recents_blue_glow.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-mdpi/recents_callout_line.png b/packages/SystemUI/res/drawable-large-mdpi/recents_callout_line.png
deleted file mode 100644
index 5f4c035..0000000
--- a/packages/SystemUI/res/drawable-large-mdpi/recents_callout_line.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg.png
deleted file mode 100644
index 87a67c9..0000000
--- a/packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg_press.png b/packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg_press.png
deleted file mode 100644
index a1c39e6..0000000
--- a/packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg_press.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/compat_mode_help_diagram.png b/packages/SystemUI/res/drawable-mdpi/compat_mode_help_diagram.png
new file mode 100644
index 0000000..518a5c1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/compat_mode_help_diagram.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/compat_mode_help_divider_bottom.9.png b/packages/SystemUI/res/drawable-mdpi/compat_mode_help_divider_bottom.9.png
new file mode 100644
index 0000000..3712abf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/compat_mode_help_divider_bottom.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/compat_mode_help_divider_top.9.png b/packages/SystemUI/res/drawable-mdpi/compat_mode_help_divider_top.9.png
new file mode 100644
index 0000000..a4d08c8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/compat_mode_help_divider_top.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/compat_mode_help_icon.png b/packages/SystemUI/res/drawable-mdpi/compat_mode_help_icon.png
new file mode 100644
index 0000000..233c4df
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/compat_mode_help_icon.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.png
index 87a67c9..23aabce 100644
--- a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.png
+++ b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.png
index a1c39e6..0b0765b 100644
--- a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.png
+++ b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/compat_mode_help_bg.png b/packages/SystemUI/res/drawable-nodpi/compat_mode_help_bg.png
index d1d32a4..59a70ff 100644
--- a/packages/SystemUI/res/drawable-nodpi/compat_mode_help_bg.png
+++ b/packages/SystemUI/res/drawable-nodpi/compat_mode_help_bg.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/app_icon.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/app_icon.png
deleted file mode 100644
index aedf7e7..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/app_icon.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/app_icon.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/app_icon.png
deleted file mode 100644
index 50a8ac8..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/app_icon.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/compat_mode_help_bg.png b/packages/SystemUI/res/drawable/compat_mode_help_bg.png
new file mode 100644
index 0000000..87d8c41
--- /dev/null
+++ b/packages/SystemUI/res/drawable/compat_mode_help_bg.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/compat_mode_help_diagram.png b/packages/SystemUI/res/drawable/compat_mode_help_diagram.png
deleted file mode 100644
index e212231..0000000
--- a/packages/SystemUI/res/drawable/compat_mode_help_diagram.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/compat_mode_help_icon.png b/packages/SystemUI/res/drawable/compat_mode_help_icon.png
deleted file mode 100644
index 03bbef9..0000000
--- a/packages/SystemUI/res/drawable/compat_mode_help_icon.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
index ce72f04..be4f1d7 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
@@ -39,8 +39,8 @@
         android:layout_height="wrap_content"
         android:layout_alignLeft="@id/app_thumbnail"
         android:layout_alignTop="@id/app_thumbnail"
-        android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_border_width"
-        android:layout_marginTop="@dimen/status_bar_recents_thumbnail_border_height"
+        android:layout_marginTop="@dimen/status_bar_recents_app_icon_top_margin"
+        android:layout_marginLeft="@dimen/status_bar_recents_app_icon_left_margin"
         android:maxWidth="@dimen/status_bar_recents_thumbnail_max_width"
         android:maxHeight="@dimen/status_bar_recents_thumbnail_max_height"
         android:adjustViewBounds="true"
@@ -56,7 +56,7 @@
         android:layout_alignLeft="@id/app_thumbnail"
         android:layout_below="@id/app_thumbnail"
         android:layout_marginTop="@dimen/status_bar_recents_text_description_padding"
-        android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_border_width"
+        android:layout_marginLeft="@dimen/recents_thumbnail_bg_padding_left"
         android:singleLine="true"
         android:ellipsize="marquee"
     />
@@ -71,7 +71,7 @@
         android:layout_alignLeft="@id/app_thumbnail"
         android:layout_below="@id/app_label"
         android:layout_marginTop="@dimen/status_bar_recents_text_description_padding"
-        android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_border_width"
+        android:layout_marginLeft="@dimen/recents_thumbnail_bg_padding_left"
         android:singleLine="true"
         android:ellipsize="marquee"
     />
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
index 75f5ee4..4a80489 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
@@ -27,10 +27,9 @@
     <FrameLayout
         android:id="@+id/recents_bg_protect"
         android:background="@drawable/recents_bg_protect_tile"
-        android:layout_width="wrap_content"
+        android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_alignParentBottom="true"
-        android:layout_alignParentRight="true"
         android:paddingBottom="@*android:dimen/status_bar_height"
         android:clipToPadding="false"
         android:clipChildren="false">
diff --git a/packages/SystemUI/res/layout/status_bar_recent_item.xml b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
similarity index 73%
rename from packages/SystemUI/res/layout/status_bar_recent_item.xml
rename to packages/SystemUI/res/layout-port/status_bar_recent_item.xml
index cd42d7e..76965c9 100644
--- a/packages/SystemUI/res/layout/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
@@ -36,53 +36,52 @@
     <ImageView android:id="@+id/app_icon"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_alignParentLeft="true"
-        android:layout_alignParentTop="true"
-        android:layout_marginLeft="131dip"
-        android:layout_marginTop="13dip"
+        android:layout_alignLeft="@id/app_thumbnail"
+        android:layout_alignTop="@id/app_thumbnail"
+        android:layout_marginLeft="@dimen/status_bar_recents_app_icon_left_margin"
+        android:layout_marginTop="@dimen/status_bar_recents_app_icon_top_margin"
         android:maxWidth="@dimen/status_bar_recents_thumbnail_max_width"
         android:maxHeight="@dimen/status_bar_recents_thumbnail_max_height"
         android:adjustViewBounds="true"
     />
 
-    <View android:id="@+id/recents_callout_line"
-        android:layout_width="97dip"
-        android:layout_height="1dip"
-        android:layout_alignParentTop="true"
-        android:layout_marginTop="61dip"
-        android:layout_alignParentLeft="true"
-        android:layout_marginLeft="16dip"
-        android:layout_toLeftOf="@id/app_thumbnail"
-        android:layout_marginRight="3dip"
-        android:background="@drawable/recents_callout_line"
-    />
-
     <TextView android:id="@+id/app_label"
-        android:layout_width="97dip"
+        android:layout_width="@dimen/status_bar_recents_app_label_width"
         android:layout_height="wrap_content"
-        android:textSize="@dimen/status_bar_recents_app_description_text_size"
+        android:textSize="@dimen/status_bar_recents_app_label_text_size"
         android:fadingEdge="horizontal"
         android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
         android:scrollHorizontally="true"
         android:layout_alignParentLeft="true"
-        android:layout_alignParentTop="true"
-        android:layout_marginLeft="16dip"
-        android:layout_marginTop="32dip"
+        android:layout_alignTop="@id/app_icon"
+        android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin"
         android:singleLine="true"
         android:ellipsize="marquee"
     />
 
+    <View android:id="@+id/recents_callout_line"
+        android:layout_width="@dimen/status_bar_recents_app_label_width"
+        android:layout_height="1dip"
+        android:layout_alignParentLeft="true"
+        android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin"
+        android:layout_toLeftOf="@id/app_thumbnail"
+        android:layout_below="@id/app_label"
+        android:layout_marginRight="3dip"
+        android:layout_marginTop="3dip"
+        android:background="@drawable/recents_callout_line"
+    />
+
     <TextView android:id="@+id/app_description"
-        android:layout_width="97dip"
+        android:layout_width="@dimen/status_bar_recents_app_label_width"
         android:layout_height="wrap_content"
         android:textSize="@dimen/status_bar_recents_app_description_text_size"
         android:fadingEdge="horizontal"
         android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
         android:scrollHorizontally="true"
         android:layout_alignParentLeft="true"
-        android:layout_alignParentTop="true"
-        android:layout_marginLeft="16dip"
-        android:layout_marginTop="61dip"
+        android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin"
+        android:layout_below="@id/recents_callout_line"
+        android:layout_marginTop="3dip"
         android:singleLine="true"
         android:ellipsize="marquee"
     />
diff --git a/packages/SystemUI/res/layout/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
similarity index 91%
rename from packages/SystemUI/res/layout/status_bar_recent_panel.xml
rename to packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
index 703cbc1..9391f9d 100644
--- a/packages/SystemUI/res/layout/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
@@ -22,12 +22,12 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/recents_root"
     android:layout_height="match_parent"
-    android:layout_width="wrap_content">
+    android:layout_width="match_parent">
 
     <FrameLayout
         android:id="@+id/recents_bg_protect"
         android:background="@drawable/recents_bg_protect_tile"
-        android:layout_width="wrap_content"
+        android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_alignParentBottom="true"
         android:paddingBottom="@*android:dimen/status_bar_height"
@@ -35,9 +35,9 @@
         android:clipChildren="false">
 
         <LinearLayout android:id="@+id/recents_glow"
-            android:layout_width="wrap_content"
+            android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_marginBottom="-49dip"
+            android:layout_marginBottom="0dp"
             android:layout_gravity="bottom"
             android:background="@drawable/recents_blue_glow"
             android:orientation="horizontal"
@@ -47,7 +47,7 @@
             <com.android.systemui.recent.RecentsVerticalScrollView android:id="@+id/recents_container"
                 android:layout_width="@dimen/status_bar_recents_width"
                 android:layout_height="wrap_content"
-                android:layout_marginRight="@dimen/status_bar_recents_right_glow_margin"
+                android:layout_marginRight="0dp"
                 android:divider="@null"
                 android:stackFromBottom="true"
                 android:fadingEdge="vertical"
diff --git a/packages/SystemUI/res/layout-sw600dp/compat_mode_help.xml b/packages/SystemUI/res/layout-sw600dp/compat_mode_help.xml
index df3c5a3..d29e495 100644
--- a/packages/SystemUI/res/layout-sw600dp/compat_mode_help.xml
+++ b/packages/SystemUI/res/layout-sw600dp/compat_mode_help.xml
@@ -27,51 +27,62 @@
         android:id="@+id/header"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginLeft="160dp"
+        android:layout_marginLeft="80dp"
         android:layout_marginTop="80dp"
+        android:layout_marginRight="80dp"
         android:textSize="60sp"
         android:maxLines="1"
         android:shadowRadius="8"
         android:shadowColor="#FF000000"
         android:text="@string/compat_mode_help_header"
+        android:background="@drawable/compat_mode_help_divider_top"
         />
     <ImageView
         android:id="@+id/diagram"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginLeft="160dp"
-        android:layout_marginTop="80dp"
         android:layout_centerInParent="true"
         android:src="@drawable/compat_mode_help_diagram"
         />
-    <TextView
-        android:id="@+id/explanation"
+    <RelativeLayout
+        android:orientation="horizontal"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginBottom="80dp"
-        android:layout_marginRight="240dp"
+        android:layout_height="190dp"
+        android:background="@drawable/compat_mode_help_divider_bottom"
+        android:layout_marginBottom="55dp"
+        android:layout_marginRight="80dp"
         android:layout_alignLeft="@id/header"
         android:layout_alignParentBottom="true"
-        android:shadowRadius="4"
-        android:shadowColor="#FF000000"
-        android:textSize="28sp"
-        android:text="@string/compat_mode_help_body"
-        />
-    <ImageView
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginRight="80dp"
-        android:layout_alignBottom="@id/explanation"
-        android:layout_alignParentRight="true"
-        android:src="@drawable/compat_mode_help_icon"
-        />
+        >
+        <ImageView
+            android:id="@+id/icon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentRight="true"
+            android:layout_centerVertical="true"
+            android:src="@drawable/compat_mode_help_icon"
+            />
+        <TextView
+            android:id="@+id/explanation"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_centerVertical="true"
+            android:layout_alignParentLeft="true"
+            android:layout_toLeftOf="@id/icon"
+            android:layout_marginRight="10dp"
+            android:shadowRadius="4"
+            android:shadowColor="#FF000000"
+            android:textSize="28sp"
+            android:text="@string/compat_mode_help_body"
+            />
+    </RelativeLayout>
     <Button
         android:id="@+id/button"
         android:layout_width="208dp"
         android:layout_height="48dp"
         android:layout_alignLeft="@id/header"
         android:layout_alignParentBottom="true"
-        android:layout_marginBottom="10dp"
+        android:layout_marginBottom="20dp"
         android:textSize="28sp"
         android:text="@android:string/ok"
         />
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_compat_mode_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_compat_mode_panel.xml
index c151565..a33741e 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_compat_mode_panel.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_compat_mode_panel.xml
@@ -31,13 +31,13 @@
         android:orientation="vertical"
         android:padding="10dp"
         >
-        <RadioButton android:id="@+id/compat_mode_on_radio"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/compat_mode_on" />
         <RadioButton android:id="@+id/compat_mode_off_radio"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/compat_mode_off" />
+        <RadioButton android:id="@+id/compat_mode_on_radio"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/compat_mode_on" />
     </RadioGroup>
 </com.android.systemui.statusbar.tablet.CompatModePanel>
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_notification_row.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_row.xml
deleted file mode 100644
index 93085d7..0000000
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_notification_row.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="@dimen/notification_height"
-    >
-
-    <ImageButton
-        android:id="@+id/veto"
-        android:layout_width="48dp"
-        android:layout_height="match_parent"
-        android:layout_centerVertical="true"
-        android:layout_alignParentRight="true"
-        android:src="@drawable/status_bar_veto"
-        android:scaleType="center"
-        android:background="@null"
-        android:paddingRight="8dp"
-        android:paddingLeft="8dp"
-        />
-
-    <ImageView
-        android:id="@+id/large_icon"
-        android:layout_width="@android:dimen/notification_large_icon_width"
-        android:layout_height="@android:dimen/notification_large_icon_height"
-        android:layout_alignParentTop="true"
-        android:layout_alignParentLeft="true"
-        android:scaleType="center"
-        />
-
-    <com.android.systemui.statusbar.LatestItemView android:id="@+id/content"
-        android:layout_width="match_parent"
-        android:layout_height="64dp"
-        android:layout_alignParentTop="true"
-        android:layout_toRightOf="@id/large_icon"
-        android:layout_toLeftOf="@id/veto"
-        android:focusable="true"
-        android:clickable="true"
-        />
-
-    <View
-        android:layout_width="match_parent"
-        android:layout_height="1dp"
-        android:layout_alignParentBottom="true"
-        android:background="@android:drawable/divider_horizontal_dark"
-        />
-
-</RelativeLayout>
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
index cd42d7e..9687866 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
@@ -36,53 +36,53 @@
     <ImageView android:id="@+id/app_icon"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_alignParentLeft="true"
-        android:layout_alignParentTop="true"
-        android:layout_marginLeft="131dip"
-        android:layout_marginTop="13dip"
+        android:layout_alignLeft="@id/app_thumbnail"
+        android:layout_alignTop="@id/app_thumbnail"
+        android:layout_marginLeft="@dimen/status_bar_recents_app_icon_left_margin"
+        android:layout_marginTop="@dimen/status_bar_recents_app_icon_top_margin"
         android:maxWidth="@dimen/status_bar_recents_thumbnail_max_width"
         android:maxHeight="@dimen/status_bar_recents_thumbnail_max_height"
         android:adjustViewBounds="true"
     />
 
-    <View android:id="@+id/recents_callout_line"
-        android:layout_width="97dip"
-        android:layout_height="1dip"
-        android:layout_alignParentTop="true"
-        android:layout_marginTop="61dip"
-        android:layout_alignParentLeft="true"
-        android:layout_marginLeft="16dip"
-        android:layout_toLeftOf="@id/app_thumbnail"
-        android:layout_marginRight="3dip"
-        android:background="@drawable/recents_callout_line"
-    />
-
     <TextView android:id="@+id/app_label"
-        android:layout_width="97dip"
+        android:layout_width="@dimen/status_bar_recents_app_label_width"
         android:layout_height="wrap_content"
-        android:textSize="@dimen/status_bar_recents_app_description_text_size"
+        android:textSize="@dimen/status_bar_recents_app_label_text_size"
         android:fadingEdge="horizontal"
         android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
         android:scrollHorizontally="true"
         android:layout_alignParentLeft="true"
         android:layout_alignParentTop="true"
-        android:layout_marginLeft="16dip"
+        android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin"
         android:layout_marginTop="32dip"
         android:singleLine="true"
         android:ellipsize="marquee"
     />
 
+    <View android:id="@+id/recents_callout_line"
+        android:layout_width="@dimen/status_bar_recents_app_label_width"
+        android:layout_height="1dip"
+        android:layout_below="@id/app_label"
+        android:layout_marginTop="3dip"
+        android:layout_alignParentLeft="true"
+        android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin"
+        android:layout_toLeftOf="@id/app_thumbnail"
+        android:layout_marginRight="3dip"
+        android:background="@drawable/recents_callout_line"
+    />
+
     <TextView android:id="@+id/app_description"
-        android:layout_width="97dip"
+        android:layout_width="@dimen/status_bar_recents_app_label_width"
         android:layout_height="wrap_content"
         android:textSize="@dimen/status_bar_recents_app_description_text_size"
         android:fadingEdge="horizontal"
         android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
         android:scrollHorizontally="true"
         android:layout_alignParentLeft="true"
-        android:layout_alignParentTop="true"
-        android:layout_marginLeft="16dip"
-        android:layout_marginTop="61dip"
+        android:layout_below="@id/recents_callout_line"
+        android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin"
+        android:layout_marginTop="3dip"
         android:singleLine="true"
         android:ellipsize="marquee"
     />
diff --git a/packages/SystemUI/res/layout/recent_apps_activity.xml b/packages/SystemUI/res/layout/recent_apps_activity.xml
deleted file mode 100644
index ec661e8..0000000
--- a/packages/SystemUI/res/layout/recent_apps_activity.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2008, 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.
-*/
--->
-
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical">
-
-    <!-- Title -->
-    <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:gravity="center"
-        android:textAppearance="?android:attr/textAppearanceSmall"
-        android:textColor="#80FFFFFF"
-        android:textStyle="bold"
-        android:singleLine="true"
-        android:text="@string/recent_tasks_title"
-        android:visibility="gone"/>
-
-    <!-- This is only intended to be visible when carousel is invisible -->
-    <TextView
-        android:id="@+id/no_applications_message"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        android:textAppearance="?android:attr/textAppearanceSmall"
-        android:text="@string/recent_tasks_empty"
-        android:visibility="gone"/>
-
-    <com.android.systemui.recent.RecentApplicationsCarouselView
-        android:id="@+id/carousel"
-        android:layout_width="match_parent"
-        android:layout_height="0dip"
-        android:layout_weight="1">
-    </com.android.systemui.recent.RecentApplicationsCarouselView>
-
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout/recents_detail_view.xml b/packages/SystemUI/res/layout/recents_detail_view.xml
deleted file mode 100644
index 879d0f2..0000000
--- a/packages/SystemUI/res/layout/recents_detail_view.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2008, 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.
-*/
--->
-
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical">
-
-    <!-- Application Title -->
-    <TextView android:id="@+id/app_title"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:textAppearance="?android:attr/textAppearanceMedium"
-        android:singleLine="true"/>
-
-    <!-- Application Details -->
-    <TextView
-        android:id="@+id/app_description"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:textAppearance="?android:attr/textAppearanceSmall"/>
-
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index 93085d7..aff6a6e 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -9,6 +9,7 @@
         android:layout_height="match_parent"
         android:layout_centerVertical="true"
         android:layout_alignParentRight="true"
+        android:layout_marginRight="-80dp"
         android:src="@drawable/status_bar_veto"
         android:scaleType="center"
         android:background="@null"
@@ -30,7 +31,7 @@
         android:layout_height="64dp"
         android:layout_alignParentTop="true"
         android:layout_toRightOf="@id/large_icon"
-        android:layout_toLeftOf="@id/veto"
+        android:layout_alignParentRight="true"
         android:focusable="true"
         android:clickable="true"
         />
diff --git a/packages/SystemUI/res/layout/usb_preference_buttons.xml b/packages/SystemUI/res/layout/usb_preference_buttons.xml
new file mode 100644
index 0000000..babe07e
--- /dev/null
+++ b/packages/SystemUI/res/layout/usb_preference_buttons.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<!-- Check box that is displayed in the activity resolver UI for the user
+     to make their selection the preferred activity. -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingLeft="14dip"
+    android:paddingRight="15dip"
+    android:orientation="vertical">
+
+    <Button
+        android:id="@+id/mtp_ptp_button"
+        android:text="@string/use_ptp_button_title"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:focusable="true"
+        android:clickable="true" />
+
+    <Button
+        android:id="@+id/installer_cd_button"
+        android:text="@string/installer_cd_button_title"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:focusable="true"
+        android:clickable="true" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/values-hdpi/dimens.xml b/packages/SystemUI/res/values-hdpi/dimens.xml
new file mode 100644
index 0000000..741b75a
--- /dev/null
+++ b/packages/SystemUI/res/values-hdpi/dimens.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * 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.
+*/
+-->
+<resources>
+    <!-- Offsets for rendering thumbnails over drawable recents_thumbnail_bg -->
+    <dimen name="recents_thumbnail_bg_padding_left">6px</dimen>
+    <dimen name="recents_thumbnail_bg_padding_top">7px</dimen>
+    <dimen name="recents_thumbnail_bg_padding_right">6px</dimen>
+    <dimen name="recents_thumbnail_bg_padding_bottom">6px</dimen>
+</resources>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index 6f1453e..0219a77 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -23,15 +23,17 @@
     <!-- Width of a recent app view, including all content -->
     <dimen name="status_bar_recents_thumbnail_view_width">156dp</dimen>
     <!-- How far the thumbnail for a recent app appears from left edge -->
-    <dimen name="status_bar_recents_thumbnail_left_margin">0dp</dimen>
+    <dimen name="status_bar_recents_thumbnail_left_margin">8dp</dimen>
+    <!-- How far the thumbnail for a recent app appears from top edge -->
+    <dimen name="status_bar_recents_thumbnail_top_margin">12dp</dimen>
     <!-- Width of scrollable area in recents -->
     <dimen name="status_bar_recents_width">128dp</dimen>
-    <!-- Thumbnail border width -->
-    <dimen name="status_bar_recents_thumbnail_border_width">8dp</dimen>
-    <!-- Thumbnail border height -->
-    <dimen name="status_bar_recents_thumbnail_border_height">12dp</dimen>
     <!-- Padding for text descriptions -->
     <dimen name="status_bar_recents_text_description_padding">8dp</dimen>
+    <!-- Width of application label text -->
+    <dimen name="status_bar_recents_app_label_width">97dip</dimen>
+    <!-- Left margin of application label text -->
+    <dimen name="status_bar_recents_app_label_left_margin">16dip</dimen>
     <!-- Margin between recents container and glow on the right -->
     <dimen name="status_bar_recents_right_glow_margin">0dip</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-large/dimens.xml b/packages/SystemUI/res/values-large/dimens.xml
index f8a4a1c..9d89e21 100644
--- a/packages/SystemUI/res/values-large/dimens.xml
+++ b/packages/SystemUI/res/values-large/dimens.xml
@@ -22,32 +22,6 @@
     <dimen name="status_bar_panel_bottom_offset">36dp</dimen>
     <!-- gap on either side of status bar notification icons -->
     <dimen name="status_bar_icon_padding">8dp</dimen>
-
-    <!-- Recent Applications parameters -->
-    <!-- Width of a recent app view, including all content -->
-    <dimen name="status_bar_recents_thumbnail_view_width">156dp</dimen>
-    <!-- How far the thumbnail for a recent app appears from left edge -->
-    <dimen name="status_bar_recents_thumbnail_left_margin">110dp</dimen>
-    <!-- Upper width limit for application icon -->
-    <dimen name="status_bar_recents_thumbnail_max_width">64dp</dimen>
-    <!-- Upper height limit for application icon -->
-    <dimen name="status_bar_recents_thumbnail_max_height">64dp</dimen>
-    <!-- Width of scrollable area in recents -->
-    <dimen name="status_bar_recents_width">356dp</dimen>
-    <!-- Thumbnail border width -->
-    <dimen name="status_bar_recents_thumbnail_border_width">12dp</dimen>
-    <!-- Thumbnail border height -->
-    <dimen name="status_bar_recents_thumbnail_border_height">12dp</dimen>
-    <!-- Padding for text descriptions -->
-    <dimen name="status_bar_recents_text_description_padding">8dp</dimen>
-    <!-- Size of application label text -->
-    <dimen name="status_bar_recents_app_label_text_size">18dip</dimen>
-    <!-- Size of application description text -->
-    <dimen name="status_bar_recents_app_description_text_size">18dip</dimen>
-    <!-- Size of fading edge for scroll effect -->
-    <dimen name="status_bar_recents_fading_edge_length">20dip</dimen>
-    <!-- Margin between recents container and glow on the right -->
-    <dimen name="status_bar_recents_right_glow_margin">100dip</dimen>
 </resources>
 
 
diff --git a/packages/SystemUI/res/values-mdpi/dimens.xml b/packages/SystemUI/res/values-mdpi/dimens.xml
new file mode 100644
index 0000000..741b75a
--- /dev/null
+++ b/packages/SystemUI/res/values-mdpi/dimens.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * 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.
+*/
+-->
+<resources>
+    <!-- Offsets for rendering thumbnails over drawable recents_thumbnail_bg -->
+    <dimen name="recents_thumbnail_bg_padding_left">6px</dimen>
+    <dimen name="recents_thumbnail_bg_padding_top">7px</dimen>
+    <dimen name="recents_thumbnail_bg_padding_right">6px</dimen>
+    <dimen name="recents_thumbnail_bg_padding_bottom">6px</dimen>
+</resources>
diff --git a/packages/SystemUI/res/values-port/dimens.xml b/packages/SystemUI/res/values-port/dimens.xml
new file mode 100644
index 0000000..54c25fa
--- /dev/null
+++ b/packages/SystemUI/res/values-port/dimens.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (c) 2006, 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.
+*/
+-->
+<resources>
+    <!-- Recent Applications parameters -->
+    <!-- Width of a recent app view, including all content -->
+    <dimen name="status_bar_recents_thumbnail_view_width">156dp</dimen>
+    <!-- How far the thumbnail for a recent app appears from left edge -->
+    <dimen name="status_bar_recents_thumbnail_left_margin">110dp</dimen>
+    <!-- Width of scrollable area in recents -->
+    <dimen name="status_bar_recents_width">356dp</dimen>
+    <!-- Padding for text descriptions -->
+    <dimen name="status_bar_recents_text_description_padding">8dp</dimen>
+    <!-- Width of application label text -->
+    <dimen name="status_bar_recents_app_label_width">97dip</dimen>
+    <!-- Left margin of application label text -->
+    <dimen name="status_bar_recents_app_label_left_margin">16dip</dimen>
+    <!-- Margin between recents container and glow on the right -->
+    <dimen name="status_bar_recents_right_glow_margin">100dip</dimen>
+</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 944e0ee..b4fd8ab 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -28,4 +28,40 @@
     <dimen name="notification_panel_min_height">770dp</dimen>
     <!-- Bottom margin (from display edge) for status bar panels -->
     <dimen name="panel_float">56dp</dimen>
+
+    <!-- Recent Applications parameters -->
+    <!-- Width of a recent app view, including all content -->
+    <dimen name="status_bar_recents_thumbnail_view_width">156dp</dimen>
+    <!-- How far the thumbnail for a recent app appears from left edge -->
+    <dimen name="status_bar_recents_thumbnail_left_margin">110dp</dimen>
+    <!-- Upper width limit for application icon -->
+    <dimen name="status_bar_recents_thumbnail_max_width">64dp</dimen>
+    <!-- Upper height limit for application icon -->
+    <dimen name="status_bar_recents_thumbnail_max_height">64dp</dimen>
+    <!-- Width of scrollable area in recents -->
+    <dimen name="status_bar_recents_width">356dp</dimen>
+    <!-- Padding for text descriptions -->
+    <dimen name="status_bar_recents_text_description_padding">8dp</dimen>
+    <!-- Size of application label text -->
+    <dimen name="status_bar_recents_app_label_text_size">18dip</dimen>
+    <!-- Size of application description text -->
+    <dimen name="status_bar_recents_app_description_text_size">18dip</dimen>
+    <!-- Width of application label text -->
+    <dimen name="status_bar_recents_app_label_width">97dip</dimen>
+    <!-- Left margin for application label -->
+    <dimen name="status_bar_recents_app_label_left_margin">16dip</dimen>
+    <!-- Size of fading edge for scroll effect -->
+    <dimen name="status_bar_recents_fading_edge_length">20dip</dimen>
+    <!-- Margin between recents container and glow on the right -->
+    <dimen name="status_bar_recents_right_glow_margin">100dip</dimen>
+
+    <!-- Offsets for rendering thumbnails over drawable recents_thumbnail_bg -->
+    <dimen name="recents_thumbnail_bg_padding_left">15px</dimen>
+    <dimen name="recents_thumbnail_bg_padding_top">8px</dimen>
+    <dimen name="recents_thumbnail_bg_padding_right">12px</dimen>
+    <dimen name="recents_thumbnail_bg_padding_bottom">8px</dimen>
+
+    <!-- Where to place the app icon over the thumbnail -->
+    <dimen name="status_bar_recents_app_icon_left_margin">13dp</dimen>
+    <dimen name="status_bar_recents_app_icon_top_margin">13dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 83eaaa8..fc35a48 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -20,22 +20,14 @@
     <dimen name="status_bar_edge_ignore">5dp</dimen>
 
     <!-- Recent Applications parameters -->
-    <!-- Width of a recent app view, including all content -->
-    <dimen name="status_bar_recents_thumbnail_view_width">156dp</dimen>
-    <!-- How far the thumbnail for a recent app appears from left edge -->
-    <dimen name="status_bar_recents_thumbnail_left_margin">110dp</dimen>
     <!-- Upper width limit for application icon -->
     <dimen name="status_bar_recents_thumbnail_max_width">64dp</dimen>
     <!-- Upper height limit for application icon -->
     <dimen name="status_bar_recents_thumbnail_max_height">64dp</dimen>
-    <!-- Width of scrollable area in recents -->
-    <dimen name="status_bar_recents_width">356dp</dimen>
-    <!-- Thumbnail border width -->
-    <dimen name="status_bar_recents_thumbnail_border_width">12dp</dimen>
-    <!-- Thumbnail border height -->
-    <dimen name="status_bar_recents_thumbnail_border_height">12dp</dimen>
-    <!-- Padding for text descriptions -->
-    <dimen name="status_bar_recents_text_description_padding">8dp</dimen>
+    <!-- Where to place the app icon over the thumbnail -->
+    <dimen name="status_bar_recents_app_icon_left_margin">13dp</dimen>
+    <dimen name="status_bar_recents_app_icon_top_margin">13dp</dimen>
+
     <!-- Size of application label text -->
     <dimen name="status_bar_recents_app_label_text_size">18dip</dimen>
     <!-- Size of application description text -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 8945da5..86e0cd0 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -156,4 +156,13 @@
 
     <!-- Compatibility mode help screen: body text. [CHAR LIMIT=150] -->
     <string name="compat_mode_help_body">When an app was designed for a smaller screen, a zoom control will appear by the clock.</string>
+
+    <!-- Title for the USB function chooser in UsbPreferenceActivity. [CHAR LIMIT=30] -->
+    <string name="usb_preference_title">USB file transfer options</string>
+    <!-- Label for the MTP USB function in UsbPreferenceActivity. [CHAR LIMIT=50] -->
+    <string name="use_mtp_button_title">Mount as a media player (MTP)</string>
+    <!-- Label for the PTP USB function in UsbPreferenceActivity. [CHAR LIMIT=50] -->
+    <string name="use_ptp_button_title">Mount as a camera (PTP)</string>
+    <!-- Label for the installer CD image option in UsbPreferenceActivity. [CHAR LIMIT=50] -->
+    <string name="installer_cd_button_title">Install Android File Transfer application for Mac</string>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java b/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
index b876075..49a65d8 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
@@ -36,14 +36,16 @@
     View mScrimView;
     View mContentView;
     AnimatorSet mContentAnim;
+    Animator.AnimatorListener mListener;
 
     // the panel will start to appear this many px from the end
     final int HYPERSPACE_OFFRAMP = 200;
 
-    public Choreographer(View root, View scrim, View content) {
+    public Choreographer(View root, View scrim, View content, Animator.AnimatorListener listener) {
         mRootView = root;
         mScrimView = scrim;
         mContentView = content;
+        mListener = listener;
     }
 
     void createAnimation(boolean appearing) {
@@ -86,6 +88,9 @@
                 .with(posAnim);
         mContentAnim.setDuration(appearing ? OPEN_DURATION : CLOSE_DURATION);
         mContentAnim.addListener(this);
+        if (mListener != null) {
+            mContentAnim.addListener(mListener);
+        }
     }
 
     void startAnimation(boolean appearing) {
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index 194c9d1..3dbcc59 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -16,7 +16,7 @@
 
 package com.android.systemui.recent;
 
-import com.android.systemui.recent.RecentsPanelView.ActvityDescriptionAdapter;
+import com.android.systemui.recent.RecentsPanelView.ActivityDescriptionAdapter;
 
 import android.animation.Animator;
 import android.animation.Animator.AnimatorListener;
@@ -49,7 +49,7 @@
     private static final float THRESHHOLD = 50;
     private static final boolean DEBUG_INVALIDATE = false;
     private LinearLayout mLinearLayout;
-    private ActvityDescriptionAdapter mAdapter;
+    private ActivityDescriptionAdapter mAdapter;
     private RecentsCallback mCallback;
     protected int mLastScrollPosition;
     private View mCurrentView;
@@ -273,7 +273,7 @@
         }
     }
 
-    public void setAdapter(ActvityDescriptionAdapter adapter) {
+    public void setAdapter(ActivityDescriptionAdapter adapter) {
         mAdapter = adapter;
         mAdapter.registerDataSetObserver(new DataSetObserver() {
             public void onChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index e2b3446..b8dc63d 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -19,6 +19,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import android.animation.Animator;
 import android.animation.LayoutTransition;
 import android.app.ActivityManager;
 import android.content.Context;
@@ -52,27 +53,33 @@
 import android.widget.TextView;
 
 import com.android.systemui.R;
+import com.android.systemui.statusbar.StatusBar;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.statusbar.tablet.StatusBarPanel;
 import com.android.systemui.statusbar.tablet.TabletStatusBar;
 
 public class RecentsPanelView extends RelativeLayout
-        implements OnItemClickListener, RecentsCallback, StatusBarPanel {
-    private static final int GLOW_PADDING = 15;
+        implements OnItemClickListener, RecentsCallback, StatusBarPanel, Animator.AnimatorListener {
     static final String TAG = "RecentsListView";
-    static final boolean DEBUG = TabletStatusBar.DEBUG;
+    static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG;
     private static final int DISPLAY_TASKS = 20;
     private static final int MAX_TASKS = DISPLAY_TASKS + 1; // allow extra for non-apps
-    private TabletStatusBar mBar;
+    private StatusBar mBar;
     private ArrayList<ActivityDescription> mActivityDescriptions;
     private int mIconDpi;
     private View mRecentsScrim;
     private View mRecentsGlowView;
     private View mRecentsContainer;
     private Bitmap mGlowBitmap;
+    // TODO: add these widgets attributes to the layout file
+    private int mGlowBitmapPaddingLeftPx;
+    private int mGlowBitmapPaddingTopPx;
+    private int mGlowBitmapPaddingRightPx;
+    private int mGlowBitmapPaddingBottomPx;
     private boolean mShowing;
     private Choreographer mChoreo;
     private View mRecentsDismissButton;
-    private ActvityDescriptionAdapter mListAdapter;
+    private ActivityDescriptionAdapter mListAdapter;
 
     /* package */ final static class ActivityDescription {
         int taskId; // application task id for curating apps
@@ -108,10 +115,10 @@
         ActivityDescription activityDescription;
     }
 
-    /* package */ final class ActvityDescriptionAdapter extends BaseAdapter {
+    /* package */ final class ActivityDescriptionAdapter extends BaseAdapter {
         private LayoutInflater mInflater;
 
-        public ActvityDescriptionAdapter(Context context) {
+        public ActivityDescriptionAdapter(Context context) {
             mInflater = LayoutInflater.from(context);
         }
 
@@ -183,6 +190,26 @@
         }
     }
 
+    public void onAnimationCancel(Animator animation) {
+    }
+
+    public void onAnimationEnd(Animator animation) {
+        if (mShowing) {
+            final LayoutTransition transitioner = new LayoutTransition();
+            ((ViewGroup)mRecentsContainer).setLayoutTransition(transitioner);
+            createCustomAnimations(transitioner);
+        } else {
+            ((ViewGroup)mRecentsContainer).setLayoutTransition(null);
+        }
+    }
+
+    public void onAnimationRepeat(Animator animation) {
+    }
+
+    public void onAnimationStart(Animator animation) {
+    }
+
+
     /**
      * We need to be aligned at the bottom.  LinearLayout can't do this, so instead,
      * let LinearLayout do all the hard work, and then shift everything down to the bottom.
@@ -201,7 +228,7 @@
         return mShowing;
     }
 
-    public void setBar(TabletStatusBar bar) {
+    public void setBar(StatusBar bar) {
         mBar = bar;
     }
 
@@ -217,7 +244,16 @@
                 & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE;
 
         mIconDpi = xlarge ? DisplayMetrics.DENSITY_HIGH : res.getDisplayMetrics().densityDpi;
+
         mGlowBitmap = BitmapFactory.decodeResource(res, R.drawable.recents_thumbnail_bg);
+        mGlowBitmapPaddingLeftPx =
+                res.getDimensionPixelSize(R.dimen.recents_thumbnail_bg_padding_left);
+        mGlowBitmapPaddingTopPx =
+                res.getDimensionPixelSize(R.dimen.recents_thumbnail_bg_padding_top);
+        mGlowBitmapPaddingRightPx =
+                res.getDimensionPixelSize(R.dimen.recents_thumbnail_bg_padding_right);
+        mGlowBitmapPaddingBottomPx =
+                res.getDimensionPixelSize(R.dimen.recents_thumbnail_bg_padding_bottom);
     }
 
     @Override
@@ -225,7 +261,7 @@
         super.onFinishInflate();
         mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         mRecentsContainer = findViewById(R.id.recents_container);
-        mListAdapter = new ActvityDescriptionAdapter(mContext);
+        mListAdapter = new ActivityDescriptionAdapter(mContext);
         if (mRecentsContainer instanceof RecentsListView) {
             RecentsListView listView = (RecentsListView) mRecentsContainer;
             listView.setAdapter(mListAdapter);
@@ -246,13 +282,10 @@
             throw new IllegalArgumentException("missing RecentsListView/RecentsScrollView");
         }
 
-        final LayoutTransition transitioner = new LayoutTransition();
-        ((ViewGroup)mRecentsContainer).setLayoutTransition(transitioner);
-        createCustomAnimations(transitioner);
 
         mRecentsGlowView = findViewById(R.id.recents_glow);
         mRecentsScrim = (View) findViewById(R.id.recents_bg_protect);
-        mChoreo = new Choreographer(this, mRecentsScrim, mRecentsGlowView);
+        mChoreo = new Choreographer(this, mRecentsScrim, mRecentsGlowView, this);
         mRecentsDismissButton = findViewById(R.id.recents_dismiss_button);
         mRecentsDismissButton.setOnClickListener(new OnClickListener() {
             public void onClick(View v) {
@@ -402,10 +435,9 @@
             Log.v(TAG, "Source thumb: " + srcWidth + "x" + srcHeight);
             canvas.drawBitmap(thumbnail,
                     new Rect(0, 0, srcWidth-1, srcHeight-1),
-                    new RectF(GLOW_PADDING,
-                            GLOW_PADDING - 7.0f,
-                            outBitmap.getWidth() - GLOW_PADDING + 3.0f,
-                            outBitmap.getHeight() - GLOW_PADDING + 7.0f), paint);
+                    new RectF(mGlowBitmapPaddingLeftPx, mGlowBitmapPaddingTopPx,
+                            outBitmap.getWidth() - mGlowBitmapPaddingRightPx,
+                            outBitmap.getHeight() - mGlowBitmapPaddingBottomPx), paint);
         }
         return outBitmap;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index 54ec6b5..6a962cb 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -16,7 +16,7 @@
 
 package com.android.systemui.recent;
 
-import com.android.systemui.recent.RecentsPanelView.ActvityDescriptionAdapter;
+import com.android.systemui.recent.RecentsPanelView.ActivityDescriptionAdapter;
 
 import android.animation.Animator;
 import android.animation.Animator.AnimatorListener;
@@ -49,7 +49,7 @@
     private static final float THRESHHOLD = 50;
     private static final boolean DEBUG_INVALIDATE = false;
     private LinearLayout mLinearLayout;
-    private ActvityDescriptionAdapter mAdapter;
+    private ActivityDescriptionAdapter mAdapter;
     private RecentsCallback mCallback;
     protected int mLastScrollPosition;
     private View mCurrentView;
@@ -275,7 +275,7 @@
         }
     }
 
-    public void setAdapter(ActvityDescriptionAdapter adapter) {
+    public void setAdapter(ActivityDescriptionAdapter adapter) {
         mAdapter = adapter;
         mAdapter.registerDataSetObserver(new DataSetObserver() {
             public void onChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/recent/carousel/RecentApplicationsActivity.java b/packages/SystemUI/src/com/android/systemui/recent/carousel/RecentApplicationsActivity.java
deleted file mode 100644
index 45e230f..0000000
--- a/packages/SystemUI/src/com/android/systemui/recent/carousel/RecentApplicationsActivity.java
+++ /dev/null
@@ -1,532 +0,0 @@
-/*
- * 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.
- * 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.systemui.recent.carousel;
-
-import com.android.systemui.R;
-
-import com.android.ex.carousel.CarouselView;
-import com.android.ex.carousel.CarouselViewHelper;
-import com.android.ex.carousel.CarouselRS.CarouselCallback;
-import com.android.ex.carousel.CarouselViewHelper.DetailTextureParameters;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
-import android.app.IActivityManager;
-import android.app.IThumbnailReceiver;
-import android.app.ActivityManager.RunningTaskInfo;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.PaintFlagsDrawFilter;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.PorterDuff;
-import android.graphics.Bitmap.Config;
-import android.graphics.drawable.Drawable;
-import android.graphics.PixelFormat;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.util.Log;
-import android.view.View;
-import android.view.View.MeasureSpec;
-import android.widget.TextView;
-
-public class RecentApplicationsActivity extends Activity {
-    private static final String TAG = "RecentApplicationsActivity";
-    private static boolean DBG = false;
-    private static final int CARD_SLOTS = 56;
-    private static final int VISIBLE_SLOTS = 7;
-    private static final int MAX_TASKS = VISIBLE_SLOTS * 2;
-
-    // TODO: these should be configurable
-    private static final int DETAIL_TEXTURE_MAX_WIDTH = 200;
-    private static final int DETAIL_TEXTURE_MAX_HEIGHT = 80;
-    private static final int TEXTURE_WIDTH = 256;
-    private static final int TEXTURE_HEIGHT = 256;
-
-    private ActivityManager mActivityManager;
-    private List<RunningTaskInfo> mRunningTaskList;
-    private boolean mPortraitMode = true;
-    private ArrayList<ActivityDescription> mActivityDescriptions
-            = new ArrayList<ActivityDescription>();
-    private CarouselView mCarouselView;
-    private LocalCarouselViewHelper mHelper;
-    private View mNoRecentsView;
-    private Bitmap mLoadingBitmap;
-    private Bitmap mRecentOverlay;
-    private boolean mHidden = false;
-    private boolean mHiding = false;
-    private DetailInfo mDetailInfo;
-
-    /**
-     * This class is a container for all items associated with the DetailView we'll
-     * be drawing to a bitmap and sending to Carousel.
-     *
-     */
-    static final class DetailInfo {
-        public DetailInfo(View _view, TextView _title, TextView _desc) {
-            view = _view;
-            title = _title;
-            description = _desc;
-        }
-
-        /**
-         * Draws view into the given bitmap, if provided
-         * @param bitmap
-         */
-        public Bitmap draw(Bitmap bitmap) {
-            resizeView(view, DETAIL_TEXTURE_MAX_WIDTH, DETAIL_TEXTURE_MAX_HEIGHT);
-            int desiredWidth = view.getWidth();
-            int desiredHeight = view.getHeight();
-            if (bitmap == null || desiredWidth != bitmap.getWidth()
-                    || desiredHeight != bitmap.getHeight()) {
-                bitmap = Bitmap.createBitmap(desiredWidth, desiredHeight, Config.ARGB_8888);
-            }
-            Canvas canvas = new Canvas(bitmap);
-            view.draw(canvas);
-            return bitmap;
-        }
-
-        /**
-         * Force a layout pass on the given view.
-         */
-        private void resizeView(View view, int maxWidth, int maxHeight) {
-            int widthSpec = MeasureSpec.getMode(MeasureSpec.AT_MOST)
-                    | MeasureSpec.getSize(maxWidth);
-            int heightSpec = MeasureSpec.getMode(MeasureSpec.AT_MOST)
-                    | MeasureSpec.getSize(maxHeight);
-            view.measure(widthSpec, heightSpec);
-            view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
-            Log.v(TAG, "RESIZED VIEW: " + view.getWidth() + ", " + view.getHeight());
-        }
-
-        public View view;
-        public TextView title;
-        public TextView description;
-    }
-
-    static class ActivityDescription {
-        int id;
-        Bitmap thumbnail; // generated by Activity.onCreateThumbnail()
-        Drawable icon; // application package icon
-        String label; // application package label
-        CharSequence description; // generated by Activity.onCreateDescription()
-        Intent intent; // launch intent for application
-        Matrix matrix; // arbitrary rotation matrix to correct orientation
-        int position; // position in list
-
-        public ActivityDescription(Bitmap _thumbnail,
-                Drawable _icon, String _label, String _desc, int _id, int _pos)
-        {
-            thumbnail = _thumbnail;
-            icon = _icon;
-            label = _label;
-            description = _desc;
-            id = _id;
-            position = _pos;
-        }
-
-        public void clear() {
-            icon = null;
-            thumbnail = null;
-            label = null;
-            description = null;
-            intent = null;
-            matrix = null;
-            id = -1;
-            position = -1;
-        }
-    };
-
-    private ActivityDescription findActivityDescription(int id) {
-        for (int i = 0; i < mActivityDescriptions.size(); i++) {
-            ActivityDescription item = mActivityDescriptions.get(i);
-            if (item != null && item.id == id) {
-                return item;
-            }
-        }
-        return null;
-    }
-
-    private class LocalCarouselViewHelper extends CarouselViewHelper {
-        private DetailTextureParameters mDetailParams = new DetailTextureParameters(10.0f, 20.0f);
-
-        public LocalCarouselViewHelper(Context context) {
-            super(context);
-        }
-
-        @Override
-        public DetailTextureParameters getDetailTextureParameters(int id) {
-            return mDetailParams;
-        }
-
-        public void onCardSelected(int n) {
-            if (n < mActivityDescriptions.size()) {
-                ActivityDescription item = mActivityDescriptions.get(n);
-                if (item.id >= 0) {
-                    // This is an active task; it should just go to the foreground.
-                    final ActivityManager am = (ActivityManager)
-                            getSystemService(Context.ACTIVITY_SERVICE);
-                    am.moveTaskToFront(item.id, ActivityManager.MOVE_TASK_WITH_HOME);
-                } else if (item.intent != null) {
-                    // prepare a launch intent and send it
-                    item.intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
-                            | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
-                    try {
-                        if (DBG) Log.v(TAG, "Starting intent " + item.intent);
-                        startActivity(item.intent);
-                        overridePendingTransition(R.anim.recent_app_enter, R.anim.recent_app_leave);
-                    } catch (ActivityNotFoundException e) {
-                        if (DBG) Log.w("Recent", "Unable to launch recent task", e);
-                    }
-                    finish();
-                }
-            }
-        }
-
-        @Override
-        public Bitmap getTexture(final int id) {
-            if (DBG) Log.v(TAG, "onRequestTexture(" + id + ")");
-            ActivityDescription info;
-            synchronized(mActivityDescriptions) {
-                info = mActivityDescriptions.get(id);
-            }
-            Bitmap bitmap = null;
-            if (info != null) {
-                bitmap = compositeBitmap(info);
-            }
-            return bitmap;
-        }
-
-        @Override
-        public Bitmap getDetailTexture(int n) {
-            Bitmap bitmap = null;
-            if (n < mActivityDescriptions.size()) {
-                ActivityDescription item = mActivityDescriptions.get(n);
-                mDetailInfo.title.setText(item.label);
-                mDetailInfo.description.setText(item.description);
-                bitmap = mDetailInfo.draw(null);
-            }
-            return bitmap;
-        }
-    };
-
-    private Bitmap compositeBitmap(ActivityDescription info) {
-        final int targetWidth = TEXTURE_WIDTH;
-        final int targetHeight = TEXTURE_HEIGHT;
-        final int border = 3; // inset along the edge for thumnnail content
-        final int overlap = 1; // how many pixels of overlap between border and thumbnail
-        final Resources res = getResources();
-        if (mRecentOverlay == null) {
-            mRecentOverlay = BitmapFactory.decodeResource(res, R.drawable.recent_overlay);
-        }
-
-        // Create a bitmap of the proper size/format and set the canvas to draw to it
-        final Bitmap result = Bitmap.createBitmap(targetWidth, targetHeight, Bitmap.Config.ARGB_8888);
-        final Canvas canvas = new Canvas(result);
-        canvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG, Paint.FILTER_BITMAP_FLAG));
-        Paint paint = new Paint();
-        paint.setFilterBitmap(false);
-
-        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
-        canvas.save();
-        if (info.thumbnail != null) {
-            // Draw the thumbnail
-            int sourceWidth = targetWidth - 2 * (border - overlap);
-            int sourceHeight = targetHeight - 2 * (border - overlap);
-            final float scaleX = (float) sourceWidth / info.thumbnail.getWidth();
-            final float scaleY = (float) sourceHeight / info.thumbnail.getHeight();
-            canvas.translate(border * 0.5f, border * 0.5f);
-            canvas.scale(scaleX, scaleY);
-            canvas.drawBitmap(info.thumbnail, 0, 0, paint);
-        } else {
-            // Draw the Loading bitmap placeholder, TODO: Remove when RS handles blending
-            final float scaleX = (float) targetWidth / mLoadingBitmap.getWidth();
-            final float scaleY = (float) targetHeight / mLoadingBitmap.getHeight();
-            canvas.scale(scaleX, scaleY);
-            canvas.drawBitmap(mLoadingBitmap, 0, 0, paint);
-        }
-        canvas.restore();
-
-        // Draw overlay
-        canvas.save();
-        final float scaleOverlayX = (float) targetWidth / mRecentOverlay.getWidth();
-        final float scaleOverlayY = (float) targetHeight / mRecentOverlay.getHeight();
-        canvas.scale(scaleOverlayX, scaleOverlayY);
-        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
-        canvas.drawBitmap(mRecentOverlay, 0, 0, paint);
-        canvas.restore();
-
-        // Draw icon
-        if (info.icon != null) {
-            canvas.save();
-            info.icon.draw(canvas);
-            canvas.restore();
-        }
-
-        return result;
-    }
-
-    private final IThumbnailReceiver mThumbnailReceiver = new IThumbnailReceiver.Stub() {
-
-        public void finished() throws RemoteException {
-
-        }
-
-        public void newThumbnail(final int id, final Bitmap bitmap, CharSequence description)
-                throws RemoteException {
-            int w = bitmap.getWidth();
-            int h = bitmap.getHeight();
-            if (DBG) Log.v(TAG, "New thumbnail for id=" + id + ", dimensions=" + w + "x" + h
-                    + " description '" + description + "'");
-            ActivityDescription info = findActivityDescription(id);
-            if (info != null) {
-                info.thumbnail = bitmap;
-                info.description = description;
-                final int thumbWidth = bitmap.getWidth();
-                final int thumbHeight = bitmap.getHeight();
-                if ((mPortraitMode && thumbWidth > thumbHeight)
-                        || (!mPortraitMode && thumbWidth < thumbHeight)) {
-                    Matrix matrix = new Matrix();
-                    matrix.setRotate(90.0f, (float) thumbWidth / 2, (float) thumbHeight / 2);
-                    info.matrix = matrix;
-                } else {
-                    info.matrix = null;
-                }
-                // Force Carousel to request new textures for this item.
-                mCarouselView.setTextureForItem(info.position, null);
-                mCarouselView.setDetailTextureForItem(info.position, 0, 0, 0, 0, null);
-            } else {
-                if (DBG) Log.v(TAG, "Can't find view for id " + id);
-            }
-        }
-    };
-
-    /**
-     * We never really finish() RecentApplicationsActivity, since we don't want to
-     * get destroyed and pay the start-up cost to restart it.
-     */
-    @Override
-    public void finish() {
-        moveTaskToBack(true);
-    }
-
-    @Override
-    protected void onNewIntent(Intent intent) {
-        mHidden = !mHidden;
-        if (mHidden) {
-            mHiding = true;
-            moveTaskToBack(true);
-        } else {
-            mHiding = false;
-        }
-        super.onNewIntent(intent);
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        final Resources res = getResources();
-        final View decorView = getWindow().getDecorView();
-
-        getWindow().getDecorView().setBackgroundColor(0x80000000);
-
-        if (mCarouselView == null) {
-            long t = System.currentTimeMillis();
-            setContentView(R.layout.recent_apps_activity);
-            long elapsed = System.currentTimeMillis() - t;
-            Log.v(TAG, "Recents layout took " + elapsed + "ms to load");
-            mLoadingBitmap = BitmapFactory.decodeResource(res, R.drawable.recent_rez_border);
-            mCarouselView = (CarouselView)findViewById(R.id.carousel);
-            mHelper = new LocalCarouselViewHelper(this);
-            mHelper.setCarouselView(mCarouselView);
-
-            mCarouselView.setSlotCount(CARD_SLOTS);
-            mCarouselView.setVisibleSlots(VISIBLE_SLOTS);
-            mCarouselView.createCards(0);
-            mCarouselView.setStartAngle((float) -(2.0f*Math.PI * 5 / CARD_SLOTS));
-            mCarouselView.setDefaultBitmap(mLoadingBitmap);
-            mCarouselView.setLoadingBitmap(mLoadingBitmap);
-            mCarouselView.setRezInCardCount(3.0f);
-            mCarouselView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
-
-            mNoRecentsView = (View) findViewById(R.id.no_applications_message);
-
-            mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
-            mPortraitMode = decorView.getHeight() > decorView.getWidth();
-
-            // Load detail view which will be used to render text
-            View detail = getLayoutInflater().inflate(R.layout.recents_detail_view, null);
-            TextView title = (TextView) detail.findViewById(R.id.app_title);
-            TextView description = (TextView) detail.findViewById(R.id.app_description);
-            mDetailInfo = new DetailInfo(detail, title, description);
-
-            refresh();
-        }
-    }
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-        refresh();
-    }
-
-    @Override
-    public void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        mPortraitMode = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT;
-        if (DBG) Log.v(TAG, "CONFIG CHANGE, mPortraitMode = " + mPortraitMode);
-        refresh();
-    }
-
-    void updateRunningTasks() {
-        mRunningTaskList = mActivityManager.getRunningTasks(MAX_TASKS,
-                0, mThumbnailReceiver);
-        if (DBG) Log.v(TAG, "Portrait: " + mPortraitMode);
-        for (RunningTaskInfo r : mRunningTaskList) {
-            if (r.thumbnail != null) {
-                int thumbWidth = r.thumbnail.getWidth();
-                int thumbHeight = r.thumbnail.getHeight();
-                if (DBG) Log.v(TAG, "Got thumbnail " + thumbWidth + "x" + thumbHeight);
-                ActivityDescription desc = findActivityDescription(r.id);
-                if (desc != null) {
-                    desc.thumbnail = r.thumbnail;
-                    desc.description = r.description;
-                    if ((mPortraitMode && thumbWidth > thumbHeight)
-                            || (!mPortraitMode && thumbWidth < thumbHeight)) {
-                        Matrix matrix = new Matrix();
-                        matrix.setRotate(90.0f, (float) thumbWidth / 2, (float) thumbHeight / 2);
-                        desc.matrix = matrix;
-                    }
-                } else {
-                    if (DBG) Log.v(TAG, "Couldn't find ActivityDesc for id=" + r.id);
-                }
-            } else {
-                if (DBG) Log.v(TAG, "*** RUNNING THUMBNAIL WAS NULL ***");
-            }
-        }
-    }
-
-    private void updateRecentTasks() {
-        final PackageManager pm = getPackageManager();
-        final ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
-
-        final List<ActivityManager.RecentTaskInfo> recentTasks =
-                am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
-
-        ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
-                    .resolveActivityInfo(pm, 0);
-
-        // IconUtilities iconUtilities = new IconUtilities(this); // FIXME
-
-        int numTasks = recentTasks.size();
-        mActivityDescriptions.clear();
-        for (int i = 0, index = 0; i < numTasks && (index < MAX_TASKS); ++i) {
-            final ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(i);
-
-            Intent intent = new Intent(recentInfo.baseIntent);
-            if (recentInfo.origActivity != null) {
-                intent.setComponent(recentInfo.origActivity);
-            }
-
-            // Skip the current home activity.
-            if (homeInfo != null
-                    && homeInfo.packageName.equals(intent.getComponent().getPackageName())
-                    && homeInfo.name.equals(intent.getComponent().getClassName())) {
-                continue;
-            }
-
-            intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
-                    | Intent.FLAG_ACTIVITY_NEW_TASK);
-            final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
-            if (resolveInfo != null) {
-                final ActivityInfo info = resolveInfo.activityInfo;
-                final String title = info.loadLabel(pm).toString();
-                Drawable icon = info.loadIcon(pm);
-
-                int id = recentTasks.get(i).id;
-                if (id != -1 && title != null && title.length() > 0 && icon != null) {
-                    // icon = null; FIXME: iconUtilities.createIconDrawable(icon);
-                    ActivityDescription item = new ActivityDescription(
-                            null, icon, title, null, id, index);
-                    item.intent = intent;
-                    mActivityDescriptions.add(item);
-                    if (DBG) Log.v(TAG, "Added item[" + index
-                            + "], id=" + item.id
-                            + ", title=" + item.label);
-                    ++index;
-                } else {
-                    if (DBG) Log.v(TAG, "SKIPPING item " + id);
-                }
-            }
-        }
-    }
-
-    private final Runnable mRefreshRunnable = new Runnable() {
-        public void run() {
-            updateRecentTasks();
-            updateRunningTasks();
-            showCarousel(mActivityDescriptions.size() > 0);
-        }
-    };
-
-    private void showCarousel(boolean show) {
-        if (show) {
-            mCarouselView.createCards(mActivityDescriptions.size());
-            for (int i = 1; i < mActivityDescriptions.size(); i++) {
-                // Force Carousel to update textures. Note we don't do this for the first item,
-                // since it will be updated when mThumbnailReceiver returns a thumbnail.
-                // TODO: only do this for apps that have changed.
-                mCarouselView.setTextureForItem(i, null);
-                mCarouselView.setDetailTextureForItem(i, 0, 0, 0, 0, null);
-            }
-            // Make carousel visible
-            mNoRecentsView.setVisibility(View.GONE);
-            mCarouselView.setVisibility(View.VISIBLE);
-            mCarouselView.createCards(mActivityDescriptions.size());
-        } else {
-            // show "No Recent Tasks"
-            mNoRecentsView.setVisibility(View.VISIBLE);
-            mCarouselView.setVisibility(View.GONE);
-        }
-    }
-
-    private void refresh() {
-        if (!mHiding && mCarouselView != null) {
-            // Don't update the view now. Instead, post a request so it happens next time
-            // we reach the looper after a delay. This way we can fold multiple refreshes
-            // into just the latest.
-            mCarouselView.removeCallbacks(mRefreshRunnable);
-            mCarouselView.postDelayed(mRefreshRunnable, 50);
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/carousel/RecentApplicationsCarouselView.java b/packages/SystemUI/src/com/android/systemui/recent/carousel/RecentApplicationsCarouselView.java
deleted file mode 100644
index 1afb086..0000000
--- a/packages/SystemUI/src/com/android/systemui/recent/carousel/RecentApplicationsCarouselView.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.
- * 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.systemui.recent.carousel;
-
-import android.content.Context;
-import android.util.AttributeSet;
-
-import com.android.ex.carousel.CarouselView;
-import com.android.systemui.R;
-
-public class RecentApplicationsCarouselView extends CarouselView {
-
-    public RecentApplicationsCarouselView(Context context) {
-        this(context, null);
-    }
-
-    public RecentApplicationsCarouselView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public Info getRenderScriptInfo() {
-        return new Info(R.raw.carousel);
-    }
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index f81820e..62d7500 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -61,6 +61,7 @@
     private static final int MSG_SET_HARD_KEYBOARD_STATUS = 10 << MSG_SHIFT;
     
     private static final int MSG_USER_ACTIVITY          = 11 << MSG_SHIFT;
+    private static final int MSG_TOGGLE_RECENT_APPS       = 12 << MSG_SHIFT;
 
     private StatusBarIconList mList;
     private Callbacks mCallbacks;
@@ -90,6 +91,7 @@
         public void setImeWindowStatus(IBinder token, int vis, int backDisposition);
         public void setHardKeyboardStatus(boolean available, boolean enabled);
         public void userActivity();
+        public void toggleRecentApps();
     }
 
     public CommandQueue(Callbacks callbacks, StatusBarIconList list) {
@@ -196,6 +198,13 @@
         }
     }
 
+    public void toggleRecentApps() {
+        synchronized (mList) {
+            mHandler.removeMessages(MSG_TOGGLE_RECENT_APPS);
+            mHandler.obtainMessage(MSG_TOGGLE_RECENT_APPS, 0, 0, null).sendToTarget();
+        }
+    }
+
     private final class H extends Handler {
         public void handleMessage(Message msg) {
             final int what = msg.what & MSG_MASK;
@@ -265,6 +274,9 @@
                 case MSG_USER_ACTIVITY:
                     mCallbacks.userActivity();
                     break;
+                case MSG_TOGGLE_RECENT_APPS:
+                    mCallbacks.toggleRecentApps();
+                    break;
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
index e567dc7..ca75138 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
@@ -53,6 +53,7 @@
     protected abstract View makeStatusBarView();
     protected abstract int getStatusBarGravity();
     public abstract int getStatusBarHeight();
+    public abstract void animateCollapse();
 
     private DoNotDisturb mDoNotDisturb;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index dbfbe11..d9d9c06 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -29,6 +29,8 @@
 import android.view.ViewDebug;
 import android.widget.FrameLayout;
 
+import java.text.NumberFormat;
+
 import com.android.internal.statusbar.StatusBarIcon;
 
 import com.android.systemui.R;
@@ -180,7 +182,18 @@
     }
 
     void placeNumber() {
-        final String str = mNumberText = Integer.toString(mIcon.number);
+        final String str;
+        final int tooBig = mContext.getResources().getInteger(
+                android.R.integer.status_bar_notification_info_maxnum);
+        if (mIcon.number > tooBig) {
+            str = mContext.getResources().getString(
+                        android.R.string.status_bar_notification_info_overflow);
+        } else {
+            NumberFormat f = NumberFormat.getIntegerInstance();
+            str = f.format(mIcon.number);
+        }
+        mNumberText = str;
+
         final int w = getWidth();
         final int h = getHeight();
         final Rect r = new Rect();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index cc8358e..0b82123 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -28,10 +28,12 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.res.Resources;
+import android.content.res.Configuration;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.Handler;
@@ -74,6 +76,7 @@
 import com.android.internal.statusbar.StatusBarNotification;
 
 import com.android.systemui.R;
+import com.android.systemui.recent.RecentsPanelView;
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.StatusBar;
 import com.android.systemui.statusbar.StatusBarIconView;
@@ -83,6 +86,7 @@
 public class PhoneStatusBar extends StatusBar {
     static final String TAG = "PhoneStatusBar";
     static final boolean SPEW = false;
+    public static final boolean DEBUG = false;
 
     public static final String ACTION_STATUSBAR_START
             = "com.android.internal.policy.statusbar.START";
@@ -94,6 +98,8 @@
     private static final int MSG_ANIMATE_REVEAL = 1001;
     private static final int MSG_SHOW_INTRUDER = 1002;
     private static final int MSG_HIDE_INTRUDER = 1003;
+    private static final int MSG_OPEN_RECENTS_PANEL = 1020;
+    private static final int MSG_CLOSE_RECENTS_PANEL = 1021;
 
     // will likely move to a resource or other tunable param at some point
     private static final int INTRUDER_ALERT_DECAY_MS = 10000;
@@ -160,6 +166,9 @@
     private View mTickerView;
     private boolean mTicking;
 
+    // Recent applications
+    private RecentsPanelView mRecentsPanel;
+
     // Tracking finger for opening/closing.
     int mEdgeBorder; // corresponds to R.dimen.status_bar_edge_ignore
     boolean mTracking;
@@ -296,6 +305,9 @@
         setAreThereNotifications();
         mDateView.setVisibility(View.INVISIBLE);
 
+        // Recents Panel
+        initializeRecentsPanel();
+
         // receive broadcasts
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
@@ -306,6 +318,51 @@
         return sb;
     }
 
+    protected WindowManager.LayoutParams getRecentsLayoutParams() {
+        boolean translucent = false;
+        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
+                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
+                | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
+                | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
+                (translucent ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT));
+        lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
+        lp.setTitle("RecentsPanel");
+        lp.windowAnimations = R.style.Animation_RecentPanel;
+        lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
+        | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
+        return lp;
+    }
+
+    protected void initializeRecentsPanel() {
+        // Recents Panel
+        boolean visible = false;
+        if (mRecentsPanel != null) {
+            visible = mRecentsPanel.getVisibility() == View.VISIBLE;
+            WindowManagerImpl.getDefault().removeView(mRecentsPanel);
+        }
+        mRecentsPanel = (RecentsPanelView) View.inflate(mContext,
+                R.layout.status_bar_recent_panel, null);
+
+        mRecentsPanel.setOnTouchListener(new TouchOutsideListener(MSG_CLOSE_RECENTS_PANEL,
+                mRecentsPanel));
+        mRecentsPanel.setVisibility(View.GONE);
+        WindowManager.LayoutParams lp = getRecentsLayoutParams();
+
+        WindowManagerImpl.getDefault().addView(mRecentsPanel, lp);
+        mRecentsPanel.setBar(this);
+        if (visible) {
+            // need to set visibility to View.GONE earlier since that
+            // triggers refreshing application list
+            mRecentsPanel.setVisibility(View.VISIBLE);
+            mRecentsPanel.show(true, false);
+        }
+
+    }
+
     protected int getStatusBarGravity() {
         return Gravity.TOP | Gravity.FILL_HORIZONTAL;
     }
@@ -581,6 +638,12 @@
         }
     }
 
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        initializeRecentsPanel();
+    }
+
+
     View[] makeNotificationView(StatusBarNotification notification, ViewGroup parent) {
         Notification n = notification.notification;
         RemoteViews remoteViews = n.contentView;
@@ -789,6 +852,21 @@
                 case MSG_HIDE_INTRUDER:
                     setIntruderAlertVisibility(false);
                     break;
+                case MSG_OPEN_RECENTS_PANEL:
+                    if (DEBUG) Slog.d(TAG, "opening recents panel");
+                    if (mRecentsPanel != null) {
+                        disable(StatusBarManager.DISABLE_BACK);
+                        mRecentsPanel.setVisibility(View.VISIBLE);
+                        mRecentsPanel.show(true, true);
+                    }
+                    break;
+                case MSG_CLOSE_RECENTS_PANEL:
+                    if (DEBUG) Slog.d(TAG, "closing recents panel");
+                    if (mRecentsPanel != null && mRecentsPanel.isShowing()) {
+                        disable(StatusBarManager.DISABLE_NONE);
+                        mRecentsPanel.show(false, true);
+                    }
+                    break;
             }
         }
     }
@@ -835,6 +913,10 @@
     }
 
     public void animateCollapse() {
+        animateCollapse(false);
+    }
+
+    public void animateCollapse(boolean excludeRecents) {
         if (SPEW) {
             Slog.d(TAG, "animateCollapse(): mExpanded=" + mExpanded
                     + " mExpandedVisible=" + mExpandedVisible
@@ -844,6 +926,11 @@
                     + " mAnimVel=" + mAnimVel);
         }
 
+        if (!excludeRecents) {
+            mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
+            mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
+        }
+
         if (!mExpandedVisible) {
             return;
         }
@@ -1557,6 +1644,13 @@
         } catch (RemoteException ex) { }
     }
 
+    public void toggleRecentApps() {
+        int msg = (mRecentsPanel.getVisibility() == View.GONE)
+                ? MSG_OPEN_RECENTS_PANEL : MSG_CLOSE_RECENTS_PANEL;
+        mHandler.removeMessages(msg);
+        mHandler.sendEmptyMessage(msg);
+    }
+
     /**
      * The LEDs are turned o)ff when the notification panel is shown, even just a little bit.
      * This was added last-minute and is inconsistent with the way the rest of the notifications
@@ -1625,7 +1719,14 @@
             String action = intent.getAction();
             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
                     || Intent.ACTION_SCREEN_OFF.equals(action)) {
-                animateCollapse();
+                boolean excludeRecents = false;
+                if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
+                    String reason = intent.getExtras().getString("reason");
+                    if (reason != null) {
+                        excludeRecents = reason.equals("recentapps");
+                    }
+                }
+                animateCollapse(excludeRecents);
             }
             else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
                 repositionNavigationBar();
@@ -1690,5 +1791,27 @@
             vibrate();
         }
     };
+
+    public class TouchOutsideListener implements View.OnTouchListener {
+        private int mMsg;
+        private RecentsPanelView mPanel;
+
+        public TouchOutsideListener(int msg, RecentsPanelView panel) {
+            mMsg = msg;
+            mPanel = panel;
+        }
+
+        public boolean onTouch(View v, MotionEvent ev) {
+            final int action = ev.getAction();
+            if (action == MotionEvent.ACTION_OUTSIDE
+                || (action == MotionEvent.ACTION_DOWN
+                    && !mPanel.isInContentArea((int)ev.getX(), (int)ev.getY()))) {
+                mHandler.removeMessages(mMsg);
+                mHandler.sendEmptyMessage(mMsg);
+                return true;
+            }
+            return false;
+        }
+    }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
index 24eee27..981fb24 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
@@ -20,6 +20,7 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
+import android.animation.TimeAnimator;
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.Resources;
@@ -30,6 +31,8 @@
 import android.util.AttributeSet;
 import android.util.Slog;
 import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.animation.AccelerateInterpolator;
@@ -45,10 +48,20 @@
 public class NotificationRowLayout extends ViewGroup {
     private static final String TAG = "NotificationRowLayout";
     private static final boolean DEBUG = false;
+    private static final boolean SLOW_ANIMATIONS = false; // DEBUG;
 
     private static final boolean ANIMATE_LAYOUT = true;
 
-    private static final int ANIM_LEN = DEBUG ? 5000 : 250;
+    private static final boolean CLEAR_IF_SWIPED_FAR_ENOUGH = true;
+    
+    private static final boolean CONSTRAIN_SWIPE_ON_PERMANENT = true;
+
+    private static final int APPEAR_ANIM_LEN = SLOW_ANIMATIONS ? 5000 : 250;
+    private static final int DISAPPEAR_ANIM_LEN = APPEAR_ANIM_LEN;
+    private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 250;
+
+    private static final float SWIPE_ESCAPE_VELOCITY = 1500f;
+    private static final float SWIPE_ANIM_VELOCITY_MIN = 1000f;
 
     Rect mTmpRect = new Rect();
     int mNumRows = 0;
@@ -58,6 +71,11 @@
     HashSet<View> mAppearingViews = new HashSet<View>();
     HashSet<View> mDisappearingViews = new HashSet<View>();
 
+    VelocityTracker mVT;
+    float mInitialTouchX, mInitialTouchY;
+    View mSlidingChild = null;
+    float mLiftoffVelocity;
+
     public NotificationRowLayout(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
@@ -65,6 +83,8 @@
     public NotificationRowLayout(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
 
+        mVT = VelocityTracker.obtain();
+
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NotificationRowLayout,
                 defStyle, 0);
         mRowHeight = a.getDimensionPixelSize(R.styleable.NotificationRowLayout_rowHeight, 0);
@@ -89,6 +109,112 @@
 
     }
 
+    // Swipey code
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        final int action = ev.getAction();
+//        if (DEBUG) Slog.d(TAG, "intercepting touch event: " + ev);
+        switch (action) {
+            case MotionEvent.ACTION_DOWN:
+                mVT.clear();
+                mVT.addMovement(ev);
+                mInitialTouchX = ev.getX();
+                mInitialTouchY = ev.getY();
+                mSlidingChild = null;
+                break;
+            case MotionEvent.ACTION_MOVE:
+                mVT.addMovement(ev);
+                if (mSlidingChild == null) {
+                    if (Math.abs(ev.getX() - mInitialTouchX) > 4) { // slide slop
+
+                        // find the view under the pointer, accounting for GONE views
+                        final int count = getChildCount();
+                        int y = 0;
+                        int childIdx = 0;
+                        for (; childIdx < count; childIdx++) {
+                            mSlidingChild = getChildAt(childIdx);
+                            if (mSlidingChild.getVisibility() == GONE) {
+                                continue;
+                            }
+                            y += mRowHeight;
+                            if (mInitialTouchY < y) break;
+                        }
+
+                        mInitialTouchX -= mSlidingChild.getTranslationX();
+                        mSlidingChild.animate().cancel();
+
+                        if (DEBUG) {
+                            Slog.d(TAG, String.format(
+                                "now sliding child %d: %s (touchY=%.1f, rowHeight=%d, count=%d)",
+                                childIdx, mSlidingChild, mInitialTouchY, mRowHeight, count));
+                        }
+                    }
+                }
+                break;
+        }
+        return mSlidingChild != null;
+    }
+
+    protected boolean canBeCleared(View v) {
+        final View veto = v.findViewById(R.id.veto);
+        return (veto != null && veto.getVisibility() != View.GONE);
+    }
+
+    protected boolean clear(View v) {
+        final View veto = v.findViewById(R.id.veto);
+        if (veto != null && veto.getVisibility() != View.GONE) {
+            veto.performClick();
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        final int action = ev.getAction();
+//        if (DEBUG) Slog.d(TAG, "touch event: " + ev + " sliding: " + mSlidingChild);
+        if (mSlidingChild != null) {
+            switch (action) {
+                case MotionEvent.ACTION_OUTSIDE:
+                case MotionEvent.ACTION_MOVE:
+                    mVT.addMovement(ev);
+
+                    float delta = (ev.getX() - mInitialTouchX);
+                    if (CONSTRAIN_SWIPE_ON_PERMANENT && !canBeCleared(mSlidingChild)) {
+                        delta = Math.copySign(
+                                    Math.min(Math.abs(delta),
+                                    mSlidingChild.getMeasuredWidth() * 0.2f), delta);
+                    }
+                    mSlidingChild.setTranslationX(delta);
+                    break;
+                case MotionEvent.ACTION_UP:
+                case MotionEvent.ACTION_CANCEL:
+                    mVT.addMovement(ev);
+                    mVT.computeCurrentVelocity(1000 /* px/sec */);
+                    if (DEBUG) Slog.d(TAG, "exit velocity: " + mVT.getXVelocity());
+                    boolean restore = true;
+                    mLiftoffVelocity = mVT.getXVelocity();
+                    if (Math.abs(mLiftoffVelocity) > SWIPE_ESCAPE_VELOCITY
+                        || (CLEAR_IF_SWIPED_FAR_ENOUGH && 
+                            (mSlidingChild.getTranslationX() * 2) > mSlidingChild.getMeasuredWidth()))
+                    {
+
+                        // flingadingy
+                        restore = ! clear(mSlidingChild);
+                    }
+                    if (restore) {
+                        // snappity
+                        mSlidingChild.animate().translationX(0)
+                            .setDuration(SNAP_ANIM_LEN)
+                            .start();
+                    }
+                    break;
+            }
+            return true;
+        }
+        return false;
+    }
+
     //**
     @Override
     public void addView(View child, int index, LayoutParams params) {
@@ -105,7 +231,7 @@
                     ObjectAnimator.ofFloat(child, "alpha", 0f, 1f)
 //                    ,ObjectAnimator.ofFloat(child, "scaleY", 0f, 1f)
             );
-            a.setDuration(ANIM_LEN);
+            a.setDuration(APPEAR_ANIM_LEN);
             a.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
@@ -127,21 +253,37 @@
             mDisappearingViews.add(child);
 
             child.setPivotY(0);
-            AnimatorSet a = new AnimatorSet();
-            a.playTogether(
-                    ObjectAnimator.ofFloat(child, "alpha", 0f)
-//                    ,ObjectAnimator.ofFloat(child, "scaleY", 0f)
-                    ,ObjectAnimator.ofFloat(child, "translationX", 300f)
-            );
-            a.setDuration(ANIM_LEN);
-            a.addListener(new AnimatorListenerAdapter() {
+
+            final float velocity = (mSlidingChild == child) 
+                    ? Math.min(mLiftoffVelocity, SWIPE_ANIM_VELOCITY_MIN)
+                    : SWIPE_ESCAPE_VELOCITY;
+            final TimeAnimator zoom = new TimeAnimator();
+            zoom.setTimeListener(new TimeAnimator.TimeListener() {
+                @Override
+                public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
+                    childF.setTranslationX(childF.getTranslationX() + deltaTime / 1000f * velocity);
+                }
+            });
+
+            final ObjectAnimator alphaFade = ObjectAnimator.ofFloat(child, "alpha", 0f);
+            alphaFade.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
+                    zoom.cancel(); // it won't end on its own
+                    if (DEBUG) Slog.d(TAG, "actually removing child: " + childF);
                     NotificationRowLayout.super.removeView(childF);
                     childF.setAlpha(1f);
                     mDisappearingViews.remove(childF);
                 }
             });
+
+            AnimatorSet a = new AnimatorSet();
+            a.playTogether(alphaFade, zoom);
+                    
+//                    ,ObjectAnimator.ofFloat(child, "scaleY", 0f)
+//                    ,ObjectAnimator.ofFloat(child, "translationX", child.getTranslationX() + 300f)
+
+            a.setDuration(DISAPPEAR_ANIM_LEN);
             a.start();
             requestLayout(); // start the container animation
         } else {
@@ -160,8 +302,8 @@
     public void onDraw(android.graphics.Canvas c) {
         super.onDraw(c);
         if (DEBUG) {
-            Slog.d(TAG, "onDraw: canvas height: " + c.getHeight() + "px; measured height: "
-                    + getMeasuredHeight() + "px");
+            //Slog.d(TAG, "onDraw: canvas height: " + c.getHeight() + "px; measured height: "
+            //        + getMeasuredHeight() + "px");
             c.save();
             c.clipRect(6, 6, c.getWidth() - 6, getMeasuredHeight() - 6,
                     android.graphics.Region.Op.DIFFERENCE);
@@ -199,7 +341,7 @@
 
             if (ANIMATE_LAYOUT && isShown()) {
                 ObjectAnimator.ofInt(this, "forcedHeight", computedHeight)
-                    .setDuration(ANIM_LEN)
+                    .setDuration(APPEAR_ANIM_LEN)
                     .start();
             } else {
                 setForcedHeight(computedHeight);
@@ -230,7 +372,7 @@
         final int width = right - left;
         final int height = bottom - top;
 
-        if (DEBUG) Slog.d(TAG, "onLayout: height=" + height);
+        //if (DEBUG) Slog.d(TAG, "onLayout: height=" + height);
 
         final int count = getChildCount();
         int y = 0;
@@ -252,7 +394,7 @@
     }
 
     public void setForcedHeight(int h) {
-        if (DEBUG) Slog.d(TAG, "forcedHeight: " + h);
+        //if (DEBUG) Slog.d(TAG, "forcedHeight: " + h);
         if (h != mHeight) {
             mHeight = h;
             requestLayout();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/CompatModePanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/CompatModePanel.java
index 5a82d1b..c62c4ad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/CompatModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/CompatModePanel.java
@@ -107,9 +107,14 @@
 
     private void refresh() {
         int mode = mAM.getFrontActivityScreenCompatMode();
+        if (mode == ActivityManager.COMPAT_MODE_ALWAYS
+                || mode == ActivityManager.COMPAT_MODE_NEVER) {
+            // No longer have something to switch.
+            closePanel();
+            return;
+        }
         final boolean on = (mode == ActivityManager.COMPAT_MODE_ENABLED);
         mOnButton.setChecked(on);
         mOffButton.setChecked(!on);
     }
-
 }
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 a7af30d..93f7af3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -76,12 +76,12 @@
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.Prefs;
 import com.android.systemui.recent.RecentsPanelView;
-import com.android.systemui.recent.carousel.RecentApplicationsActivity;
 
 public class TabletStatusBar extends StatusBar implements
         HeightReceiver.OnBarHeightChangedListener,
         InputMethodsPanel.OnHardKeyboardEnabledChangeListener {
     public static final boolean DEBUG = false;
+    public static final boolean DEBUG_COMPAT_HELP = false;
     public static final String TAG = "TabletStatusBar";
 
 
@@ -166,6 +166,8 @@
     View mFakeSpaceBar;
     KeyEvent mSpaceBarKeyEvent = null;
 
+    View mCompatibilityHelpDialog = null;
+    
     // for disabling the status bar
     int mDisabled = 0;
 
@@ -1010,20 +1012,31 @@
 
         mCompatModeButton.refresh();
         if (mCompatModeButton.getVisibility() == View.VISIBLE) {
-            if (! Prefs.read(mContext).getBoolean(Prefs.SHOWN_COMPAT_MODE_HELP, false)) {
+            if (DEBUG_COMPAT_HELP
+                    || ! Prefs.read(mContext).getBoolean(Prefs.SHOWN_COMPAT_MODE_HELP, false)) {
                 showCompatibilityHelp();
             }
+        } else {
+            hideCompatibilityHelp();
+            mCompatModePanel.closePanel();
         }
     }
 
     private void showCompatibilityHelp() {
-        final View dlg = View.inflate(mContext, R.layout.compat_mode_help, null);
-        View button = dlg.findViewById(R.id.button);
+        if (mCompatibilityHelpDialog != null) {
+            return;
+        }
+        
+        mCompatibilityHelpDialog = View.inflate(mContext, R.layout.compat_mode_help, null);
+        View button = mCompatibilityHelpDialog.findViewById(R.id.button);
 
         button.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                WindowManagerImpl.getDefault().removeView(dlg);
+                hideCompatibilityHelp();
+                SharedPreferences.Editor editor = Prefs.edit(mContext);
+                editor.putBoolean(Prefs.SHOWN_COMPAT_MODE_HELP, true);
+                editor.apply();
             }
         });
 
@@ -1040,13 +1053,16 @@
                 | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
         lp.windowAnimations = com.android.internal.R.style.Animation_ZoomButtons; // simple fade
 
-        WindowManagerImpl.getDefault().addView(dlg, lp);
-
-        SharedPreferences.Editor editor = Prefs.edit(mContext);
-        editor.putBoolean(Prefs.SHOWN_COMPAT_MODE_HELP, true);
-        editor.apply();
+        WindowManagerImpl.getDefault().addView(mCompatibilityHelpDialog, lp);
     }
 
+    private void hideCompatibilityHelp() {
+        if (mCompatibilityHelpDialog != null) {
+            WindowManagerImpl.getDefault().removeView(mCompatibilityHelpDialog);
+            mCompatibilityHelpDialog = null;
+        }
+    }
+    
     public void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
         mInputMethodSwitchButton.setImeWindowStatus(token,
                 (vis & InputMethodService.IME_ACTIVE) != 0);
@@ -1156,20 +1172,12 @@
 
     public void onClickRecentButton() {
         if (DEBUG) Slog.d(TAG, "clicked recent apps; disabled=" + mDisabled);
-        if (mRecentsPanel == null) {
-            Intent intent = new Intent();
-            intent.setClass(mContext, RecentApplicationsActivity.class);
-            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-            mContext.startActivity(intent);
-        } else {
-            if ((mDisabled & StatusBarManager.DISABLE_EXPAND) == 0) {
-                int msg = (mRecentsPanel.getVisibility() == View.GONE)
-                    ? MSG_OPEN_RECENTS_PANEL
-                    : MSG_CLOSE_RECENTS_PANEL;
-                mHandler.removeMessages(msg);
-                mHandler.sendEmptyMessage(msg);
-            }
+        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) == 0) {
+            int msg = (mRecentsPanel.getVisibility() == View.GONE)
+                ? MSG_OPEN_RECENTS_PANEL
+                : MSG_CLOSE_RECENTS_PANEL;
+            mHandler.removeMessages(msg);
+            mHandler.sendEmptyMessage(msg);
         }
     }
 
@@ -1681,6 +1689,13 @@
     public void userActivity() {
     }
 
+    public void toggleRecentApps() {
+        int msg = (mRecentsPanel.getVisibility() == View.GONE)
+                ? MSG_OPEN_RECENTS_PANEL : MSG_CLOSE_RECENTS_PANEL;
+        mHandler.removeMessages(msg);
+        mHandler.sendEmptyMessage(msg);
+    }
+
     public class TouchOutsideListener implements View.OnTouchListener {
         private int mMsg;
         private StatusBarPanel mPanel;
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbPreferenceActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbPreferenceActivity.java
new file mode 100644
index 0000000..3ed44e8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbPreferenceActivity.java
@@ -0,0 +1,91 @@
+/*

+ * 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.systemui.usb;

+

+import android.app.Activity;

+import android.app.AlertDialog;

+import android.content.Context;

+import android.content.DialogInterface;

+import android.hardware.usb.UsbManager;

+import android.os.Bundle;

+import android.view.LayoutInflater;

+import android.view.View;

+import android.util.Log;

+import android.widget.Button;

+

+import java.io.File;

+

+import com.android.systemui.R;

+

+public class UsbPreferenceActivity extends Activity implements View.OnClickListener  {

+

+    private static final String TAG = "UsbPreferenceActivity";

+

+    private UsbManager mUsbManager;

+    private String mCurrentFunction;

+    private String[] mFunctions;

+    private String mInstallerImagePath;

+    private Button mMtpPtpButton;

+    private Button mInstallerCdButton;

+    private boolean mPtpActive;

+

+    @Override

+    public void onCreate(Bundle icicle) {

+        super.onCreate(icicle);

+

+        mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE);

+

+        AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);

+        dialogBuilder.setTitle(getString(R.string.usb_preference_title));

+

+        LayoutInflater inflater = (LayoutInflater)getSystemService(

+                Context.LAYOUT_INFLATER_SERVICE);

+        View buttonView = inflater.inflate(R.layout.usb_preference_buttons, null);

+        dialogBuilder.setView(buttonView);

+        mMtpPtpButton = (Button)buttonView.findViewById(R.id.mtp_ptp_button);

+        mInstallerCdButton = (Button)buttonView.findViewById(R.id.installer_cd_button);

+        mMtpPtpButton.setOnClickListener(this);

+        mInstallerCdButton.setOnClickListener(this);

+

+        mPtpActive = mUsbManager.isFunctionEnabled(UsbManager.USB_FUNCTION_PTP);

+        if (mPtpActive) {

+            mMtpPtpButton.setText(R.string.use_mtp_button_title);

+        }

+

+        mInstallerImagePath = getString(com.android.internal.R.string.config_isoImagePath);

+        if (!(new File(mInstallerImagePath)).exists()) {

+            mInstallerCdButton.setVisibility(View.GONE);

+        }

+

+        dialogBuilder.show();

+    }

+

+    public void onClick(View v) {

+        if (v.equals(mMtpPtpButton)) {

+            if (mPtpActive) {

+                mUsbManager.setPrimaryFunction(UsbManager.USB_FUNCTION_MTP);

+            } else {

+                mUsbManager.setPrimaryFunction(UsbManager.USB_FUNCTION_PTP);

+            }

+        } else if (v.equals(mInstallerCdButton)) {

+            mUsbManager.setPrimaryFunction(UsbManager.USB_FUNCTION_MASS_STORAGE);

+            mUsbManager.setMassStorageBackingFile(mInstallerImagePath);

+        }

+

+        finish();

+    }

+}

diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
index 8fa6c7a..c54e719 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
@@ -23,7 +23,8 @@
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.net.ConnectivityManager;
+import android.net.IConnectivityManager;
+import android.os.ServiceManager;
 import android.util.Log;
 import android.view.View;
 import android.widget.Button;
@@ -37,7 +38,7 @@
 
     private String mPackageName;
 
-    private ConnectivityManager mService;
+    private IConnectivityManager mService;
 
     private AlertDialog mDialog;
     private Button mButton;
@@ -47,7 +48,9 @@
         super.onResume();
         try {
             mPackageName = getCallingPackage();
-            mService = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
+
+            mService = IConnectivityManager.Stub.asInterface(
+                    ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
 
             if (mPackageName.equals(mService.prepareVpn(null))) {
                 setResult(RESULT_OK);
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
index 853e625..ba3f344 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
@@ -23,9 +23,10 @@
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.net.ConnectivityManager;
+import android.net.IConnectivityManager;
 import android.os.Handler;
 import android.os.Message;
+import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.util.Log;
 import android.view.View;
@@ -34,45 +35,41 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import com.android.internal.net.VpnConfig;
+
 import java.io.DataInputStream;
 import java.io.FileInputStream;
 
-public class ManageDialog extends Activity implements
+public class ManageDialog extends Activity implements Handler.Callback,
         DialogInterface.OnClickListener, DialogInterface.OnDismissListener {
     private static final String TAG = "VpnManage";
 
-    private String mPackageName;
-    private String mInterfaceName;
-    private long mStartTime;
+    private VpnConfig mConfig;
 
-    private ConnectivityManager mService;
+    private IConnectivityManager mService;
 
     private AlertDialog mDialog;
     private TextView mDuration;
     private TextView mDataTransmitted;
     private TextView mDataReceived;
 
-    private Updater mUpdater;
+    private Handler mHandler;
 
     @Override
     protected void onResume() {
         super.onResume();
         try {
-            Intent intent = getIntent();
-            // TODO: Move constants into VpnBuilder.
-            mPackageName = intent.getStringExtra("packageName");
-            mInterfaceName = intent.getStringExtra("interfaceName");
-            mStartTime = intent.getLongExtra("startTime", 0);
+            mConfig = getIntent().getParcelableExtra("config");
 
-            mService = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
+            mService = IConnectivityManager.Stub.asInterface(
+                    ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
 
             PackageManager pm = getPackageManager();
-            ApplicationInfo app = pm.getApplicationInfo(mPackageName, 0);
+            ApplicationInfo app = pm.getApplicationInfo(mConfig.packageName, 0);
 
             View view = View.inflate(this, R.layout.manage, null);
-            String session = intent.getStringExtra("session");
-            if (session != null) {
-                ((TextView) view.findViewById(R.id.session)).setText(session);
+            if (mConfig.sessionName != null) {
+                ((TextView) view.findViewById(R.id.session)).setText(mConfig.sessionName);
             }
             mDuration = (TextView) view.findViewById(R.id.duration);
             mDataTransmitted = (TextView) view.findViewById(R.id.data_transmitted);
@@ -82,15 +79,21 @@
                     .setIcon(app.loadIcon(pm))
                     .setTitle(app.loadLabel(pm))
                     .setView(view)
-                    .setPositiveButton(R.string.configure, this)
                     .setNeutralButton(R.string.disconnect, this)
                     .setNegativeButton(android.R.string.cancel, this)
                     .create();
+
+            if (mConfig.configureActivity != null) {
+                mDialog.setButton(DialogInterface.BUTTON_POSITIVE,
+                        getText(R.string.configure), this);
+            }
             mDialog.setOnDismissListener(this);
             mDialog.show();
 
-            mUpdater = new Updater();
-            mUpdater.sendEmptyMessage(0);
+            if (mHandler == null) {
+                mHandler = new Handler(this);
+            }
+            mHandler.sendEmptyMessage(0);
         } catch (Exception e) {
             Log.e(TAG, "onResume", e);
             finish();
@@ -110,14 +113,15 @@
     public void onClick(DialogInterface dialog, int which) {
         try {
             if (which == AlertDialog.BUTTON_POSITIVE) {
-                Intent intent = new Intent(Intent.ACTION_MAIN);
-                intent.setPackage(mPackageName);
+                Intent intent = new Intent();
+                intent.setClassName(mConfig.packageName, mConfig.configureActivity);
                 startActivity(intent);
             } else if (which == AlertDialog.BUTTON_NEUTRAL) {
-                mService.prepareVpn(mPackageName);
+                mService.prepareVpn("");
             }
         } catch (Exception e) {
             Log.e(TAG, "onClick", e);
+            finish();
         }
     }
 
@@ -126,30 +130,30 @@
         finish();
     }
 
-    private class Updater extends Handler {
-        public void handleMessage(Message message) {
-            removeMessages(0);
+    @Override
+    public boolean handleMessage(Message message) {
+        mHandler.removeMessages(0);
 
-            if (mDialog.isShowing()) {
-                if (mStartTime != 0) {
-                    long seconds = (SystemClock.elapsedRealtime() - mStartTime) / 1000;
-                    mDuration.setText(String.format("%02d:%02d:%02d",
-                            seconds / 3600, seconds / 60 % 60, seconds % 60));
-                }
-
-                String[] numbers = getStatistics();
-                if (numbers != null) {
-                    // [1] and [2] are received data in bytes and packets.
-                    mDataReceived.setText(getString(R.string.data_value_format,
-                            numbers[1], numbers[2]));
-
-                    // [9] and [10] are transmitted data in bytes and packets.
-                    mDataTransmitted.setText(getString(R.string.data_value_format,
-                            numbers[9], numbers[10]));
-                }
-                sendEmptyMessageDelayed(0, 1000);
+        if (mDialog.isShowing()) {
+            if (mConfig.startTime != 0) {
+                long seconds = (SystemClock.elapsedRealtime() - mConfig.startTime) / 1000;
+                mDuration.setText(String.format("%02d:%02d:%02d",
+                        seconds / 3600, seconds / 60 % 60, seconds % 60));
             }
+
+            String[] numbers = getStatistics();
+            if (numbers != null) {
+                // [1] and [2] are received data in bytes and packets.
+                mDataReceived.setText(getString(R.string.data_value_format,
+                        numbers[1], numbers[2]));
+
+                // [9] and [10] are transmitted data in bytes and packets.
+                mDataTransmitted.setText(getString(R.string.data_value_format,
+                        numbers[9], numbers[10]));
+            }
+            mHandler.sendEmptyMessageDelayed(0, 1000);
         }
+        return true;
     }
 
     private String[] getStatistics() {
@@ -157,7 +161,7 @@
         try {
             // See dev_seq_printf_stats() in net/core/dev.c.
             in = new DataInputStream(new FileInputStream("/proc/net/dev"));
-            String prefix = mInterfaceName + ':';
+            String prefix = mConfig.interfaceName + ':';
 
             while (true) {
                 String line = in.readLine().trim();
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
index 72209f6..f385a23 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
@@ -114,7 +114,15 @@
             }
             String stateExtra = intent.getStringExtra(IccCard.INTENT_KEY_ICC_STATE);
             if (IccCard.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
-                this.simState = IccCard.State.ABSENT;
+                final String absentReason = intent
+                    .getStringExtra(IccCard.INTENT_KEY_LOCKED_REASON);
+
+                if (IccCard.INTENT_VALUE_ABSENT_ON_PERM_DISABLED.equals(
+                        absentReason)) {
+                    this.simState = IccCard.State.PERM_DISABLED;
+                } else {
+                    this.simState = IccCard.State.ABSENT;
+                }
             } else if (IccCard.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
                 this.simState = IccCard.State.READY;
             } else if (IccCard.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
index 8a60098..8ba235b 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
@@ -580,7 +580,9 @@
             final boolean provisioned = mUpdateMonitor.isDeviceProvisioned();
             final IccCard.State state = mUpdateMonitor.getSimState();
             final boolean lockedOrMissing = state.isPinLocked()
-                    || ((state == IccCard.State.ABSENT) && requireSim);
+                    || ((state == IccCard.State.ABSENT
+                            || state == IccCard.State.PERM_DISABLED)
+                            && requireSim);
 
             if (!lockedOrMissing && !provisioned) {
                 if (DEBUG) Log.d(TAG, "doKeyguard: not showing because device isn't provisioned"
@@ -687,12 +689,15 @@
 
         switch (simState) {
             case ABSENT:
+            case PERM_DISABLED:
                 // only force lock screen in case of missing sim if user hasn't
                 // gone through setup wizard
                 if (!mUpdateMonitor.isDeviceProvisioned()) {
                     if (!isShowing()) {
-                        if (DEBUG) Log.d(TAG, "INTENT_VALUE_ICC_ABSENT and keygaurd isn't showing, we need "
-                             + "to show the keyguard since the device isn't provisioned yet.");
+                        if (DEBUG) Log.d(TAG, "INTENT_VALUE_ICC_ABSENT "
+                                + "or PERM_DISABLED and keygaurd isn't showing,"
+                                + " we need to show the keyguard since the "
+                                + "device isn't provisioned yet.");
                         doKeyguard();
                     } else {
                         resetStateLocked();
diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
index 874acd0..eea30407 100644
--- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
+++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
@@ -181,7 +181,8 @@
     private boolean stuckOnLockScreenBecauseSimMissing() {
         return mRequiresSim
                 && (!mUpdateMonitor.isDeviceProvisioned())
-                && (mUpdateMonitor.getSimState() == IccCard.State.ABSENT);
+                && (mUpdateMonitor.getSimState() == IccCard.State.ABSENT ||
+                    mUpdateMonitor.getSimState() == IccCard.State.PERM_DISABLED);
     }
 
     /**
diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java
index ed5a058..19adb3e 100644
--- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java
+++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java
@@ -55,8 +55,10 @@
 
     private boolean isSimPinSecure() {
         final IccCard.State simState = mUpdateMonitor.getSimState();
-        return (simState == IccCard.State.PIN_REQUIRED || simState == IccCard.State.PUK_REQUIRED
-            || simState == IccCard.State.ABSENT);
+        return (simState == IccCard.State.PIN_REQUIRED
+                || simState == IccCard.State.PUK_REQUIRED
+                || simState == IccCard.State.ABSENT
+                || simState == IccCard.State.PERM_DISABLED);
     }
 
 }
diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java
index 08f9ebb..8b7a61e 100644
--- a/policy/src/com/android/internal/policy/impl/LockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/LockScreen.java
@@ -129,7 +129,12 @@
         /**
          * The sim card is locked.
          */
-        SimLocked(true);
+        SimLocked(true),
+
+        /**
+         * The sim card is permanently disabled due to puk unlock failure
+         */
+        SimPermDisabled(false);
 
         private final boolean mShowStatusLines;
 
@@ -503,7 +508,9 @@
      */
     private Status getCurrentStatus(IccCard.State simState) {
         boolean missingAndNotProvisioned = (!mUpdateMonitor.isDeviceProvisioned()
-                && simState == IccCard.State.ABSENT);
+                && (simState == IccCard.State.ABSENT
+                        || simState == IccCard.State.PERM_DISABLED));
+
         if (missingAndNotProvisioned) {
             return Status.SimMissingLocked;
         }
@@ -521,6 +528,8 @@
                 return Status.SimPukLocked;
             case READY:
                 return Status.Normal;
+            case PERM_DISABLED:
+                return Status.SimPermDisabled;
             case UNKNOWN:
                 return Status.SimMissing;
         }
@@ -595,6 +604,18 @@
                 enableUnlock(); // do not need to show the e-call button; user may unlock
                 break;
 
+            case SimPermDisabled:
+                // text
+                mStatusView.setCarrierText(R.string.lockscreen_missing_sim_message_short);
+                mScreenLocked.setText(
+                        R.string.lockscreen_permanent_disabled_sim_instructions);
+
+                // layout
+                mScreenLocked.setVisibility(View.VISIBLE);
+                mLockPatternUtils.updateEmergencyCallText(mEmergencyCallText);
+                enableUnlock(); // do not need to show the e-call button; user may unlock
+                break;
+
             case SimMissingLocked:
                 // text
                 mStatusView.setCarrierText(
diff --git a/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java b/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java
index a685497..cd79b60 100644
--- a/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java
@@ -23,6 +23,7 @@
 import android.security.KeyStore;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.View.OnClickListener;
 import android.view.ViewGroup;
 import android.view.MotionEvent;
 import android.widget.Button;
@@ -73,12 +74,8 @@
     private boolean mEnableFallback;
 
     private StatusView mStatusView;
-
     private LockPatternView mLockPatternView;
 
-    private ViewGroup mFooterNormal;
-    private ViewGroup mFooterForgotPattern;
-
     /**
      * Keeps track of the last time we poked the wake lock during dispatching
      * of the touch event, initalized to something gauranteed to make us
@@ -96,9 +93,20 @@
         }
     };
 
+    private final OnClickListener mEmergencyClick = new OnClickListener() {
+        public void onClick(View v) {
+            mCallback.takeEmergencyCallAction();
+        }
+    };
+
+    private final OnClickListener mForgotPatternClick = new OnClickListener() {
+        public void onClick(View v) {
+            mCallback.forgotPattern(true);
+        }
+    };
+
     private Button mForgotPatternButton;
-    private Button mEmergencyAlone;
-    private Button mEmergencyTogether;
+    private Button mEmergencyButton;
     private int mCreationOrientation;
 
     enum FooterMode {
@@ -107,23 +115,27 @@
         VerifyUnlocked
     }
 
+    private void hideForgotPatternButton() {
+        mForgotPatternButton.setVisibility(View.GONE);
+    }
+
+    private void showForgotPatternButton() {
+        mForgotPatternButton.setVisibility(View.VISIBLE);
+    }
+
     private void updateFooter(FooterMode mode) {
         switch (mode) {
             case Normal:
-                Log.d(TAG, "mode normal");
-                mFooterNormal.setVisibility(View.VISIBLE);
-                mFooterForgotPattern.setVisibility(View.GONE);
+                if (DEBUG) Log.d(TAG, "mode normal");
+                hideForgotPatternButton();
                 break;
             case ForgotLockPattern:
-                Log.d(TAG, "mode ForgotLockPattern");
-                mFooterNormal.setVisibility(View.GONE);
-                mFooterForgotPattern.setVisibility(View.VISIBLE);
-                mForgotPatternButton.setVisibility(View.VISIBLE);
+                if (DEBUG) Log.d(TAG, "mode ForgotLockPattern");
+                showForgotPatternButton();
                 break;
             case VerifyUnlocked:
-                Log.d(TAG, "mode VerifyUnlocked");
-                mFooterNormal.setVisibility(View.GONE);
-                mFooterForgotPattern.setVisibility(View.GONE);
+                if (DEBUG) Log.d(TAG, "mode VerifyUnlocked");
+                hideForgotPatternButton();
         }
     }
 
@@ -176,32 +188,16 @@
 
         mLockPatternView = (LockPatternView) findViewById(R.id.lockPattern);
 
-        mFooterNormal = (ViewGroup) findViewById(R.id.footerNormal);
-        mFooterForgotPattern = (ViewGroup) findViewById(R.id.footerForgotPattern);
-
         // emergency call buttons
-        final OnClickListener emergencyClick = new OnClickListener() {
-            public void onClick(View v) {
-                mCallback.takeEmergencyCallAction();
-            }
-        };
+        mEmergencyButton = (Button) findViewById(R.id.emergencyCallButton);
+        mEmergencyButton.setFocusable(false); // touch only!
+        mEmergencyButton.setOnClickListener(mEmergencyClick);
 
-        mEmergencyAlone = (Button) findViewById(R.id.emergencyCallAlone);
-        mEmergencyAlone.setFocusable(false); // touch only!
-        mEmergencyAlone.setOnClickListener(emergencyClick);
-        mEmergencyTogether = (Button) findViewById(R.id.emergencyCallTogether);
-        mEmergencyTogether.setFocusable(false);
-        mEmergencyTogether.setOnClickListener(emergencyClick);
         refreshEmergencyButtonText();
 
-        mForgotPatternButton = (Button) findViewById(R.id.forgotPattern);
+        mForgotPatternButton = (Button) findViewById(R.id.forgotPatternButton);
         mForgotPatternButton.setText(R.string.lockscreen_forgot_pattern_button_text);
-        mForgotPatternButton.setOnClickListener(new OnClickListener() {
-
-            public void onClick(View v) {
-                mCallback.forgotPattern(true);
-            }
-        });
+        mForgotPatternButton.setOnClickListener(mForgotPatternClick);
 
         // make it so unhandled touch events within the unlock screen go to the
         // lock pattern view.
@@ -232,8 +228,7 @@
     }
 
     private void refreshEmergencyButtonText() {
-        mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyAlone);
-        mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyTogether);
+        mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyButton);
     }
 
     public void setEnableFallback(boolean state) {
@@ -338,8 +333,11 @@
         mLockPatternView.clearPattern();
 
         // show "forgot pattern?" button if we have an alternate authentication method
-        mForgotPatternButton.setVisibility(mCallback.doesFallbackUnlockScreenExist()
-                ? View.VISIBLE : View.INVISIBLE);
+        if (mCallback.doesFallbackUnlockScreenExist()) {
+            showForgotPatternButton();
+        } else {
+            hideForgotPatternButton();
+        }
 
         // if the user is currently locked out, enforce it.
         long deadline = mLockPatternUtils.getLockoutAttemptDeadline();
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 5728989..b52e7e1 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -149,10 +149,12 @@
     static final int LONG_PRESS_POWER_NOTHING = 0;
     static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1;
     static final int LONG_PRESS_POWER_SHUT_OFF = 2;
-    
+
+    // These need to match the documentation/constant in
+    // core/res/res/values/config.xml
     static final int LONG_PRESS_HOME_NOTHING = 0;
     static final int LONG_PRESS_HOME_RECENT_DIALOG = 1;
-    static final int LONG_PRESS_HOME_RECENT_ACTIVITY = 2;
+    static final int LONG_PRESS_HOME_RECENT_SYSTEM_UI = 2;
 
     // wallpaper is at the bottom, though the window manager may move it.
     static final int WALLPAPER_LAYER = 2;
@@ -623,7 +625,7 @@
             mLongPressOnHomeBehavior
                     = mContext.getResources().getInteger(R.integer.config_longPressOnHomeBehavior);
             if (mLongPressOnHomeBehavior < LONG_PRESS_HOME_NOTHING ||
-                    mLongPressOnHomeBehavior > LONG_PRESS_HOME_RECENT_ACTIVITY) {
+                    mLongPressOnHomeBehavior > LONG_PRESS_HOME_RECENT_SYSTEM_UI) {
                 mLongPressOnHomeBehavior = LONG_PRESS_HOME_NOTHING;
             }
         }
@@ -639,17 +641,11 @@
 
         if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_DIALOG) {
             showOrHideRecentAppsDialog(0, true /*dismissIfShown*/);
-        } else if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_ACTIVITY) {
+        } else if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_SYSTEM_UI) {
             try {
-                Intent intent = new Intent();
-                intent.setClassName("com.android.systemui", 
-                        "com.android.systemui.recent.RecentApplicationsActivity");
-                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 
-                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-                mContext.startActivity(intent);
-                return;
-            } catch (ActivityNotFoundException e) {
-                Log.e(TAG, "Failed to launch RecentAppsIntent", e);
+                mStatusBarService.toggleRecentApps();
+            } catch (RemoteException e) {
+                Slog.e(TAG, "RemoteException when showing recent apps", e);
             }
         }
     }
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 1e8c30b..a011ae2 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -147,6 +147,14 @@
         return NULL;
     }
 
+    char value[PROPERTY_VALUE_MAX];
+    property_get("sys.secpolicy.camera.disabled", value, "0");
+    if (strcmp(value, "1") == 0) {
+        // Camera is disabled by DevicePolicyManager.
+        LOGI("Camera is disabled. connect X (pid %d) rejected", callingPid);
+        return NULL;
+    }
+
     Mutex::Autolock lock(mServiceLock);
     if (mClient[cameraId] != 0) {
         client = mClient[cameraId].promote();
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index fd502d8..158c778 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -395,41 +395,47 @@
     public void bindAppWidgetId(int appWidgetId, ComponentName provider) {
         mContext.enforceCallingPermission(android.Manifest.permission.BIND_APPWIDGET,
                 "bindGagetId appWidgetId=" + appWidgetId + " provider=" + provider);
-        synchronized (mAppWidgetIds) {
-            AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
-            if (id == null) {
-                throw new IllegalArgumentException("bad appWidgetId");
+        
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (mAppWidgetIds) {
+                AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
+                if (id == null) {
+                    throw new IllegalArgumentException("bad appWidgetId");
+                }
+                if (id.provider != null) {
+                    throw new IllegalArgumentException("appWidgetId " + appWidgetId + " already bound to "
+                            + id.provider.info.provider);
+                }
+                Provider p = lookupProviderLocked(provider);
+                if (p == null) {
+                    throw new IllegalArgumentException("not a appwidget provider: " + provider);
+                }
+                if (p.zombie) {
+                    throw new IllegalArgumentException("can't bind to a 3rd party provider in"
+                            + " safe mode: " + provider);
+                }
+    
+                id.provider = p;
+                p.instances.add(id);
+                int instancesSize = p.instances.size();
+                if (instancesSize == 1) {
+                    // tell the provider that it's ready
+                    sendEnableIntentLocked(p);
+                }
+    
+                // send an update now -- We need this update now, and just for this appWidgetId.
+                // It's less critical when the next one happens, so when we schdule the next one,
+                // we add updatePeriodMillis to its start time.  That time will have some slop,
+                // but that's okay.
+                sendUpdateIntentLocked(p, new int[] { appWidgetId });
+    
+                // schedule the future updates
+                registerForBroadcastsLocked(p, getAppWidgetIds(p));
+                saveStateLocked();
             }
-            if (id.provider != null) {
-                throw new IllegalArgumentException("appWidgetId " + appWidgetId + " already bound to "
-                        + id.provider.info.provider);
-            }
-            Provider p = lookupProviderLocked(provider);
-            if (p == null) {
-                throw new IllegalArgumentException("not a appwidget provider: " + provider);
-            }
-            if (p.zombie) {
-                throw new IllegalArgumentException("can't bind to a 3rd party provider in"
-                        + " safe mode: " + provider);
-            }
-
-            id.provider = p;
-            p.instances.add(id);
-            int instancesSize = p.instances.size();
-            if (instancesSize == 1) {
-                // tell the provider that it's ready
-                sendEnableIntentLocked(p);
-            }
-
-            // send an update now -- We need this update now, and just for this appWidgetId.
-            // It's less critical when the next one happens, so when we schdule the next one,
-            // we add updatePeriodMillis to its start time.  That time will have some slop,
-            // but that's okay.
-            sendUpdateIntentLocked(p, new int[] { appWidgetId });
-
-            // schedule the future updates
-            registerForBroadcastsLocked(p, getAppWidgetIds(p));
-            saveStateLocked();
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index c6f4c20..aa3dfa6 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -16,11 +16,10 @@
 
 package com.android.server;
 
-import static android.Manifest.permission.READ_PHONE_STATE;
-import static android.Manifest.permission.UPDATE_DEVICE_STATS;
+import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
 import static android.net.ConnectivityManager.isNetworkTypeValid;
 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
-import static android.net.NetworkPolicyManager.RULE_REJECT_PAID;
+import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
 
 import android.bluetooth.BluetoothTetheringDataTracker;
 import android.content.ContentResolver;
@@ -48,7 +47,6 @@
 import android.net.vpn.VpnManager;
 import android.net.wifi.WifiStateTracker;
 import android.os.Binder;
-import android.os.Bundle;
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -67,11 +65,13 @@
 import android.util.Slog;
 import android.util.SparseIntArray;
 
+import com.android.internal.net.VpnConfig;
 import com.android.internal.telephony.Phone;
 import com.android.server.connectivity.Tethering;
 import com.android.server.connectivity.Vpn;
 
 import com.google.android.collect.Lists;
+import com.google.android.collect.Sets;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
@@ -79,8 +79,10 @@
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.GregorianCalendar;
+import java.util.HashSet;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -109,8 +111,12 @@
 
     private Vpn mVpn;
 
+    /** Lock around {@link #mUidRules} and {@link #mMeteredIfaces}. */
+    private Object mRulesLock = new Object();
     /** Currently active network rules by UID. */
     private SparseIntArray mUidRules = new SparseIntArray();
+    /** Set of ifaces that are costly. */
+    private HashSet<String> mMeteredIfaces = Sets.newHashSet();
 
     /**
      * Sometimes we want to refer to the individual network state
@@ -571,31 +577,35 @@
     }
 
     /**
-     * Check if UID is blocked from using the given {@link NetworkInfo}.
+     * Check if UID should be blocked from using the network represented by the
+     * given {@link NetworkStateTracker}.
      */
-    private boolean isNetworkBlocked(NetworkInfo info, int uid) {
-        synchronized (mUidRules) {
-            // TODO: expand definition of "paid" network to cover tethered or
-            // paid hotspot use cases.
-            final boolean networkIsPaid = info.getType() != ConnectivityManager.TYPE_WIFI;
-            final int uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
+    private boolean isNetworkBlocked(NetworkStateTracker tracker, int uid) {
+        final String iface = tracker.getLinkProperties().getInterfaceName();
 
-            if (networkIsPaid && (uidRules & RULE_REJECT_PAID) != 0) {
-                return true;
-            }
-
-            // no restrictive rules; network is visible
-            return false;
+        final boolean networkCostly;
+        final int uidRules;
+        synchronized (mRulesLock) {
+            networkCostly = mMeteredIfaces.contains(iface);
+            uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
         }
+
+        if (networkCostly && (uidRules & RULE_REJECT_METERED) != 0) {
+            return true;
+        }
+
+        // no restrictive rules; network is visible
+        return false;
     }
 
     /**
-     * Return a filtered version of the given {@link NetworkInfo}, potentially
-     * marked {@link DetailedState#BLOCKED} based on
-     * {@link #isNetworkBlocked(NetworkInfo, int)}.
+     * Return a filtered {@link NetworkInfo}, potentially marked
+     * {@link DetailedState#BLOCKED} based on
+     * {@link #isNetworkBlocked(NetworkStateTracker, int)}.
      */
-    private NetworkInfo filterNetworkInfo(NetworkInfo info, int uid) {
-        if (isNetworkBlocked(info, uid)) {
+    private NetworkInfo getFilteredNetworkInfo(NetworkStateTracker tracker, int uid) {
+        NetworkInfo info = tracker.getNetworkInfo();
+        if (isNetworkBlocked(tracker, uid)) {
             // network is blocked; clone and override state
             info = new NetworkInfo(info);
             info.setDetailedState(DetailedState.BLOCKED, null, null);
@@ -635,7 +645,7 @@
         if (isNetworkTypeValid(networkType)) {
             final NetworkStateTracker tracker = mNetTrackers[networkType];
             if (tracker != null) {
-                info = filterNetworkInfo(tracker.getNetworkInfo(), uid);
+                info = getFilteredNetworkInfo(tracker, uid);
             }
         }
         return info;
@@ -646,10 +656,10 @@
         enforceAccessPermission();
         final int uid = Binder.getCallingUid();
         final ArrayList<NetworkInfo> result = Lists.newArrayList();
-        synchronized (mUidRules) {
+        synchronized (mRulesLock) {
             for (NetworkStateTracker tracker : mNetTrackers) {
                 if (tracker != null) {
-                    result.add(filterNetworkInfo(tracker.getNetworkInfo(), uid));
+                    result.add(getFilteredNetworkInfo(tracker, uid));
                 }
             }
         }
@@ -686,10 +696,10 @@
         enforceAccessPermission();
         final int uid = Binder.getCallingUid();
         final ArrayList<NetworkState> result = Lists.newArrayList();
-        synchronized (mUidRules) {
+        synchronized (mRulesLock) {
             for (NetworkStateTracker tracker : mNetTrackers) {
                 if (tracker != null) {
-                    final NetworkInfo info = filterNetworkInfo(tracker.getNetworkInfo(), uid);
+                    final NetworkInfo info = getFilteredNetworkInfo(tracker, uid);
                     result.add(new NetworkState(
                             info, tracker.getLinkProperties(), tracker.getLinkCapabilities()));
                 }
@@ -1140,16 +1150,15 @@
 
     private INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() {
         @Override
-        public void onRulesChanged(int uid, int uidRules) {
+        public void onUidRulesChanged(int uid, int uidRules) {
             // only someone like NPMS should only be calling us
-            // TODO: create permission for modifying data policy
-            mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG);
+            mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
 
             if (LOGD_RULES) {
-                Slog.d(TAG, "onRulesChanged(uid=" + uid + ", uidRules=" + uidRules + ")");
+                Slog.d(TAG, "onUidRulesChanged(uid=" + uid + ", uidRules=" + uidRules + ")");
             }
 
-            synchronized (mUidRules) {
+            synchronized (mRulesLock) {
                 // skip update when we've already applied rules
                 final int oldRules = mUidRules.get(uid, RULE_ALLOW_ALL);
                 if (oldRules == uidRules) return;
@@ -1160,6 +1169,24 @@
             // TODO: dispatch into NMS to push rules towards kernel module
             // TODO: notify UID when it has requested targeted updates
         }
+
+        @Override
+        public void onMeteredIfacesChanged(String[] meteredIfaces) {
+            // only someone like NPMS should only be calling us
+            mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+
+            if (LOGD_RULES) {
+                Slog.d(TAG,
+                        "onMeteredIfacesChanged(ifaces=" + Arrays.toString(meteredIfaces) + ")");
+            }
+
+            synchronized (mRulesLock) {
+                mMeteredIfaces.clear();
+                for (String iface : meteredIfaces) {
+                    mMeteredIfaces.add(iface);
+                }
+            }
+        }
     };
 
     /**
@@ -1267,8 +1294,30 @@
             }
         }
         intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
+
+        // Reset interface if no other connections are using the same interface
+        boolean doReset = true;
+        LinkProperties linkProperties = mNetTrackers[prevNetType].getLinkProperties();
+        if (linkProperties != null) {
+            String oldIface = linkProperties.getInterfaceName();
+            if (TextUtils.isEmpty(oldIface) == false) {
+                for (NetworkStateTracker networkStateTracker : mNetTrackers) {
+                    if (networkStateTracker == null) continue;
+                    NetworkInfo networkInfo = networkStateTracker.getNetworkInfo();
+                    if (networkInfo.isConnected() && networkInfo.getType() != prevNetType) {
+                        LinkProperties l = networkStateTracker.getLinkProperties();
+                        if (l == null) continue;
+                        if (oldIface.equals(l.getInterfaceName())) {
+                            doReset = false;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
         // do this before we broadcast the change
-        handleConnectivityChange(prevNetType);
+        handleConnectivityChange(prevNetType, doReset);
 
         sendStickyBroadcast(intent);
         /*
@@ -1490,7 +1539,7 @@
         }
         thisNet.setTeardownRequested(false);
         updateNetworkSettings(thisNet);
-        handleConnectivityChange(type);
+        handleConnectivityChange(type, false);
         sendConnectedBroadcast(info);
     }
 
@@ -1500,7 +1549,7 @@
      * according to which networks are connected, and ensuring that the
      * right routing table entries exist.
      */
-    private void handleConnectivityChange(int netType) {
+    private void handleConnectivityChange(int netType, boolean doReset) {
         /*
          * If a non-default network is enabled, add the host routes that
          * will allow it's DNS servers to be accessed.
@@ -1540,6 +1589,17 @@
                 removePrivateDnsRoutes(mNetTrackers[netType]);
             }
         }
+
+        if (doReset) {
+            LinkProperties linkProperties = mNetTrackers[netType].getLinkProperties();
+            if (linkProperties != null) {
+                String iface = linkProperties.getInterfaceName();
+                if (TextUtils.isEmpty(iface) == false) {
+                    if (DBG) log("resetConnections(" + iface + ")");
+                    NetworkUtils.resetConnections(iface);
+                }
+            }
+        }
     }
 
     private void addPrivateDnsRoutes(NetworkStateTracker nt) {
@@ -1965,7 +2025,7 @@
                     break;
                 case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED:
                     info = (NetworkInfo) msg.obj;
-                    handleConnectivityChange(info.getType());
+                    handleConnectivityChange(info.getType(), true);
                     break;
                 case EVENT_CLEAR_NET_TRANSITION_WAKELOCK:
                     String causedBy = null;
@@ -2396,24 +2456,37 @@
         return value;
     }
 
-    // @see ConnectivityManager#protectVpn(ParcelFileDescriptor)
-    // Permission checks are done in Vpn class.
+    /**
+     * Protect a socket from VPN routing rules. This method is used by
+     * VpnBuilder and not available in ConnectivityManager. Permission
+     * checks are done in Vpn class.
+     * @hide
+     */
     @Override
     public void protectVpn(ParcelFileDescriptor socket) {
         mVpn.protect(socket, getDefaultInterface());
     }
 
-    // @see ConnectivityManager#prepareVpn(String)
-    // Permission checks are done in Vpn class.
+    /**
+     * Prepare for a VPN application. This method is used by VpnDialogs
+     * and not available in ConnectivityManager. Permission checks are
+     * done in Vpn class.
+     * @hide
+     */
     @Override
     public String prepareVpn(String packageName) {
         return mVpn.prepare(packageName);
     }
 
-    // @see ConnectivityManager#establishVpn(Bundle)
-    // Permission checks are done in Vpn class.
+    /**
+     * Configure a TUN interface and return its file descriptor. Parameters
+     * are encoded and opaque to this class. This method is used by VpnBuilder
+     * and not available in ConnectivityManager. Permission checks are done
+     * in Vpn class.
+     * @hide
+     */
     @Override
-    public ParcelFileDescriptor establishVpn(Bundle config) {
+    public ParcelFileDescriptor establishVpn(VpnConfig config) {
         return mVpn.establish(config);
     }
 
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index c86f962..d3244ec 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -33,6 +33,7 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
+import android.hardware.usb.UsbManager;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Environment;
@@ -152,7 +153,6 @@
          * 600 series - Unsolicited broadcasts.
          */
         public static final int VolumeStateChange              = 605;
-        public static final int ShareAvailabilityChange        = 620;
         public static final int VolumeDiskInserted             = 630;
         public static final int VolumeDiskRemoved              = 631;
         public static final int VolumeBadRemoval               = 632;
@@ -167,6 +167,7 @@
     private String                                mExternalStoragePath;
     private PackageManagerService                 mPms;
     private boolean                               mUmsEnabling;
+    private boolean                               mUmsAvailable = false;
     // Used as a lock for methods that register/unregister listeners.
     final private ArrayList<MountServiceBinderListener> mListeners =
             new ArrayList<MountServiceBinderListener>();
@@ -525,6 +526,10 @@
                         }
                     }
                 }.start();
+            } else if (action.equals(UsbManager.ACTION_USB_STATE)) {
+                boolean available = (intent.getBooleanExtra(UsbManager.USB_CONNECTED, false) &&
+                        intent.getBooleanExtra(UsbManager.USB_FUNCTION_MASS_STORAGE, false));
+                notifyShareAvailabilityChange(available);
             }
         }
     };
@@ -654,12 +659,6 @@
                     updatePublicVolumeState(mExternalStoragePath, Environment.MEDIA_REMOVED);
                 }
 
-                try {
-                    boolean avail = doGetShareMethodAvailable("ums");
-                    notifyShareAvailabilityChange("ums", avail);
-                } catch (Exception ex) {
-                    Slog.w(TAG, "Failed to get share availability");
-                }
                 /*
                  * Now that we've done our initialization, release
                  * the hounds!
@@ -694,13 +693,6 @@
             notifyVolumeStateChange(
                     cooked[2], cooked[3], Integer.parseInt(cooked[7]),
                             Integer.parseInt(cooked[10]));
-        } else if (code == VoldResponseCode.ShareAvailabilityChange) {
-            // FMT: NNN Share method <method> now <available|unavailable>
-            boolean avail = false;
-            if (cooked[5].equals("available")) {
-                avail = true;
-            }
-            notifyShareAvailabilityChange(cooked[3], avail);
         } else if ((code == VoldResponseCode.VolumeDiskInserted) ||
                    (code == VoldResponseCode.VolumeDiskRemoved) ||
                    (code == VoldResponseCode.VolumeBadRemoval)) {
@@ -835,42 +827,6 @@
         }
     }
 
-    private boolean doGetShareMethodAvailable(String method) {
-        ArrayList<String> rsp;
-        try {
-            rsp = mConnector.doCommand("share status " + method);
-        } catch (NativeDaemonConnectorException ex) {
-            Slog.e(TAG, "Failed to determine whether share method " + method + " is available.");
-            return false;
-        }
-
-        for (String line : rsp) {
-            String[] tok = line.split(" ");
-            if (tok.length < 3) {
-                Slog.e(TAG, "Malformed response to share status " + method);
-                return false;
-            }
-
-            int code;
-            try {
-                code = Integer.parseInt(tok[0]);
-            } catch (NumberFormatException nfe) {
-                Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
-                return false;
-            }
-            if (code == VoldResponseCode.ShareStatusResult) {
-                if (tok[2].equals("available"))
-                    return true;
-                return false;
-            } else {
-                Slog.e(TAG, String.format("Unexpected response code %d", code));
-                return false;
-            }
-        }
-        Slog.e(TAG, "Got an empty response");
-        return false;
-    }
-
     private int doMountVolume(String path) {
         int rc = StorageResultCode.OperationSucceeded;
 
@@ -1018,13 +974,9 @@
         return false;
     }
 
-    private void notifyShareAvailabilityChange(String method, final boolean avail) {
-        if (!method.equals("ums")) {
-           Slog.w(TAG, "Ignoring unsupported share method {" + method + "}");
-           return;
-        }
-
+    private void notifyShareAvailabilityChange(final boolean avail) {
         synchronized (mListeners) {
+            mUmsAvailable = avail;
             for (int i = mListeners.size() -1; i >= 0; i--) {
                 MountServiceBinderListener bl = mListeners.get(i);
                 try {
@@ -1189,8 +1141,13 @@
         // XXX: This will go away soon in favor of IMountServiceObserver
         mPms = (PackageManagerService) ServiceManager.getService("package");
 
-        mContext.registerReceiver(mBroadcastReceiver,
-                new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_BOOT_COMPLETED);
+        // don't bother monitoring USB if mass storage is not supported on our primary volume
+        if (mPrimaryVolume != null && mPrimaryVolume.allowMassStorage()) {
+            filter.addAction(UsbManager.ACTION_USB_STATE);
+        }
+        mContext.registerReceiver(mBroadcastReceiver, filter, null, null);
 
         mHandlerThread = new HandlerThread("MountService");
         mHandlerThread.start();
@@ -1323,7 +1280,9 @@
         if (getUmsEnabling()) {
             return true;
         }
-        return doGetShareMethodAvailable("ums");
+        synchronized (mListeners) {
+            return mUmsAvailable;
+        }
     }
 
     public void setUsbMassStorageEnabled(boolean enable) {
@@ -1419,7 +1378,7 @@
         return doFormatVolume(path);
     }
 
-    public int []getStorageUsers(String path) {
+    public int[] getStorageUsers(String path) {
         validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
         waitForReady();
         try {
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 2190b30..d6704f4 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -16,6 +16,10 @@
 
 package com.android.server;
 
+import static android.net.NetworkStats.IFACE_ALL;
+import static android.net.NetworkStats.TAG_NONE;
+import static android.net.NetworkStats.UID_ALL;
+
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.net.INetworkManagementEventObserver;
@@ -37,6 +41,7 @@
 import java.io.DataInputStream;
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.net.Inet4Address;
@@ -59,8 +64,9 @@
     private static final int ADD = 1;
     private static final int REMOVE = 2;
 
-    /** Base path to UID-granularity network statistics. */
-    private static final File PATH_PROC_UID_STAT = new File("/proc/uid_stat");
+    @Deprecated
+    private static final File STATS_UIDSTAT = new File("/proc/uid_stat");
+    private static final File STATS_NETFILTER = new File("/proc/net/xt_qtaguid/stats");
 
     class NetdResponseCode {
         public static final int InterfaceListResult       = 110;
@@ -311,6 +317,18 @@
         }
     }
 
+    /* TODO: This is right now a IPv4 only function. Works for wifi which loses its
+       IPv6 addresses on interface down, but we need to do full clean up here */
+    public void clearInterfaceAddresses(String iface) throws IllegalStateException {
+         String cmd = String.format("interface clearaddrs %s", iface);
+        try {
+            mConnector.doCommand(cmd);
+        } catch (NativeDaemonConnectorException e) {
+            throw new IllegalStateException(
+                    "Unable to communicate with native daemon to interface clearallips - " + e);
+        }
+    }
+
     public void addRoute(String interfaceName, RouteInfo route) {
         modifyRoute(interfaceName, ADD, route);
     }
@@ -887,7 +905,7 @@
         for (String iface : ifaces) {
             final long rx = getInterfaceCounter(iface, true);
             final long tx = getInterfaceCounter(iface, false);
-            stats.addEntry(iface, NetworkStats.UID_ALL, rx, tx);
+            stats.addEntry(iface, UID_ALL, TAG_NONE, rx, tx);
         }
 
         return stats;
@@ -898,16 +916,11 @@
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
 
-        final String[] knownUids = PATH_PROC_UID_STAT.list();
-        final NetworkStats stats = new NetworkStats(
-                SystemClock.elapsedRealtime(), knownUids.length);
-
-        for (String uid : knownUids) {
-            final int uidInt = Integer.parseInt(uid);
-            collectNetworkStatsDetail(stats, uidInt);
+        if (STATS_NETFILTER.exists()) {
+            return getNetworkStatsDetailNetfilter(UID_ALL);
+        } else {
+            return getNetworkStatsDetailUidstat(UID_ALL);
         }
-
-        return stats;
     }
 
     @Override
@@ -917,19 +930,84 @@
                     android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
         }
 
-        final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
-        collectNetworkStatsDetail(stats, uid);
+        if (STATS_NETFILTER.exists()) {
+            return getNetworkStatsDetailNetfilter(uid);
+        } else {
+            return getNetworkStatsDetailUidstat(uid);
+        }
+    }
+
+    /**
+     * Build {@link NetworkStats} with detailed UID statistics.
+     */
+    private NetworkStats getNetworkStatsDetailNetfilter(int limitUid) {
+        final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24);
+
+        BufferedReader reader = null;
+        try {
+            reader = new BufferedReader(new FileReader(STATS_NETFILTER));
+
+            // assumes format from kernel:
+            // idx iface acct_tag_hex uid_tag_int rx_bytes tx_bytes
+
+            // skip first line, which is legend
+            String line = reader.readLine();
+            while ((line = reader.readLine()) != null) {
+                final StringTokenizer t = new StringTokenizer(line);
+
+                final String idx = t.nextToken();
+                final String iface = t.nextToken();
+
+                try {
+                    // TODO: kernel currently emits tag in upper half of long;
+                    // eventually switch to directly using int.
+                    final int tag = (int) (Long.parseLong(t.nextToken().substring(2), 16) >> 32);
+                    final int uid = Integer.parseInt(t.nextToken());
+                    final long rx = Long.parseLong(t.nextToken());
+                    final long tx = Long.parseLong(t.nextToken());
+
+                    if (limitUid == UID_ALL || limitUid == uid) {
+                        stats.addEntry(iface, uid, tag, rx, tx);
+                    }
+                } catch (NumberFormatException e) {
+                    Slog.w(TAG, "problem parsing stats for idx " + idx + ": " + e);
+                }
+            }
+        } catch (IOException e) {
+            Slog.w(TAG, "problem parsing stats: " + e);
+        } finally {
+            IoUtils.closeQuietly(reader);
+        }
+
         return stats;
     }
 
-    private void collectNetworkStatsDetail(NetworkStats stats, int uid) {
-        // TODO: kernel module will provide interface-level stats in future
-        // TODO: migrate these stats to come across netd in bulk, instead of all
-        // these individual file reads.
-        final File uidPath = new File(PATH_PROC_UID_STAT, Integer.toString(uid));
-        final long rx = readSingleLongFromFile(new File(uidPath, "tcp_rcv"));
-        final long tx = readSingleLongFromFile(new File(uidPath, "tcp_snd"));
-        stats.addEntry(NetworkStats.IFACE_ALL, uid, rx, tx);
+    /**
+     * Build {@link NetworkStats} with detailed UID statistics.
+     *
+     * @deprecated since this uses older "uid_stat" data, and doesn't provide
+     *             tag-level granularity or additional variables.
+     */
+    @Deprecated
+    private NetworkStats getNetworkStatsDetailUidstat(int limitUid) {
+        final String[] knownUids;
+        if (limitUid == UID_ALL) {
+            knownUids = STATS_UIDSTAT.list();
+        } else {
+            knownUids = new String[] { String.valueOf(limitUid) };
+        }
+
+        final NetworkStats stats = new NetworkStats(
+                SystemClock.elapsedRealtime(), knownUids.length);
+        for (String uid : knownUids) {
+            final int uidInt = Integer.parseInt(uid);
+            final File uidPath = new File(STATS_UIDSTAT, uid);
+            final long rx = readSingleLongFromFile(new File(uidPath, "tcp_rcv"));
+            final long tx = readSingleLongFromFile(new File(uidPath, "tcp_snd"));
+            stats.addEntry(IFACE_ALL, uidInt, TAG_NONE, rx, tx);
+        }
+
+        return stats;
     }
 
     public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/StatusBarManagerService.java
index b1bce50..286a937 100644
--- a/services/java/com/android/server/StatusBarManagerService.java
+++ b/services/java/com/android/server/StatusBarManagerService.java
@@ -345,6 +345,15 @@
         });
     }
 
+    @Override
+    public void toggleRecentApps() {
+        if (mBar != null) {
+            try {
+                mBar.toggleRecentApps();
+            } catch (RemoteException ex) {}
+        }
+    }
+
     private void enforceStatusBar() {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR,
                 "StatusBarManagerService");
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 2769004..a23bacf 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -406,8 +406,8 @@
             }
 
             try {
-                Slog.i(TAG, "USB Observer");
-                // Listen for USB changes
+                Slog.i(TAG, "USB Service");
+                // Manage USB host and device support
                 usb = new UsbService(context);
                 ServiceManager.addService(Context.USB_SERVICE, usb);
             } catch (Throwable e) {
diff --git a/services/java/com/android/server/ThrottleService.java b/services/java/com/android/server/ThrottleService.java
index 510ff62..7266d7d 100644
--- a/services/java/com/android/server/ThrottleService.java
+++ b/services/java/com/android/server/ThrottleService.java
@@ -533,7 +533,8 @@
             long incWrite = 0;
             try {
                 final NetworkStats stats = mNMService.getNetworkStatsSummary();
-                final int index = stats.findIndex(mIface, NetworkStats.UID_ALL);
+                final int index = stats.findIndex(
+                        mIface, NetworkStats.UID_ALL, NetworkStats.TAG_NONE);
 
                 if (index != -1) {
                     incRead = stats.rx[index] - mLastRead;
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index ec59da6..a9dfb22 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -441,6 +441,14 @@
             if (oldService != null) {
                 tryRemoveServiceLocked(oldService);
             }
+            // This API is intended for testing so enable accessibility to make
+            // sure clients can start poking with the window content.
+            Settings.Secure.putInt(mContext.getContentResolver(),
+                    Settings.Secure.ACCESSIBILITY_ENABLED, 1);
+            // Also disable all accessibility services to avoid interference
+            // with the tests.
+            Settings.Secure.putString(mContext.getContentResolver(),
+                    Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, "");
         }
         AccessibilityServiceInfo accessibilityServiceInfo = new AccessibilityServiceInfo();
         accessibilityServiceInfo.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index f1098a8..4ec71c1 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1933,6 +1933,9 @@
             int debugFlags = 0;
             if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
                 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
+                // Also turn on CheckJNI for debuggable apps. It's quite
+                // awkward to turn on otherwise.
+                debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
             }
             // Run the app in safe mode if its manifest requests so or the
             // system is booted in safe mode.
diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java
index ab85b14..47813f8 100644
--- a/services/java/com/android/server/connectivity/Vpn.java
+++ b/services/java/com/android/server/connectivity/Vpn.java
@@ -18,7 +18,6 @@
 
 import android.app.Notification;
 import android.app.NotificationManager;
-import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
@@ -29,12 +28,12 @@
 import android.graphics.drawable.Drawable;
 import android.net.INetworkManagementEventObserver;
 import android.os.Binder;
-import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.util.Log;
 
 import com.android.internal.R;
+import com.android.internal.net.VpnConfig;
 import com.android.server.ConnectivityService.VpnCallback;
 
 /**
@@ -64,42 +63,61 @@
      * @return The name of the current prepared package.
      */
     public synchronized String prepare(String packageName) {
-
-        // TODO: Check if the caller is VpnDialogs.
-
+        // Return the current prepared package if the new one is null.
         if (packageName == null) {
             return mPackageName;
         }
 
-        // Check the permission of the given application.
+        // Check the permission of the caller.
         PackageManager pm = mContext.getPackageManager();
-        if (pm.checkPermission(VPN, packageName) != PackageManager.PERMISSION_GRANTED) {
+        VpnConfig.enforceCallingPackage(pm.getNameForUid(Binder.getCallingUid()));
+
+        // Check the permission of the given package.
+        if (packageName.isEmpty()) {
+            packageName = null;
+        } else if (pm.checkPermission(VPN, packageName) != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException(packageName + " does not have " + VPN);
         }
 
         // Reset the interface and hide the notification.
         if (mInterfaceName != null) {
             nativeReset(mInterfaceName);
-            mInterfaceName = null;
+            mCallback.restore();
             hideNotification();
-            // TODO: Send out a broadcast.
+            mInterfaceName = null;
         }
 
+        // Notify the package being revoked.
+        if (mPackageName != null) {
+            Intent intent = new Intent(VpnConfig.ACTION_VPN_REVOKED);
+            intent.setPackage(mPackageName);
+            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+            mContext.sendBroadcast(intent);
+        }
+
+        Log.i(TAG, "Switched from " + mPackageName + " to " + packageName);
         mPackageName = packageName;
-        Log.i(TAG, "Prepared for " + packageName);
         return mPackageName;
     }
 
     /**
      * Protect a socket from routing changes by binding it to the given
-     * interface. The socket is NOT closed by this method.
+     * interface. The socket IS closed by this method.
      *
      * @param socket The socket to be bound.
      * @param name The name of the interface.
      */
     public void protect(ParcelFileDescriptor socket, String name) {
-        mContext.enforceCallingPermission(VPN, "protect");
-        nativeProtect(socket.getFd(), name);
+        try {
+            mContext.enforceCallingPermission(VPN, "protect");
+            nativeProtect(socket.getFd(), name);
+        } finally {
+            try {
+                socket.close();
+            } catch (Exception e) {
+                // ignore
+            }
+        }
     }
 
     /**
@@ -108,7 +126,7 @@
      * @param configuration The parameters to configure the interface.
      * @return The file descriptor of the interface.
      */
-    public synchronized ParcelFileDescriptor establish(Bundle config) {
+    public synchronized ParcelFileDescriptor establish(VpnConfig config) {
         // Check the permission of the caller.
         mContext.enforceCallingPermission(VPN, "establish");
 
@@ -118,23 +136,15 @@
         try {
             app = pm.getApplicationInfo(mPackageName, 0);
         } catch (Exception e) {
-            throw new SecurityException("Not prepared");
+            return null;
         }
         if (Binder.getCallingUid() != app.uid) {
-            throw new SecurityException("Not prepared");
+            return null;
         }
 
-        // Unpack the config.
-        // TODO: move constants into VpnBuilder.
-        int mtu = config.getInt("mtu", -1);
-        String session = config.getString("session");
-        String addresses = config.getString("addresses");
-        String routes = config.getString("routes");
-        String dnsServers = config.getString("dnsServers");
-
         // Create and configure the interface.
-        ParcelFileDescriptor descriptor =
-                ParcelFileDescriptor.adoptFd(nativeEstablish(mtu, addresses, routes));
+        ParcelFileDescriptor descriptor = ParcelFileDescriptor.adoptFd(
+                nativeEstablish(config.mtu, config.addresses, config.routes));
 
         // Replace the interface and abort if it fails.
         try {
@@ -153,22 +163,15 @@
             throw e;
         }
 
-        dnsServers = (dnsServers == null) ? "" : dnsServers.trim();
+        String dnsServers = (config.dnsServers == null) ? "" : config.dnsServers.trim();
         mCallback.override(dnsServers.isEmpty() ? null : dnsServers.split(" "));
 
-        showNotification(pm, app, session);
+        config.packageName = mPackageName;
+        config.interfaceName = mInterfaceName;
+        showNotification(pm, app, config);
         return descriptor;
     }
 
-    public synchronized boolean onInterfaceRemoved(String name) {
-        if (name.equals(mInterfaceName) && nativeCheck(name) == 0) {
-            hideNotification();
-            mInterfaceName = null;
-            return true;
-        }
-        return false;
-    }
-
     // INetworkManagementEventObserver.Stub
     public void interfaceLinkStatusChanged(String name, boolean up) {
     }
@@ -186,7 +189,7 @@
         }
     }
 
-    private void showNotification(PackageManager pm, ApplicationInfo app, String session) {
+    private void showNotification(PackageManager pm, ApplicationInfo app, VpnConfig config) {
         NotificationManager nm = (NotificationManager)
                 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
 
@@ -207,35 +210,20 @@
             // Load the label.
             String label = app.loadLabel(pm).toString();
 
-            // If session is null, use the application name instead.
-            if (session == null) {
-                session = label;
-            }
-
-            // Build the intent.
-            // TODO: move these into VpnBuilder.
-            Intent intent = new Intent();
-            intent.setClassName("com.android.vpndialogs",
-                    "com.android.vpndialogs.ManageDialog");
-            intent.putExtra("packageName", mPackageName);
-            intent.putExtra("interfaceName", mInterfaceName);
-            intent.putExtra("session", session);
-            intent.putExtra("startTime", android.os.SystemClock.elapsedRealtime());
-            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-
             // Build the notification.
+            String text = (config.sessionName == null) ? mContext.getString(R.string.vpn_text) :
+                    mContext.getString(R.string.vpn_text_long, config.sessionName);
             long identity = Binder.clearCallingIdentity();
             Notification notification = new Notification.Builder(mContext)
                     .setSmallIcon(R.drawable.vpn_connected)
                     .setLargeIcon(bitmap)
                     .setTicker(mContext.getString(R.string.vpn_ticker, label))
                     .setContentTitle(mContext.getString(R.string.vpn_title, label))
-                    .setContentText(mContext.getString(R.string.vpn_text, session))
-                    .setContentIntent(PendingIntent.getActivity(mContext, 0, intent, 0))
+                    .setContentText(text)
+                    .setContentIntent(VpnConfig.getIntentForNotification(mContext, config))
                     .setDefaults(Notification.DEFAULT_ALL)
                     .setOngoing(true)
                     .getNotification();
-
             nm.notify(R.drawable.vpn_connected, notification);
             Binder.restoreCallingIdentity(identity);
         }
diff --git a/services/java/com/android/server/net/InterfaceIdentity.java b/services/java/com/android/server/net/InterfaceIdentity.java
deleted file mode 100644
index ff86581..0000000
--- a/services/java/com/android/server/net/InterfaceIdentity.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * 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.server.net;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.net.ProtocolException;
-import java.util.HashSet;
-
-/**
- * Identity of a {@code iface}, defined by the set of {@link NetworkIdentity}
- * active on that interface.
- *
- * @hide
- */
-public class InterfaceIdentity extends HashSet<NetworkIdentity> {
-    private static final int VERSION_CURRENT = 1;
-
-    public InterfaceIdentity() {
-    }
-
-    public InterfaceIdentity(DataInputStream in) throws IOException {
-        final int version = in.readInt();
-        switch (version) {
-            case VERSION_CURRENT: {
-                final int size = in.readInt();
-                for (int i = 0; i < size; i++) {
-                    add(new NetworkIdentity(in));
-                }
-                break;
-            }
-            default: {
-                throw new ProtocolException("unexpected version: " + version);
-            }
-        }
-    }
-
-    public void writeToStream(DataOutputStream out) throws IOException {
-        out.writeInt(VERSION_CURRENT);
-        out.writeInt(size());
-        for (NetworkIdentity ident : this) {
-            ident.writeToStream(out);
-        }
-    }
-
-    /**
-     * Test if any {@link NetworkIdentity} on this interface matches the given
-     * template and IMEI.
-     */
-    public boolean matchesTemplate(int networkTemplate, String subscriberId) {
-        for (NetworkIdentity ident : this) {
-            if (ident.matchesTemplate(networkTemplate, subscriberId)) {
-                return true;
-            }
-        }
-        return false;
-    }
-}
diff --git a/services/java/com/android/server/net/NetworkIdentity.java b/services/java/com/android/server/net/NetworkIdentity.java
deleted file mode 100644
index 4a207f7..0000000
--- a/services/java/com/android/server/net/NetworkIdentity.java
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * 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.server.net;
-
-import static android.net.ConnectivityManager.TYPE_WIFI;
-import static android.net.ConnectivityManager.TYPE_WIMAX;
-import static android.net.ConnectivityManager.isNetworkTypeMobile;
-import static android.net.TrafficStats.TEMPLATE_MOBILE_3G_LOWER;
-import static android.net.TrafficStats.TEMPLATE_MOBILE_4G;
-import static android.net.TrafficStats.TEMPLATE_MOBILE_ALL;
-import static android.net.TrafficStats.TEMPLATE_WIFI;
-import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G;
-import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G;
-import static android.telephony.TelephonyManager.NETWORK_CLASS_4_G;
-import static android.telephony.TelephonyManager.NETWORK_CLASS_UNKNOWN;
-import static android.telephony.TelephonyManager.getNetworkClass;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.net.NetworkState;
-import android.telephony.TelephonyManager;
-
-import com.android.internal.util.Objects;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.net.ProtocolException;
-
-/**
- * Identity of a {@link NetworkInfo}, defined by network type and billing
- * relationship (such as IMSI).
- *
- * @hide
- */
-public class NetworkIdentity {
-    private static final int VERSION_CURRENT = 1;
-
-    public final int type;
-    public final int subType;
-    public final String subscriberId;
-
-    public NetworkIdentity(int type, int subType, String subscriberId) {
-        this.type = type;
-        this.subType = subType;
-        this.subscriberId = subscriberId;
-    }
-
-    public NetworkIdentity(DataInputStream in) throws IOException {
-        final int version = in.readInt();
-        switch (version) {
-            case VERSION_CURRENT: {
-                type = in.readInt();
-                subType = in.readInt();
-                subscriberId = readOptionalString(in);
-                break;
-            }
-            default: {
-                throw new ProtocolException("unexpected version: " + version);
-            }
-        }
-    }
-
-    public void writeToStream(DataOutputStream out) throws IOException {
-        out.writeInt(VERSION_CURRENT);
-        out.writeInt(type);
-        out.writeInt(subType);
-        writeOptionalString(out, subscriberId);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(type, subType, subscriberId);
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj instanceof NetworkIdentity) {
-            final NetworkIdentity ident = (NetworkIdentity) obj;
-            return type == ident.type && subType == ident.subType
-                    && Objects.equal(subscriberId, ident.subscriberId);
-        }
-        return false;
-    }
-
-    @Override
-    public String toString() {
-        final String typeName = ConnectivityManager.getNetworkTypeName(type);
-        final String subTypeName;
-        if (ConnectivityManager.isNetworkTypeMobile(type)) {
-            subTypeName = TelephonyManager.getNetworkTypeName(subType);
-        } else {
-            subTypeName = Integer.toString(subType);
-        }
-
-        return "[type=" + typeName + ", subType=" + subTypeName + ", subId=" + subscriberId + "]";
-    }
-
-    /**
-     * Test if this network matches the given template and IMEI.
-     */
-    public boolean matchesTemplate(int networkTemplate, String subscriberId) {
-        switch (networkTemplate) {
-            case TEMPLATE_MOBILE_ALL:
-                return matchesMobile(subscriberId);
-            case TEMPLATE_MOBILE_3G_LOWER:
-                return matchesMobile3gLower(subscriberId);
-            case TEMPLATE_MOBILE_4G:
-                return matchesMobile4g(subscriberId);
-            case TEMPLATE_WIFI:
-                return matchesWifi();
-            default:
-                throw new IllegalArgumentException("unknown network template");
-        }
-    }
-
-    /**
-     * Check if mobile network with matching IMEI. Also matches
-     * {@link #TYPE_WIMAX}.
-     */
-    private boolean matchesMobile(String subscriberId) {
-        if (isNetworkTypeMobile(type) && Objects.equal(this.subscriberId, subscriberId)) {
-            return true;
-        } else if (type == TYPE_WIMAX) {
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Check if mobile network classified 3G or lower with matching IMEI.
-     */
-    private boolean matchesMobile3gLower(String subscriberId) {
-        if (isNetworkTypeMobile(type)
-                && Objects.equal(this.subscriberId, subscriberId)) {
-            switch (getNetworkClass(subType)) {
-                case NETWORK_CLASS_UNKNOWN:
-                case NETWORK_CLASS_2_G:
-                case NETWORK_CLASS_3_G:
-                    return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Check if mobile network classified 4G with matching IMEI. Also matches
-     * {@link #TYPE_WIMAX}.
-     */
-    private boolean matchesMobile4g(String subscriberId) {
-        if (isNetworkTypeMobile(type)
-                && Objects.equal(this.subscriberId, subscriberId)) {
-            switch (getNetworkClass(subType)) {
-                case NETWORK_CLASS_4_G:
-                    return true;
-            }
-        } else if (type == TYPE_WIMAX) {
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Check if matches Wi-Fi network template.
-     */
-    private boolean matchesWifi() {
-        if (type == TYPE_WIFI) {
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Build a {@link NetworkIdentity} from the given {@link NetworkState},
-     * assuming that any mobile networks are using the current IMSI.
-     */
-    public static NetworkIdentity buildNetworkIdentity(Context context, NetworkState state) {
-        final int type = state.networkInfo.getType();
-        final int subType = state.networkInfo.getSubtype();
-
-        // TODO: consider moving subscriberId over to LinkCapabilities, so it
-        // comes from an authoritative source.
-
-        final String subscriberId;
-        if (isNetworkTypeMobile(type)) {
-            final TelephonyManager telephony = (TelephonyManager) context.getSystemService(
-                    Context.TELEPHONY_SERVICE);
-            subscriberId = telephony.getSubscriberId();
-        } else {
-            subscriberId = null;
-        }
-        return new NetworkIdentity(type, subType, subscriberId);
-    }
-
-    private static void writeOptionalString(DataOutputStream out, String value) throws IOException {
-        if (value != null) {
-            out.writeByte(1);
-            out.writeUTF(value);
-        } else {
-            out.writeByte(0);
-        }
-    }
-
-    private static String readOptionalString(DataInputStream in) throws IOException {
-        if (in.readByte() != 0) {
-            return in.readUTF();
-        } else {
-            return null;
-        }
-    }
-
-}
diff --git a/services/java/com/android/server/net/NetworkIdentitySet.java b/services/java/com/android/server/net/NetworkIdentitySet.java
new file mode 100644
index 0000000..af03fb3
--- /dev/null
+++ b/services/java/com/android/server/net/NetworkIdentitySet.java
@@ -0,0 +1,98 @@
+/*
+ * 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.server.net;
+
+import android.net.NetworkIdentity;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.net.ProtocolException;
+import java.util.HashSet;
+
+/**
+ * Identity of a {@code iface}, defined by the set of {@link NetworkIdentity}
+ * active on that interface.
+ *
+ * @hide
+ */
+public class NetworkIdentitySet extends HashSet<NetworkIdentity> {
+    private static final int VERSION_INIT = 1;
+    private static final int VERSION_ADD_ROAMING = 2;
+
+    public NetworkIdentitySet() {
+    }
+
+    public NetworkIdentitySet(DataInputStream in) throws IOException {
+        final int version = in.readInt();
+        switch (version) {
+            case VERSION_INIT: {
+                final int size = in.readInt();
+                for (int i = 0; i < size; i++) {
+                    final int ignoredVersion = in.readInt();
+                    final int type = in.readInt();
+                    final int subType = in.readInt();
+                    final String subscriberId = readOptionalString(in);
+                    add(new NetworkIdentity(type, subType, subscriberId, false));
+                }
+                break;
+            }
+            case VERSION_ADD_ROAMING: {
+                final int size = in.readInt();
+                for (int i = 0; i < size; i++) {
+                    final int type = in.readInt();
+                    final int subType = in.readInt();
+                    final String subscriberId = readOptionalString(in);
+                    final boolean roaming = in.readBoolean();
+                    add(new NetworkIdentity(type, subType, subscriberId, roaming));
+                }
+                break;
+            }
+            default: {
+                throw new ProtocolException("unexpected version: " + version);
+            }
+        }
+    }
+
+    public void writeToStream(DataOutputStream out) throws IOException {
+        out.writeInt(VERSION_ADD_ROAMING);
+        out.writeInt(size());
+        for (NetworkIdentity ident : this) {
+            out.writeInt(ident.getType());
+            out.writeInt(ident.getSubType());
+            writeOptionalString(out, ident.getSubscriberId());
+            out.writeBoolean(ident.getRoaming());
+        }
+    }
+
+    private static void writeOptionalString(DataOutputStream out, String value) throws IOException {
+        if (value != null) {
+            out.writeByte(1);
+            out.writeUTF(value);
+        } else {
+            out.writeByte(0);
+        }
+    }
+
+    private static String readOptionalString(DataInputStream in) throws IOException {
+        if (in.readByte() != 0) {
+            return in.readUTF();
+        } else {
+            return null;
+        }
+    }
+}
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 2164334..584cd03 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -22,21 +22,26 @@
 import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
 import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
 import static android.Manifest.permission.READ_PHONE_STATE;
+import static android.content.Intent.ACTION_UID_REMOVED;
+import static android.content.Intent.EXTRA_UID;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
+import static android.net.ConnectivityManager.TYPE_MOBILE;
 import static android.net.NetworkPolicy.LIMIT_DISABLED;
 import static android.net.NetworkPolicy.WARNING_DISABLED;
+import static android.net.NetworkPolicyManager.ACTION_DATA_USAGE_LIMIT;
+import static android.net.NetworkPolicyManager.ACTION_DATA_USAGE_WARNING;
+import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
 import static android.net.NetworkPolicyManager.POLICY_NONE;
-import static android.net.NetworkPolicyManager.POLICY_REJECT_PAID_BACKGROUND;
+import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
-import static android.net.NetworkPolicyManager.RULE_REJECT_PAID;
+import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
 import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
 import static android.net.NetworkPolicyManager.dumpPolicy;
 import static android.net.NetworkPolicyManager.dumpRules;
 import static android.net.NetworkPolicyManager.isUidValidForPolicy;
-import static android.net.TrafficStats.TEMPLATE_MOBILE_3G_LOWER;
-import static android.net.TrafficStats.TEMPLATE_MOBILE_4G;
-import static android.net.TrafficStats.TEMPLATE_MOBILE_ALL;
-import static android.net.TrafficStats.isNetworkTemplateMobile;
+import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
+import static android.net.NetworkTemplate.MATCH_MOBILE_4G;
+import static android.net.NetworkTemplate.MATCH_MOBILE_ALL;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
 import static com.android.internal.util.Preconditions.checkNotNull;
 import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED;
@@ -58,9 +63,11 @@
 import android.net.INetworkPolicyListener;
 import android.net.INetworkPolicyManager;
 import android.net.INetworkStatsService;
+import android.net.NetworkIdentity;
 import android.net.NetworkPolicy;
 import android.net.NetworkState;
 import android.net.NetworkStats;
+import android.net.NetworkTemplate;
 import android.os.Environment;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -81,9 +88,9 @@
 import com.android.internal.R;
 import com.android.internal.os.AtomicFile;
 import com.android.internal.util.FastXmlSerializer;
-import com.android.internal.util.Objects;
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
+import com.google.android.collect.Sets;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -100,6 +107,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.HashSet;
 
 import libcore.io.IoUtils;
 
@@ -138,11 +146,6 @@
     private static final String ATTR_UID = "uid";
     private static final String ATTR_POLICY = "policy";
 
-    public static final String ACTION_DATA_USAGE_WARNING =
-            "android.intent.action.DATA_USAGE_WARNING";
-    public static final String ACTION_DATA_USAGE_LIMIT =
-            "android.intent.action.DATA_USAGE_LIMIT";
-
     private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS;
 
     private final Context mContext;
@@ -166,6 +169,9 @@
     /** Current derived network rules for each UID. */
     private SparseIntArray mUidRules = new SparseIntArray();
 
+    /** Set of ifaces that are metered. */
+    private HashSet<String> mMeteredIfaces = Sets.newHashSet();
+
     /** Foreground at both UID and PID granularity. */
     private SparseBooleanArray mUidForeground = new SparseBooleanArray();
     private SparseArray<SparseBooleanArray> mUidPidForeground = new SparseArray<
@@ -243,9 +249,12 @@
         mContext.registerReceiver(mScreenReceiver, screenFilter);
 
         // watch for network interfaces to be claimed
-        final IntentFilter ifaceFilter = new IntentFilter();
-        ifaceFilter.addAction(CONNECTIVITY_ACTION);
-        mContext.registerReceiver(mIfaceReceiver, ifaceFilter, CONNECTIVITY_INTERNAL, mHandler);
+        final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION);
+        mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
+
+        // listen for uid removal to clean policy
+        final IntentFilter removedFilter = new IntentFilter(ACTION_UID_REMOVED);
+        mContext.registerReceiver(mRemovedReceiver, removedFilter, null, mHandler);
 
         // listen for warning polling events; currently dispatched by
         final IntentFilter statsFilter = new IntentFilter(ACTION_NETWORK_STATS_UPDATED);
@@ -308,6 +317,21 @@
         }
     };
 
+    private BroadcastReceiver mRemovedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            // on background handler thread, and UID_REMOVED is protected
+            // broadcast.
+            final int uid = intent.getIntExtra(EXTRA_UID, 0);
+            synchronized (mRulesLock) {
+                // remove any policy and update rules to clean up
+                mUidPolicy.delete(uid);
+                updateRulesForUidLocked(uid);
+                writePolicyLocked();
+            }
+        }
+    };
+
     /**
      * Receiver that watches for {@link INetworkStatsService} updates, which we
      * use to check against {@link NetworkPolicy#warningBytes}.
@@ -350,10 +374,10 @@
             final long total;
             try {
                 final NetworkStats stats = mNetworkStats.getSummaryForNetwork(
-                        start, end, policy.networkTemplate, policy.subscriberId);
+                        policy.template, start, end);
                 total = stats.rx[0] + stats.tx[0];
             } catch (RemoteException e) {
-                Slog.w(TAG, "problem reading summary for template " + policy.networkTemplate);
+                Slog.w(TAG, "problem reading summary for template " + policy.template);
                 continue;
             }
 
@@ -377,8 +401,7 @@
      * notification of a specific type, like {@link #TYPE_LIMIT}.
      */
     private String buildNotificationTag(NetworkPolicy policy, int type) {
-        // TODO: consider splicing subscriberId hash into mix
-        return TAG + ":" + policy.networkTemplate + ":" + type;
+        return TAG + ":" + policy.template.hashCode() + ":" + type;
     }
 
     /**
@@ -402,19 +425,22 @@
                 builder.setTicker(title);
                 builder.setContentTitle(title);
                 builder.setContentText(body);
-                builder.setContentIntent(PendingIntent.getActivity(mContext, 0,
-                        new Intent(ACTION_DATA_USAGE_WARNING),
-                        PendingIntent.FLAG_UPDATE_CURRENT));
+
+                final Intent intent = new Intent(ACTION_DATA_USAGE_WARNING);
+                intent.addCategory(Intent.CATEGORY_DEFAULT);
+                intent.putExtra(EXTRA_NETWORK_TEMPLATE, policy.template.getMatchRule());
+                builder.setContentIntent(PendingIntent.getActivity(
+                        mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
                 break;
             }
             case TYPE_LIMIT: {
                 final String title;
                 final String body = res.getString(R.string.data_usage_limit_body);
-                switch (policy.networkTemplate) {
-                    case TEMPLATE_MOBILE_3G_LOWER:
+                switch (policy.template.getMatchRule()) {
+                    case MATCH_MOBILE_3G_LOWER:
                         title = res.getString(R.string.data_usage_3g_limit_title);
                         break;
-                    case TEMPLATE_MOBILE_4G:
+                    case MATCH_MOBILE_4G:
                         title = res.getString(R.string.data_usage_4g_limit_title);
                         break;
                     default:
@@ -426,9 +452,12 @@
                 builder.setTicker(title);
                 builder.setContentTitle(title);
                 builder.setContentText(body);
-                builder.setContentIntent(PendingIntent.getActivity(mContext, 0,
-                        new Intent(ACTION_DATA_USAGE_LIMIT),
-                        PendingIntent.FLAG_UPDATE_CURRENT));
+
+                final Intent intent = new Intent(ACTION_DATA_USAGE_LIMIT);
+                intent.addCategory(Intent.CATEGORY_DEFAULT);
+                intent.putExtra(EXTRA_NETWORK_TEMPLATE, policy.template.getMatchRule());
+                builder.setContentIntent(PendingIntent.getActivity(
+                        mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
                 break;
             }
         }
@@ -464,7 +493,7 @@
      * Receiver that watches for {@link IConnectivityManager} to claim network
      * interfaces. Used to apply {@link NetworkPolicy} to matching networks.
      */
-    private BroadcastReceiver mIfaceReceiver = new BroadcastReceiver() {
+    private BroadcastReceiver mConnReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             // on background handler thread, and verified CONNECTIVITY_INTERNAL
@@ -512,7 +541,7 @@
             // collect all active ifaces that match this template
             ifaceList.clear();
             for (NetworkIdentity ident : networks.keySet()) {
-                if (ident.matchesTemplate(policy.networkTemplate, policy.subscriberId)) {
+                if (policy.template.matches(ident)) {
                     final String iface = networks.get(ident);
                     ifaceList.add(iface);
                 }
@@ -532,6 +561,8 @@
         final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
                 : System.currentTimeMillis();
 
+        mMeteredIfaces.clear();
+
         // apply each policy that we found ifaces for; compute remaining data
         // based on current cycle and historical stats, and push to kernel.
         for (NetworkPolicy policy : rules.keySet()) {
@@ -543,11 +574,10 @@
             final NetworkStats stats;
             final long total;
             try {
-                stats = mNetworkStats.getSummaryForNetwork(
-                        start, end, policy.networkTemplate, policy.subscriberId);
+                stats = mNetworkStats.getSummaryForNetwork(policy.template, start, end);
                 total = stats.rx[0] + stats.tx[0];
             } catch (RemoteException e) {
-                Slog.w(TAG, "problem reading summary for template " + policy.networkTemplate);
+                Slog.w(TAG, "problem reading summary for template " + policy.template);
                 continue;
             }
 
@@ -562,8 +592,27 @@
                 // remaining "quota" is based on usage in current cycle
                 final long quota = Math.max(0, policy.limitBytes - total);
                 //kernelSetIfacesQuota(ifaces, quota);
+
+                for (String iface : ifaces) {
+                    mMeteredIfaces.add(iface);
+                }
             }
         }
+
+        // dispatch changed rule to existing listeners
+        // TODO: dispatch outside of holding lock
+        final String[] meteredIfaces = mMeteredIfaces.toArray(new String[mMeteredIfaces.size()]);
+        final int length = mListeners.beginBroadcast();
+        for (int i = 0; i < length; i++) {
+            final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
+            if (listener != null) {
+                try {
+                    listener.onMeteredIfacesChanged(meteredIfaces);
+                } catch (RemoteException e) {
+                }
+            }
+        }
+        mListeners.finishBroadcast();
     }
 
     /**
@@ -573,12 +622,13 @@
     private void ensureActiveMobilePolicyLocked() {
         if (LOGV) Slog.v(TAG, "ensureActiveMobilePolicyLocked()");
         final String subscriberId = getActiveSubscriberId();
+        final NetworkIdentity probeIdent = new NetworkIdentity(
+                TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, false);
 
         // examine to see if any policy is defined for active mobile
         boolean mobileDefined = false;
         for (NetworkPolicy policy : mNetworkPolicy) {
-            if (isNetworkTemplateMobile(policy.networkTemplate)
-                    && Objects.equal(subscriberId, policy.subscriberId)) {
+            if (policy.template.matches(probeIdent)) {
                 mobileDefined = true;
             }
         }
@@ -594,8 +644,9 @@
             time.setToNow();
             final int cycleDay = time.monthDay;
 
-            mNetworkPolicy.add(new NetworkPolicy(
-                    TEMPLATE_MOBILE_ALL, subscriberId, cycleDay, 4 * GB_IN_BYTES, LIMIT_DISABLED));
+            final NetworkTemplate template = new NetworkTemplate(MATCH_MOBILE_ALL, subscriberId);
+            mNetworkPolicy.add(
+                    new NetworkPolicy(template, cycleDay, 4 * GB_IN_BYTES, LIMIT_DISABLED));
             writePolicyLocked();
         }
     }
@@ -628,8 +679,10 @@
                         final long warningBytes = readLongAttribute(in, ATTR_WARNING_BYTES);
                         final long limitBytes = readLongAttribute(in, ATTR_LIMIT_BYTES);
 
-                        mNetworkPolicy.add(new NetworkPolicy(
-                                networkTemplate, subscriberId, cycleDay, warningBytes, limitBytes));
+                        final NetworkTemplate template = new NetworkTemplate(
+                                networkTemplate, subscriberId);
+                        mNetworkPolicy.add(
+                                new NetworkPolicy(template, cycleDay, warningBytes, limitBytes));
 
                     } else if (TAG_UID_POLICY.equals(tag)) {
                         final int uid = readIntAttribute(in, ATTR_UID);
@@ -671,10 +724,13 @@
 
             // write all known network policies
             for (NetworkPolicy policy : mNetworkPolicy) {
+                final NetworkTemplate template = policy.template;
+
                 out.startTag(null, TAG_NETWORK_POLICY);
-                writeIntAttribute(out, ATTR_NETWORK_TEMPLATE, policy.networkTemplate);
-                if (policy.subscriberId != null) {
-                    out.attribute(null, ATTR_SUBSCRIBER_ID, policy.subscriberId);
+                writeIntAttribute(out, ATTR_NETWORK_TEMPLATE, template.getMatchRule());
+                final String subscriberId = template.getSubscriberId();
+                if (subscriberId != null) {
+                    out.attribute(null, ATTR_SUBSCRIBER_ID, subscriberId);
                 }
                 writeIntAttribute(out, ATTR_CYCLE_DAY, policy.cycleDay);
                 writeLongAttribute(out, ATTR_WARNING_BYTES, policy.warningBytes);
@@ -743,26 +799,44 @@
 
     @Override
     public void registerListener(INetworkPolicyListener listener) {
+        // TODO: create permission for observing network policy
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+
         mListeners.register(listener);
 
         synchronized (mRulesLock) {
             // dispatch any existing rules to new listeners
+            // TODO: dispatch outside of holding lock
             final int size = mUidRules.size();
             for (int i = 0; i < size; i++) {
                 final int uid = mUidRules.keyAt(i);
                 final int uidRules = mUidRules.valueAt(i);
                 if (uidRules != RULE_ALLOW_ALL) {
                     try {
-                        listener.onRulesChanged(uid, uidRules);
+                        listener.onUidRulesChanged(uid, uidRules);
                     } catch (RemoteException e) {
                     }
                 }
             }
+
+            // dispatch any metered ifaces to new listeners
+            // TODO: dispatch outside of holding lock
+            if (mMeteredIfaces.size() > 0) {
+                final String[] meteredIfaces = mMeteredIfaces.toArray(
+                        new String[mMeteredIfaces.size()]);
+                try {
+                    listener.onMeteredIfacesChanged(meteredIfaces);
+                } catch (RemoteException e) {
+                }
+            }
         }
     }
 
     @Override
     public void unregisterListener(INetworkPolicyListener listener) {
+        // TODO: create permission for observing network policy
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+
         mListeners.unregister(listener);
     }
 
@@ -911,9 +985,9 @@
 
         // derive active rules based on policy and active state
         int uidRules = RULE_ALLOW_ALL;
-        if (!uidForeground && (uidPolicy & POLICY_REJECT_PAID_BACKGROUND) != 0) {
-            // uid in background, and policy says to block paid data
-            uidRules = RULE_REJECT_PAID;
+        if (!uidForeground && (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
+            // uid in background, and policy says to block metered data
+            uidRules = RULE_REJECT_METERED;
         }
 
         // TODO: only dispatch when rules actually change
@@ -921,16 +995,17 @@
         // record rule locally to dispatch to new listeners
         mUidRules.put(uid, uidRules);
 
-        final boolean rejectPaid = (uidRules & RULE_REJECT_PAID) != 0;
+        final boolean rejectMetered = (uidRules & RULE_REJECT_METERED) != 0;
         //kernelSetUidRejectPaid(uid, rejectPaid);
 
         // dispatch changed rule to existing listeners
+        // TODO: dispatch outside of holding lock
         final int length = mListeners.beginBroadcast();
         for (int i = 0; i < length; i++) {
             final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
             if (listener != null) {
                 try {
-                    listener.onRulesChanged(uid, uidRules);
+                    listener.onUidRulesChanged(uid, uidRules);
                 } catch (RemoteException e) {
                 }
             }
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index f762123..043a581 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -19,14 +19,19 @@
 import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
 import static android.Manifest.permission.DUMP;
 import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
-import static android.Manifest.permission.SHUTDOWN;
+import static android.content.Intent.ACTION_SHUTDOWN;
+import static android.content.Intent.ACTION_UID_REMOVED;
+import static android.content.Intent.EXTRA_UID;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
 import static android.net.NetworkStats.IFACE_ALL;
+import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
+import static android.net.TrafficStats.UID_REMOVED;
 import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION;
 import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY;
 import static android.provider.Settings.Secure.NETSTATS_PERSIST_THRESHOLD;
 import static android.provider.Settings.Secure.NETSTATS_POLL_INTERVAL;
+import static android.provider.Settings.Secure.NETSTATS_TAG_MAX_HISTORY;
 import static android.provider.Settings.Secure.NETSTATS_UID_BUCKET_DURATION;
 import static android.provider.Settings.Secure.NETSTATS_UID_MAX_HISTORY;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
@@ -45,10 +50,12 @@
 import android.content.pm.ApplicationInfo;
 import android.net.IConnectivityManager;
 import android.net.INetworkStatsService;
+import android.net.NetworkIdentity;
 import android.net.NetworkInfo;
 import android.net.NetworkState;
 import android.net.NetworkStats;
 import android.net.NetworkStatsHistory;
+import android.net.NetworkTemplate;
 import android.os.Environment;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -57,14 +64,14 @@
 import android.os.SystemClock;
 import android.provider.Settings;
 import android.telephony.TelephonyManager;
+import android.util.LongSparseArray;
 import android.util.NtpTrustedTime;
 import android.util.Slog;
-import android.util.SparseArray;
 import android.util.TrustedTime;
 
 import com.android.internal.os.AtomicFile;
-import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
+import com.google.android.collect.Sets;
 
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
@@ -76,9 +83,9 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.net.ProtocolException;
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 
 import libcore.io.IoUtils;
 
@@ -93,7 +100,10 @@
 
     /** File header magic number: "ANET" */
     private static final int FILE_MAGIC = 0x414E4554;
-    private static final int VERSION_CURRENT = 1;
+    private static final int VERSION_NETWORK_INIT = 1;
+    private static final int VERSION_UID_INIT = 1;
+    private static final int VERSION_UID_WITH_IDENT = 2;
+    private static final int VERSION_UID_WITH_TAG = 3;
 
     private final Context mContext;
     private final INetworkManagementService mNetworkManager;
@@ -112,6 +122,9 @@
     private PendingIntent mPollIntent;
 
     // TODO: listen for kernel push events through netd instead of polling
+    // TODO: watch for UID uninstall, and transfer stats into single bucket
+
+    // TODO: trim empty history objects entirely
 
     private static final long KB_IN_BYTES = 1024;
     private static final long MB_IN_BYTES = 1024 * KB_IN_BYTES;
@@ -127,26 +140,27 @@
         public long getNetworkMaxHistory();
         public long getUidBucketDuration();
         public long getUidMaxHistory();
+        public long getTagMaxHistory();
         public long getTimeCacheMaxAge();
     }
 
     private final Object mStatsLock = new Object();
 
-    /** Set of active ifaces during this boot. */
-    private HashMap<String, InterfaceIdentity> mActiveIface = Maps.newHashMap();
-
-    /** Set of historical stats for known ifaces. */
-    private HashMap<InterfaceIdentity, NetworkStatsHistory> mNetworkStats = Maps.newHashMap();
+    /** Set of currently active ifaces. */
+    private HashMap<String, NetworkIdentitySet> mActiveIfaces = Maps.newHashMap();
+    /** Set of historical stats for known networks. */
+    private HashMap<NetworkIdentitySet, NetworkStatsHistory> mNetworkStats = Maps.newHashMap();
     /** Set of historical stats for known UIDs. */
-    private SparseArray<NetworkStatsHistory> mUidStats = new SparseArray<NetworkStatsHistory>();
+    private HashMap<NetworkIdentitySet, LongSparseArray<NetworkStatsHistory>> mUidStats =
+            Maps.newHashMap();
 
     /** Flag if {@link #mUidStats} have been loaded from disk. */
     private boolean mUidStatsLoaded = false;
 
-    private NetworkStats mLastNetworkPoll;
-    private NetworkStats mLastNetworkPersist;
+    private NetworkStats mLastNetworkSnapshot;
+    private NetworkStats mLastPersistNetworkSnapshot;
 
-    private NetworkStats mLastUidPoll;
+    private NetworkStats mLastUidSnapshot;
 
     private final HandlerThread mHandlerThread;
     private final Handler mHandler;
@@ -200,17 +214,20 @@
         }
 
         // watch for network interfaces to be claimed
-        final IntentFilter ifaceFilter = new IntentFilter();
-        ifaceFilter.addAction(CONNECTIVITY_ACTION);
-        mContext.registerReceiver(mIfaceReceiver, ifaceFilter, CONNECTIVITY_INTERNAL, mHandler);
+        final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION);
+        mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
 
         // listen for periodic polling events
         final IntentFilter pollFilter = new IntentFilter(ACTION_NETWORK_STATS_POLL);
         mContext.registerReceiver(mPollReceiver, pollFilter, READ_NETWORK_USAGE_HISTORY, mHandler);
 
+        // listen for uid removal to clean stats
+        final IntentFilter removedFilter = new IntentFilter(ACTION_UID_REMOVED);
+        mContext.registerReceiver(mRemovedReceiver, removedFilter, null, mHandler);
+
         // persist stats during clean shutdown
-        final IntentFilter shutdownFilter = new IntentFilter(Intent.ACTION_SHUTDOWN);
-        mContext.registerReceiver(mShutdownReceiver, shutdownFilter, SHUTDOWN, null);
+        final IntentFilter shutdownFilter = new IntentFilter(ACTION_SHUTDOWN);
+        mContext.registerReceiver(mShutdownReceiver, shutdownFilter);
 
         try {
             registerPollAlarmLocked();
@@ -220,12 +237,15 @@
     }
 
     private void shutdownLocked() {
-        mContext.unregisterReceiver(mIfaceReceiver);
+        mContext.unregisterReceiver(mConnReceiver);
         mContext.unregisterReceiver(mPollReceiver);
+        mContext.unregisterReceiver(mRemovedReceiver);
         mContext.unregisterReceiver(mShutdownReceiver);
 
         writeNetworkStatsLocked();
-        writeUidStatsLocked();
+        if (mUidStatsLoaded) {
+            writeUidStatsLocked();
+        }
         mNetworkStats.clear();
         mUidStats.clear();
         mUidStatsLoaded = false;
@@ -249,18 +269,19 @@
     }
 
     @Override
-    public NetworkStatsHistory getHistoryForNetwork(int networkTemplate) {
+    public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template) {
         mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
 
         synchronized (mStatsLock) {
             // combine all interfaces that match template
-            final String subscriberId = getActiveSubscriberId();
             final NetworkStatsHistory combined = new NetworkStatsHistory(
                     mSettings.getNetworkBucketDuration(), estimateNetworkBuckets());
-            for (InterfaceIdentity ident : mNetworkStats.keySet()) {
-                final NetworkStatsHistory history = mNetworkStats.get(ident);
-                if (ident.matchesTemplate(networkTemplate, subscriberId)) {
-                    combined.recordEntireHistory(history);
+            for (NetworkIdentitySet ident : mNetworkStats.keySet()) {
+                if (templateMatches(template, ident)) {
+                    final NetworkStatsHistory history = mNetworkStats.get(ident);
+                    if (history != null) {
+                        combined.recordEntireHistory(history);
+                    }
                 }
             }
             return combined;
@@ -268,19 +289,30 @@
     }
 
     @Override
-    public NetworkStatsHistory getHistoryForUid(int uid, int networkTemplate) {
+    public NetworkStatsHistory getHistoryForUid(NetworkTemplate template, int uid, int tag) {
         mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
 
         synchronized (mStatsLock) {
-            // TODO: combine based on template, if we store that granularity
             ensureUidStatsLoadedLocked();
-            return mUidStats.get(uid);
+            final long packed = packUidAndTag(uid, tag);
+
+            // combine all interfaces that match template
+            final NetworkStatsHistory combined = new NetworkStatsHistory(
+                    mSettings.getUidBucketDuration(), estimateUidBuckets());
+            for (NetworkIdentitySet ident : mUidStats.keySet()) {
+                if (templateMatches(template, ident)) {
+                    final NetworkStatsHistory history = mUidStats.get(ident).get(packed);
+                    if (history != null) {
+                        combined.recordEntireHistory(history);
+                    }
+                }
+            }
+            return combined;
         }
     }
 
     @Override
-    public NetworkStats getSummaryForNetwork(
-            long start, long end, int networkTemplate, String subscriberId) {
+    public NetworkStats getSummaryForNetwork(NetworkTemplate template, long start, long end) {
         mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
 
         synchronized (mStatsLock) {
@@ -289,9 +321,9 @@
             long[] networkTotal = new long[2];
 
             // combine total from all interfaces that match template
-            for (InterfaceIdentity ident : mNetworkStats.keySet()) {
-                final NetworkStatsHistory history = mNetworkStats.get(ident);
-                if (ident.matchesTemplate(networkTemplate, subscriberId)) {
+            for (NetworkIdentitySet ident : mNetworkStats.keySet()) {
+                if (templateMatches(template, ident)) {
+                    final NetworkStatsHistory history = mNetworkStats.get(ident);
                     networkTotal = history.getTotalData(start, end, networkTotal);
                     rx += networkTotal[0];
                     tx += networkTotal[1];
@@ -299,30 +331,45 @@
             }
 
             final NetworkStats stats = new NetworkStats(end - start, 1);
-            stats.addEntry(IFACE_ALL, UID_ALL, rx, tx);
+            stats.addEntry(IFACE_ALL, UID_ALL, TAG_NONE, rx, tx);
             return stats;
         }
     }
 
     @Override
-    public NetworkStats getSummaryForAllUid(long start, long end, int networkTemplate) {
+    public NetworkStats getSummaryForAllUid(
+            NetworkTemplate template, long start, long end, boolean includeTags) {
         mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
 
-        // TODO: apply networktemplate once granular uid stats are stored.
-
         synchronized (mStatsLock) {
             ensureUidStatsLoadedLocked();
 
-            final int size = mUidStats.size();
-            final NetworkStats stats = new NetworkStats(end - start, size);
-
+            final NetworkStats stats = new NetworkStats(end - start, 24);
             long[] total = new long[2];
-            for (int i = 0; i < size; i++) {
-                final int uid = mUidStats.keyAt(i);
-                final NetworkStatsHistory history = mUidStats.valueAt(i);
-                total = history.getTotalData(start, end, total);
-                stats.addEntry(IFACE_ALL, uid, total[0], total[1]);
+
+            for (NetworkIdentitySet ident : mUidStats.keySet()) {
+                if (templateMatches(template, ident)) {
+                    final LongSparseArray<NetworkStatsHistory> uidStats = mUidStats.get(ident);
+                    for (int i = 0; i < uidStats.size(); i++) {
+                        final long packed = uidStats.keyAt(i);
+                        final int uid = unpackUid(packed);
+                        final int tag = unpackTag(packed);
+
+                        // always include summary under TAG_NONE, and include
+                        // other tags when requested.
+                        if (tag == TAG_NONE || includeTags) {
+                            final NetworkStatsHistory history = uidStats.valueAt(i);
+                            total = history.getTotalData(start, end, total);
+                            final long rx = total[0];
+                            final long tx = total[1];
+                            if (rx > 0 || tx > 0) {
+                                stats.combineEntry(IFACE_ALL, uid, tag, rx, tx);
+                            }
+                        }
+                    }
+                }
             }
+
             return stats;
         }
     }
@@ -332,7 +379,7 @@
      * interfaces. Used to associate {@link TelephonyManager#getSubscriberId()}
      * with mobile interfaces.
      */
-    private BroadcastReceiver mIfaceReceiver = new BroadcastReceiver() {
+    private BroadcastReceiver mConnReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             // on background handler thread, and verified CONNECTIVITY_INTERNAL
@@ -350,7 +397,19 @@
             // permission above.
             synchronized (mStatsLock) {
                 // TODO: acquire wakelock while performing poll
-                performPollLocked(true);
+                performPollLocked(true, false);
+            }
+        }
+    };
+
+    private BroadcastReceiver mRemovedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            // on background handler thread, and UID_REMOVED is protected
+            // broadcast.
+            final int uid = intent.getIntExtra(EXTRA_UID, 0);
+            synchronized (mStatsLock) {
+                removeUidLocked(uid);
             }
         }
     };
@@ -358,7 +417,7 @@
     private BroadcastReceiver mShutdownReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            // verified SHUTDOWN permission above.
+            // SHUTDOWN is protected broadcast.
             synchronized (mStatsLock) {
                 shutdownLocked();
             }
@@ -369,7 +428,7 @@
      * Inspect all current {@link NetworkState} to derive mapping from {@code
      * iface} to {@link NetworkStatsHistory}. When multiple {@link NetworkInfo}
      * are active on a single {@code iface}, they are combined under a single
-     * {@link InterfaceIdentity}.
+     * {@link NetworkIdentitySet}.
      */
     private void updateIfacesLocked() {
         if (LOGV) Slog.v(TAG, "updateIfacesLocked()");
@@ -377,7 +436,7 @@
         // take one last stats snapshot before updating iface mapping. this
         // isn't perfect, since the kernel may already be counting traffic from
         // the updated network.
-        performPollLocked(false);
+        performPollLocked(false, false);
 
         final NetworkState[] states;
         try {
@@ -388,13 +447,19 @@
         }
 
         // rebuild active interfaces based on connected networks
-        mActiveIface.clear();
+        mActiveIfaces.clear();
 
         for (NetworkState state : states) {
             if (state.networkInfo.isConnected()) {
                 // collect networks under their parent interfaces
                 final String iface = state.linkProperties.getInterfaceName();
-                final InterfaceIdentity ident = findOrCreateInterfaceLocked(iface);
+
+                NetworkIdentitySet ident = mActiveIfaces.get(iface);
+                if (ident == null) {
+                    ident = new NetworkIdentitySet();
+                    mActiveIfaces.put(iface, ident);
+                }
+
                 ident.add(NetworkIdentity.buildNetworkIdentity(mContext, state));
             }
         }
@@ -407,7 +472,7 @@
      * @param detailedPoll Indicate if detailed UID stats should be collected
      *            during this poll operation.
      */
-    private void performPollLocked(boolean detailedPoll) {
+    private void performPollLocked(boolean detailedPoll, boolean forcePersist) {
         if (LOGV) Slog.v(TAG, "performPollLocked()");
 
         // try refreshing time source when stale
@@ -419,31 +484,34 @@
         final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
                 : System.currentTimeMillis();
 
-        final NetworkStats networkStats;
-        final NetworkStats uidStats;
+        final NetworkStats networkSnapshot;
+        final NetworkStats uidSnapshot;
         try {
-            networkStats = mNetworkManager.getNetworkStatsSummary();
-            uidStats = detailedPoll ? mNetworkManager.getNetworkStatsDetail() : null;
+            networkSnapshot = mNetworkManager.getNetworkStatsSummary();
+            uidSnapshot = detailedPoll ? mNetworkManager.getNetworkStatsDetail() : null;
         } catch (RemoteException e) {
             Slog.w(TAG, "problem reading network stats");
             return;
         }
 
-        performNetworkPollLocked(networkStats, currentTime);
+        performNetworkPollLocked(networkSnapshot, currentTime);
         if (detailedPoll) {
-            performUidPollLocked(uidStats, currentTime);
+            performUidPollLocked(uidSnapshot, currentTime);
         }
 
         // decide if enough has changed to trigger persist
-        final NetworkStats persistDelta = computeStatsDelta(mLastNetworkPersist, networkStats);
+        final NetworkStats persistDelta = computeStatsDelta(
+                mLastPersistNetworkSnapshot, networkSnapshot);
         final long persistThreshold = mSettings.getPersistThreshold();
         for (String iface : persistDelta.getUniqueIfaces()) {
-            final int index = persistDelta.findIndex(iface, UID_ALL);
-            if (persistDelta.rx[index] > persistThreshold
+            final int index = persistDelta.findIndex(iface, UID_ALL, TAG_NONE);
+            if (forcePersist || persistDelta.rx[index] > persistThreshold
                     || persistDelta.tx[index] > persistThreshold) {
                 writeNetworkStatsLocked();
-                writeUidStatsLocked();
-                mLastNetworkPersist = networkStats;
+                if (mUidStatsLoaded) {
+                    writeUidStatsLocked();
+                }
+                mLastPersistNetworkSnapshot = networkSnapshot;
                 break;
             }
         }
@@ -457,28 +525,33 @@
     /**
      * Update {@link #mNetworkStats} historical usage.
      */
-    private void performNetworkPollLocked(NetworkStats networkStats, long currentTime) {
-        final ArrayList<String> unknownIface = Lists.newArrayList();
+    private void performNetworkPollLocked(NetworkStats networkSnapshot, long currentTime) {
+        final HashSet<String> unknownIface = Sets.newHashSet();
 
-        final NetworkStats delta = computeStatsDelta(mLastNetworkPoll, networkStats);
+        final NetworkStats delta = computeStatsDelta(mLastNetworkSnapshot, networkSnapshot);
         final long timeStart = currentTime - delta.elapsedRealtime;
-        final long maxHistory = mSettings.getNetworkMaxHistory();
-        for (String iface : delta.getUniqueIfaces()) {
-            final InterfaceIdentity ident = mActiveIface.get(iface);
+        for (int i = 0; i < delta.size; i++) {
+            final String iface = delta.iface[i];
+            final NetworkIdentitySet ident = mActiveIfaces.get(iface);
             if (ident == null) {
                 unknownIface.add(iface);
                 continue;
             }
 
-            final int index = delta.findIndex(iface, UID_ALL);
-            final long rx = delta.rx[index];
-            final long tx = delta.tx[index];
+            final long rx = delta.rx[i];
+            final long tx = delta.tx[i];
 
-            final NetworkStatsHistory history = findOrCreateNetworkLocked(ident);
+            final NetworkStatsHistory history = findOrCreateNetworkStatsLocked(ident);
             history.recordData(timeStart, currentTime, rx, tx);
+        }
+
+        // trim any history beyond max
+        final long maxHistory = mSettings.getNetworkMaxHistory();
+        for (NetworkStatsHistory history : mNetworkStats.values()) {
             history.removeBucketsBefore(currentTime - maxHistory);
         }
-        mLastNetworkPoll = networkStats;
+
+        mLastNetworkSnapshot = networkSnapshot;
 
         if (LOGD && unknownIface.size() > 0) {
             Slog.w(TAG, "unknown interfaces " + unknownIface.toString() + ", ignoring those stats");
@@ -488,32 +561,84 @@
     /**
      * Update {@link #mUidStats} historical usage.
      */
-    private void performUidPollLocked(NetworkStats uidStats, long currentTime) {
+    private void performUidPollLocked(NetworkStats uidSnapshot, long currentTime) {
         ensureUidStatsLoadedLocked();
 
-        final NetworkStats delta = computeStatsDelta(mLastUidPoll, uidStats);
+        final NetworkStats delta = computeStatsDelta(mLastUidSnapshot, uidSnapshot);
         final long timeStart = currentTime - delta.elapsedRealtime;
-        final long maxHistory = mSettings.getUidMaxHistory();
-        for (int uid : delta.getUniqueUids()) {
-            // TODO: traverse all ifaces once surfaced in stats
-            final int index = delta.findIndex(IFACE_ALL, uid);
-            if (index != -1) {
-                final long rx = delta.rx[index];
-                final long tx = delta.tx[index];
 
-                final NetworkStatsHistory history = findOrCreateUidLocked(uid);
-                history.recordData(timeStart, currentTime, rx, tx);
-                history.removeBucketsBefore(currentTime - maxHistory);
+        for (int i = 0; i < delta.size; i++) {
+            final String iface = delta.iface[i];
+            final NetworkIdentitySet ident = mActiveIfaces.get(iface);
+            if (ident == null) {
+                continue;
+            }
+
+            final int uid = delta.uid[i];
+            final int tag = delta.tag[i];
+            final long rx = delta.rx[i];
+            final long tx = delta.tx[i];
+
+            final NetworkStatsHistory history = findOrCreateUidStatsLocked(ident, uid, tag);
+            history.recordData(timeStart, currentTime, rx, tx);
+        }
+
+        // trim any history beyond max
+        final long maxUidHistory = mSettings.getUidMaxHistory();
+        final long maxTagHistory = mSettings.getTagMaxHistory();
+        for (LongSparseArray<NetworkStatsHistory> uidStats : mUidStats.values()) {
+            for (int i = 0; i < uidStats.size(); i++) {
+                final long packed = uidStats.keyAt(i);
+                final NetworkStatsHistory history = uidStats.valueAt(i);
+
+                // detailed tags are trimmed sooner than summary in TAG_NONE
+                if (unpackTag(packed) == TAG_NONE) {
+                    history.removeBucketsBefore(currentTime - maxUidHistory);
+                } else {
+                    history.removeBucketsBefore(currentTime - maxTagHistory);
+                }
             }
         }
-        mLastUidPoll = uidStats;
+
+        mLastUidSnapshot = uidSnapshot;
     }
 
-    private NetworkStatsHistory findOrCreateNetworkLocked(InterfaceIdentity ident) {
-        final long bucketDuration = mSettings.getNetworkBucketDuration();
+    /**
+     * Clean up {@link #mUidStats} after UID is removed.
+     */
+    private void removeUidLocked(int uid) {
+        ensureUidStatsLoadedLocked();
+
+        // migrate all UID stats into special "removed" bucket
+        for (NetworkIdentitySet ident : mUidStats.keySet()) {
+            final LongSparseArray<NetworkStatsHistory> uidStats = mUidStats.get(ident);
+            for (int i = 0; i < uidStats.size(); i++) {
+                final long packed = uidStats.keyAt(i);
+                if (unpackUid(packed) == uid) {
+                    // only migrate combined TAG_NONE history
+                    if (unpackTag(packed) == TAG_NONE) {
+                        final NetworkStatsHistory uidHistory = uidStats.valueAt(i);
+                        final NetworkStatsHistory removedHistory = findOrCreateUidStatsLocked(
+                                ident, UID_REMOVED, TAG_NONE);
+                        removedHistory.recordEntireHistory(uidHistory);
+                    }
+                    uidStats.remove(packed);
+                }
+            }
+        }
+
+        // TODO: push kernel event to wipe stats for UID, otherwise we risk
+        // picking them up again during next poll.
+
+        // since this was radical rewrite, push to disk
+        writeUidStatsLocked();
+    }
+
+    private NetworkStatsHistory findOrCreateNetworkStatsLocked(NetworkIdentitySet ident) {
         final NetworkStatsHistory existing = mNetworkStats.get(ident);
 
         // update when no existing, or when bucket duration changed
+        final long bucketDuration = mSettings.getNetworkBucketDuration();
         NetworkStatsHistory updated = null;
         if (existing == null) {
             updated = new NetworkStatsHistory(bucketDuration, 10);
@@ -531,11 +656,21 @@
         }
     }
 
-    private NetworkStatsHistory findOrCreateUidLocked(int uid) {
-        final long bucketDuration = mSettings.getUidBucketDuration();
-        final NetworkStatsHistory existing = mUidStats.get(uid);
+    private NetworkStatsHistory findOrCreateUidStatsLocked(
+            NetworkIdentitySet ident, int uid, int tag) {
+        ensureUidStatsLoadedLocked();
+
+        LongSparseArray<NetworkStatsHistory> uidStats = mUidStats.get(ident);
+        if (uidStats == null) {
+            uidStats = new LongSparseArray<NetworkStatsHistory>();
+            mUidStats.put(ident, uidStats);
+        }
+
+        final long packed = packUidAndTag(uid, tag);
+        final NetworkStatsHistory existing = uidStats.get(packed);
 
         // update when no existing, or when bucket duration changed
+        final long bucketDuration = mSettings.getUidBucketDuration();
         NetworkStatsHistory updated = null;
         if (existing == null) {
             updated = new NetworkStatsHistory(bucketDuration, 10);
@@ -546,22 +681,13 @@
         }
 
         if (updated != null) {
-            mUidStats.put(uid, updated);
+            uidStats.put(packed, updated);
             return updated;
         } else {
             return existing;
         }
     }
 
-    private InterfaceIdentity findOrCreateInterfaceLocked(String iface) {
-        InterfaceIdentity ident = mActiveIface.get(iface);
-        if (ident == null) {
-            ident = new InterfaceIdentity();
-            mActiveIface.put(iface, ident);
-        }
-        return ident;
-    }
-
     private void readNetworkStatsLocked() {
         if (LOGV) Slog.v(TAG, "readNetworkStatsLocked()");
 
@@ -581,15 +707,12 @@
 
             final int version = in.readInt();
             switch (version) {
-                case VERSION_CURRENT: {
-                    // file format is pairs of interfaces and stats:
-                    // network := size *(InterfaceIdentity NetworkStatsHistory)
-
+                case VERSION_NETWORK_INIT: {
+                    // network := size *(NetworkIdentitySet NetworkStatsHistory)
                     final int size = in.readInt();
                     for (int i = 0; i < size; i++) {
-                        final InterfaceIdentity ident = new InterfaceIdentity(in);
+                        final NetworkIdentitySet ident = new NetworkIdentitySet(in);
                         final NetworkStatsHistory history = new NetworkStatsHistory(in);
-
                         mNetworkStats.put(ident, history);
                     }
                     break;
@@ -633,16 +756,39 @@
 
             final int version = in.readInt();
             switch (version) {
-                case VERSION_CURRENT: {
-                    // file format is pairs of UIDs and stats:
+                case VERSION_UID_INIT: {
                     // uid := size *(UID NetworkStatsHistory)
 
-                    final int size = in.readInt();
-                    for (int i = 0; i < size; i++) {
-                        final int uid = in.readInt();
-                        final NetworkStatsHistory history = new NetworkStatsHistory(in);
+                    // drop this data version, since we don't have a good
+                    // mapping into NetworkIdentitySet.
+                    break;
+                }
+                case VERSION_UID_WITH_IDENT: {
+                    // uid := size *(NetworkIdentitySet size *(UID NetworkStatsHistory))
 
-                        mUidStats.put(uid, history);
+                    // drop this data version, since this version only existed
+                    // for a short time.
+                    break;
+                }
+                case VERSION_UID_WITH_TAG: {
+                    // uid := size *(NetworkIdentitySet size *(UID tag NetworkStatsHistory))
+                    final int ifaceSize = in.readInt();
+                    for (int i = 0; i < ifaceSize; i++) {
+                        final NetworkIdentitySet ident = new NetworkIdentitySet(in);
+
+                        final int childSize = in.readInt();
+                        final LongSparseArray<NetworkStatsHistory> uidStats = new LongSparseArray<
+                                NetworkStatsHistory>(childSize);
+                        for (int j = 0; j < childSize; j++) {
+                            final int uid = in.readInt();
+                            final int tag = in.readInt();
+                            final long packed = packUidAndTag(uid, tag);
+
+                            final NetworkStatsHistory history = new NetworkStatsHistory(in);
+                            uidStats.put(packed, history);
+                        }
+
+                        mUidStats.put(ident, uidStats);
                     }
                     break;
                 }
@@ -670,10 +816,10 @@
             final DataOutputStream out = new DataOutputStream(fos);
 
             out.writeInt(FILE_MAGIC);
-            out.writeInt(VERSION_CURRENT);
+            out.writeInt(VERSION_NETWORK_INIT);
 
             out.writeInt(mNetworkStats.size());
-            for (InterfaceIdentity ident : mNetworkStats.keySet()) {
+            for (NetworkIdentitySet ident : mNetworkStats.keySet()) {
                 final NetworkStatsHistory history = mNetworkStats.get(ident);
                 ident.writeToStream(out);
                 history.writeToStream(out);
@@ -690,6 +836,11 @@
     private void writeUidStatsLocked() {
         if (LOGV) Slog.v(TAG, "writeUidStatsLocked()");
 
+        if (!mUidStatsLoaded) {
+            Slog.w(TAG, "asked to write UID stats when not loaded; skipping");
+            return;
+        }
+
         // TODO: consider duplicating stats and releasing lock while writing
 
         FileOutputStream fos = null;
@@ -698,16 +849,25 @@
             final DataOutputStream out = new DataOutputStream(fos);
 
             out.writeInt(FILE_MAGIC);
-            out.writeInt(VERSION_CURRENT);
+            out.writeInt(VERSION_UID_WITH_TAG);
 
             final int size = mUidStats.size();
-
             out.writeInt(size);
-            for (int i = 0; i < size; i++) {
-                final int uid = mUidStats.keyAt(i);
-                final NetworkStatsHistory history = mUidStats.valueAt(i);
-                out.writeInt(uid);
-                history.writeToStream(out);
+            for (NetworkIdentitySet ident : mUidStats.keySet()) {
+                final LongSparseArray<NetworkStatsHistory> uidStats = mUidStats.get(ident);
+                ident.writeToStream(out);
+
+                final int childSize = uidStats.size();
+                out.writeInt(childSize);
+                for (int i = 0; i < childSize; i++) {
+                    final long packed = uidStats.keyAt(i);
+                    final int uid = unpackUid(packed);
+                    final int tag = unpackTag(packed);
+                    final NetworkStatsHistory history = uidStats.valueAt(i);
+                    out.writeInt(uid);
+                    out.writeInt(tag);
+                    history.writeToStream(out);
+                }
             }
 
             mUidFile.finishWrite(fos);
@@ -736,35 +896,44 @@
             }
 
             if (argSet.contains("poll")) {
-                performPollLocked(true);
+                performPollLocked(true, true);
                 pw.println("Forced poll");
                 return;
             }
 
             pw.println("Active interfaces:");
-            for (String iface : mActiveIface.keySet()) {
-                final InterfaceIdentity ident = mActiveIface.get(iface);
+            for (String iface : mActiveIfaces.keySet()) {
+                final NetworkIdentitySet ident = mActiveIfaces.get(iface);
                 pw.print("  iface="); pw.print(iface);
                 pw.print(" ident="); pw.println(ident.toString());
             }
 
             pw.println("Known historical stats:");
-            for (InterfaceIdentity ident : mNetworkStats.keySet()) {
-                final NetworkStatsHistory stats = mNetworkStats.get(ident);
+            for (NetworkIdentitySet ident : mNetworkStats.keySet()) {
+                final NetworkStatsHistory history = mNetworkStats.get(ident);
                 pw.print("  ident="); pw.println(ident.toString());
-                stats.dump("    ", pw);
+                history.dump("  ", pw);
             }
 
             if (argSet.contains("detail")) {
                 // since explicitly requested with argument, we're okay to load
                 // from disk if not already in memory.
                 ensureUidStatsLoadedLocked();
-                pw.println("Known UID stats:");
-                for (int i = 0; i < mUidStats.size(); i++) {
-                    final int uid = mUidStats.keyAt(i);
-                    final NetworkStatsHistory stats = mUidStats.valueAt(i);
-                    pw.print("  UID="); pw.println(uid);
-                    stats.dump("    ", pw);
+
+                pw.println("Detailed UID stats:");
+                for (NetworkIdentitySet ident : mUidStats.keySet()) {
+                    pw.print("  ident="); pw.println(ident.toString());
+
+                    final LongSparseArray<NetworkStatsHistory> uidStats = mUidStats.get(ident);
+                    for (int i = 0; i < uidStats.size(); i++) {
+                        final long packed = uidStats.keyAt(i);
+                        final int uid = unpackUid(packed);
+                        final int tag = unpackTag(packed);
+                        final NetworkStatsHistory history = uidStats.valueAt(i);
+                        pw.print("    UID="); pw.print(uid);
+                        pw.print(" tag="); pw.println(tag);
+                        history.dump("    ", pw);
+                    }
                 }
             }
         }
@@ -775,27 +944,30 @@
      */
     @Deprecated
     private void generateRandomLocked() {
-        long end = System.currentTimeMillis();
-        long start = end - mSettings.getNetworkMaxHistory();
-        long rx = 3 * GB_IN_BYTES;
-        long tx = 2 * GB_IN_BYTES;
+        long networkEnd = System.currentTimeMillis();
+        long networkStart = networkEnd - mSettings.getNetworkMaxHistory();
+        long networkRx = 3 * GB_IN_BYTES;
+        long networkTx = 2 * GB_IN_BYTES;
+
+        long uidEnd = System.currentTimeMillis();
+        long uidStart = uidEnd - mSettings.getUidMaxHistory();
+        long uidRx = 500 * MB_IN_BYTES;
+        long uidTx = 100 * MB_IN_BYTES;
+
+        final List<ApplicationInfo> installedApps = mContext
+                .getPackageManager().getInstalledApplications(0);
 
         mNetworkStats.clear();
-        for (InterfaceIdentity ident : mActiveIface.values()) {
-            final NetworkStatsHistory stats = findOrCreateNetworkLocked(ident);
-            stats.generateRandom(start, end, rx, tx);
-        }
-
-        end = System.currentTimeMillis();
-        start = end - mSettings.getUidMaxHistory();
-        rx = 500 * MB_IN_BYTES;
-        tx = 100 * MB_IN_BYTES;
-
         mUidStats.clear();
-        for (ApplicationInfo info : mContext.getPackageManager().getInstalledApplications(0)) {
-            final int uid = info.uid;
-            final NetworkStatsHistory stats = findOrCreateUidLocked(uid);
-            stats.generateRandom(start, end, rx, tx);
+        for (NetworkIdentitySet ident : mActiveIfaces.values()) {
+            findOrCreateNetworkStatsLocked(ident).generateRandom(
+                    networkStart, networkEnd, networkRx, networkTx);
+
+            for (ApplicationInfo info : installedApps) {
+                final int uid = info.uid;
+                findOrCreateUidStatsLocked(ident, uid, TAG_NONE).generateRandom(
+                        uidStart, uidEnd, uidRx, uidTx);
+            }
         }
     }
 
@@ -811,12 +983,6 @@
         }
     }
 
-    private String getActiveSubscriberId() {
-        final TelephonyManager telephony = (TelephonyManager) mContext.getSystemService(
-                Context.TELEPHONY_SERVICE);
-        return telephony.getSubscriberId();
-    }
-
     private int estimateNetworkBuckets() {
         return (int) (mSettings.getNetworkMaxHistory() / mSettings.getNetworkBucketDuration());
     }
@@ -829,6 +995,36 @@
         return (int) (existing.bucketCount * existing.bucketDuration / newBucketDuration);
     }
 
+    // @VisibleForTesting
+    public static long packUidAndTag(int uid, int tag) {
+        final long uidLong = uid;
+        final long tagLong = tag;
+        return (uidLong << 32) | (tagLong & 0xFFFFFFFFL);
+    }
+
+    // @VisibleForTesting
+    public static int unpackUid(long packed) {
+        return (int) (packed >> 32);
+    }
+
+    // @VisibleForTesting
+    public static int unpackTag(long packed) {
+        return (int) (packed & 0xFFFFFFFFL);
+    }
+
+    /**
+     * Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity}
+     * in the given {@link NetworkIdentitySet}.
+     */
+    private static boolean templateMatches(NetworkTemplate template, NetworkIdentitySet identSet) {
+        for (NetworkIdentity ident : identSet) {
+            if (template.matches(ident)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Default external settings that read from {@link Settings.Secure}.
      */
@@ -862,6 +1058,9 @@
         public long getUidMaxHistory() {
             return getSecureLong(NETSTATS_UID_MAX_HISTORY, 90 * DAY_IN_MILLIS);
         }
+        public long getTagMaxHistory() {
+            return getSecureLong(NETSTATS_TAG_MAX_HISTORY, 30 * DAY_IN_MILLIS);
+        }
         public long getTimeCacheMaxAge() {
             return DAY_IN_MILLIS;
         }
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index e1fbe1c..5a9dae9 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -18,6 +18,7 @@
 
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
 
 import com.android.internal.app.IMediaContainerService;
@@ -7048,7 +7049,8 @@
             final String packageName, String className, int newState, final int flags) {
         if (!(newState == COMPONENT_ENABLED_STATE_DEFAULT
               || newState == COMPONENT_ENABLED_STATE_ENABLED
-              || newState == COMPONENT_ENABLED_STATE_DISABLED)) {
+              || newState == COMPONENT_ENABLED_STATE_DISABLED
+              || newState == COMPONENT_ENABLED_STATE_DISABLED_USER)) {
             throw new IllegalArgumentException("Invalid new component state: "
                     + newState);
         }
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 2720bf8..5ed7988 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -18,6 +18,7 @@
 
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
 
 import com.android.internal.util.FastXmlSerializer;
@@ -1912,6 +1913,7 @@
             return false;
         }
         if (packageSettings.enabled == COMPONENT_ENABLED_STATE_DISABLED
+                || packageSettings.enabled == COMPONENT_ENABLED_STATE_DISABLED_USER
                 || (packageSettings.pkg != null && !packageSettings.pkg.applicationInfo.enabled
                         && packageSettings.enabled == COMPONENT_ENABLED_STATE_DEFAULT)) {
             return false;
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index ca8a184..b7f9d5c 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -19,7 +19,6 @@
 import android.app.PendingIntent;
 import android.app.Notification;
 import android.app.NotificationManager;
-import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -33,10 +32,16 @@
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.FileUtils;
 import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
 import android.os.Message;
 import android.os.Parcelable;
 import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageVolume;
 import android.os.SystemProperties;
 import android.os.UEventObserver;
 import android.provider.Settings;
@@ -46,7 +51,7 @@
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
-import java.io.FileReader;
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
@@ -55,77 +60,110 @@
  * UsbDeviceManager manages USB state in device mode.
  */
 public class UsbDeviceManager {
+
     private static final String TAG = UsbDeviceManager.class.getSimpleName();
     private static final boolean LOG = false;
 
-    private static final String USB_CONNECTED_MATCH =
-            "DEVPATH=/devices/virtual/switch/usb_connected";
-    private static final String USB_CONFIGURATION_MATCH =
-            "DEVPATH=/devices/virtual/switch/usb_configuration";
-    private static final String USB_FUNCTIONS_MATCH =
-            "DEVPATH=/devices/virtual/usb_composite/";
-    private static final String USB_CONNECTED_PATH =
-            "/sys/class/switch/usb_connected/state";
-    private static final String USB_CONFIGURATION_PATH =
-            "/sys/class/switch/usb_configuration/state";
-    private static final String USB_COMPOSITE_CLASS_PATH =
-            "/sys/class/usb_composite";
+    private static final String USB_STATE_MATCH =
+            "DEVPATH=/devices/virtual/android_usb/android0";
+    private static final String ACCESSORY_START_MATCH =
+            "DEVPATH=/devices/virtual/misc/usb_accessory";
+    private static final String FUNCTIONS_PATH =
+            "/sys/class/android_usb/android0/functions";
+    private static final String STATE_PATH =
+            "/sys/class/android_usb/android0/state";
+    private static final String MASS_STORAGE_FILE_PATH =
+            "/sys/class/android_usb/f_mass_storage/lun/file";
 
     private static final int MSG_UPDATE_STATE = 0;
-    private static final int MSG_FUNCTION_ENABLED = 1;
-    private static final int MSG_FUNCTION_DISABLED = 2;
+    private static final int MSG_ENABLE_ADB = 1;
+    private static final int MSG_SET_PRIMARY_FUNCTION = 2;
+    private static final int MSG_SET_DEFAULT_FUNCTION = 3;
+    private static final int MSG_SYSTEM_READY = 4;
 
     // Delay for debouncing USB disconnects.
     // We often get rapid connect/disconnect events when enabling USB functions,
     // which need debouncing.
     private static final int UPDATE_DELAY = 1000;
 
-    // current connected and configuration state
-    private int mConnected;
-    private int mConfiguration;
-
-    // last broadcasted connected and configuration state
-    private int mLastConnected = -1;
-    private int mLastConfiguration = -1;
-
-    // lists of enabled and disabled USB functions
-    private final ArrayList<String> mEnabledFunctions = new ArrayList<String>();
-
+    private UsbHandler mHandler;
     private boolean mSystemReady;
 
-    private UsbAccessory mCurrentAccessory;
-    // USB functions that are enabled by default, to restore after exiting accessory mode
-    private final ArrayList<String> mDefaultFunctions = new ArrayList<String>();
-
     private final Context mContext;
-    ContentResolver mContentResolver;
-    private final Object mLock = new Object();
+    private final ContentResolver mContentResolver;
     private final UsbSettingsManager mSettingsManager;
     private NotificationManager mNotificationManager;
     private final boolean mHasUsbAccessory;
 
-    // for adb connected notifications
-    private boolean mAdbNotificationShown = false;
+    // for USB connected notification
+    private boolean mUsbNotificationShown;
+    private boolean mUseUsbNotification;
+    private Notification mUsbNotification;
+
+    // for adb connected notification
+    private boolean mAdbNotificationShown;
     private Notification mAdbNotification;
     private boolean mAdbEnabled;
 
+
     private class AdbSettingsObserver extends ContentObserver {
         public AdbSettingsObserver() {
             super(null);
         }
         @Override
         public void onChange(boolean selfChange) {
-            mAdbEnabled = (Settings.Secure.getInt(mContentResolver,
-                Settings.Secure.ADB_ENABLED, 0) > 0);
-            // setting this secure property will start or stop adbd
-           SystemProperties.set("persist.service.adb.enable", mAdbEnabled ? "1" : "0");
-           updateAdbNotification();
+            boolean enable = (Settings.Secure.getInt(mContentResolver,
+                    Settings.Secure.ADB_ENABLED, 0) > 0);
+            mHandler.sendMessage(MSG_ENABLE_ADB, enable);
         }
     }
 
-    private void updateAdbNotification() {
+    private void updateUsbNotification(boolean connected) {
+        if (mNotificationManager == null || !mUseUsbNotification) return;
+        if (connected) {
+            if (!mUsbNotificationShown) {
+                Resources r = mContext.getResources();
+                CharSequence title = r.getText(
+                        com.android.internal.R.string.usb_preferences_notification_title);
+                CharSequence message = r.getText(
+                        com.android.internal.R.string.usb_preferece_notification_message);
+
+                if (mUsbNotification == null) {
+                    mUsbNotification = new Notification();
+                    mUsbNotification.icon = com.android.internal.R.drawable.stat_sys_data_usb;
+                    mUsbNotification.when = 0;
+                    mUsbNotification.flags = Notification.FLAG_ONGOING_EVENT;
+                    mUsbNotification.tickerText = title;
+                    mUsbNotification.defaults = 0; // please be quiet
+                    mUsbNotification.sound = null;
+                    mUsbNotification.vibrate = null;
+                }
+
+                Intent intent = new Intent();
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
+                        Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+                intent.setClassName("com.android.systemui",
+                        "com.android.systemui.usb.UsbPreferenceActivity");
+                PendingIntent pi = PendingIntent.getActivity(mContext, 0,
+                        intent, 0);
+
+                mUsbNotification.setLatestEventInfo(mContext, title, message, pi);
+
+                mUsbNotificationShown = true;
+                mNotificationManager.notify(
+                        com.android.internal.R.string.usb_preferences_notification_title,
+                        mUsbNotification);
+            }
+
+        } else if (mUsbNotificationShown) {
+            mUsbNotificationShown = false;
+            mNotificationManager.cancel(
+                    com.android.internal.R.string.usb_preferences_notification_title);
+        }
+    }
+
+    private void updateAdbNotification(boolean adbEnabled) {
         if (mNotificationManager == null) return;
-        boolean adbEnabled = mAdbEnabled && (mConnected == 1);
         if (adbEnabled) {
             if ("0".equals(SystemProperties.get("persist.adb.notify"))) return;
 
@@ -173,38 +211,6 @@
         }
     }
 
-    private final void readCurrentAccessoryLocked() {
-        if (mHasUsbAccessory) {
-            String[] strings = nativeGetAccessoryStrings();
-            if (strings != null) {
-                mCurrentAccessory = new UsbAccessory(strings);
-                Log.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
-                if (mSystemReady) {
-                    mSettingsManager.accessoryAttached(mCurrentAccessory);
-                }
-            } else {
-                Log.e(TAG, "nativeGetAccessoryStrings failed");
-            }
-        }
-    }
-
-    /*
-     * Handles USB function enable/disable events
-     */
-    private final void functionEnabledLocked(String function, boolean enabled) {
-        if (enabled) {
-            if (!mEnabledFunctions.contains(function)) {
-                mEnabledFunctions.add(function);
-            }
-
-            if (UsbManager.USB_FUNCTION_ACCESSORY.equals(function)) {
-                readCurrentAccessoryLocked();
-            }
-        } else {
-            mEnabledFunctions.remove(function);
-        }
-    }
-
     /*
      * Listens for uevent messages from the kernel to monitor the USB state
      */
@@ -215,53 +221,13 @@
                 Slog.v(TAG, "USB UEVENT: " + event.toString());
             }
 
-            synchronized (mLock) {
-                String name = event.get("SWITCH_NAME");
-                String state = event.get("SWITCH_STATE");
-                if (name != null && state != null) {
-                    try {
-                        int intState = Integer.parseInt(state);
-                        if ("usb_connected".equals(name)) {
-                            mConnected = intState;
-                            // trigger an Intent broadcast
-                            if (mSystemReady) {
-                                // debounce disconnects to avoid problems bringing up USB tethering
-                                update(mConnected == 0);
-                            }
-                        } else if ("usb_configuration".equals(name)) {
-                            mConfiguration = intState;
-                            // trigger an Intent broadcast
-                            if (mSystemReady) {
-                                update(mConnected == 0);
-                            }
-                        }
-                    } catch (NumberFormatException e) {
-                        Slog.e(TAG, "Could not parse switch state from event " + event);
-                    }
-                } else {
-                    String function = event.get("FUNCTION");
-                    String enabledStr = event.get("ENABLED");
-                    if (function != null && enabledStr != null) {
-                        // Note: we do not broadcast a change when a function is enabled or disabled.
-                        // We just record the state change for the next broadcast.
-                        int what = ("1".equals(enabledStr) ?
-                                MSG_FUNCTION_ENABLED : MSG_FUNCTION_DISABLED);
-                        Message msg = Message.obtain(mHandler, what);
-                        msg.obj = function;
-                        mHandler.sendMessage(msg);
-                    }
-                }
-            }
-        }
-    };
-
-   private final BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() {
-        public void onReceive(Context context, Intent intent) {
-            // handle accessories attached at boot time
-            synchronized (mLock) {
-                if (mCurrentAccessory != null) {
-                    mSettingsManager.accessoryAttached(mCurrentAccessory);
-                }
+            String state = event.get("USB_STATE");
+            String accessory = event.get("ACCESSORY");
+            if (state != null) {
+                mHandler.updateState(state);
+            } else if ("START".equals(accessory)) {
+                Slog.d(TAG, "got accessory start");
+                setPrimaryFunction(UsbManager.USB_FUNCTION_ACCESSORY);
             }
         }
     };
@@ -273,229 +239,378 @@
         PackageManager pm = mContext.getPackageManager();
         mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
 
-        synchronized (mLock) {
-            init();  // set initial status
-
-            // make sure the ADB_ENABLED setting value matches the secure property value
-            mAdbEnabled = "1".equals(SystemProperties.get("persist.service.adb.enable"));
-            Settings.Secure.putInt(mContentResolver, Settings.Secure.ADB_ENABLED,
-                    mAdbEnabled ? 1 : 0);
-
-            // register observer to listen for settings changes
-            mContentResolver.registerContentObserver(
-                    Settings.Secure.getUriFor(Settings.Secure.ADB_ENABLED),
-                            false, new AdbSettingsObserver());
-
-            // Watch for USB configuration changes
-            if (mConfiguration >= 0) {
-                mUEventObserver.startObserving(USB_CONNECTED_MATCH);
-                mUEventObserver.startObserving(USB_CONFIGURATION_MATCH);
-                mUEventObserver.startObserving(USB_FUNCTIONS_MATCH);
+        // create a thread for our Handler
+        HandlerThread thread = new HandlerThread("UsbDeviceManager",
+                Process.THREAD_PRIORITY_BACKGROUND) {
+            protected void onLooperPrepared() {
+                mHandler = new UsbHandler();
             }
-        }
-    }
-
-    private final void init() {
-        char[] buffer = new char[1024];
-        boolean inAccessoryMode = false;
-
-        // Read initial USB state
-        mConfiguration = -1;
-        try {
-            FileReader file = new FileReader(USB_CONNECTED_PATH);
-            int len = file.read(buffer, 0, 1024);
-            file.close();
-            mConnected = Integer.valueOf((new String(buffer, 0, len)).trim());
-
-            file = new FileReader(USB_CONFIGURATION_PATH);
-            len = file.read(buffer, 0, 1024);
-            file.close();
-            mConfiguration = Integer.valueOf((new String(buffer, 0, len)).trim());
-
-        } catch (FileNotFoundException e) {
-            Slog.i(TAG, "This kernel does not have USB configuration switch support");
-        } catch (Exception e) {
-            Slog.e(TAG, "" , e);
-        }
-        if (mConfiguration < 0) {
-            // This may happen in the emulator or devices without USB device mode support
-            return;
-        }
-
-        // Read initial list of enabled and disabled functions (device mode)
-        try {
-            File[] files = new File(USB_COMPOSITE_CLASS_PATH).listFiles();
-            for (int i = 0; i < files.length; i++) {
-                File file = new File(files[i], "enable");
-                FileReader reader = new FileReader(file);
-                int len = reader.read(buffer, 0, 1024);
-                reader.close();
-                int value = Integer.valueOf((new String(buffer, 0, len)).trim());
-                String functionName = files[i].getName();
-                if (value == 1) {
-                    mEnabledFunctions.add(functionName);
-                if (UsbManager.USB_FUNCTION_ACCESSORY.equals(functionName)) {
-                        // The USB accessory driver is on by default, but it might have been
-                        // enabled before the USB service has initialized.
-                        inAccessoryMode = true;
-                    } else if (!UsbManager.USB_FUNCTION_ADB.equals(functionName)) {
-                        // adb is enabled/disabled automatically by the adbd daemon,
-                        // so don't treat it as a default function.
-                        mDefaultFunctions.add(functionName);
-                    }
-                }
-            }
-        } catch (FileNotFoundException e) {
-            Slog.w(TAG, "This kernel does not have USB composite class support");
-        } catch (Exception e) {
-            Slog.e(TAG, "" , e);
-        }
-
-        // handle the case where an accessory switched the driver to accessory mode
-        // before the framework finished booting
-        if (inAccessoryMode) {
-            readCurrentAccessoryLocked();
-
-            // FIXME - if we booted in accessory mode, then we have no way to figure out
-            // which functions are enabled by default.
-            // For now, assume that MTP or mass storage are the only possibilities
-            if (!mEnabledFunctions.contains(UsbManager.USB_FUNCTION_MTP)) {
-                mDefaultFunctions.add(UsbManager.USB_FUNCTION_MTP);
-            } else if (!mEnabledFunctions.contains(UsbManager.USB_FUNCTION_MASS_STORAGE)) {
-                mDefaultFunctions.add(UsbManager.USB_FUNCTION_MASS_STORAGE);
-            }
-        }
+        };
+        thread.start();
     }
 
     public void systemReady() {
-        synchronized (mLock) {
-                mNotificationManager = (NotificationManager)
-                        mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+        mSystemReady = true;
 
-            update(false);
-            if (mCurrentAccessory != null) {
-                Log.d(TAG, "accessoryAttached at systemReady");
-                // its still too early to handle accessories, so add a BOOT_COMPLETED receiver
-                // to handle this later.
-                mContext.registerReceiver(mBootCompletedReceiver,
-                        new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
-            }
-            mSystemReady = true;
+        mNotificationManager = (NotificationManager)
+                mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+
+        // We do not show the USB notification if the primary volume supports mass storage.
+        // The legacy mass storage UI will be used instead.
+        boolean massStorageSupported = false;
+        StorageManager storageManager = (StorageManager)
+                mContext.getSystemService(Context.STORAGE_SERVICE);
+        StorageVolume[] volumes = storageManager.getVolumeList();
+        if (volumes.length > 0) {
+            massStorageSupported = volumes[0].allowMassStorage();
         }
+        mUseUsbNotification = !massStorageSupported;
+
+        // make sure the ADB_ENABLED setting value matches the current state
+        Settings.Secure.putInt(mContentResolver, Settings.Secure.ADB_ENABLED, mAdbEnabled ? 1 : 0);
+
+        mHandler.sendEmptyMessage(MSG_SYSTEM_READY);
     }
 
-    /*
-     * Sends a message to update the USB connected and configured state (device mode).
-     * If delayed is true, then we add a small delay in sending the message to debounce
-     * the USB connection when enabling USB tethering.
-     */
-    private final void update(boolean delayed) {
-        mHandler.removeMessages(MSG_UPDATE_STATE);
-        mHandler.sendEmptyMessageDelayed(MSG_UPDATE_STATE, delayed ? UPDATE_DELAY : 0);
-    }
-
-    /* returns the currently attached USB accessory (device mode) */
-    public UsbAccessory getCurrentAccessory() {
-        return mCurrentAccessory;
-    }
-
-    /* opens the currently attached USB accessory (device mode) */
-    public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
-        synchronized (mLock) {
-            if (mCurrentAccessory == null) {
-                throw new IllegalArgumentException("no accessory attached");
+     private static String addFunction(String functions, String function) {
+        if (!containsFunction(functions, function)) {
+            if (functions.length() > 0) {
+                functions += ",";
             }
-            if (!mCurrentAccessory.equals(accessory)) {
-                Log.e(TAG, accessory.toString() + " does not match current accessory "
-                        + mCurrentAccessory);
-                throw new IllegalArgumentException("accessory not attached");
-            }
-            mSettingsManager.checkPermission(mCurrentAccessory);
-            return nativeOpenAccessory();
+            functions += function;
         }
+        return functions;
     }
 
-    /*
-     * This handler is for deferred handling of events related to device mode and accessories.
-     */
-    private final Handler mHandler = new Handler() {
+    private static String removeFunction(String functions, String function) {
+        String[] split = functions.split(",");
+        for (int i = 0; i < split.length; i++) {
+            if (function.equals(split[i])) {
+                split[i] = null;
+            }
+        }
+        StringBuilder builder = new StringBuilder();
+         for (int i = 0; i < split.length; i++) {
+            String s = split[i];
+            if (s != null) {
+                if (builder.length() > 0) {
+                    builder.append(",");
+                }
+                builder.append(s);
+            }
+        }
+        return builder.toString();
+    }
 
-        @Override
-        public void handleMessage(Message msg) {
-            synchronized (mLock) {
-                switch (msg.what) {
-                    case MSG_UPDATE_STATE:
-                        if (mConnected != mLastConnected || mConfiguration != mLastConfiguration) {
-                            updateAdbNotification();
-                            if (mConnected == 0) {
-                                if (UsbManager.isFunctionEnabled(
-                                            UsbManager.USB_FUNCTION_ACCESSORY)) {
-                                    // make sure accessory mode is off, and restore default functions
-                                    Log.d(TAG, "exited USB accessory mode");
-                                    if (!UsbManager.setFunctionEnabled
-                                            (UsbManager.USB_FUNCTION_ACCESSORY, false)) {
-                                        Log.e(TAG, "could not disable accessory function");
-                                    }
-                                    int count = mDefaultFunctions.size();
-                                    for (int i = 0; i < count; i++) {
-                                        String function = mDefaultFunctions.get(i);
-                                        if (!UsbManager.setFunctionEnabled(function, true)) {
-                                            Log.e(TAG, "could not reenable function " + function);
-                                        }
-                                    }
+    private static boolean containsFunction(String functions, String function) {
+        int index = functions.indexOf(function);
+        if (index < 0) return false;
+        if (index > 0 && functions.charAt(index - 1) != ',') return false;
+        int charAfter = index + function.length();
+        if (charAfter < functions.length() && functions.charAt(charAfter) != ',') return false;
+        return true;
+    }
 
-                                    if (mCurrentAccessory != null) {
-                                        mSettingsManager.accessoryDetached(mCurrentAccessory);
-                                        mCurrentAccessory = null;
-                                    }
-                                }
-                            }
+    private final class UsbHandler extends Handler {
 
-                            final ContentResolver cr = mContext.getContentResolver();
-                            if (Settings.Secure.getInt(cr,
-                                    Settings.Secure.DEVICE_PROVISIONED, 0) == 0) {
-                                Slog.i(TAG, "Device not provisioned, skipping USB broadcast");
-                                return;
-                            }
+        // current USB state
+        private boolean mConnected;
+        private boolean mConfigured;
+        private String mCurrentFunctions;
+        private String mDefaultFunctions;
+        private UsbAccessory mCurrentAccessory;
+        private boolean mDeferAccessoryAttached;
 
-                            mLastConnected = mConnected;
-                            mLastConfiguration = mConfiguration;
+        public UsbHandler() {
+            // Read initial USB state
+            try {
+                mCurrentFunctions = FileUtils.readTextFile(
+                        new File(FUNCTIONS_PATH), 0, null).trim();
+                mDefaultFunctions = mCurrentFunctions;
+                String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
+                updateState(state);
 
-                            // send a sticky broadcast containing current USB state
-                            Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
-                            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
-                            intent.putExtra(UsbManager.USB_CONNECTED, mConnected != 0);
-                            intent.putExtra(UsbManager.USB_CONFIGURATION, mConfiguration);
-                            for (int i = 0; i < mEnabledFunctions.size(); i++) {
-                                intent.putExtra(mEnabledFunctions.get(i), true);
-                            }
-                            mContext.sendStickyBroadcast(intent);
-                        }
-                        break;
-                    case MSG_FUNCTION_ENABLED:
-                    case MSG_FUNCTION_DISABLED:
-                        functionEnabledLocked((String)msg.obj, msg.what == MSG_FUNCTION_ENABLED);
-                        break;
+                mAdbEnabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB);
+
+                // Upgrade step for previous versions that used persist.service.adb.enable
+                String value = SystemProperties.get("persist.service.adb.enable", "");
+                if (value.length() > 0) {
+                    char enable = value.charAt(0);
+                    if (enable == '1') {
+                        setAdbEnabled(true);
+                    } else if (enable == '0') {
+                        setAdbEnabled(false);
+                    }
+                    SystemProperties.set("persist.service.adb.enable", "");
+                }
+
+                // register observer to listen for settings changes
+                mContentResolver.registerContentObserver(
+                        Settings.Secure.getUriFor(Settings.Secure.ADB_ENABLED),
+                                false, new AdbSettingsObserver());
+
+                // Watch for USB configuration changes
+                mUEventObserver.startObserving(USB_STATE_MATCH);
+                mUEventObserver.startObserving(ACCESSORY_START_MATCH);
+            } catch (Exception e) {
+                Slog.e(TAG, "Error initializing UsbHandler", e);
+            }
+        }
+
+        public void sendMessage(int what, boolean arg) {
+            removeMessages(what);
+            Message m = Message.obtain(this, what);
+            m.arg1 = (arg ? 1 : 0);
+            sendMessage(m);
+        }
+
+        public void sendMessage(int what, Object arg) {
+            removeMessages(what);
+            Message m = Message.obtain(this, what);
+            m.obj = arg;
+            sendMessage(m);
+        }
+
+        public void updateState(String state) {
+            int connected, configured;
+
+            if ("DISCONNECTED".equals(state)) {
+                connected = 0;
+                configured = 0;
+            } else if ("CONNECTED".equals(state)) {
+                connected = 1;
+                configured = 0;
+            } else if ("CONFIGURED".equals(state)) {
+                connected = 1;
+                configured = 1;
+            } else {
+                Slog.e(TAG, "unknown state " + state);
+                return;
+            }
+            removeMessages(MSG_UPDATE_STATE);
+            Message msg = Message.obtain(this, MSG_UPDATE_STATE);
+            msg.arg1 = connected;
+            msg.arg2 = configured;
+            // debounce disconnects to avoid problems bringing up USB tethering
+            sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0);
+        }
+
+        private boolean setUsbConfig(String config) {
+            // set the new configuration
+            SystemProperties.set("sys.usb.config", config);
+            // wait for the transition to complete.
+            // give up after 1 second.
+            for (int i = 0; i < 20; i++) {
+                // State transition is done when sys.usb.conf.done is set to the new configuration
+                if (config.equals(SystemProperties.get("sys.usb.state"))) return true;
+                try {
+                    // try again in 50ms
+                    Thread.sleep(50);
+                } catch (InterruptedException e) {
+                }
+            }
+            return false;
+        }
+
+        private void setCurrentFunctions(String functions) {
+            if (!mCurrentFunctions.equals(functions)) {
+                if (!setUsbConfig("none") || !setUsbConfig(functions)) {
+                    Log.e(TAG, "Failed to switch USB configuration to " + functions);
+                    // revert to previous configuration if we fail
+                    setUsbConfig(mCurrentFunctions);
+                } else {
+                    mCurrentFunctions = functions;
                 }
             }
         }
-    };
+
+        private void setAdbEnabled(boolean enable) {
+            if (enable != mAdbEnabled) {
+                mAdbEnabled = enable;
+                String functions;
+                if (enable) {
+                    functions = addFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB);
+                    mDefaultFunctions = addFunction(mDefaultFunctions,
+                            UsbManager.USB_FUNCTION_ADB);
+                } else {
+                    functions = removeFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB);
+                    mDefaultFunctions = removeFunction(mDefaultFunctions,
+                            UsbManager.USB_FUNCTION_ADB);
+                }
+                SystemProperties.set("persist.sys.usb.config", mDefaultFunctions);
+                setCurrentFunctions(functions);
+                updateAdbNotification(mAdbEnabled && mConnected);
+            }
+        }
+
+        private void setEnabledFunctions(String functionList) {
+            if (mAdbEnabled) {
+                functionList = addFunction(functionList, UsbManager.USB_FUNCTION_ADB);
+            } else {
+                functionList = removeFunction(functionList, UsbManager.USB_FUNCTION_ADB);
+            }
+            setCurrentFunctions(functionList);
+        }
+
+        private void updateCurrentAccessory() {
+            if (!mHasUsbAccessory) return;
+
+            if (mConfigured) {
+                String[] strings = nativeGetAccessoryStrings();
+                if (strings != null) {
+                    mCurrentAccessory = new UsbAccessory(strings);
+                    Log.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
+                    // defer accessoryAttached if system is not ready
+                    if (mSystemReady) {
+                        mSettingsManager.accessoryAttached(mCurrentAccessory);
+                    } else {
+                        mDeferAccessoryAttached = true;
+                    }
+                } else {
+                    Log.e(TAG, "nativeGetAccessoryStrings failed");
+                }
+            } else if (!mConnected) {
+                // make sure accessory mode is off
+                // and restore default functions
+                Log.d(TAG, "exited USB accessory mode");
+                setEnabledFunctions(mDefaultFunctions);
+
+                if (mCurrentAccessory != null) {
+                    if (mSystemReady) {
+                        mSettingsManager.accessoryDetached(mCurrentAccessory);
+                    }
+                    mCurrentAccessory = null;
+                }
+            }
+        }
+
+        private void updateUsbState() {
+            // send a sticky broadcast containing current USB state
+            Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
+            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+            intent.putExtra(UsbManager.USB_CONNECTED, mConnected);
+            intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured);
+
+            if (mCurrentFunctions != null) {
+                String[] functions = mCurrentFunctions.split(",");
+                for (int i = 0; i < functions.length; i++) {
+                    intent.putExtra(functions[i], true);
+                }
+            }
+
+            mContext.sendStickyBroadcast(intent);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            String function;
+
+            switch (msg.what) {
+                case MSG_UPDATE_STATE:
+                    mConnected = (msg.arg1 == 1);
+                    mConfigured = (msg.arg2 == 1);
+                    updateUsbNotification(mConnected);
+                    updateAdbNotification(mAdbEnabled && mConnected);
+                    if (containsFunction(mCurrentFunctions,
+                            UsbManager.USB_FUNCTION_ACCESSORY)) {
+                        updateCurrentAccessory();
+                    }
+
+                    if (!mConnected) {
+                        // restore defaults when USB is disconnected
+                        setCurrentFunctions(mDefaultFunctions);
+                    }
+                    if (mSystemReady) {
+                        updateUsbState();
+                    }
+                    break;
+                case MSG_ENABLE_ADB:
+                    setAdbEnabled(msg.arg1 == 1);
+                    break;
+                case MSG_SET_PRIMARY_FUNCTION:
+                    function = (String)msg.obj;
+                    if (function == null) {
+                        function = mDefaultFunctions;
+                    }
+                    setEnabledFunctions(function);
+                    break;
+                case MSG_SET_DEFAULT_FUNCTION:
+                    function = (String)msg.obj;
+                    if (mAdbEnabled) {
+                        function = addFunction(function, UsbManager.USB_FUNCTION_ADB);
+                    }
+                    SystemProperties.set("persist.sys.usb.config", function);
+                    mDefaultFunctions = function;
+                    break;
+                case MSG_SYSTEM_READY:
+                    updateUsbNotification(mConnected);
+                    updateAdbNotification(mAdbEnabled && mConnected);
+                    updateUsbState();
+                    if (mCurrentAccessory != null && mDeferAccessoryAttached) {
+                        mSettingsManager.accessoryAttached(mCurrentAccessory);
+                    }
+                    break;
+            }
+        }
+
+        public UsbAccessory getCurrentAccessory() {
+            return mCurrentAccessory;
+        }
+
+        public void dump(FileDescriptor fd, PrintWriter pw) {
+            pw.println("  USB Device State:");
+            pw.println("    Current Functions: " + mCurrentFunctions);
+            pw.println("    Default Functions: " + mDefaultFunctions);
+            pw.println("    mConnected: " + mConnected);
+            pw.println("    mConfigured: " + mConfigured);
+            pw.println("    mCurrentAccessory: " + mCurrentAccessory);
+        }
+    }
+
+    /* returns the currently attached USB accessory */
+    public UsbAccessory getCurrentAccessory() {
+        return mHandler.getCurrentAccessory();
+    }
+
+    /* opens the currently attached USB accessory */
+        public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
+            UsbAccessory currentAccessory = mHandler.getCurrentAccessory();
+            if (currentAccessory == null) {
+                throw new IllegalArgumentException("no accessory attached");
+            }
+            if (!currentAccessory.equals(accessory)) {
+                String error = accessory.toString()
+                        + " does not match current accessory "
+                        + currentAccessory;
+                throw new IllegalArgumentException(error);
+            }
+            mSettingsManager.checkPermission(accessory);
+            return nativeOpenAccessory();
+        }
+
+    public void setPrimaryFunction(String function) {
+        mHandler.sendMessage(MSG_SET_PRIMARY_FUNCTION, function);
+    }
+
+    public void setDefaultFunction(String function) {
+        if (function == null) {
+            throw new NullPointerException();
+        }
+        mHandler.sendMessage(MSG_SET_DEFAULT_FUNCTION, function);
+    }
+
+    public void setMassStorageBackingFile(String path) {
+        if (path == null) path = "";
+        try {
+            FileUtils.stringToFile(MASS_STORAGE_FILE_PATH, path);
+        } catch (IOException e) {
+           Slog.e(TAG, "failed to write to " + MASS_STORAGE_FILE_PATH);
+        }
+    }
 
     public void dump(FileDescriptor fd, PrintWriter pw) {
-        synchronized (mLock) {
-            pw.println("  USB Device State:");
-            pw.print("    Enabled Functions: ");
-            for (int i = 0; i < mEnabledFunctions.size(); i++) {
-                pw.print(mEnabledFunctions.get(i) + " ");
-            }
-            pw.println("");
-            pw.print("    Default Functions: ");
-            for (int i = 0; i < mDefaultFunctions.size(); i++) {
-                pw.print(mDefaultFunctions.get(i) + " ");
-            }
-            pw.println("");
-            pw.println("    mConnected: " + mConnected + ", mConfiguration: " + mConfiguration);
-            pw.println("    mCurrentAccessory: " + mCurrentAccessory);
+        if (mHandler != null) {
+            mHandler.dump(fd, pw);
         }
     }
 
diff --git a/services/java/com/android/server/usb/UsbService.java b/services/java/com/android/server/usb/UsbService.java
index 21e5997c..193638f 100644
--- a/services/java/com/android/server/usb/UsbService.java
+++ b/services/java/com/android/server/usb/UsbService.java
@@ -50,7 +50,7 @@
         if (pm.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
             mHostManager = new UsbHostManager(context, mSettingsManager);
         }
-        if (new File("/sys/class/usb_composite").exists()) {
+        if (new File("/sys/class/android_usb").exists()) {
             mDeviceManager = new UsbDeviceManager(context, mSettingsManager);
         }
     }
@@ -92,7 +92,7 @@
     /* opens the currently attached USB accessory (device mode) */
     public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
         if (mDeviceManager != null) {
-            return openAccessory(accessory);
+            return mDeviceManager.openAccessory(accessory);
         } else {
             return null;
         }
@@ -146,6 +146,33 @@
         mSettingsManager.clearDefaults(packageName);
     }
 
+    public void setPrimaryFunction(String function) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+        if (mDeviceManager != null) {
+            mDeviceManager.setPrimaryFunction(function);
+        } else {
+            throw new IllegalStateException("USB device mode not supported");
+        }
+    }
+
+    public void setDefaultFunction(String function) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+        if (mDeviceManager != null) {
+            mDeviceManager.setDefaultFunction(function);
+        } else {
+            throw new IllegalStateException("USB device mode not supported");
+        }
+    }
+
+    public void setMassStorageBackingFile(String path) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+        if (mDeviceManager != null) {
+            mDeviceManager.setMassStorageBackingFile(path);
+        } else {
+            throw new IllegalStateException("USB device mode not supported");
+        }
+    }
+
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
diff --git a/services/jni/com_android_server_connectivity_Vpn.cpp b/services/jni/com_android_server_connectivity_Vpn.cpp
index 206df25..ae7fbfe 100644
--- a/services/jni/com_android_server_connectivity_Vpn.cpp
+++ b/services/jni/com_android_server_connectivity_Vpn.cpp
@@ -55,6 +55,7 @@
 {
     int tun = open("/dev/tun", O_RDWR);
     int inet4 = socket(AF_INET, SOCK_DGRAM, 0);
+    int flags;
 
     ifreq ifr4;
     memset(&ifr4, 0, sizeof(ifr4));
@@ -86,6 +87,13 @@
         goto error;
     }
 
+    // Make it non-blocking.
+    flags = fcntl(tun, F_GETFL, 0);
+    if (flags == -1 || fcntl(tun, F_SETFL, flags | O_NONBLOCK)) {
+        LOGE("Cannot set non-blocking on %s: %s", ifr4.ifr_name, strerror(errno));
+        goto error;
+    }
+
     strcpy(name, ifr4.ifr_name);
     *index = ifr4.ifr_ifindex;
     close(inet4);
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 151fde7..ee5f3f5 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -28,6 +28,7 @@
     <uses-permission android:name="android.permission.MANAGE_APP_TOKENS" />
     <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
     <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
+    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 476aded..07e5425 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -16,22 +16,29 @@
 
 package com.android.server;
 
+import static android.content.Intent.ACTION_UID_REMOVED;
+import static android.content.Intent.EXTRA_UID;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
 import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.NetworkPolicyManager.POLICY_NONE;
-import static android.net.NetworkPolicyManager.POLICY_REJECT_PAID_BACKGROUND;
+import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
-import static android.net.NetworkPolicyManager.RULE_REJECT_PAID;
+import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
 import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
+import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
-import static android.net.TrafficStats.TEMPLATE_WIFI;
+import static android.net.NetworkTemplate.MATCH_WIFI;
+import static org.easymock.EasyMock.anyInt;
+import static org.easymock.EasyMock.aryEq;
 import static org.easymock.EasyMock.capture;
 import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.eq;
 import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.isA;
 
 import android.app.IActivityManager;
+import android.app.INotificationManager;
 import android.app.IProcessObserver;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -45,6 +52,7 @@
 import android.net.NetworkPolicy;
 import android.net.NetworkState;
 import android.net.NetworkStats;
+import android.net.NetworkTemplate;
 import android.os.Binder;
 import android.os.IPowerManager;
 import android.test.AndroidTestCase;
@@ -72,6 +80,8 @@
     private static final long TEST_START = 1194220800000L;
     private static final String TEST_IFACE = "test0";
 
+    private static NetworkTemplate sTemplateWifi = new NetworkTemplate(MATCH_WIFI, null);
+
     private BroadcastInterceptingContext mServiceContext;
     private File mPolicyDir;
 
@@ -81,14 +91,15 @@
     private INetworkPolicyListener mPolicyListener;
     private TrustedTime mTime;
     private IConnectivityManager mConnManager;
+    private INotificationManager mNotifManager;
 
     private NetworkPolicyManagerService mService;
     private IProcessObserver mProcessObserver;
 
     private Binder mStubBinder = new Binder();
 
-    private static final int UID_A = 800;
-    private static final int UID_B = 801;
+    private static final int UID_A = android.os.Process.FIRST_APPLICATION_UID + 800;
+    private static final int UID_B = android.os.Process.FIRST_APPLICATION_UID + 801;
 
     private static final int PID_1 = 400;
     private static final int PID_2 = 401;
@@ -119,10 +130,12 @@
         mPolicyListener = createMock(INetworkPolicyListener.class);
         mTime = createMock(TrustedTime.class);
         mConnManager = createMock(IConnectivityManager.class);
+        mNotifManager = createMock(INotificationManager.class);
 
         mService = new NetworkPolicyManagerService(
                 mServiceContext, mActivityManager, mPowerManager, mStatsService, mTime, mPolicyDir);
         mService.bindConnectivityManager(mConnManager);
+        mService.bindNotificationManager(mNotifManager);
 
         // RemoteCallbackList needs a binder to use as key
         expect(mPolicyListener.asBinder()).andReturn(mStubBinder).atLeastOnce();
@@ -137,6 +150,7 @@
 
         // expect to answer screen status during systemReady()
         expect(mPowerManager.isScreenOn()).andReturn(true).atLeastOnce();
+        expectTime(System.currentTimeMillis());
 
         replay();
         mService.systemReady();
@@ -175,7 +189,7 @@
         final Future<Intent> backgroundChanged = mServiceContext.nextBroadcastIntent(
                 ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
 
-        mService.setUidPolicy(UID_A, POLICY_REJECT_PAID_BACKGROUND);
+        mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
 
         backgroundChanged.get();
     }
@@ -218,12 +232,12 @@
         expectRulesChanged(UID_A, RULE_ALLOW_ALL);
         replay();
         mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true);
-        mService.setUidPolicy(UID_A, POLICY_REJECT_PAID_BACKGROUND);
+        mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
         verifyAndReset();
 
         // now turn screen off and verify REJECT rule
         expect(mPowerManager.isScreenOn()).andReturn(false).atLeastOnce();
-        expectRulesChanged(UID_A, RULE_REJECT_PAID);
+        expectRulesChanged(UID_A, RULE_REJECT_METERED);
         replay();
         mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SCREEN_OFF));
         verifyAndReset();
@@ -253,9 +267,9 @@
 
     public void testPolicyReject() throws Exception {
         // POLICY_REJECT should RULE_ALLOW in background
-        expectRulesChanged(UID_A, RULE_REJECT_PAID);
+        expectRulesChanged(UID_A, RULE_REJECT_METERED);
         replay();
-        mService.setUidPolicy(UID_A, POLICY_REJECT_PAID_BACKGROUND);
+        mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
         verifyAndReset();
 
         // POLICY_REJECT should RULE_ALLOW in foreground
@@ -265,7 +279,7 @@
         verifyAndReset();
 
         // POLICY_REJECT should RULE_REJECT in background
-        expectRulesChanged(UID_A, RULE_REJECT_PAID);
+        expectRulesChanged(UID_A, RULE_REJECT_METERED);
         replay();
         mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
         verifyAndReset();
@@ -280,9 +294,9 @@
         verifyAndReset();
 
         // adding POLICY_REJECT should cause RULE_REJECT
-        expectRulesChanged(UID_A, RULE_REJECT_PAID);
+        expectRulesChanged(UID_A, RULE_REJECT_METERED);
         replay();
-        mService.setUidPolicy(UID_A, POLICY_REJECT_PAID_BACKGROUND);
+        mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
         verifyAndReset();
 
         // removing POLICY_REJECT should return us to RULE_ALLOW
@@ -297,7 +311,7 @@
         final long currentTime = parseTime("2007-11-14T00:00:00.000Z");
         final long expectedCycle = parseTime("2007-11-05T00:00:00.000Z");
 
-        final NetworkPolicy policy = new NetworkPolicy(TEMPLATE_WIFI, null, 5, 1024L, 1024L);
+        final NetworkPolicy policy = new NetworkPolicy(sTemplateWifi, 5, 1024L, 1024L);
         final long actualCycle = computeLastCycleBoundary(currentTime, policy);
         assertEquals(expectedCycle, actualCycle);
     }
@@ -307,7 +321,7 @@
         final long currentTime = parseTime("2007-11-14T00:00:00.000Z");
         final long expectedCycle = parseTime("2007-10-20T00:00:00.000Z");
 
-        final NetworkPolicy policy = new NetworkPolicy(TEMPLATE_WIFI, null, 20, 1024L, 1024L);
+        final NetworkPolicy policy = new NetworkPolicy(sTemplateWifi, 20, 1024L, 1024L);
         final long actualCycle = computeLastCycleBoundary(currentTime, policy);
         assertEquals(expectedCycle, actualCycle);
     }
@@ -317,7 +331,7 @@
         final long currentTime = parseTime("2007-02-14T00:00:00.000Z");
         final long expectedCycle = parseTime("2007-01-30T00:00:00.000Z");
 
-        final NetworkPolicy policy = new NetworkPolicy(TEMPLATE_WIFI, null, 30, 1024L, 1024L);
+        final NetworkPolicy policy = new NetworkPolicy(sTemplateWifi, 30, 1024L, 1024L);
         final long actualCycle = computeLastCycleBoundary(currentTime, policy);
         assertEquals(expectedCycle, actualCycle);
     }
@@ -327,7 +341,7 @@
         final long currentTime = parseTime("2007-03-14T00:00:00.000Z");
         final long expectedCycle = parseTime("2007-03-01T00:00:00.000Z");
 
-        final NetworkPolicy policy = new NetworkPolicy(TEMPLATE_WIFI, null, 30, 1024L, 1024L);
+        final NetworkPolicy policy = new NetworkPolicy(sTemplateWifi, 30, 1024L, 1024L);
         final long actualCycle = computeLastCycleBoundary(currentTime, policy);
         assertEquals(expectedCycle, actualCycle);
     }
@@ -346,6 +360,7 @@
         state = new NetworkState[] { buildWifi() };
         expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
         expectTime(TIME_MAR_10 + elapsedRealtime);
+        expectMeteredIfacesChanged();
 
         replay();
         mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
@@ -358,15 +373,34 @@
 
         // pretend that 512 bytes total have happened
         stats = new NetworkStats(elapsedRealtime, 1)
-                .addEntry(TEST_IFACE, UID_ALL, 256L, 256L);
-        expect(mStatsService.getSummaryForNetwork(TIME_FEB_15, TIME_MAR_10, TEMPLATE_WIFI, null))
+                .addEntry(TEST_IFACE, UID_ALL, TAG_NONE, 256L, 256L);
+        expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, TIME_MAR_10))
                 .andReturn(stats).atLeastOnce();
 
         // expect that quota remaining should be 1536 bytes
         // TODO: write up NetworkManagementService mock
 
+        expectClearNotifications();
+        expectMeteredIfacesChanged(TEST_IFACE);
+
         replay();
-        setNetworkPolicies(new NetworkPolicy(TEMPLATE_WIFI, null, CYCLE_DAY, 1024L, 2048L));
+        setNetworkPolicies(new NetworkPolicy(sTemplateWifi, CYCLE_DAY, 1024L, 2048L));
+        verifyAndReset();
+    }
+
+    public void testUidRemovedPolicyCleared() throws Exception {
+        // POLICY_REJECT should RULE_REJECT in background
+        expectRulesChanged(UID_A, RULE_REJECT_METERED);
+        replay();
+        mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
+        verifyAndReset();
+
+        // uninstall should clear RULE_REJECT
+        expectRulesChanged(UID_A, RULE_ALLOW_ALL);
+        replay();
+        final Intent intent = new Intent(ACTION_UID_REMOVED);
+        intent.putExtra(EXTRA_UID, UID_A);
+        mServiceContext.sendBroadcast(intent);
         verifyAndReset();
     }
 
@@ -388,7 +422,7 @@
         return new NetworkState(info, prop, null);
     }
 
-    public void expectTime(long currentTime) throws Exception {
+    private void expectTime(long currentTime) throws Exception {
         expect(mTime.forceRefresh()).andReturn(false).anyTimes();
         expect(mTime.hasCache()).andReturn(true).anyTimes();
         expect(mTime.currentTimeMillis()).andReturn(currentTime).anyTimes();
@@ -396,20 +430,30 @@
         expect(mTime.getCacheCertainty()).andReturn(0L).anyTimes();
     }
 
+    private void expectClearNotifications() throws Exception {
+        mNotifManager.cancelNotificationWithTag(isA(String.class), isA(String.class), anyInt());
+        expectLastCall().anyTimes();
+    }
+
     private void expectRulesChanged(int uid, int policy) throws Exception {
-        mPolicyListener.onRulesChanged(eq(uid), eq(policy));
+        mPolicyListener.onUidRulesChanged(eq(uid), eq(policy));
+        expectLastCall().atLeastOnce();
+    }
+
+    private void expectMeteredIfacesChanged(String... ifaces) throws Exception {
+        mPolicyListener.onMeteredIfacesChanged(aryEq(ifaces));
         expectLastCall().atLeastOnce();
     }
 
     private void replay() {
         EasyMock.replay(mActivityManager, mPowerManager, mStatsService, mPolicyListener, mTime,
-                mConnManager);
+                mConnManager, mNotifManager);
     }
 
     private void verifyAndReset() {
         EasyMock.verify(mActivityManager, mPowerManager, mStatsService, mPolicyListener, mTime,
-                mConnManager);
+                mConnManager, mNotifManager);
         EasyMock.reset(mActivityManager, mPowerManager, mStatsService, mPolicyListener, mTime,
-                mConnManager);
+                mConnManager, mNotifManager);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index 2457ff3..636d059 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
@@ -16,16 +16,26 @@
 
 package com.android.server;
 
+import static android.content.Intent.ACTION_UID_REMOVED;
+import static android.content.Intent.EXTRA_UID;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
+import static android.net.ConnectivityManager.TYPE_MOBILE;
 import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.ConnectivityManager.TYPE_WIMAX;
 import static android.net.NetworkStats.IFACE_ALL;
+import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
-import static android.net.TrafficStats.TEMPLATE_WIFI;
+import static android.net.NetworkTemplate.MATCH_MOBILE_ALL;
+import static android.net.NetworkTemplate.MATCH_WIFI;
+import static android.net.TrafficStats.UID_REMOVED;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
 import static android.text.format.DateUtils.WEEK_IN_MILLIS;
 import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL;
+import static com.android.server.net.NetworkStatsService.packUidAndTag;
+import static com.android.server.net.NetworkStatsService.unpackTag;
+import static com.android.server.net.NetworkStatsService.unpackUid;
 import static org.easymock.EasyMock.anyLong;
 import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.eq;
@@ -44,9 +54,12 @@
 import android.net.NetworkState;
 import android.net.NetworkStats;
 import android.net.NetworkStatsHistory;
+import android.net.NetworkTemplate;
 import android.os.INetworkManagementService;
+import android.telephony.TelephonyManager;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
 import android.util.TrustedTime;
 
 import com.android.server.net.NetworkStatsService;
@@ -66,8 +79,16 @@
     private static final String TEST_IFACE = "test0";
     private static final long TEST_START = 1194220800000L;
 
-    private static final int TEST_UID_1 = 1001;
-    private static final int TEST_UID_2 = 1002;
+    private static final String IMSI_1 = "310004";
+    private static final String IMSI_2 = "310260";
+
+    private static NetworkTemplate sTemplateWifi = new NetworkTemplate(MATCH_WIFI, null);
+    private static NetworkTemplate sTemplateImsi1 = new NetworkTemplate(MATCH_MOBILE_ALL, IMSI_1);
+    private static NetworkTemplate sTemplateImsi2 = new NetworkTemplate(MATCH_MOBILE_ALL, IMSI_2);
+
+    private static final int UID_RED = 1001;
+    private static final int UID_BLUE = 1002;
+    private static final int UID_GREEN = 1003;
 
     private BroadcastInterceptingContext mServiceContext;
     private File mStatsDir;
@@ -118,13 +139,15 @@
         mNetManager = null;
         mAlarmManager = null;
         mTime = null;
+        mSettings = null;
+        mConnManager = null;
 
         mService = null;
 
         super.tearDown();
     }
 
-    public void testSummaryStatsWifi() throws Exception {
+    public void testNetworkStatsWifi() throws Exception {
         long elapsedRealtime = 0;
 
         // pretend that wifi network comes online; service should ask about full
@@ -138,7 +161,7 @@
         mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
 
         // verify service has empty history for wifi
-        assertNetworkTotal(TEMPLATE_WIFI, 0L, 0L);
+        assertNetworkTotal(sTemplateWifi, 0L, 0L);
         verifyAndReset();
 
         // modify some number on wifi, and trigger poll event
@@ -146,14 +169,14 @@
         expectTime(TEST_START + elapsedRealtime);
         expectDefaultSettings();
         expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1)
-                .addEntry(TEST_IFACE, UID_ALL, 1024L, 2048L));
+                .addEntry(TEST_IFACE, UID_ALL, TAG_NONE, 1024L, 2048L));
         expectNetworkStatsDetail(buildEmptyStats(elapsedRealtime));
 
         replay();
         mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
 
         // verify service recorded history
-        assertNetworkTotal(TEMPLATE_WIFI, 1024L, 2048L);
+        assertNetworkTotal(sTemplateWifi, 1024L, 2048L);
         verifyAndReset();
 
         // and bump forward again, with counters going higher. this is
@@ -162,14 +185,14 @@
         expectTime(TEST_START + elapsedRealtime);
         expectDefaultSettings();
         expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1)
-                .addEntry(TEST_IFACE, UID_ALL, 4096L, 8192L));
+                .addEntry(TEST_IFACE, UID_ALL, TAG_NONE, 4096L, 8192L));
         expectNetworkStatsDetail(buildEmptyStats(elapsedRealtime));
 
         replay();
         mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
 
         // verify service recorded history
-        assertNetworkTotal(TEMPLATE_WIFI, 4096L, 8192L);
+        assertNetworkTotal(sTemplateWifi, 4096L, 8192L);
         verifyAndReset();
 
     }
@@ -189,7 +212,7 @@
         mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
 
         // verify service has empty history for wifi
-        assertNetworkTotal(TEMPLATE_WIFI, 0L, 0L);
+        assertNetworkTotal(sTemplateWifi, 0L, 0L);
         verifyAndReset();
 
         // modify some number on wifi, and trigger poll event
@@ -197,19 +220,18 @@
         expectTime(TEST_START + elapsedRealtime);
         expectDefaultSettings();
         expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1)
-                .addEntry(TEST_IFACE, UID_ALL, 1024L, 2048L));
-        // TODO: switch these stats to specific iface
+                .addEntry(TEST_IFACE, UID_ALL, TAG_NONE, 1024L, 2048L));
         expectNetworkStatsDetail(new NetworkStats(elapsedRealtime, 2)
-                .addEntry(IFACE_ALL, TEST_UID_1, 512L, 256L)
-                .addEntry(IFACE_ALL, TEST_UID_2, 128L, 128L));
+                .addEntry(TEST_IFACE, UID_RED, TAG_NONE, 512L, 256L)
+                .addEntry(TEST_IFACE, UID_BLUE, TAG_NONE, 128L, 128L));
 
         replay();
         mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
 
         // verify service recorded history
-        assertNetworkTotal(TEMPLATE_WIFI, 1024L, 2048L);
-        assertUidTotal(TEST_UID_1, TEMPLATE_WIFI, 512L, 256L);
-        assertUidTotal(TEST_UID_2, TEMPLATE_WIFI, 128L, 128L);
+        assertNetworkTotal(sTemplateWifi, 1024L, 2048L);
+        assertUidTotal(sTemplateWifi, UID_RED, 512L, 256L);
+        assertUidTotal(sTemplateWifi, UID_BLUE, 128L, 128L);
         verifyAndReset();
 
         // graceful shutdown system, which should trigger persist of stats, and
@@ -220,7 +242,7 @@
         // we persisted them to file.
         expectDefaultSettings();
         replay();
-        assertNetworkTotal(TEMPLATE_WIFI, 0L, 0L);
+        assertNetworkTotal(sTemplateWifi, 0L, 0L);
         verifyAndReset();
 
         assertStatsFilesExist(true);
@@ -233,9 +255,9 @@
         mService.systemReady();
 
         // after systemReady(), we should have historical stats loaded again
-        assertNetworkTotal(TEMPLATE_WIFI, 1024L, 2048L);
-        assertUidTotal(TEST_UID_1, TEMPLATE_WIFI, 512L, 256L);
-        assertUidTotal(TEST_UID_2, TEMPLATE_WIFI, 128L, 128L);
+        assertNetworkTotal(sTemplateWifi, 1024L, 2048L);
+        assertUidTotal(sTemplateWifi, UID_RED, 512L, 256L);
+        assertUidTotal(sTemplateWifi, UID_BLUE, 128L, 128L);
         verifyAndReset();
 
     }
@@ -263,14 +285,14 @@
         expectTime(TEST_START + elapsedRealtime);
         expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS);
         expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1)
-                .addEntry(TEST_IFACE, UID_ALL, 512L, 512L));
+                .addEntry(TEST_IFACE, UID_ALL, TAG_NONE, 512L, 512L));
         expectNetworkStatsDetail(buildEmptyStats(elapsedRealtime));
 
         replay();
         mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
 
         // verify service recorded history
-        history = mService.getHistoryForNetwork(TEMPLATE_WIFI);
+        history = mService.getHistoryForNetwork(new NetworkTemplate(MATCH_WIFI, null));
         total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null);
         assertEquals(512L, total[0]);
         assertEquals(512L, total[1]);
@@ -289,7 +311,7 @@
         mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
 
         // verify identical stats, but spread across 4 buckets now
-        history = mService.getHistoryForNetwork(TEMPLATE_WIFI);
+        history = mService.getHistoryForNetwork(new NetworkTemplate(MATCH_WIFI, null));
         total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null);
         assertEquals(512L, total[0]);
         assertEquals(512L, total[1]);
@@ -299,15 +321,284 @@
 
     }
 
-    private void assertNetworkTotal(int template, long rx, long tx) {
+    public void testUidStatsAcrossNetworks() throws Exception {
+        long elapsedRealtime = 0;
+
+        // pretend first mobile network comes online
+        expectTime(TEST_START + elapsedRealtime);
+        expectDefaultSettings();
+        expectNetworkState(buildMobile3gState(IMSI_1));
+        expectNetworkStatsSummary(buildEmptyStats(elapsedRealtime));
+
+        replay();
+        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
+        verifyAndReset();
+
+        // create some traffic on first network
+        elapsedRealtime += HOUR_IN_MILLIS;
+        expectTime(TEST_START + elapsedRealtime);
+        expectDefaultSettings();
+        expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1)
+                .addEntry(TEST_IFACE, UID_ALL, TAG_NONE, 2048L, 512L));
+        expectNetworkStatsDetail(new NetworkStats(elapsedRealtime, 3)
+                .addEntry(TEST_IFACE, UID_RED, TAG_NONE, 1536L, 512L)
+                .addEntry(TEST_IFACE, UID_RED, 0xF00D, 512L, 512L)
+                .addEntry(TEST_IFACE, UID_BLUE, TAG_NONE, 512L, 0L));
+
+        replay();
+        mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+
+        // verify service recorded history
+        assertNetworkTotal(sTemplateImsi1, 2048L, 512L);
+        assertNetworkTotal(sTemplateWifi, 0L, 0L);
+        assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 512L);
+        assertUidTotal(sTemplateImsi1, UID_BLUE, 512L, 0L);
+        verifyAndReset();
+
+        // now switch networks; this also tests that we're okay with interfaces
+        // disappearing, to verify we don't count backwards.
+        elapsedRealtime += HOUR_IN_MILLIS;
+        expectTime(TEST_START + elapsedRealtime);
+        expectDefaultSettings();
+        expectNetworkState(buildMobile3gState(IMSI_2));
+        expectNetworkStatsSummary(buildEmptyStats(elapsedRealtime));
+        expectNetworkStatsDetail(buildEmptyStats(elapsedRealtime));
+
+        replay();
+        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
+        mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+        verifyAndReset();
+
+        // create traffic on second network
+        elapsedRealtime += HOUR_IN_MILLIS;
+        expectTime(TEST_START + elapsedRealtime);
+        expectDefaultSettings();
+        expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1)
+                .addEntry(TEST_IFACE, UID_ALL, TAG_NONE, 128L, 1024L));
+        expectNetworkStatsDetail(new NetworkStats(elapsedRealtime, 1)
+                .addEntry(TEST_IFACE, UID_BLUE, TAG_NONE, 128L, 1024L));
+
+        replay();
+        mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+
+        // verify original history still intact
+        assertNetworkTotal(sTemplateImsi1, 2048L, 512L);
+        assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 512L);
+        assertUidTotal(sTemplateImsi1, UID_BLUE, 512L, 0L);
+
+        // and verify new history also recorded under different template, which
+        // verifies that we didn't cross the streams.
+        assertNetworkTotal(sTemplateImsi2, 128L, 1024L);
+        assertNetworkTotal(sTemplateWifi, 0L, 0L);
+        assertUidTotal(sTemplateImsi2, UID_BLUE, 128L, 1024L);
+        verifyAndReset();
+
+    }
+
+    public void testUidRemovedIsMoved() throws Exception {
+        long elapsedRealtime = 0;
+
+        // pretend that network comes online
+        expectTime(TEST_START + elapsedRealtime);
+        expectDefaultSettings();
+        expectNetworkState(buildWifiState());
+        expectNetworkStatsSummary(buildEmptyStats(elapsedRealtime));
+
+        replay();
+        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
+        verifyAndReset();
+
+        // create some traffic
+        elapsedRealtime += HOUR_IN_MILLIS;
+        expectTime(TEST_START + elapsedRealtime);
+        expectDefaultSettings();
+        expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1)
+                .addEntry(TEST_IFACE, UID_ALL, TAG_NONE, 4128L, 544L));
+        expectNetworkStatsDetail(new NetworkStats(elapsedRealtime, 1)
+                .addEntry(TEST_IFACE, UID_RED, TAG_NONE, 16L, 16L)
+                .addEntry(TEST_IFACE, UID_BLUE, TAG_NONE, 4096L, 512L)
+                .addEntry(TEST_IFACE, UID_GREEN, TAG_NONE, 16L, 16L));
+
+        replay();
+        mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+
+        // verify service recorded history
+        assertNetworkTotal(sTemplateWifi, 4128L, 544L);
+        assertUidTotal(sTemplateWifi, UID_RED, 16L, 16L);
+        assertUidTotal(sTemplateWifi, UID_BLUE, 4096L, 512L);
+        assertUidTotal(sTemplateWifi, UID_GREEN, 16L, 16L);
+        verifyAndReset();
+
+        // now pretend two UIDs are uninstalled, which should migrate stats to
+        // special "removed" bucket.
+        expectDefaultSettings();
+        replay();
+        final Intent intent = new Intent(ACTION_UID_REMOVED);
+        intent.putExtra(EXTRA_UID, UID_BLUE);
+        mServiceContext.sendBroadcast(intent);
+        intent.putExtra(EXTRA_UID, UID_RED);
+        mServiceContext.sendBroadcast(intent);
+
+        // existing uid and total should remain unchanged; but removed UID
+        // should be gone completely.
+        assertNetworkTotal(sTemplateWifi, 4128L, 544L);
+        assertUidTotal(sTemplateWifi, UID_RED, 0L, 0L);
+        assertUidTotal(sTemplateWifi, UID_BLUE, 0L, 0L);
+        assertUidTotal(sTemplateWifi, UID_GREEN, 16L, 16L);
+        assertUidTotal(sTemplateWifi, UID_REMOVED, 4112L, 528L);
+        verifyAndReset();
+
+    }
+
+    public void testUid3g4gCombinedByTemplate() throws Exception {
+        long elapsedRealtime = 0;
+
+        // pretend that network comes online
+        expectTime(TEST_START + elapsedRealtime);
+        expectDefaultSettings();
+        expectNetworkState(buildMobile3gState(IMSI_1));
+        expectNetworkStatsSummary(buildEmptyStats(elapsedRealtime));
+
+        replay();
+        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
+        verifyAndReset();
+
+        // create some traffic
+        elapsedRealtime += HOUR_IN_MILLIS;
+        expectTime(TEST_START + elapsedRealtime);
+        expectDefaultSettings();
+        expectNetworkStatsSummary(buildEmptyStats(elapsedRealtime));
+        expectNetworkStatsDetail(new NetworkStats(elapsedRealtime, 1)
+                .addEntry(TEST_IFACE, UID_RED, TAG_NONE, 1024L, 1024L)
+                .addEntry(TEST_IFACE, UID_RED, 0xF00D, 512L, 512L));
+
+        replay();
+        mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+
+        // verify service recorded history
+        assertUidTotal(sTemplateImsi1, UID_RED, 1024L, 1024L);
+        verifyAndReset();
+
+        // now switch over to 4g network
+        elapsedRealtime += HOUR_IN_MILLIS;
+        expectTime(TEST_START + elapsedRealtime);
+        expectDefaultSettings();
+        expectNetworkState(buildMobile4gState());
+        expectNetworkStatsSummary(buildEmptyStats(elapsedRealtime));
+        expectNetworkStatsDetail(buildEmptyStats(elapsedRealtime));
+
+        replay();
+        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
+        mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+        verifyAndReset();
+
+        // create traffic on second network
+        elapsedRealtime += HOUR_IN_MILLIS;
+        expectTime(TEST_START + elapsedRealtime);
+        expectDefaultSettings();
+        expectNetworkStatsSummary(buildEmptyStats(elapsedRealtime));
+        expectNetworkStatsDetail(new NetworkStats(elapsedRealtime, 1)
+                .addEntry(TEST_IFACE, UID_RED, TAG_NONE, 512L, 256L));
+
+        replay();
+        mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+
+        // verify that ALL_MOBILE template combines both
+        assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 1280L);
+
+        verifyAndReset();
+
+    }
+    
+    public void testPackedUidAndTag() throws Exception {
+        assertEquals(0x0000000000000000L, packUidAndTag(0, 0x0));
+        assertEquals(0x000003E900000000L, packUidAndTag(1001, 0x0));
+        assertEquals(0x000003E90000F00DL, packUidAndTag(1001, 0xF00D));
+
+        long packed;
+        packed = packUidAndTag(Integer.MAX_VALUE, Integer.MIN_VALUE);
+        assertEquals(Integer.MAX_VALUE, unpackUid(packed));
+        assertEquals(Integer.MIN_VALUE, unpackTag(packed));
+
+        packed = packUidAndTag(Integer.MIN_VALUE, Integer.MAX_VALUE);
+        assertEquals(Integer.MIN_VALUE, unpackUid(packed));
+        assertEquals(Integer.MAX_VALUE, unpackTag(packed));
+
+        packed = packUidAndTag(10005, 0xFFFFFFFF);
+        assertEquals(10005, unpackUid(packed));
+        assertEquals(0xFFFFFFFF, unpackTag(packed));
+        
+    }
+
+    public void testSummaryForAllUid() throws Exception {
+        long elapsedRealtime = 0;
+
+        // pretend that network comes online
+        expectTime(TEST_START + elapsedRealtime);
+        expectDefaultSettings();
+        expectNetworkState(buildWifiState());
+        expectNetworkStatsSummary(buildEmptyStats(elapsedRealtime));
+
+        replay();
+        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
+        verifyAndReset();
+
+        // create some traffic for two apps
+        elapsedRealtime += HOUR_IN_MILLIS;
+        expectTime(TEST_START + elapsedRealtime);
+        expectDefaultSettings();
+        expectNetworkStatsSummary(buildEmptyStats(elapsedRealtime));
+        expectNetworkStatsDetail(new NetworkStats(elapsedRealtime, 1)
+                .addEntry(TEST_IFACE, UID_RED, TAG_NONE, 50L, 50L)
+                .addEntry(TEST_IFACE, UID_RED, 0xF00D, 10L, 10L)
+                .addEntry(TEST_IFACE, UID_BLUE, TAG_NONE, 1024L, 512L));
+
+        replay();
+        mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+
+        // verify service recorded history
+        assertUidTotal(sTemplateWifi, UID_RED, 50L, 50L);
+        assertUidTotal(sTemplateWifi, UID_BLUE, 1024L, 512L);
+        verifyAndReset();
+        
+        // now create more traffic in next hour, but only for one app
+        elapsedRealtime += HOUR_IN_MILLIS;
+        expectTime(TEST_START + elapsedRealtime);
+        expectDefaultSettings();
+        expectNetworkStatsSummary(buildEmptyStats(elapsedRealtime));
+        expectNetworkStatsDetail(new NetworkStats(elapsedRealtime, 1)
+                .addEntry(TEST_IFACE, UID_BLUE, TAG_NONE, 2048L, 1024L));
+
+        replay();
+        mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+
+        // first verify entire history present
+        NetworkStats stats = mService.getSummaryForAllUid(
+                sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
+        assertEquals(3, stats.size);
+        assertStatsEntry(stats, 0, IFACE_ALL, UID_RED, TAG_NONE, 50L, 50L);
+        assertStatsEntry(stats, 1, IFACE_ALL, UID_RED, 0xF00D, 10L, 10L);
+        assertStatsEntry(stats, 2, IFACE_ALL, UID_BLUE, TAG_NONE, 2048L, 1024L);
+
+        // now verify that recent history only contains one uid
+        final long currentTime = TEST_START + elapsedRealtime;
+        stats = mService.getSummaryForAllUid(
+                sTemplateWifi, currentTime - HOUR_IN_MILLIS, currentTime, true);
+        assertEquals(1, stats.size);
+        assertStatsEntry(stats, 0, IFACE_ALL, UID_BLUE, TAG_NONE, 1024L, 512L);
+
+        verifyAndReset();
+    }
+
+    private void assertNetworkTotal(NetworkTemplate template, long rx, long tx) {
         final NetworkStatsHistory history = mService.getHistoryForNetwork(template);
         final long[] total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null);
         assertEquals(rx, total[0]);
         assertEquals(tx, total[1]);
     }
 
-    private void assertUidTotal(int uid, int template, long rx, long tx) {
-        final NetworkStatsHistory history = mService.getHistoryForUid(uid, template);
+    private void assertUidTotal(NetworkTemplate template, int uid, long rx, long tx) {
+        final NetworkStatsHistory history = mService.getHistoryForUid(template, uid, TAG_NONE);
         final long[] total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null);
         assertEquals(rx, total[0]);
         assertEquals(tx, total[1]);
@@ -346,6 +637,7 @@
         expect(mSettings.getNetworkMaxHistory()).andReturn(maxHistory).anyTimes();
         expect(mSettings.getUidBucketDuration()).andReturn(bucketDuration).anyTimes();
         expect(mSettings.getUidMaxHistory()).andReturn(maxHistory).anyTimes();
+        expect(mSettings.getTagMaxHistory()).andReturn(maxHistory).anyTimes();
         expect(mSettings.getTimeCacheMaxAge()).andReturn(DAY_IN_MILLIS).anyTimes();
     }
 
@@ -358,17 +650,26 @@
     }
 
     private void assertStatsFilesExist(boolean exist) {
-        final File summaryFile = new File(mStatsDir, "netstats.bin");
-        final File detailFile = new File(mStatsDir, "netstats_uid.bin");
+        final File networkFile = new File(mStatsDir, "netstats.bin");
+        final File uidFile = new File(mStatsDir, "netstats_uid.bin");
         if (exist) {
-            assertTrue(summaryFile.exists());
-            assertTrue(detailFile.exists());
+            assertTrue(networkFile.exists());
+            assertTrue(uidFile.exists());
         } else {
-            assertFalse(summaryFile.exists());
-            assertFalse(detailFile.exists());
+            assertFalse(networkFile.exists());
+            assertFalse(uidFile.exists());
         }
     }
 
+    private static void assertStatsEntry(
+            NetworkStats stats, int i, String iface, int uid, int tag, long rx, long tx) {
+        assertEquals(iface, stats.iface[i]);
+        assertEquals(uid, stats.uid[i]);
+        assertEquals(tag, stats.tag[i]);
+        assertEquals(rx, stats.rx[i]);
+        assertEquals(tx, stats.tx[i]);
+    }
+
     private static NetworkState buildWifiState() {
         final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0, null, null);
         info.setDetailedState(DetailedState.CONNECTED, null, null);
@@ -377,6 +678,23 @@
         return new NetworkState(info, prop, null);
     }
 
+    private static NetworkState buildMobile3gState(String subscriberId) {
+        final NetworkInfo info = new NetworkInfo(
+                TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UMTS, null, null);
+        info.setDetailedState(DetailedState.CONNECTED, null, null);
+        final LinkProperties prop = new LinkProperties();
+        prop.setInterfaceName(TEST_IFACE);
+        return new NetworkState(info, prop, null, subscriberId);
+    }
+
+    private static NetworkState buildMobile4gState() {
+        final NetworkInfo info = new NetworkInfo(TYPE_WIMAX, 0, null, null);
+        info.setDetailedState(DetailedState.CONNECTED, null, null);
+        final LinkProperties prop = new LinkProperties();
+        prop.setInterfaceName(TEST_IFACE);
+        return new NetworkState(info, prop, null);
+    }
+
     private static NetworkStats buildEmptyStats(long elapsedRealtime) {
         return new NetworkStats(elapsedRealtime, 0);
     }
diff --git a/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java b/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java
index 30afdd8..2f275c3 100644
--- a/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java
@@ -289,7 +289,7 @@
     public void expectGetInterfaceCounter(long rx, long tx) throws Exception {
         // TODO: provide elapsedRealtime mock to match TimeAuthority
         final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
-        stats.addEntry(TEST_IFACE, NetworkStats.UID_ALL, rx, tx);
+        stats.addEntry(TEST_IFACE, NetworkStats.UID_ALL, NetworkStats.TAG_NONE, rx, tx);
 
         expect(mMockNMService.getNetworkStatsSummary()).andReturn(stats).atLeastOnce();
     }
diff --git a/telephony/java/com/android/internal/telephony/DataCallState.java b/telephony/java/com/android/internal/telephony/DataCallState.java
index 1d67d45..f5651e0 100644
--- a/telephony/java/com/android/internal/telephony/DataCallState.java
+++ b/telephony/java/com/android/internal/telephony/DataCallState.java
@@ -202,7 +202,7 @@
 
                 result = SetupResult.SUCCESS;
             } catch (UnknownHostException e) {
-                Log.d(LOG_TAG, "onSetupCompleted: UnknownHostException " + e);
+                Log.d(LOG_TAG, "setLinkProperties: UnknownHostException " + e);
                 e.printStackTrace();
                 result = SetupResult.ERR_UnacceptableParameter;
             }
@@ -216,8 +216,10 @@
 
         // An error occurred so clear properties
         if (result != SetupResult.SUCCESS) {
-            if(DBG) Log.d(LOG_TAG,
-                    "onSetupConnectionCompleted with an error, clearing LinkProperties");
+            if(DBG) {
+                Log.d(LOG_TAG, "setLinkProperties: error clearing LinkProperties " +
+                        "status=" + status + " result=" + result);
+            }
             linkProperties.clear();
         }
 
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index c21a96a..5c030fd 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -228,7 +228,6 @@
         mId = id;
         mRetryMgr = rm;
         this.cid = -1;
-        clearSettings();
 
         setDbg(false);
         addState(mDefaultState);
@@ -313,7 +312,6 @@
             AsyncResult.forMessage(msg);
             msg.sendToTarget();
         }
-        clearSettings();
         if (DBG) log("NotifyDisconnectCompleted DisconnectParams=" + dp);
     }
 
@@ -632,7 +630,6 @@
                 }
                 case DataConnectionAc.REQ_RESET:
                     if (VDBG) log("DcDefaultState: msg.what=REQ_RESET");
-                    clearSettings();
                     mAc.replyToMessage(msg, DataConnectionAc.RSP_RESET);
                     transitionTo(mInactiveState);
                     break;
@@ -718,6 +715,7 @@
                 if (VDBG) log("DcInactiveState: enter notifyDisconnectCompleted");
                 notifyDisconnectCompleted(mDisconnectParams);
             }
+            clearSettings();
         }
 
         @Override
diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java
index 5d8fc78..02617c8 100644
--- a/telephony/java/com/android/internal/telephony/IccCard.java
+++ b/telephony/java/com/android/internal/telephony/IccCard.java
@@ -84,6 +84,9 @@
     static public final String INTENT_VALUE_LOCKED_ON_PUK = "PUK";
     /* NETWORK means ICC is locked on NETWORK PERSONALIZATION */
     static public final String INTENT_VALUE_LOCKED_NETWORK = "NETWORK";
+    /* PERM_DISABLED means ICC is permanently disabled due to puk fails */
+    static public final String INTENT_VALUE_ABSENT_ON_PERM_DISABLED = "PERM_DISABLED";
+
 
     protected static final int EVENT_ICC_LOCKED_OR_ABSENT = 1;
     private static final int EVENT_GET_ICC_STATUS_DONE = 2;
@@ -112,7 +115,8 @@
         PUK_REQUIRED,
         NETWORK_LOCKED,
         READY,
-        NOT_READY;
+        NOT_READY,
+        PERM_DISABLED;
 
         public boolean isPinLocked() {
             return ((this == PIN_REQUIRED) || (this == PUK_REQUIRED));
@@ -120,7 +124,8 @@
 
         public boolean iccCardExist() {
             return ((this == PIN_REQUIRED) || (this == PUK_REQUIRED)
-                    || (this == NETWORK_LOCKED) || (this == READY));
+                    || (this == NETWORK_LOCKED) || (this == READY)
+                    || (this == PERM_DISABLED));
         }
     }
 
@@ -416,6 +421,7 @@
         boolean transitionedIntoPinLocked;
         boolean transitionedIntoAbsent;
         boolean transitionedIntoNetworkLocked;
+        boolean transitionedIntoPermBlocked;
         boolean isIccCardRemoved;
         boolean isIccCardAdded;
 
@@ -434,6 +440,8 @@
         transitionedIntoAbsent = (oldState != State.ABSENT && newState == State.ABSENT);
         transitionedIntoNetworkLocked = (oldState != State.NETWORK_LOCKED
                 && newState == State.NETWORK_LOCKED);
+        transitionedIntoPermBlocked = (oldState != State.PERM_DISABLED
+                && newState == State.PERM_DISABLED);
         isIccCardRemoved = (oldState != null &&
                         oldState.iccCardExist() && newState == State.ABSENT);
         isIccCardAdded = (oldState == State.ABSENT &&
@@ -454,6 +462,10 @@
             mNetworkLockedRegistrants.notifyRegistrants();
             broadcastIccStateChangedIntent(INTENT_VALUE_ICC_LOCKED,
                   INTENT_VALUE_LOCKED_NETWORK);
+        } else if (transitionedIntoPermBlocked) {
+            if (mDbg) log("Notify SIM permanently disabled.");
+            broadcastIccStateChangedIntent(INTENT_VALUE_ICC_ABSENT,
+                    INTENT_VALUE_ABSENT_ON_PERM_DISABLED);
         }
 
         if (isIccCardRemoved) {
@@ -762,6 +774,9 @@
         }
 
         // check if PIN required
+        if (app.pin1.isPermBlocked()) {
+            return IccCard.State.PERM_DISABLED;
+        }
         if (app.app_state.isPinRequired()) {
             return IccCard.State.PIN_REQUIRED;
         }
diff --git a/telephony/java/com/android/internal/telephony/IccCardApplication.java b/telephony/java/com/android/internal/telephony/IccCardApplication.java
index 434c484..abb740e 100644
--- a/telephony/java/com/android/internal/telephony/IccCardApplication.java
+++ b/telephony/java/com/android/internal/telephony/IccCardApplication.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.telephony;
 
+import com.android.internal.telephony.IccCardStatus.PinState;
+
 
 /**
  * See also RIL_AppStatus in include/telephony/ril.h
@@ -104,8 +106,8 @@
     public String         app_label;
     // applicable to USIM and CSIM
     public int            pin1_replaced;
-    public int            pin1;
-    public int            pin2;
+    public PinState            pin1;
+    public PinState            pin2;
 
     AppType AppTypeFromRILInt(int type) {
         AppType newType;
@@ -177,6 +179,33 @@
         return newSubState;
     }
 
+    PinState PinStateFromRILInt(int state) {
+        PinState newPinState;
+        switch(state) {
+            case 0:
+                newPinState = PinState.PINSTATE_UNKNOWN;
+                break;
+            case 1:
+                newPinState = PinState.PINSTATE_ENABLED_NOT_VERIFIED;
+                break;
+            case 2:
+                newPinState = PinState.PINSTATE_ENABLED_VERIFIED;
+                break;
+            case 3:
+                newPinState = PinState.PINSTATE_DISABLED;
+                break;
+            case 4:
+                newPinState = PinState.PINSTATE_ENABLED_BLOCKED;
+                break;
+            case 5:
+                newPinState = PinState.PINSTATE_ENABLED_PERM_BLOCKED;
+                break;
+            default:
+                throw new RuntimeException("Unrecognized RIL_PinState: " + state);
+        }
+        return newPinState;
+    }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -185,6 +214,12 @@
         if (app_state == AppState.APPSTATE_SUBSCRIPTION_PERSO) {
             sb.append(",").append(perso_substate);
         }
+        if (app_type == AppType.APPTYPE_CSIM ||
+                app_type == AppType.APPTYPE_USIM ||
+                app_type == AppType.APPTYPE_ISIM) {
+            sb.append(",pin1=").append(pin1);
+            sb.append(",pin2=").append(pin2);
+        }
         sb.append("}");
         return sb.toString();
     }
diff --git a/telephony/java/com/android/internal/telephony/IccCardStatus.java b/telephony/java/com/android/internal/telephony/IccCardStatus.java
index e9de922..c751a21 100644
--- a/telephony/java/com/android/internal/telephony/IccCardStatus.java
+++ b/telephony/java/com/android/internal/telephony/IccCardStatus.java
@@ -42,7 +42,19 @@
         PINSTATE_ENABLED_VERIFIED,
         PINSTATE_DISABLED,
         PINSTATE_ENABLED_BLOCKED,
-        PINSTATE_ENABLED_PERM_BLOCKED
+        PINSTATE_ENABLED_PERM_BLOCKED;
+
+        boolean isPermBlocked() {
+            return this == PINSTATE_ENABLED_PERM_BLOCKED;
+        }
+
+        boolean isPinRequired() {
+            return this == PINSTATE_ENABLED_NOT_VERIFIED;
+        }
+
+        boolean isPukRequired() {
+            return this == PINSTATE_ENABLED_BLOCKED;
+        }
     }
 
     private CardState  mCardState;
diff --git a/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java b/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java
index 5fef6de..9763265 100644
--- a/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java
@@ -112,7 +112,7 @@
      */
     public void sendText(String destAddr, String scAddr,
             String text, PendingIntent sentIntent, PendingIntent deliveryIntent) {
-        mPhone.getContext().enforceCallingPermission(
+        mPhone.getContext().enforceCallingOrSelfPermission(
                 "android.permission.SEND_SMS",
                 "Sending SMS message");
         if (Log.isLoggable("SMS", Log.VERBOSE)) {
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 572bbaa..76f1ab7 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -2924,8 +2924,8 @@
             ca.aid            = p.readString();
             ca.app_label      = p.readString();
             ca.pin1_replaced  = p.readInt();
-            ca.pin1           = p.readInt();
-            ca.pin2           = p.readInt();
+            ca.pin1           = ca.PinStateFromRILInt(p.readInt());
+            ca.pin2           = ca.PinStateFromRILInt(p.readInt());
             status.addApplication(ca);
         }
         return status;
diff --git a/telephony/java/com/android/internal/telephony/WapPushOverSms.java b/telephony/java/com/android/internal/telephony/WapPushOverSms.java
old mode 100644
new mode 100755
diff --git a/telephony/java/com/android/internal/telephony/WspTypeDecoder.java b/telephony/java/com/android/internal/telephony/WspTypeDecoder.java
old mode 100644
new mode 100755
index c8dd718..73260fb
--- a/telephony/java/com/android/internal/telephony/WspTypeDecoder.java
+++ b/telephony/java/com/android/internal/telephony/WspTypeDecoder.java
@@ -194,6 +194,7 @@
 
     public static final String CONTENT_TYPE_B_PUSH_CO = "application/vnd.wap.coc";
     public static final String CONTENT_TYPE_B_MMS = "application/vnd.wap.mms-message";
+    public static final String CONTENT_TYPE_B_PUSH_SYNCML_NOTI = "application/vnd.syncml.notification";
 
     byte[] wspData;
     int    dataLength;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
old mode 100644
new mode 100755
index 29349db..07b0f4f
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -41,6 +41,7 @@
 import com.android.internal.telephony.SmsMessageBase;
 import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails;
 import com.android.internal.telephony.TelephonyProperties;
+import com.android.internal.telephony.WspTypeDecoder;
 import com.android.internal.telephony.cdma.sms.SmsEnvelope;
 import com.android.internal.telephony.cdma.sms.UserData;
 import com.android.internal.util.HexDump;
@@ -50,6 +51,8 @@
 import java.util.Arrays;
 import java.util.HashMap;
 
+import android.content.res.Resources;
+
 
 final class CdmaSMSDispatcher extends SMSDispatcher {
     private static final String TAG = "CDMA";
@@ -57,6 +60,9 @@
     private byte[] mLastDispatchedSmsFingerprint;
     private byte[] mLastAcknowledgedSmsFingerprint;
 
+    private boolean mCheckForDuplicatePortsInOmadmWapPush = Resources.getSystem().getBoolean(
+            com.android.internal.R.bool.config_duplicate_port_omadm_wappush);
+
     CdmaSMSDispatcher(CDMAPhone phone) {
         super(phone);
     }
@@ -253,6 +259,13 @@
             sourcePort |= 0xFF & pdu[index++];
             destinationPort = (0xFF & pdu[index++]) << 8;
             destinationPort |= 0xFF & pdu[index++];
+            // Some carriers incorrectly send duplicate port fields in omadm wap pushes.
+            // If configured, check for that here
+            if (mCheckForDuplicatePortsInOmadmWapPush) {
+                if (checkDuplicatePortOmadmWappush(pdu,index)) {
+                    index = index + 4; // skip duplicate port fields
+                }
+            }
         }
 
         // Lookup all other related parts
@@ -502,4 +515,42 @@
             return CommandsInterface.CDMA_SMS_FAIL_CAUSE_ENCODING_PROBLEM;
         }
     }
+
+    /**
+     * Optional check to see if the received WapPush is an OMADM notification with erroneous
+     * extra port fields.
+     * - Some carriers make this mistake.
+     * ex: MSGTYPE-TotalSegments-CurrentSegment
+     *       -SourcePortDestPort-SourcePortDestPort-OMADM PDU
+     * @param origPdu The WAP-WDP PDU segment
+     * @param index Current Index while parsing the PDU.
+     * @return True if OrigPdu is OmaDM Push Message which has duplicate ports.
+     *         False if OrigPdu is NOT OmaDM Push Message which has duplicate ports.
+     */
+    private boolean checkDuplicatePortOmadmWappush(byte[] origPdu, int index) {
+        index += 4;
+        byte[] omaPdu = new byte[origPdu.length - index];
+        System.arraycopy(origPdu, index, omaPdu, 0, omaPdu.length);
+
+        WspTypeDecoder pduDecoder = new WspTypeDecoder(omaPdu);
+        int wspIndex = 2;
+
+        // Process header length field
+        if (pduDecoder.decodeUintvarInteger(wspIndex) == false) {
+            return false;
+        }
+
+        wspIndex += pduDecoder.getDecodedDataLength(); // advance to next field
+
+        // Process content type field
+        if (pduDecoder.decodeContentType(wspIndex) == false) {
+            return false;
+        }
+
+        String mimeType = pduDecoder.getValueString();
+        if (mimeType != null && mimeType.equals(WspTypeDecoder.CONTENT_TYPE_B_PUSH_SYNCML_NOTI)) {
+            return true;
+        }
+        return false;
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
index ee63ede..9af2d26 100755
--- a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
@@ -119,8 +119,11 @@
 
         adnCache.reset();
 
-        phone.setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, null);
-        phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, null);
+        // Don't clean up PROPERTY_ICC_OPERATOR_ISO_COUNTRY and
+        // PROPERTY_ICC_OPERATOR_NUMERIC here. Since not all CDMA
+        // devices have RUIM, these properties should keep the original
+        // values, e.g. build time settings, when there is no RUIM but
+        // set new values when RUIM is available and loaded.
 
         // recordsRequested is set to false indicating that the SIM
         // read requests made so far are not valid. This is set to
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index dcde71a..19c06f6 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -1850,7 +1850,7 @@
             if (!dc.configureRetry(SystemProperties.get("ro.gsm.data_retry_config"))) {
                 if (!dc.configureRetry(DEFAULT_DATA_RETRY_CONFIG)) {
                     // Should never happen, log an error and default to a simple linear sequence.
-                    loge("createDataConnection: Could not configure using " +
+                    loge("configureRetry: Could not configure using " +
                             "DEFAULT_DATA_RETRY_CONFIG=" + DEFAULT_DATA_RETRY_CONFIG);
                     dc.configureRetry(20, 2000, 1000);
                 }
@@ -1859,7 +1859,7 @@
             if (!dc.configureRetry(SystemProperties.get("ro.gsm.2nd_data_retry_config"))) {
                 if (!dc.configureRetry(SECONDARY_DATA_RETRY_CONFIG)) {
                     // Should never happen, log an error and default to a simple sequence.
-                    loge("createDataConnection: Could note configure using " +
+                    loge("configureRetry: Could note configure using " +
                             "SECONDARY_DATA_RETRY_CONFIG=" + SECONDARY_DATA_RETRY_CONFIG);
                     dc.configureRetry("max_retries=3, 333, 333, 333");
                 }
@@ -1872,7 +1872,7 @@
             if (DBG) log("destroyDataConnections: clear mDataConnectionList");
             mDataConnections.clear();
         } else {
-            if (DBG) log("destroyDataConnectionList mDataConnecitonList is empty, ignore");
+            if (DBG) log("destroyDataConnections: mDataConnecitonList is empty, ignore");
         }
     }
 
diff --git a/tests/BiDiTests/res/layout/table_layout_locale.xml b/tests/BiDiTests/res/layout/table_layout_locale.xml
index 2589b40..bd2ad23 100644
--- a/tests/BiDiTests/res/layout/table_layout_locale.xml
+++ b/tests/BiDiTests/res/layout/table_layout_locale.xml
@@ -44,7 +44,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_after_text"
                         android:textSize="24dip"
-                        android:gravity="after"
+                        android:gravity="end"
                         />
             </TableRow>
 
@@ -64,7 +64,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_before_text"
                         android:textSize="24dip"
-                        android:gravity="before"
+                        android:gravity="start"
                         />
             </TableRow>
         </TableLayout>
@@ -73,7 +73,7 @@
                      android:layout_height="wrap_content"
                      android:stretchColumns="1,2"
                      android:layoutDirection="inherit">
-    
+
             <TableRow>
                 <Button android:layout_height="wrap_content"
                         android:layout_width="wrap_content"
@@ -90,7 +90,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_after_text"
                         android:textSize="24dip"
-                        android:gravity="after"
+                        android:gravity="end"
                         />
             </TableRow>
 
@@ -110,7 +110,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_before_text"
                         android:textSize="24dip"
-                        android:gravity="before"
+                        android:gravity="start"
                         />
             </TableRow>
         </TableLayout>
@@ -119,7 +119,7 @@
                      android:layout_height="wrap_content"
                      android:stretchColumns="1,2"
                      android:layoutDirection="ltr">
-    
+
             <TableRow>
                 <Button android:layout_height="wrap_content"
                         android:layout_width="wrap_content"
@@ -136,7 +136,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_after_text"
                         android:textSize="24dip"
-                        android:gravity="after"
+                        android:gravity="end"
                         />
             </TableRow>
 
@@ -156,7 +156,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_before_text"
                         android:textSize="24dip"
-                        android:gravity="before"
+                        android:gravity="start"
                         />
             </TableRow>
         </TableLayout>
@@ -165,7 +165,7 @@
                      android:layout_height="wrap_content"
                      android:stretchColumns="1,2"
                      android:layoutDirection="rtl">
-    
+
             <TableRow>
                 <Button android:layout_height="wrap_content"
                         android:layout_width="wrap_content"
@@ -182,7 +182,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_after_text"
                         android:textSize="24dip"
-                        android:gravity="after"
+                        android:gravity="end"
                         />
             </TableRow>
 
@@ -202,7 +202,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_before_text"
                         android:textSize="24dip"
-                        android:gravity="before"
+                        android:gravity="start"
                         />
             </TableRow>
         </TableLayout>
@@ -211,7 +211,7 @@
                      android:layout_height="wrap_content"
                      android:stretchColumns="1,2"
                      android:layoutDirection="locale">
-    
+
             <TableRow>
                 <Button android:layout_height="wrap_content"
                         android:layout_width="wrap_content"
@@ -228,7 +228,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_after_text"
                         android:textSize="24dip"
-                        android:gravity="after"
+                        android:gravity="end"
                         />
             </TableRow>
 
@@ -248,7 +248,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_before_text"
                         android:textSize="24dip"
-                        android:gravity="before"
+                        android:gravity="start"
                         />
             </TableRow>
         </TableLayout>
diff --git a/tests/BiDiTests/res/layout/table_layout_ltr.xml b/tests/BiDiTests/res/layout/table_layout_ltr.xml
index d8d412c..18c0817 100644
--- a/tests/BiDiTests/res/layout/table_layout_ltr.xml
+++ b/tests/BiDiTests/res/layout/table_layout_ltr.xml
@@ -44,7 +44,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_after_text"
                         android:textSize="24dip"
-                        android:gravity="after"
+                        android:gravity="end"
                         />
             </TableRow>
 
@@ -64,7 +64,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_before_text"
                         android:textSize="24dip"
-                        android:gravity="before"
+                        android:gravity="start"
                         />
             </TableRow>
         </TableLayout>
@@ -90,7 +90,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_after_text"
                         android:textSize="24dip"
-                        android:gravity="after"
+                        android:gravity="end"
                         />
             </TableRow>
 
@@ -110,7 +110,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_before_text"
                         android:textSize="24dip"
-                        android:gravity="before"
+                        android:gravity="start"
                         />
             </TableRow>
         </TableLayout>
@@ -136,7 +136,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_after_text"
                         android:textSize="24dip"
-                        android:gravity="after"
+                        android:gravity="end"
                         />
             </TableRow>
 
@@ -156,7 +156,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_before_text"
                         android:textSize="24dip"
-                        android:gravity="before"
+                        android:gravity="start"
                         />
             </TableRow>
         </TableLayout>
@@ -182,7 +182,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_after_text"
                         android:textSize="24dip"
-                        android:gravity="after"
+                        android:gravity="end"
                         />
             </TableRow>
 
@@ -202,7 +202,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_before_text"
                         android:textSize="24dip"
-                        android:gravity="before"
+                        android:gravity="start"
                         />
             </TableRow>
         </TableLayout>
@@ -228,7 +228,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_after_text"
                         android:textSize="24dip"
-                        android:gravity="after"
+                        android:gravity="end"
                         />
             </TableRow>
 
@@ -248,7 +248,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_before_text"
                         android:textSize="24dip"
-                        android:gravity="before"
+                        android:gravity="start"
                         />
             </TableRow>
         </TableLayout>
diff --git a/tests/BiDiTests/res/layout/table_layout_rtl.xml b/tests/BiDiTests/res/layout/table_layout_rtl.xml
index 53130fe2..d7e097d 100644
--- a/tests/BiDiTests/res/layout/table_layout_rtl.xml
+++ b/tests/BiDiTests/res/layout/table_layout_rtl.xml
@@ -44,7 +44,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_after_text"
                         android:textSize="24dip"
-                        android:gravity="after"
+                        android:gravity="end"
                         />
             </TableRow>
 
@@ -64,7 +64,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_before_text"
                         android:textSize="24dip"
-                        android:gravity="before"
+                        android:gravity="start"
                         />
             </TableRow>
         </TableLayout>
@@ -73,7 +73,7 @@
                      android:layout_height="wrap_content"
                      android:stretchColumns="1,2"
                      android:layoutDirection="inherit">
-    
+
             <TableRow>
                 <Button android:layout_height="wrap_content"
                         android:layout_width="wrap_content"
@@ -90,7 +90,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_after_text"
                         android:textSize="24dip"
-                        android:gravity="after"
+                        android:gravity="end"
                         />
             </TableRow>
 
@@ -110,7 +110,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_before_text"
                         android:textSize="24dip"
-                        android:gravity="before"
+                        android:gravity="start"
                         />
             </TableRow>
         </TableLayout>
@@ -119,7 +119,7 @@
                      android:layout_height="wrap_content"
                      android:stretchColumns="1,2"
                      android:layoutDirection="ltr">
-    
+
             <TableRow>
                 <Button android:layout_height="wrap_content"
                         android:layout_width="wrap_content"
@@ -136,7 +136,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_after_text"
                         android:textSize="24dip"
-                        android:gravity="after"
+                        android:gravity="end"
                         />
             </TableRow>
 
@@ -156,7 +156,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_before_text"
                         android:textSize="24dip"
-                        android:gravity="before"
+                        android:gravity="start"
                         />
             </TableRow>
         </TableLayout>
@@ -165,7 +165,7 @@
                      android:layout_height="wrap_content"
                      android:stretchColumns="1,2"
                      android:layoutDirection="rtl">
-    
+
             <TableRow>
                 <Button android:layout_height="wrap_content"
                         android:layout_width="wrap_content"
@@ -182,7 +182,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_after_text"
                         android:textSize="24dip"
-                        android:gravity="after"
+                        android:gravity="end"
                         />
             </TableRow>
 
@@ -202,7 +202,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_before_text"
                         android:textSize="24dip"
-                        android:gravity="before"
+                        android:gravity="start"
                         />
             </TableRow>
         </TableLayout>
@@ -211,7 +211,7 @@
                      android:layout_height="wrap_content"
                      android:stretchColumns="1,2"
                      android:layoutDirection="locale">
-    
+
             <TableRow>
                 <Button android:layout_height="wrap_content"
                         android:layout_width="wrap_content"
@@ -228,7 +228,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_after_text"
                         android:textSize="24dip"
-                        android:gravity="after"
+                        android:gravity="end"
                         />
             </TableRow>
 
@@ -248,7 +248,7 @@
                         android:layout_width="wrap_content"
                         android:text="@string/button_before_text"
                         android:textSize="24dip"
-                        android:gravity="before"
+                        android:gravity="start"
                         />
             </TableRow>
         </TableLayout>
diff --git a/tests/BiDiTests/res/layout/view_padding.xml b/tests/BiDiTests/res/layout/view_padding.xml
new file mode 100644
index 0000000..1652d04
--- /dev/null
+++ b/tests/BiDiTests/res/layout/view_padding.xml
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/view_padding"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
+
+    <FrameLayout android:layout_width="match_parent"
+                 android:layout_height="match_parent">
+
+        <FrameLayout
+                android:layout_width="300dp"
+                android:layout_height="300dp"
+                android:layout_gravity="top|left"
+                android:background="#FF888888"
+                android:paddingTop="20dip"
+                android:paddingLeft="40dip"
+                android:paddingBottom="30dip"
+                android:paddingRight="50dip">
+
+            <FrameLayout
+                    android:layout_width="100dp"
+                    android:layout_height="100dp"
+                    android:layout_gravity="top|left"
+                    android:background="#FF0000FF">
+            </FrameLayout>
+
+            <FrameLayout
+                    android:layout_width="100dp"
+                    android:layout_height="100dp"
+                    android:layout_gravity="bottom|right"
+                    android:background="#FF00FF00">
+            </FrameLayout>
+        </FrameLayout>
+
+        <FrameLayout
+                android:layout_width="300dp"
+                android:layout_height="300dp"
+                android:layout_gravity="top|center_horizontal"
+                android:background="#FF888888"
+                android:paddingTop="20dip"
+                android:paddingLeft="40dip"
+                android:paddingBottom="30dip"
+                android:paddingRight="50dip"
+                android:layoutDirection="inherit">
+
+            <FrameLayout
+                    android:layout_width="100dp"
+                    android:layout_height="100dp"
+                    android:layout_gravity="top|left"
+                    android:background="#FF0000FF">
+            </FrameLayout>
+
+            <FrameLayout
+                    android:layout_width="100dp"
+                    android:layout_height="100dp"
+                    android:layout_gravity="bottom|right"
+                    android:background="#FF00FF00">
+            </FrameLayout>
+        </FrameLayout>
+
+        <FrameLayout
+                android:layout_width="300dp"
+                android:layout_height="300dp"
+                android:layout_gravity="top|right"
+                android:background="#FF888888"
+                android:paddingTop="20dip"
+                android:paddingLeft="40dip"
+                android:paddingBottom="30dip"
+                android:paddingRight="50dip"
+                android:layoutDirection="ltr">
+
+            <FrameLayout
+                    android:layout_width="100dp"
+                    android:layout_height="100dp"
+                    android:layout_gravity="top|left"
+                    android:background="#FF0000FF">
+            </FrameLayout>
+
+            <FrameLayout
+                    android:layout_width="100dp"
+                    android:layout_height="100dp"
+                    android:layout_gravity="bottom|right"
+                    android:background="#FF00FF00">
+            </FrameLayout>
+        </FrameLayout>
+
+        <FrameLayout
+                android:layout_width="300dp"
+                android:layout_height="300dp"
+                android:layout_gravity="bottom|left"
+                android:background="#FF888888"
+                android:paddingTop="20dip"
+                android:paddingLeft="40dip"
+                android:paddingBottom="30dip"
+                android:paddingRight="50dip"
+                android:layoutDirection="rtl">
+
+            <FrameLayout
+                    android:layout_width="100dp"
+                    android:layout_height="100dp"
+                    android:layout_gravity="top|left"
+                    android:background="#FF0000FF">
+            </FrameLayout>
+
+            <FrameLayout
+                    android:layout_width="100dp"
+                    android:layout_height="100dp"
+                    android:layout_gravity="bottom|right"
+                    android:background="#FF00FF00">
+            </FrameLayout>
+        </FrameLayout>
+
+        <FrameLayout
+                android:layout_width="300dp"
+                android:layout_height="300dp"
+                android:layout_gravity="bottom|center_horizontal"
+                android:background="#FF888888"
+                android:paddingTop="20dip"
+                android:paddingLeft="40dip"
+                android:paddingBottom="30dip"
+                android:paddingRight="50dip"
+                android:layoutDirection="locale">
+
+            <FrameLayout
+                    android:layout_width="100dp"
+                    android:layout_height="100dp"
+                    android:layout_gravity="top|left"
+                    android:background="#FF0000FF">
+            </FrameLayout>
+
+            <FrameLayout
+                    android:layout_width="100dp"
+                    android:layout_height="100dp"
+                    android:layout_gravity="bottom|right"
+                    android:background="#FF00FF00">
+            </FrameLayout>
+        </FrameLayout>
+
+    </FrameLayout>
+
+</FrameLayout>
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
index a3a0041..0bed7ce 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
@@ -119,6 +119,8 @@
         addItem(result, "Table RTL", BiDiTestTableLayoutRtl.class, R.id.table_layout_rtl);
         addItem(result, "Table LOC", BiDiTestTableLayoutLocale.class, R.id.table_layout_locale);
 
+        addItem(result, "ViewPadding", BiDiTestViewPadding.class, R.id.view_padding);
+
         return result;
     }
 }
\ No newline at end of file
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestViewPadding.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestViewPadding.java
new file mode 100644
index 0000000..6bb410a
--- /dev/null
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestViewPadding.java
@@ -0,0 +1,17 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+package com.android.bidi;
+
+import android.app.Fragment;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class BiDiTestViewPadding extends Fragment {
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.view_padding, container, false);
+    }
+}
diff --git a/tests/GridLayoutTest/res/layout/grid3.xml b/tests/GridLayoutTest/res/layout/grid3.xml
index 5cdacf7..ba911c2 100644
--- a/tests/GridLayoutTest/res/layout/grid3.xml
+++ b/tests/GridLayoutTest/res/layout/grid3.xml
@@ -21,7 +21,7 @@
         android:layout_height="match_parent"
 
         android:useDefaultMargins="true"
-        android:marginsIncludedInAlignment="false"
+        android:alignmentMode="alignBounds"
 
         android:columnCount="4"
         >
diff --git a/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java b/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
index 32365d7..e010a00 100644
--- a/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
+++ b/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
@@ -36,7 +36,7 @@
     public static View create(Context context) {
         GridLayout vg = new GridLayout(context);
         vg.setUseDefaultMargins(true);
-        vg.setMarginsIncludedInAlignment(false);
+        vg.setAlignmentMode(ALIGN_BOUNDS);
 
         Group row1 = new Group(1, CENTER);
         Group row2 = new Group(2, CENTER);
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 3e7ca08..c650021 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -31,6 +31,24 @@
         android:hardwareAccelerated="true">
 
         <activity
+                android:name="GetBitmapActivity"
+                android:label="_GetBitmap">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        
+        <activity
+                android:name="SmallCircleActivity"
+                android:label="_SmallCircle">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <activity
                 android:name="ClearActivity"
                 android:label="_Clear">
             <intent-filter>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GetBitmapActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GetBitmapActivity.java
new file mode 100644
index 0000000..2e23aaa
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GetBitmapActivity.java
@@ -0,0 +1,103 @@
+/*
+ * 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.test.hwui;
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.graphics.SurfaceTexture;
+import android.hardware.Camera;
+import android.os.Bundle;
+import android.os.Environment;
+import android.view.Gravity;
+import android.view.TextureView;
+import android.view.View;
+import android.widget.Button;
+import android.widget.FrameLayout;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class GetBitmapActivity extends Activity implements TextureView.SurfaceTextureListener {
+    private Camera mCamera;
+    private TextureView mTextureView;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        FrameLayout content = new FrameLayout(this);
+
+        mTextureView = new TextureView(this);
+        mTextureView.setSurfaceTextureListener(this);
+
+        Button button = new Button(this);
+        button.setText("Copy bitmap to /sdcard/textureview.png");
+        button.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Bitmap b = mTextureView.getBitmap();
+                try {
+                    FileOutputStream out = new FileOutputStream(
+                            Environment.getExternalStorageDirectory() + "/textureview.png");
+                    try {
+                        b.compress(Bitmap.CompressFormat.PNG, 100, out);
+                    } finally {
+                        try {
+                            out.close();
+                        } catch (IOException e) {
+                            // Ignore
+                        }
+                    }
+                } catch (FileNotFoundException e) {
+                    // Ignore
+                }
+            }
+        });
+
+        content.addView(mTextureView, new FrameLayout.LayoutParams(500, 400, Gravity.CENTER));
+        content.addView(button, new FrameLayout.LayoutParams(
+                FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT,
+                Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM));
+        setContentView(content);
+    }
+
+    @Override
+    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
+        mCamera = Camera.open();
+
+        try {
+            mCamera.setPreviewTexture(surface);
+        } catch (IOException t) {
+            android.util.Log.e("TextureView", "Cannot set preview texture target!", t);
+        }
+
+        mCamera.startPreview();
+    }
+
+    @Override
+    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+        // Ignored, the Camera does all the work for us
+    }
+
+    @Override
+    public void onSurfaceTextureDestroyed(SurfaceTexture surface) {
+        mCamera.stopPreview();
+        mCamera.release();
+    }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/SmallCircleActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/SmallCircleActivity.java
new file mode 100644
index 0000000..8c02539
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/SmallCircleActivity.java
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ * 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.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.LinearLayout;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class SmallCircleActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        final LinearLayout layout = new LinearLayout(this);
+        layout.setOrientation(LinearLayout.VERTICAL);
+
+        View view = new PathView(this);
+        layout.addView(view, new LinearLayout.LayoutParams(PathView.SIZE, PathView.SIZE));
+        view = new PathView(this);
+        view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+        layout.addView(view, new LinearLayout.LayoutParams(PathView.SIZE, PathView.SIZE));
+
+        setContentView(layout);
+    }
+
+    static class PathView extends View {
+        private static final int SIZE = 37;
+        private final Paint mPaint;
+        private final Path mPath;
+
+        PathView(Context c) {
+            super(c);
+
+            mPath = new Path();
+            mPath.addCircle(SIZE * 0.5f, SIZE * 0.5f, SIZE * 0.275f, Path.Direction.CW);
+            mPath.addCircle(SIZE * 0.5f, SIZE * 0.5f, SIZE * 0.225f, Path.Direction.CCW);
+            
+            mPaint = new Paint();
+            mPaint.setAntiAlias(true);
+            mPaint.setColor(0xffffffff);
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+
+            canvas.drawPath(mPath, mPaint);
+        }
+    }
+}
diff --git a/tests/RenderScriptTests/FBOTest/AndroidManifest.xml b/tests/RenderScriptTests/FBOTest/AndroidManifest.xml
index c2e0cc6..788e856 100644
--- a/tests/RenderScriptTests/FBOTest/AndroidManifest.xml
+++ b/tests/RenderScriptTests/FBOTest/AndroidManifest.xml
@@ -3,11 +3,20 @@
     package="com.android.fbotest">
     <application android:label="_FBOTest">
         <activity android:name="FBOTest"
+                  android:label="FBO Base Test"
                   android:theme="@android:style/Theme.Black.NoTitleBar">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
-        </activity>        
+        </activity>
+        <activity android:name="FBOSync"
+                  android:label="FBO Sync Test"
+                  android:theme="@android:style/Theme.Black.NoTitleBar">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOSync.java b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOSync.java
new file mode 100644
index 0000000..d30ad7e
--- /dev/null
+++ b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOSync.java
@@ -0,0 +1,72 @@
+/*
+ * 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.fbotest;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings.System;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.MenuInflater;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ListView;
+import android.net.Uri;
+
+import java.lang.Runtime;
+
+public class FBOSync extends Activity {
+
+    private FBOSyncView mView;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        // Create our Preview view and set it as the content of our
+        // Activity
+        mView = new FBOSyncView(this);
+        setContentView(mView);
+    }
+
+    @Override
+    protected void onResume() {
+        // Ideally a game should implement onResume() and onPause()
+        // to take appropriate action when the activity looses focus
+        super.onResume();
+        mView.resume();
+    }
+
+    @Override
+    protected void onPause() {
+        // Ideally a game should implement onResume() and onPause()
+        // to take appropriate action when the activity looses focus
+        super.onPause();
+        mView.pause();
+    }
+}
+
diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOSyncRS.java b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOSyncRS.java
new file mode 100644
index 0000000..57a117c
--- /dev/null
+++ b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOSyncRS.java
@@ -0,0 +1,213 @@
+/*
+ * 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.fbotest;
+
+import java.io.Writer;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.Element.DataType;
+import android.renderscript.Element.DataKind;
+import android.renderscript.ProgramStore.DepthFunc;
+import android.renderscript.Type.Builder;
+import android.util.Log;
+
+
+public class FBOSyncRS {
+
+    public FBOSyncRS() {
+    }
+
+    public void init(RenderScriptGL rs, Resources res) {
+        mRS = rs;
+        mRes = res;
+        initRS();
+    }
+
+    public void surfaceChanged() {
+        mRS.getWidth();
+        mRS.getHeight();
+    }
+
+    private Resources mRes;
+    private RenderScriptGL mRS;
+    private Sampler mSampler;
+    private ProgramStore mPSBackground;
+    private ProgramFragment mPFBackground;
+    private ProgramVertex mPVBackground;
+    private ProgramVertexFixedFunction.Constants mPVA;
+
+    private Allocation mGridImage;
+    private Allocation mOffscreen;
+    private Allocation mOffscreenDepth;
+    private Allocation mAllocPV;
+    private Allocation mReadBackTest;
+
+    private Font mItalic;
+    private Allocation mTextAlloc;
+
+    private ScriptField_MeshInfo mMeshes;
+    private ScriptC_fbosync mScript;
+
+
+    public void onActionDown(float x, float y) {
+        mScript.invoke_onActionDown(x, y);
+    }
+
+    public void onActionScale(float scale) {
+        mScript.invoke_onActionScale(scale);
+    }
+
+    public void onActionMove(float x, float y) {
+        mScript.invoke_onActionMove(x, y);
+    }
+
+    private void initPFS() {
+        ProgramStore.Builder b = new ProgramStore.Builder(mRS);
+
+        b.setDepthFunc(ProgramStore.DepthFunc.LESS);
+        b.setDitherEnabled(false);
+        b.setDepthMaskEnabled(true);
+        mPSBackground = b.create();
+
+        mScript.set_gPFSBackground(mPSBackground);
+    }
+
+    private void initPF() {
+        Sampler.Builder bs = new Sampler.Builder(mRS);
+        bs.setMinification(Sampler.Value.LINEAR);
+        bs.setMagnification(Sampler.Value.LINEAR);
+        bs.setWrapS(Sampler.Value.CLAMP);
+        bs.setWrapT(Sampler.Value.CLAMP);
+        mSampler = bs.create();
+
+        ProgramFragmentFixedFunction.Builder b = new ProgramFragmentFixedFunction.Builder(mRS);
+        b.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
+                     ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
+        mPFBackground = b.create();
+        mPFBackground.bindSampler(mSampler, 0);
+
+        mScript.set_gPFBackground(mPFBackground);
+    }
+
+    private void initPV() {
+        ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS);
+        mPVBackground = pvb.create();
+
+        mPVA = new ProgramVertexFixedFunction.Constants(mRS);
+        ((ProgramVertexFixedFunction)mPVBackground).bindConstants(mPVA);
+
+        mScript.set_gPVBackground(mPVBackground);
+    }
+
+    private void loadImage() {
+        mGridImage = Allocation.createFromBitmapResource(mRS, mRes, R.drawable.robot,
+                                                         Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
+                                                         Allocation.USAGE_GRAPHICS_TEXTURE);
+        mScript.set_gTGrid(mGridImage);
+    }
+
+    private void initTextAllocation(String fileName) {
+        String allocString = "Displaying file: " + fileName;
+        mTextAlloc = Allocation.createFromString(mRS, allocString, Allocation.USAGE_SCRIPT);
+        mScript.set_gTextAlloc(mTextAlloc);
+    }
+
+    private void initMeshes(FileA3D model) {
+        int numEntries = model.getIndexEntryCount();
+        int numMeshes = 0;
+        for (int i = 0; i < numEntries; i ++) {
+            FileA3D.IndexEntry entry = model.getIndexEntry(i);
+            if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) {
+                numMeshes ++;
+            }
+        }
+
+        if (numMeshes > 0) {
+            mMeshes = new ScriptField_MeshInfo(mRS, numMeshes);
+
+            for (int i = 0; i < numEntries; i ++) {
+                FileA3D.IndexEntry entry = model.getIndexEntry(i);
+                if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) {
+                    Mesh mesh = entry.getMesh();
+                    mMeshes.set_mMesh(i, mesh, false);
+                    mMeshes.set_mNumIndexSets(i, mesh.getPrimitiveCount(), false);
+                }
+            }
+            mMeshes.copyAll();
+        } else {
+            throw new RSRuntimeException("No valid meshes in file");
+        }
+
+        mScript.bind_gMeshes(mMeshes);
+        mScript.invoke_updateMeshInfo();
+    }
+
+    public void loadA3DFile(String path) {
+        FileA3D model = FileA3D.createFromFile(mRS, path);
+        initMeshes(model);
+        initTextAllocation(path);
+    }
+
+    private void initRS() {
+
+        mScript = new ScriptC_fbosync(mRS, mRes, R.raw.fbosync);
+
+        initPFS();
+        initPF();
+        initPV();
+
+        loadImage();
+
+        Type.Builder b = new Type.Builder(mRS, Element.RGBA_8888(mRS));
+        b.setX(512).setY(512);
+        mOffscreen = Allocation.createTyped(mRS,
+                                            b.create(),
+                                            Allocation.USAGE_SCRIPT |
+                                            Allocation.USAGE_GRAPHICS_TEXTURE |
+                                            Allocation.USAGE_GRAPHICS_RENDER_TARGET);
+        mScript.set_gOffscreen(mOffscreen);
+
+        mReadBackTest = Allocation.createTyped(mRS,
+                                               b.create(),
+                                               Allocation.USAGE_SCRIPT |
+                                               Allocation.USAGE_GRAPHICS_TEXTURE);
+        mScript.set_gReadBackTest(mReadBackTest);
+
+        b = new Type.Builder(mRS,
+                             Element.createPixel(mRS, DataType.UNSIGNED_16,
+                             DataKind.PIXEL_DEPTH));
+        b.setX(512).setY(512);
+        mOffscreenDepth = Allocation.createTyped(mRS,
+                                                 b.create(),
+                                                 Allocation.USAGE_GRAPHICS_RENDER_TARGET);
+        mScript.set_gOffscreenDepth(mOffscreenDepth);
+
+        FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.robot);
+        initMeshes(model);
+
+        mItalic = Font.create(mRS, mRes, "serif", Font.Style.ITALIC, 8);
+        mScript.set_gItalic(mItalic);
+
+        initTextAllocation("R.raw.robot");
+
+        mRS.bindRootScript(mScript);
+    }
+}
+
+
+
diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOSyncView.java b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOSyncView.java
new file mode 100644
index 0000000..6a85628
--- /dev/null
+++ b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOSyncView.java
@@ -0,0 +1,144 @@
+/*
+ * 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.fbotest;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScriptGL;
+
+import android.content.Context;
+import android.view.MotionEvent;
+import android.view.SurfaceHolder;
+import android.view.ScaleGestureDetector;
+import android.util.Log;
+
+public class FBOSyncView extends RSSurfaceView {
+
+    private RenderScriptGL mRS;
+    private FBOSyncRS mRender;
+
+    private ScaleGestureDetector mScaleDetector;
+
+    private static final int INVALID_POINTER_ID = -1;
+    private int mActivePointerId = INVALID_POINTER_ID;
+
+    public FBOSyncView(Context context) {
+        super(context);
+        ensureRenderScript();
+        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
+    }
+
+    private void ensureRenderScript() {
+        if (mRS == null) {
+            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
+            sc.setDepth(16, 24);
+            mRS = createRenderScriptGL(sc);
+            mRender = new FBOSyncRS();
+            mRender.init(mRS, getResources());
+        }
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        ensureRenderScript();
+    }
+
+    @Override
+    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+        super.surfaceChanged(holder, format, w, h);
+        mRender.surfaceChanged();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        mRender = null;
+        if (mRS != null) {
+            mRS = null;
+            destroyRenderScriptGL();
+        }
+    }
+
+    public void loadA3DFile(String path) {
+        mRender.loadA3DFile(path);
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        mScaleDetector.onTouchEvent(ev);
+
+        boolean ret = false;
+        float x = ev.getX();
+        float y = ev.getY();
+
+        final int action = ev.getAction();
+
+        switch (action & MotionEvent.ACTION_MASK) {
+        case MotionEvent.ACTION_DOWN: {
+            mRender.onActionDown(x, y);
+            mActivePointerId = ev.getPointerId(0);
+            ret = true;
+            break;
+        }
+        case MotionEvent.ACTION_MOVE: {
+            if (!mScaleDetector.isInProgress()) {
+                mRender.onActionMove(x, y);
+            }
+            mRender.onActionDown(x, y);
+            ret = true;
+            break;
+        }
+
+        case MotionEvent.ACTION_UP: {
+            mActivePointerId = INVALID_POINTER_ID;
+            break;
+        }
+
+        case MotionEvent.ACTION_CANCEL: {
+            mActivePointerId = INVALID_POINTER_ID;
+            break;
+        }
+
+        case MotionEvent.ACTION_POINTER_UP: {
+            final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
+                    >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+            final int pointerId = ev.getPointerId(pointerIndex);
+            if (pointerId == mActivePointerId) {
+                // This was our active pointer going up. Choose a new
+                // active pointer and adjust accordingly.
+                final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
+                x = ev.getX(newPointerIndex);
+                y = ev.getY(newPointerIndex);
+                mRender.onActionDown(x, y);
+                mActivePointerId = ev.getPointerId(newPointerIndex);
+            }
+            break;
+        }
+        }
+
+        return ret;
+    }
+
+    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
+        @Override
+        public boolean onScale(ScaleGestureDetector detector) {
+            mRender.onActionScale(detector.getScaleFactor());
+            return true;
+        }
+    }
+}
+
+
diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs
new file mode 100644
index 0000000..b77ccb4
--- /dev/null
+++ b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs
@@ -0,0 +1,233 @@
+// 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.fbotest)
+
+#include "rs_graphics.rsh"
+
+rs_program_vertex gPVBackground;
+rs_program_fragment gPFBackground;
+
+rs_allocation gTGrid;
+
+rs_program_store gPFSBackground;
+
+rs_font gItalic;
+rs_allocation gTextAlloc;
+
+rs_allocation gOffscreen;
+rs_allocation gOffscreenDepth;
+rs_allocation gReadBackTest;
+
+typedef struct MeshInfo {
+    rs_mesh mMesh;
+    int mNumIndexSets;
+    float3 bBoxMin;
+    float3 bBoxMax;
+} MeshInfo_t;
+
+MeshInfo_t *gMeshes;
+
+static float3 gLookAt;
+
+static float gRotateX;
+static float gRotateY;
+static float gZoom;
+
+static float gLastX;
+static float gLastY;
+
+void onActionDown(float x, float y) {
+    gLastX = x;
+    gLastY = y;
+}
+
+void onActionScale(float scale) {
+
+    gZoom *= 1.0f / scale;
+    gZoom = max(0.1f, min(gZoom, 500.0f));
+}
+
+void onActionMove(float x, float y) {
+    float dx = gLastX - x;
+    float dy = gLastY - y;
+
+    if (fabs(dy) <= 2.0f) {
+        dy = 0.0f;
+    }
+    if (fabs(dx) <= 2.0f) {
+        dx = 0.0f;
+    }
+
+    gRotateY -= dx;
+    if (gRotateY > 360) {
+        gRotateY -= 360;
+    }
+    if (gRotateY < 0) {
+        gRotateY += 360;
+    }
+
+    gRotateX -= dy;
+    gRotateX = min(gRotateX, 80.0f);
+    gRotateX = max(gRotateX, -80.0f);
+
+    gLastX = x;
+    gLastY = y;
+}
+
+void init() {
+    gRotateX = 0.0f;
+    gRotateY = 0.0f;
+    gZoom = 50.0f;
+    gLookAt = 0.0f;
+}
+
+void updateMeshInfo() {
+    rs_allocation allMeshes = rsGetAllocation(gMeshes);
+    int size = rsAllocationGetDimX(allMeshes);
+    gLookAt = 0.0f;
+    float minX, minY, minZ, maxX, maxY, maxZ;
+    for (int i = 0; i < size; i++) {
+        MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i);
+        rsgMeshComputeBoundingBox(info->mMesh,
+                                  &minX, &minY, &minZ,
+                                  &maxX, &maxY, &maxZ);
+        info->bBoxMin = (minX, minY, minZ);
+        info->bBoxMax = (maxX, maxY, maxZ);
+        gLookAt += (info->bBoxMin + info->bBoxMax)*0.5f;
+    }
+    gLookAt = gLookAt / (float)size;
+}
+
+static void renderAllMeshes() {
+    rs_allocation allMeshes = rsGetAllocation(gMeshes);
+    int size = rsAllocationGetDimX(allMeshes);
+    gLookAt = 0.0f;
+    float minX, minY, minZ, maxX, maxY, maxZ;
+    for (int i = 0; i < size; i++) {
+        MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i);
+        rsgDrawMesh(info->mMesh);
+    }
+}
+
+static void drawDescription() {
+    uint width = rsgGetWidth();
+    uint height = rsgGetHeight();
+    int left = 0, right = 0, top = 0, bottom = 0;
+
+    rsgBindFont(gItalic);
+
+    rsgMeasureText(gTextAlloc, &left, &right, &top, &bottom);
+    rsgDrawText(gTextAlloc, 2 -left, height - 2 + bottom);
+}
+
+static void renderOffscreen(bool useDepth) {
+
+    rsgBindColorTarget(gOffscreen, 0);
+    if (useDepth) {
+        rsgBindDepthTarget(gOffscreenDepth);
+        rsgClearDepth(1.0f);
+    } else {
+        rsgClearDepthTarget();
+    }
+    rsgClearColor(0.8f, 0.0f, 0.0f, 1.0f);
+
+    rsgBindProgramVertex(gPVBackground);
+    rs_matrix4x4 proj;
+    float aspect = (float)rsAllocationGetDimX(gOffscreen) / (float)rsAllocationGetDimY(gOffscreen);
+    rsMatrixLoadPerspective(&proj, 30.0f, aspect, 1.0f, 100.0f);
+    rsgProgramVertexLoadProjectionMatrix(&proj);
+
+    rsgBindProgramFragment(gPFBackground);
+    rsgBindProgramStore(gPFSBackground);
+    rsgBindTexture(gPFBackground, 0, gTGrid);
+
+    rs_matrix4x4 matrix;
+    rsMatrixLoadIdentity(&matrix);
+    // Position our models on the screen
+    rsMatrixTranslate(&matrix, gLookAt.x, gLookAt.y, gLookAt.z - gZoom);
+    rsMatrixRotate(&matrix, gRotateX, 1.0f, 0.0f, 0.0f);
+    rsMatrixRotate(&matrix, gRotateY, 0.0f, 1.0f, 0.0f);
+    rsgProgramVertexLoadModelMatrix(&matrix);
+
+    renderAllMeshes();
+
+    // Render into the frambuffer
+    rsgClearAllRenderTargets();
+}
+
+static void drawOffscreenResult(int posX, int posY, rs_allocation texture) {
+    // display the result
+    rs_matrix4x4 proj, matrix;
+    rsMatrixLoadOrtho(&proj, 0, rsgGetWidth(), rsgGetHeight(), 0, -500, 500);
+    rsgProgramVertexLoadProjectionMatrix(&proj);
+    rsMatrixLoadIdentity(&matrix);
+    rsgProgramVertexLoadModelMatrix(&matrix);
+    rsgBindTexture(gPFBackground, 0, texture);
+    float startX = posX, startY = posY;
+    float width = 256, height = 256;
+    rsgDrawQuadTexCoords(startX, startY, 0, 0, 1,
+                         startX, startY + height, 0, 0, 0,
+                         startX + width, startY + height, 0, 1, 0,
+                         startX + width, startY, 0, 1, 1);
+}
+
+int root(void) {
+
+    rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+    rsgClearDepth(1.0f);
+
+    renderOffscreen(true);
+    drawOffscreenResult(0, 0, gOffscreen);
+
+
+    uint32_t w = rsAllocationGetDimX(gOffscreen);
+    uint32_t h = rsAllocationGetDimY(gOffscreen);
+    uint32_t numElements = w*h;
+
+    rsgAllocationSyncAll(gOffscreen, RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET);
+
+    rsAllocationCopy2DRange(gReadBackTest, 0, 0, 0,
+                            RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, w, h,
+                            gOffscreen, 0, 0, 0, RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X);
+
+    rsgAllocationSyncAll(gReadBackTest);
+    drawOffscreenResult(0, 300, gReadBackTest);
+
+    rsgBindProgramVertex(gPVBackground);
+    rs_matrix4x4 proj;
+    float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
+    rsMatrixLoadPerspective(&proj, 30.0f, aspect, 1.0f, 100.0f);
+    rsgProgramVertexLoadProjectionMatrix(&proj);
+
+    rsgBindProgramFragment(gPFBackground);
+    rsgBindProgramStore(gPFSBackground);
+    rsgBindTexture(gPFBackground, 0, gTGrid);
+
+    rs_matrix4x4 matrix;
+    rsMatrixLoadIdentity(&matrix);
+    // Position our models on the screen
+    rsMatrixTranslate(&matrix, gLookAt.x, gLookAt.y, gLookAt.z - gZoom);
+    rsMatrixRotate(&matrix, gRotateX, 1.0f, 0.0f, 0.0f);
+    rsMatrixRotate(&matrix, gRotateY, 0.0f, 1.0f, 0.0f);
+    rsgProgramVertexLoadModelMatrix(&matrix);
+
+    renderAllMeshes();
+
+    drawDescription();
+
+    return 0;
+}
diff --git a/tests/RenderScriptTests/PerfTest/res/drawable/flares.png b/tests/RenderScriptTests/PerfTest/res/drawable/flares.png
new file mode 100644
index 0000000..3a5c970
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/res/drawable/flares.png
Binary files differ
diff --git a/tests/RenderScriptTests/PerfTest/res/drawable/light1.jpg b/tests/RenderScriptTests/PerfTest/res/drawable/light1.jpg
new file mode 100644
index 0000000..2f2f10e
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/res/drawable/light1.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/PerfTest/res/drawable/space.jpg b/tests/RenderScriptTests/PerfTest/res/drawable/space.jpg
new file mode 100644
index 0000000..b61f6a3
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/res/drawable/space.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
index b568781..3f57799 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
@@ -38,6 +38,10 @@
 import android.renderscript.ProgramStore.BlendDstFunc;
 import android.renderscript.RenderScript.RSMessageHandler;
 import android.renderscript.Sampler.Value;
+import android.renderscript.Mesh.Primitive;
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramVertexFixedFunction;
+
 import android.util.Log;
 
 
@@ -45,7 +49,9 @@
 
     private static final String TAG = "RsBenchRS";
     private static final String SAMPLE_TEXT = "Bench Test";
-
+    private static final String LIST_TEXT =
+      "This is a sample list of text to show in the list view";
+    private static int PARTICLES_COUNT = 12000;
     int mWidth;
     int mHeight;
     int mLoops;
@@ -82,6 +88,7 @@
     private Sampler mLinearWrap;
     private Sampler mMipLinearWrap;
     private Sampler mNearestClamp;
+    private Sampler mNearesWrap;
 
     private ProgramStore mProgStoreBlendNoneDepth;
     private ProgramStore mProgStoreBlendNone;
@@ -106,6 +113,7 @@
     private ScriptField_VertexShaderConstants3_s mVSConstPixel;
     private ScriptField_FragentShaderConstants3_s mFSConstPixel;
 
+
     private ProgramRaster mCullBack;
     private ProgramRaster mCullFront;
     private ProgramRaster mCullNone;
@@ -121,6 +129,7 @@
     private Mesh mWbyHMesh;
     private Mesh mTorus;
     private Mesh mSingleMesh;
+    private Mesh mParticlesMesh;
 
     Font mFontSans;
     Font mFontSerif;
@@ -128,6 +137,9 @@
 
     private ScriptField_ListAllocs_s mTextureAllocs;
     private ScriptField_ListAllocs_s mSampleTextAllocs;
+    private ScriptField_ListAllocs_s mSampleListViewAllocs;
+    private ScriptField_VpConsts mPvStarAlloc;
+
 
     private ScriptC_rsbench mScript;
 
@@ -300,6 +312,15 @@
         mScript.set_gProgStoreBlendNone(mProgStoreBlendNone);
         mScript.set_gProgStoreBlendAlpha(mProgStoreBlendAlpha);
         mScript.set_gProgStoreBlendAdd(mProgStoreBlendAdd);
+
+        // For GALAXY
+        builder = new ProgramStore.Builder(mRS);
+        builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ZERO);
+        mRS.bindProgramStore(builder.create());
+
+        builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE);
+        mScript.set_gPSLights(builder.create());
+
     }
 
     private void initProgramFragment() {
@@ -316,8 +337,59 @@
 
         mScript.set_gProgFragmentColor(mProgFragmentColor);
         mScript.set_gProgFragmentTexture(mProgFragmentTexture);
+
+
+        // For Galaxy live wallpaper drawing
+        ProgramFragmentFixedFunction.Builder builder = new ProgramFragmentFixedFunction.Builder(mRS);
+        builder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
+                           ProgramFragmentFixedFunction.Builder.Format.RGB, 0);
+        ProgramFragment pfb = builder.create();
+        pfb.bindSampler(mNearesWrap, 0);
+        mScript.set_gPFBackground(pfb);
+
+        builder = new ProgramFragmentFixedFunction.Builder(mRS);
+        builder.setPointSpriteTexCoordinateReplacement(true);
+        builder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.MODULATE,
+                           ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
+        builder.setVaryingColor(true);
+        ProgramFragment pfs = builder.create();
+        pfs.bindSampler(mMipLinearWrap, 0);
+        mScript.set_gPFStars(pfs);
+
     }
 
+    private Matrix4f getProjectionNormalized(int w, int h) {
+      // range -1,1 in the narrow axis at z = 0.
+      Matrix4f m1 = new Matrix4f();
+      Matrix4f m2 = new Matrix4f();
+
+      if(w > h) {
+          float aspect = ((float)w) / h;
+          m1.loadFrustum(-aspect,aspect,  -1,1,  1,100);
+      } else {
+          float aspect = ((float)h) / w;
+          m1.loadFrustum(-1,1, -aspect,aspect, 1,100);
+      }
+
+      m2.loadRotate(180, 0, 1, 0);
+      m1.loadMultiply(m1, m2);
+
+      m2.loadScale(-2, 2, 1);
+      m1.loadMultiply(m1, m2);
+
+      m2.loadTranslate(0, 0, 2);
+      m1.loadMultiply(m1, m2);
+      return m1;
+  }
+
+    private void updateProjectionMatrices() {
+      Matrix4f projNorm = getProjectionNormalized(mBenchmarkDimX, mBenchmarkDimY);
+      ScriptField_VpConsts.Item i = new ScriptField_VpConsts.Item();
+      i.Proj = projNorm;
+      i.MVP = projNorm;
+      mPvStarAlloc.set(i, 0, true);
+  }
+
     private void initProgramVertex() {
         ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS);
         mProgVertex = pvb.create();
@@ -329,6 +401,39 @@
         mPVA.setProjection(proj);
 
         mScript.set_gProgVertex(mProgVertex);
+
+        // For galaxy live wallpaper
+        mPvStarAlloc = new ScriptField_VpConsts(mRS, 1);
+        mScript.bind_vpConstants(mPvStarAlloc);
+        updateProjectionMatrices();
+
+        ProgramVertex.Builder sb = new ProgramVertex.Builder(mRS);
+        String t =  "varying vec4 varColor;\n" +
+                    "varying vec2 varTex0;\n" +
+                    "void main() {\n" +
+                    "  float dist = ATTRIB_position.y;\n" +
+                    "  float angle = ATTRIB_position.x;\n" +
+                    "  float x = dist * sin(angle);\n" +
+                    "  float y = dist * cos(angle) * 0.892;\n" +
+                    "  float p = dist * 5.5;\n" +
+                    "  float s = cos(p);\n" +
+                    "  float t = sin(p);\n" +
+                    "  vec4 pos;\n" +
+                    "  pos.x = t * x + s * y;\n" +
+                    "  pos.y = s * x - t * y;\n" +
+                    "  pos.z = ATTRIB_position.z;\n" +
+                    "  pos.w = 1.0;\n" +
+                    "  gl_Position = UNI_MVP * pos;\n" +
+                    "  gl_PointSize = ATTRIB_color.a * 10.0;\n" +
+                    "  varColor.rgb = ATTRIB_color.rgb;\n" +
+                    "  varColor.a = 1.0;\n" +
+                    "}\n";
+        sb.setShader(t);
+        sb.addInput(mParticlesMesh.getVertexAllocation(0).getType().getElement());
+        sb.addConstant(mPvStarAlloc.getType());
+        ProgramVertex pvs = sb.create();
+        pvs.bindConstants(mPvStarAlloc.getAllocation(), 0);
+        mScript.set_gPVStars(pvs);
     }
 
     private void initCustomShaders() {
@@ -426,6 +531,11 @@
         mScript.set_gTexTransparent(mTexTransparent);
         mScript.set_gTexChecker(mTexChecker);
         mScript.set_gTexGlobe(mTexGlobe);
+
+        // For Galaxy live wallpaper
+        mScript.set_gTSpace(loadTextureRGB(R.drawable.space));
+        mScript.set_gTLight1(loadTextureRGB(R.drawable.light1));
+        mScript.set_gTFlares(loadTextureARGB(R.drawable.flares));
     }
 
     private void initFonts() {
@@ -440,6 +550,19 @@
         mScript.set_gFontSerif(mFontSerif);
     }
 
+    private void createParticlesMesh() {
+        ScriptField_Particle p = new ScriptField_Particle(mRS, PARTICLES_COUNT);
+
+        final Mesh.AllocationBuilder meshBuilder = new Mesh.AllocationBuilder(mRS);
+        meshBuilder.addVertexAllocation(p.getAllocation());
+        final int vertexSlot = meshBuilder.getCurrentVertexTypeIndex();
+        meshBuilder.addIndexSetType(Primitive.POINT);
+        mParticlesMesh = meshBuilder.create();
+
+        mScript.set_gParticlesMesh(mParticlesMesh);
+        mScript.bind_Particles(p);
+    }
+
     private void initMesh() {
         m10by10Mesh = getMbyNMesh(mBenchmarkDimX, mBenchmarkDimY, 10, 10);
         mScript.set_g10by10Mesh(m10by10Mesh);
@@ -458,6 +581,8 @@
             mTorus = (Mesh)entry.getObject();
             mScript.set_gTorusMesh(mTorus);
         }
+
+        createParticlesMesh();
     }
 
     private void initSamplers() {
@@ -471,6 +596,7 @@
         mLinearClamp = Sampler.CLAMP_LINEAR(mRS);
         mNearestClamp = Sampler.CLAMP_NEAREST(mRS);
         mMipLinearWrap = Sampler.WRAP_LINEAR_MIP_LINEAR(mRS);
+        mNearesWrap = Sampler.WRAP_NEAREST(mRS);
 
         mScript.set_gLinearClamp(mLinearClamp);
         mScript.set_gLinearWrap(mLinearWrap);
@@ -524,10 +650,10 @@
         initSamplers();
         initProgramStore();
         initProgramFragment();
+        initMesh();
         initProgramVertex();
         initFonts();
         loadImages();
-        initMesh();
         initProgramRaster();
         initCustomShaders();
 
@@ -567,6 +693,15 @@
         mSampleTextAllocs.copyAll();
         mScript.bind_gSampleTextList100(mSampleTextAllocs);
 
+        mSampleListViewAllocs = new ScriptField_ListAllocs_s(mRS, 1000);
+        for (int i = 0; i < 1000; i++) {
+            ScriptField_ListAllocs_s.Item textElem = new ScriptField_ListAllocs_s.Item();
+            textElem.item = Allocation.createFromString(mRS, LIST_TEXT, Allocation.USAGE_SCRIPT);
+            mSampleListViewAllocs.set(textElem, i, false);
+        }
+        mSampleListViewAllocs.copyAll();
+        mScript.bind_gListViewText(mSampleListViewAllocs);
+
         mRS.bindRootScript(mScript);
     }
 }
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
index 0294b31..6d80b0e 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
@@ -23,9 +23,50 @@
 const int RS_MSG_TEST_DONE = 100;
 const int RS_MSG_RESULTS_READY = 101;
 
-const int gMaxModes = 29;
+const int gMaxModes = 31;
 int gMaxLoops;
 
+// Parameters for galaxy live wallpaper
+rs_allocation gTSpace;
+rs_allocation gTLight1;
+rs_allocation gTFlares;
+rs_mesh gParticlesMesh;
+
+rs_program_fragment gPFBackground;
+rs_program_fragment gPFStars;
+rs_program_vertex gPVStars;
+rs_program_vertex gPVBkProj;
+rs_program_store gPSLights;
+
+float gXOffset = 0.5f;
+
+#define ELLIPSE_RATIO 0.892f
+#define PI 3.1415f
+#define TWO_PI 6.283f
+#define ELLIPSE_TWIST 0.023333333f
+
+static float angle = 50.f;
+static int gOldWidth;
+static int gOldHeight;
+static int gWidth;
+static int gHeight;
+static float gSpeed[12000];
+static int gGalaxyRadius = 300;
+static rs_allocation gParticlesBuffer;
+
+typedef struct __attribute__((packed, aligned(4))) Particle {
+    uchar4 color;
+    float3 position;
+} Particle_t;
+Particle_t *Particles;
+
+typedef struct VpConsts {
+    rs_matrix4x4 Proj;
+    rs_matrix4x4 MVP;
+} VpConsts_t;
+VpConsts_t *vpConstants;
+// End of parameters for galaxy live wallpaper
+
 // Allocation to send test names back to java
 char *gStringBuffer = 0;
 // Allocation to write the results into
@@ -52,6 +93,7 @@
 
 ListAllocs *gTexList100;
 ListAllocs *gSampleTextList100;
+ListAllocs *gListViewText;
 
 rs_mesh g10by10Mesh;
 rs_mesh g100by100Mesh;
@@ -109,6 +151,141 @@
                              0.5f, 0.6f, 0.7f, 1.0f,
 };
 
+/**
+  * Methods to draw the galaxy live wall paper
+  */
+static float mapf(float minStart, float minStop, float maxStart, float maxStop, float value) {
+    return maxStart + (maxStart - maxStop) * ((value - minStart) / (minStop - minStart));
+}
+
+/**
+ * Helper function to generate the stars.
+ */
+static float randomGauss() {
+    float x1;
+    float x2;
+    float w = 2.f;
+
+    while (w >= 1.0f) {
+        x1 = rsRand(2.0f) - 1.0f;
+        x2 = rsRand(2.0f) - 1.0f;
+        w = x1 * x1 + x2 * x2;
+    }
+
+    w = sqrt(-2.0f * log(w) / w);
+    return x1 * w;
+}
+
+/**
+ * Generates the properties for a given star.
+ */
+static void createParticle(Particle_t *part, int idx, float scale) {
+    float d = fabs(randomGauss()) * gGalaxyRadius * 0.5f + rsRand(64.0f);
+    float id = d / gGalaxyRadius;
+    float z = randomGauss() * 0.4f * (1.0f - id);
+    float p = -d * ELLIPSE_TWIST;
+
+    if (d < gGalaxyRadius * 0.33f) {
+        part->color.x = (uchar) (220 + id * 35);
+        part->color.y = 220;
+        part->color.z = 220;
+    } else {
+        part->color.x = 180;
+        part->color.y = 180;
+        part->color.z = (uchar) clamp(140.f + id * 115.f, 140.f, 255.f);
+    }
+    // Stash point size * 10 in Alpha
+    part->color.w = (uchar) (rsRand(1.2f, 2.1f) * 60);
+
+    if (d > gGalaxyRadius * 0.15f) {
+        z *= 0.6f * (1.0f - id);
+    } else {
+        z *= 0.72f;
+    }
+
+    // Map to the projection coordinates (viewport.x = -1.0 -> 1.0)
+    d = mapf(-4.0f, gGalaxyRadius + 4.0f, 0.0f, scale, d);
+
+    part->position.x = rsRand(TWO_PI);
+    part->position.y = d;
+    gSpeed[idx] = rsRand(0.0015f, 0.0025f) * (0.5f + (scale / d)) * 0.8f;
+
+    part->position.z = z / 5.0f;
+}
+
+/**
+ * Initialize all the starts, called from Java
+ */
+void initParticles() {
+    Particle_t *part = Particles;
+    float scale = gGalaxyRadius / (gWidth * 0.5f);
+    int count = rsAllocationGetDimX(gParticlesBuffer);
+    for (int i = 0; i < count; i ++) {
+        createParticle(part, i, scale);
+        part++;
+    }
+}
+
+static void drawSpace() {
+    rsgBindProgramFragment(gPFBackground);
+    rsgBindTexture(gPFBackground, 0, gTSpace);
+    rsgDrawQuadTexCoords(
+            0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
+            gWidth, 0.0f, 0.0f, 2.0f, 1.0f,
+            gWidth, gHeight, 0.0f, 2.0f, 0.0f,
+            0.0f, gHeight, 0.0f, 0.0f, 0.0f);
+}
+
+static void drawLights() {
+    rsgBindProgramVertex(gPVBkProj);
+    rsgBindProgramFragment(gPFBackground);
+    rsgBindTexture(gPFBackground, 0, gTLight1);
+
+    float scale = 512.0f / gWidth;
+    float x = -scale - scale * 0.05f;
+    float y = -scale;
+
+    scale *= 2.0f;
+
+    rsgDrawQuad(x, y, 0.0f,
+             x + scale * 1.1f, y, 0.0f,
+             x + scale * 1.1f, y + scale, 0.0f,
+             x, y + scale, 0.0f);
+}
+
+static void drawParticles(float offset) {
+    float a = offset * angle;
+    float absoluteAngle = fabs(a);
+
+    rs_matrix4x4 matrix;
+    rsMatrixLoadTranslate(&matrix, 0.0f, 0.0f, 10.0f - 6.0f * absoluteAngle / 50.0f);
+    if (gHeight > gWidth) {
+        rsMatrixScale(&matrix, 6.6f, 6.0f, 1.0f);
+    } else {
+        rsMatrixScale(&matrix, 12.6f, 12.0f, 1.0f);
+    }
+    rsMatrixRotate(&matrix, absoluteAngle, 1.0f, 0.0f, 0.0f);
+    rsMatrixRotate(&matrix, a, 0.0f, 0.4f, 0.1f);
+    rsMatrixLoad(&vpConstants->MVP, &vpConstants->Proj);
+    rsMatrixMultiply(&vpConstants->MVP, &matrix);
+    rsgAllocationSyncAll(rsGetAllocation(vpConstants));
+
+    rsgBindProgramVertex(gPVStars);
+    rsgBindProgramFragment(gPFStars);
+    rsgBindProgramStore(gPSLights);
+    rsgBindTexture(gPFStars, 0, gTFlares);
+
+    Particle_t *vtx = Particles;
+    int count = rsAllocationGetDimX(gParticlesBuffer);
+    for (int i = 0; i < count; i++) {
+        vtx->position.x = vtx->position.x + gSpeed[i];
+        vtx++;
+    }
+
+    rsgDrawMesh(gParticlesMesh);
+}
+/* end of methods for drawing galaxy */
+
 static void setupOffscreenTarget() {
     rsgBindColorTarget(gRenderBufferColor, 0);
     rsgBindDepthTarget(gRenderBufferDepth);
@@ -303,6 +480,71 @@
     }
 }
 
+// Display a list of text as the list view
+static void displayListView() {
+    // set text color
+    rsgFontColor(0.9f, 0.9f, 0.9f, 1.0f);
+    rsgBindFont(gFontSans);
+
+    // get the size of the list
+    rs_allocation textAlloc;
+    textAlloc = rsGetAllocation(gListViewText);
+    int allocSize = rsAllocationGetDimX(textAlloc);
+
+    int listItemHeight = 80;
+    int yOffset = listItemHeight;
+
+    // set the color for the list divider
+    rsgBindProgramFragment(gProgFragmentColor);
+    rsgProgramFragmentConstantColor(gProgFragmentColor, 1.0, 1.0, 1.0, 1);
+
+    // draw the list with divider
+    for (int i = 0; i < allocSize; i++) {
+        if (yOffset - listItemHeight > gRenderSurfaceH) {
+            break;
+        }
+        rsgDrawRect(0, yOffset - 1, gRenderSurfaceW, yOffset, 0);
+        rsgDrawText(gListViewText[i].item, 20, yOffset - 10);
+        yOffset += listItemHeight;
+    }
+}
+
+static void drawGalaxy() {
+    rsgClearColor(0.f, 0.f, 0.f, 1.f);
+    gParticlesBuffer = rsGetAllocation(Particles);
+    rsgBindProgramFragment(gPFBackground);
+
+    gWidth = rsgGetWidth();
+    gHeight = rsgGetHeight();
+    if ((gWidth != gOldWidth) || (gHeight != gOldHeight)) {
+        initParticles();
+        gOldWidth = gWidth;
+        gOldHeight = gHeight;
+    }
+
+    float offset = mix(-1.0f, 1.0f, gXOffset);
+    drawSpace();
+    drawParticles(offset);
+    drawLights();
+}
+
+// Display images and text with live wallpaper in the background
+static void dispalyLiveWallPaper(int wResolution, int hResolution) {
+    bindProgramVertexOrtho();
+
+    drawGalaxy();
+
+    rsgBindProgramStore(gProgStoreBlendAlpha);
+    rsgBindProgramFragment(gProgFragmentTexture);
+    rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
+
+    drawMeshInPage(0, 0, wResolution, hResolution);
+    drawMeshInPage(-1.0f*gRenderSurfaceW, 0, wResolution, hResolution);
+    drawMeshInPage(1.0f*gRenderSurfaceW, 0, wResolution, hResolution);
+    drawMeshInPage(-2.0f*gRenderSurfaceW, 0, wResolution, hResolution);
+    drawMeshInPage(2.0f*gRenderSurfaceW, 0, wResolution, hResolution);
+}
+
 static float gTorusRotation = 0;
 static void updateModelMatrix(rs_matrix4x4 *matrix, void *buffer) {
     if (buffer == 0) {
@@ -602,14 +844,12 @@
     "Geo test 25.6k heavy fragment heavy vertex",
     "Geo test 51.2k heavy fragment heavy vertex",
     "Geo test 204.8k small tries heavy fragment heavy vertex",
-    "UI test with icon display 10 by 10",     // 25
-    "UI test with icon display 100 by 100",   // 26
-    "UI test with image and text display 3 pages",  // 27
-    "UI test with image and text display 5 pages",  // 28
-    "UI test with list view",                       // 29
-//    "UI test with live wallpaper",                  // 30
-//    "Mesh with 10 by 10 texture",
-//    "Mesh with 100 by 100 texture",
+    "UI test with icon display 10 by 10",
+    "UI test with icon display 100 by 100",
+    "UI test with image and text display 3 pages",
+    "UI test with image and text display 5 pages",
+    "UI test with list view",
+    "UI test with live wallpaper",
 };
 
 void getTestName(int testIndex) {
@@ -714,6 +954,12 @@
     case 28:
         displayImageWithText(7, 5, 1);
         break;
+    case 29:
+        displayListView();
+        break;
+    case 30:
+        dispalyLiveWallPaper(7, 5);
+        break;
     }
 }
 
@@ -737,7 +983,6 @@
 }
 
 int root(void) {
-
     gRenderSurfaceW = rsgGetWidth();
     gRenderSurfaceH = rsgGetHeight();
     rsgClearColor(0.2f, 0.2f, 0.2f, 1.0f);
diff --git a/tests/StatusBar/res/drawable-hdpi/emo_im_kissing.png b/tests/StatusBar/res/drawable-hdpi/emo_im_kissing.png
new file mode 100644
index 0000000..0a8f0d7
--- /dev/null
+++ b/tests/StatusBar/res/drawable-hdpi/emo_im_kissing.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable-hdpi/notification0.png b/tests/StatusBar/res/drawable-hdpi/notification0.png
new file mode 100644
index 0000000..6d2612e
--- /dev/null
+++ b/tests/StatusBar/res/drawable-hdpi/notification0.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable-hdpi/notification1.png b/tests/StatusBar/res/drawable-hdpi/notification1.png
new file mode 100644
index 0000000..ce9009c
--- /dev/null
+++ b/tests/StatusBar/res/drawable-hdpi/notification1.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable-hdpi/notification2.png b/tests/StatusBar/res/drawable-hdpi/notification2.png
new file mode 100644
index 0000000..772d70a
--- /dev/null
+++ b/tests/StatusBar/res/drawable-hdpi/notification2.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable-hdpi/notification3.png b/tests/StatusBar/res/drawable-hdpi/notification3.png
new file mode 100644
index 0000000..61127ee
--- /dev/null
+++ b/tests/StatusBar/res/drawable-hdpi/notification3.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable-hdpi/notification4.png b/tests/StatusBar/res/drawable-hdpi/notification4.png
new file mode 100644
index 0000000..40b7d55
--- /dev/null
+++ b/tests/StatusBar/res/drawable-hdpi/notification4.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable-hdpi/notification5.png b/tests/StatusBar/res/drawable-hdpi/notification5.png
new file mode 100644
index 0000000..e89903a
--- /dev/null
+++ b/tests/StatusBar/res/drawable-hdpi/notification5.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable-hdpi/notification6.png b/tests/StatusBar/res/drawable-hdpi/notification6.png
new file mode 100644
index 0000000..e0878f5
--- /dev/null
+++ b/tests/StatusBar/res/drawable-hdpi/notification6.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable-hdpi/notification7.png b/tests/StatusBar/res/drawable-hdpi/notification7.png
new file mode 100644
index 0000000..49397ca
--- /dev/null
+++ b/tests/StatusBar/res/drawable-hdpi/notification7.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable-hdpi/notification8.png b/tests/StatusBar/res/drawable-hdpi/notification8.png
new file mode 100644
index 0000000..763b048
--- /dev/null
+++ b/tests/StatusBar/res/drawable-hdpi/notification8.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable-hdpi/notification9.png b/tests/StatusBar/res/drawable-hdpi/notification9.png
new file mode 100644
index 0000000..c3c3771
--- /dev/null
+++ b/tests/StatusBar/res/drawable-hdpi/notification9.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable-hdpi/notificationx.png b/tests/StatusBar/res/drawable-hdpi/notificationx.png
new file mode 100644
index 0000000..7267286
--- /dev/null
+++ b/tests/StatusBar/res/drawable-hdpi/notificationx.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable-hdpi/pineapple.png b/tests/StatusBar/res/drawable-hdpi/pineapple.png
new file mode 100644
index 0000000..e62d3c8
--- /dev/null
+++ b/tests/StatusBar/res/drawable-hdpi/pineapple.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable-hdpi/pineapple2.png b/tests/StatusBar/res/drawable-hdpi/pineapple2.png
new file mode 100644
index 0000000..54146a8
--- /dev/null
+++ b/tests/StatusBar/res/drawable-hdpi/pineapple2.png
Binary files differ
diff --git a/tests/StatusBar/res/layout/notification_builder_test.xml b/tests/StatusBar/res/layout/notification_builder_test.xml
index 3c37a73..e1199c7 100644
--- a/tests/StatusBar/res/layout/notification_builder_test.xml
+++ b/tests/StatusBar/res/layout/notification_builder_test.xml
@@ -1,224 +1,220 @@
 <?xml version="1.0" encoding="utf-8"?>
-<LinearLayout
-        xmlns:android="http://schemas.android.com/apk/res/android"
+<ScrollView
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:orientation="horizontal"
-        android:paddingLeft="40dp"
-        android:paddingTop="12dp"
-        android:paddingRight="24dp"
-        android:paddingBottom="12dp"
+        xmlns:android="http://schemas.android.com/apk/res/android"
         >
-
     <LinearLayout
-            android:layout_width="220sp"
+            android:layout_width="match_parent"
             android:layout_height="match_parent"
-            android:layout_marginRight="24dp"
-            android:orientation="vertical"
+            android:orientation="horizontal"
             >
+
         <LinearLayout
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="horizontal"
+                android:layout_width="120dp"
+                android:layout_height="match_parent"
+                android:orientation="vertical"
                 >
+            <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    >
+                <Button
+                        style="@style/IdButton.Minus"
+                        android:id="@+id/clear_1"
+                        />
+                <TextView
+                        style="@style/IdTitle"
+                        android:text="1"
+                        />
+                <Button
+                        style="@style/IdButton.Plus"
+                        android:id="@+id/notify_1"
+                        />
+            </LinearLayout>
+            <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    >
+                <Button
+                        style="@style/IdButton.Minus"
+                        android:id="@+id/clear_2"
+                        />
+                <TextView
+                        style="@style/IdTitle"
+                        android:text="2"
+                        />
+                <Button
+                        style="@style/IdButton.Plus"
+                        android:id="@+id/notify_2"
+                        />
+            </LinearLayout>
+            <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    >
+                <Button
+                        style="@style/IdButton.Minus"
+                        android:id="@+id/clear_3"
+                        />
+                <TextView
+                        style="@style/IdTitle"
+                        android:text="3"
+                        />
+                <Button
+                        style="@style/IdButton.Plus"
+                        android:id="@+id/notify_3"
+                        />
+            </LinearLayout>
+            <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    >
+                <Button
+                        style="@style/IdButton.Minus"
+                        android:id="@+id/clear_4"
+                        />
+                <TextView
+                        style="@style/IdTitle"
+                        android:text="4"
+                        />
+                <Button
+                        style="@style/IdButton.Plus"
+                        android:id="@+id/notify_4"
+                        />
+            </LinearLayout>
+            <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    >
+                <Button
+                        style="@style/IdButton.Minus"
+                        android:id="@+id/clear_5"
+                        />
+                <TextView
+                        style="@style/IdTitle"
+                        android:text="5"
+                        />
+                <Button
+                        style="@style/IdButton.Plus"
+                        android:id="@+id/notify_5"
+                        />
+            </LinearLayout>
+            <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    >
+                <Button
+                        style="@style/IdButton.Minus"
+                        android:id="@+id/clear_6"
+                        />
+                <TextView
+                        style="@style/IdTitle"
+                        android:text="6"
+                        />
+                <Button
+                        style="@style/IdButton.Plus"
+                        android:id="@+id/notify_6"
+                        />
+            </LinearLayout>
+            <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    >
+                <Button
+                        style="@style/IdButton.Minus"
+                        android:id="@+id/clear_7"
+                        />
+                <TextView
+                        style="@style/IdTitle"
+                        android:text="7"
+                        />
+                <Button
+                        style="@style/IdButton.Plus"
+                        android:id="@+id/notify_7"
+                        />
+            </LinearLayout>
+            <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    >
+                <Button
+                        style="@style/IdButton.Minus"
+                        android:id="@+id/clear_8"
+                        />
+                <TextView
+                        style="@style/IdTitle"
+                        android:text="8"
+                        />
+                <Button
+                        style="@style/IdButton.Plus"
+                        android:id="@+id/notify_8"
+                        />
+            </LinearLayout>
+            <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    >
+                <Button
+                        style="@style/IdButton.Minus"
+                        android:id="@+id/clear_9"
+                        />
+                <TextView
+                        style="@style/IdTitle"
+                        android:text="9"
+                        />
+                <Button
+                        style="@style/IdButton.Plus"
+                        android:id="@+id/notify_9"
+                        />
+            </LinearLayout>
+            <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    >
+                <Button
+                        style="@style/IdButton.Minus"
+                        android:id="@+id/clear_10"
+                        />
+                <TextView
+                        style="@style/IdTitle"
+                        android:text="10"
+                        />
+                <Button
+                        style="@style/IdButton.Plus"
+                        android:id="@+id/notify_10"
+                        />
+            </LinearLayout>
+
             <Button
-                    style="@style/IdButton.Minus"
-                    android:id="@+id/clear_1"
-                    />
-            <TextView
-                    style="@style/IdTitle"
-                    android:text="1"
+                    android:id="@+id/clear_all"
+                    android:textAppearance="?android:attr/textAppearanceSmall"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="12dp"
+                    android:layout_marginBottom="12dp"
+                    android:text="Clear All"
                     />
             <Button
-                    style="@style/IdButton.Plus"
-                    android:id="@+id/notify_1"
+                    android:id="@+id/ten"
+                    android:textAppearance="?android:attr/textAppearanceSmall"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="Ten notifications"
                     />
-        </LinearLayout>
-        <LinearLayout
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="horizontal"
-                >
-            <Button
-                    style="@style/IdButton.Minus"
-                    android:id="@+id/clear_2"
-                    />
-            <TextView
-                    style="@style/IdTitle"
-                    android:text="2"
-                    />
-            <Button
-                    style="@style/IdButton.Plus"
-                    android:id="@+id/notify_2"
-                    />
-        </LinearLayout>
-        <LinearLayout
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="horizontal"
-                >
-            <Button
-                    style="@style/IdButton.Minus"
-                    android:id="@+id/clear_3"
-                    />
-            <TextView
-                    style="@style/IdTitle"
-                    android:text="3"
-                    />
-            <Button
-                    style="@style/IdButton.Plus"
-                    android:id="@+id/notify_3"
-                    />
-        </LinearLayout>
-        <LinearLayout
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="horizontal"
-                >
-            <Button
-                    style="@style/IdButton.Minus"
-                    android:id="@+id/clear_4"
-                    />
-            <TextView
-                    style="@style/IdTitle"
-                    android:text="4"
-                    />
-            <Button
-                    style="@style/IdButton.Plus"
-                    android:id="@+id/notify_4"
-                    />
-        </LinearLayout>
-        <LinearLayout
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="horizontal"
-                >
-            <Button
-                    style="@style/IdButton.Minus"
-                    android:id="@+id/clear_5"
-                    />
-            <TextView
-                    style="@style/IdTitle"
-                    android:text="5"
-                    />
-            <Button
-                    style="@style/IdButton.Plus"
-                    android:id="@+id/notify_5"
-                    />
-        </LinearLayout>
-        <LinearLayout
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="horizontal"
-                >
-            <Button
-                    style="@style/IdButton.Minus"
-                    android:id="@+id/clear_6"
-                    />
-            <TextView
-                    style="@style/IdTitle"
-                    android:text="6"
-                    />
-            <Button
-                    style="@style/IdButton.Plus"
-                    android:id="@+id/notify_6"
-                    />
-        </LinearLayout>
-        <LinearLayout
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="horizontal"
-                >
-            <Button
-                    style="@style/IdButton.Minus"
-                    android:id="@+id/clear_7"
-                    />
-            <TextView
-                    style="@style/IdTitle"
-                    android:text="7"
-                    />
-            <Button
-                    style="@style/IdButton.Plus"
-                    android:id="@+id/notify_7"
-                    />
-        </LinearLayout>
-        <LinearLayout
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="horizontal"
-                >
-            <Button
-                    style="@style/IdButton.Minus"
-                    android:id="@+id/clear_8"
-                    />
-            <TextView
-                    style="@style/IdTitle"
-                    android:text="8"
-                    />
-            <Button
-                    style="@style/IdButton.Plus"
-                    android:id="@+id/notify_8"
-                    />
-        </LinearLayout>
-        <LinearLayout
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="horizontal"
-                >
-            <Button
-                    style="@style/IdButton.Minus"
-                    android:id="@+id/clear_9"
-                    />
-            <TextView
-                    style="@style/IdTitle"
-                    android:text="9"
-                    />
-            <Button
-                    style="@style/IdButton.Plus"
-                    android:id="@+id/notify_9"
-                    />
-        </LinearLayout>
-        <LinearLayout
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="horizontal"
-                >
-            <Button
-                    style="@style/IdButton.Minus"
-                    android:id="@+id/clear_10"
-                    />
-            <TextView
-                    style="@style/IdTitle"
-                    android:text="10"
-                    />
-            <Button
-                    style="@style/IdButton.Plus"
-                    android:id="@+id/notify_10"
-                    />
+                    
         </LinearLayout>
 
-        <Button
-                android:id="@+id/clear_all"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="12dp"
-                android:layout_marginBottom="12dp"
-                android:text="Clear All"
-                />
-        <Button
-                android:id="@+id/ten"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:text="Ten notifications"
-                />
-                
-    </LinearLayout>
-
-    <ScrollView
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:layout_weight="1"
-            >
         <LinearLayout
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
@@ -818,7 +814,6 @@
 
 
         </LinearLayout>
-    </ScrollView>
+    </LinearLayout>
 
-
-</LinearLayout>
+</ScrollView>
diff --git a/tests/StatusBar/res/values-sw600dp/styles.xml b/tests/StatusBar/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..f29847c
--- /dev/null
+++ b/tests/StatusBar/res/values-sw600dp/styles.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<resources>
+    <style name="IdTitle">
+        <item name="android:textAppearance">?android:attr/textAppearanceLarge</item>
+        <item name="android:layout_width">30sp</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:gravity">center</item>
+        <item name="android:textStyle">bold</item>
+    </style>
+
+    <style name="IdButton">
+        <item name="android:textAppearance">?android:attr/textAppearanceLarge</item>
+        <item name="android:layout_width">0dp</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:layout_weight">1</item>
+        <item name="android:layout_marginRight">8dp</item>
+        <item name="android:layout_marginLeft">8dp</item>
+        <item name="android:textStyle">bold</item>
+    </style>
+
+    <style name="IdButton.Minus">
+        <item name="android:text">-</item>
+    </style>
+
+    <style name="IdButton.Plus">
+        <item name="android:text">+</item>
+    </style>
+
+    <style name="FieldTitle">
+        <item name="android:textAppearance">?android:attr/textAppearanceLarge</item>
+        <item name="android:layout_width">208sp</item>
+        <item name="android:layout_height">wrap_content</item>
+    </style>
+
+    <style name="FieldContents">
+        <item name="android:textAppearance">?android:attr/textAppearanceMedium</item>
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:layout_marginRight">20dp</item>
+    </style>
+
+    <style name="FieldContents.Disabled">
+        <item name="android:clickable">false</item>
+        <item name="android:visibility">gone</item>
+    </style>
+
+</resources>
+
+
diff --git a/tests/StatusBar/res/values/styles.xml b/tests/StatusBar/res/values/styles.xml
index e051efd..103a25a 100644
--- a/tests/StatusBar/res/values/styles.xml
+++ b/tests/StatusBar/res/values/styles.xml
@@ -16,21 +16,23 @@
 <resources>
 
     <style name="IdTitle">
-        <item name="android:textAppearance">?android:attr/textAppearanceLarge</item>
-        <item name="android:layout_width">30sp</item>
+        <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
+        <item name="android:layout_width">20sp</item>
         <item name="android:layout_height">wrap_content</item>
         <item name="android:gravity">center</item>
         <item name="android:textStyle">bold</item>
     </style>
 
     <style name="IdButton">
-        <item name="android:textAppearance">?android:attr/textAppearanceLarge</item>
-        <item name="android:layout_width">0dp</item>
+        <item name="android:textAppearance">?android:attr/textAppearanceMedium</item>
+        <item name="android:layout_width">10dp</item>
         <item name="android:layout_height">wrap_content</item>
         <item name="android:layout_weight">1</item>
-        <item name="android:layout_marginRight">8dp</item>
-        <item name="android:layout_marginLeft">8dp</item>
         <item name="android:textStyle">bold</item>
+        <item name="android:layout_marginLeft">1dp</item>
+        <item name="android:layout_marginRight">1dp</item>
+        <item name="android:paddingLeft">6dp</item>
+        <item name="android:paddingRight">6dp</item>
     </style>
 
     <style name="IdButton.Minus">
@@ -42,16 +44,16 @@
     </style>
 
     <style name="FieldTitle">
-        <item name="android:textAppearance">?android:attr/textAppearanceLarge</item>
-        <item name="android:layout_width">208sp</item>
+        <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
+        <item name="android:layout_width">wrap_content</item>
         <item name="android:layout_height">wrap_content</item>
     </style>
 
     <style name="FieldContents">
-        <item name="android:textAppearance">?android:attr/textAppearanceMedium</item>
+        <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
         <item name="android:layout_width">wrap_content</item>
         <item name="android:layout_height">wrap_content</item>
-        <item name="android:layout_marginRight">20dp</item>
+        <item name="android:layout_marginRight">4dp</item>
     </style>
 
     <style name="FieldContents.Disabled">
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 223b1fa..7852197 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -291,6 +291,27 @@
     return value.data;
 }
 
+static int32_t getResolvedIntegerAttribute(const ResTable* resTable, const ResXMLTree& tree,
+        uint32_t attrRes, String8* outError, int32_t defValue = -1)
+{
+    ssize_t idx = indexOfAttribute(tree, attrRes);
+    if (idx < 0) {
+        return defValue;
+    }
+    Res_value value;
+    if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
+        if (value.dataType == Res_value::TYPE_REFERENCE) {
+            resTable->resolveReference(&value, 0);
+        }
+        if (value.dataType < Res_value::TYPE_FIRST_INT
+                || value.dataType > Res_value::TYPE_LAST_INT) {
+            if (outError != NULL) *outError = "attribute is not an integer value";
+            return defValue;
+        }
+    }
+    return value.data;
+}
+
 static String8 getResolvedAttribute(const ResTable* resTable, const ResXMLTree& tree,
         uint32_t attrRes, String8* outError)
 {
@@ -320,11 +341,12 @@
 // These are attribute resource constants for the platform, as found
 // in android.R.attr
 enum {
+    LABEL_ATTR = 0x01010001,
+    ICON_ATTR = 0x01010002,
     NAME_ATTR = 0x01010003,
     VERSION_CODE_ATTR = 0x0101021b,
     VERSION_NAME_ATTR = 0x0101021c,
-    LABEL_ATTR = 0x01010001,
-    ICON_ATTR = 0x01010002,
+    SCREEN_ORIENTATION_ATTR = 0x0101001e,
     MIN_SDK_VERSION_ATTR = 0x0101020c,
     MAX_SDK_VERSION_ATTR = 0x01010271,
     REQ_TOUCH_SCREEN_ATTR = 0x01010227,
@@ -634,6 +656,8 @@
             bool reqDistinctMultitouchFeature = false;
             bool specScreenPortraitFeature = false;
             bool specScreenLandscapeFeature = false;
+            bool reqScreenPortraitFeature = false;
+            bool reqScreenLandscapeFeature = false;
             // 2.2 also added some other features that apps can request, but that
             // have no corresponding permission, so we cannot implement any
             // back-compatibility heuristic for them. The below are thus unnecessary
@@ -1022,6 +1046,18 @@
                             fprintf(stderr, "ERROR getting 'android:icon' attribute: %s\n", error.string());
                             goto bail;
                         }
+
+                        int32_t orien = getResolvedIntegerAttribute(&res, tree,
+                                SCREEN_ORIENTATION_ATTR, &error);
+                        if (error == "") {
+                            if (orien == 0 || orien == 6 || orien == 8) {
+                                // Requests landscape, sensorLandscape, or reverseLandscape.
+                                reqScreenLandscapeFeature = true;
+                            } else if (orien == 1 || orien == 7 || orien == 9) {
+                                // Requests portrait, sensorPortrait, or reversePortrait.
+                                reqScreenPortraitFeature = true;
+                            }
+                        }
                     } else if (tag == "uses-library") {
                         String8 libraryName = getAttribute(tree, NAME_ATTR, &error);
                         if (error != "") {
@@ -1182,12 +1218,16 @@
             }
 
             // Landscape/portrait-related compatibility logic
-            if (!specScreenLandscapeFeature && !specScreenPortraitFeature && (targetSdk < 13)) {
-                // If app has not specified whether it requires portrait or landscape
-                // and is targeting an API before Honeycomb MR2, then assume it requires
-                // both.
-                printf("uses-feature:'android.hardware.screen.portrait'\n");
-                printf("uses-feature:'android.hardware.screen.landscape'\n");
+            if (!specScreenLandscapeFeature && !specScreenPortraitFeature) {
+                // If the app has specified any activities in its manifest
+                // that request a specific orientation, then assume that
+                // orientation is required.
+                if (reqScreenLandscapeFeature) {
+                    printf("uses-feature:'android.hardware.screen.landscape'\n");
+                }
+                if (reqScreenPortraitFeature) {
+                    printf("uses-feature:'android.hardware.screen.portrait'\n");
+                }
             }
 
             if (hasMainActivity) {
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index 8e3ed93..b4448a9 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -1093,6 +1093,33 @@
     }
 
     @LayoutlibDelegate
+    /*package*/ static void native_drawTextWithGlyphs(int nativeCanvas, char[] text,
+            int index, int count, float x,
+            float y, int flags, int paint) {
+        native_drawText(nativeCanvas, text, index, count, x, y, flags, paint);
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void native_drawTextWithGlyphs(int nativeCanvas, String text,
+            int start, int end, float x,
+            float y, int flags, int paint) {
+        int count = end - start;
+        char[] buffer = TemporaryBuffer.obtain(count);
+        TextUtils.getChars(text, start, end, buffer, 0);
+
+        native_drawText(nativeCanvas, text, 0, count, x, y, flags, paint);
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void native_drawGlyphs(int nativeCanvas, char[] glyphs,
+            int index, int count, float x,
+            float y, int flags, int paint) {
+        // FIXME
+        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+                "Canvas.drawGlyphs is not supported.", null, null /*data*/);
+    }
+
+    @LayoutlibDelegate
     /*package*/ static void native_drawPosText(int nativeCanvas,
                                                   char[] text, int index,
                                                   int count, float[] pos,
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index 373f482..7777e19 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -940,9 +940,16 @@
     }
 
     @LayoutlibDelegate
+    /* package */static int native_getTextGlyphs(int native_object, String text, int start,
+            int end, int contextStart, int contextEnd, int flags, char[] glyphs) {
+        // FIXME
+        return 0;
+    }
+
+    @LayoutlibDelegate
     /*package*/ static float native_getTextRunAdvances(int native_object,
             char[] text, int index, int count, int contextIndex, int contextCount,
-            int flags, float[] advances, int advancesIndex) {
+            int flags, float[] advances, int advancesIndex, int reserved) {
         // get the delegate from the native int.
         Paint_Delegate delegate = sManager.getDelegate(native_object);
         if (delegate == null) {
@@ -986,14 +993,14 @@
     @LayoutlibDelegate
     /*package*/ static float native_getTextRunAdvances(int native_object,
             String text, int start, int end, int contextStart, int contextEnd,
-            int flags, float[] advances, int advancesIndex) {
+            int flags, float[] advances, int advancesIndex, int reserved) {
         // FIXME: support contextStart, contextEnd and direction flag
         int count = end - start;
         char[] buffer = TemporaryBuffer.obtain(count);
         TextUtils.getChars(text, start, end, buffer, 0);
 
         return native_getTextRunAdvances(native_object, buffer, 0, count, contextStart,
-                contextEnd - contextStart, flags, advances, advancesIndex);
+                contextEnd - contextStart, flags, advances, advancesIndex, reserved);
     }
 
     @LayoutlibDelegate
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 7380fc1..47fa68e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -25,11 +25,11 @@
 import com.android.ide.common.rendering.api.StyleResourceValue;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.BridgeConstants;
+import com.android.layoutlib.bridge.impl.ParserFactory;
 import com.android.layoutlib.bridge.impl.Stack;
 import com.android.resources.ResourceType;
 import com.android.util.Pair;
 
-import org.kxml2.io.KXmlParser;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -206,6 +206,9 @@
      * @param parser the parser to add.
      */
     public void pushParser(BridgeXmlBlockParser parser) {
+        if (ParserFactory.LOG_PARSER) {
+            System.out.println("PUSH " + parser.getParser().toString());
+        }
         mParserStack.push(parser);
     }
 
@@ -213,7 +216,10 @@
      * Removes the parser at the top of the stack
      */
     public void popParser() {
-        mParserStack.pop();
+        BridgeXmlBlockParser parser = mParserStack.pop();
+        if (ParserFactory.LOG_PARSER) {
+            System.out.println("POPD " + parser.getParser().toString());
+        }
     }
 
     /**
@@ -346,9 +352,7 @@
                 // we need to create a pull parser around the layout XML file, and then
                 // give that to our XmlBlockParser
                 try {
-                    KXmlParser parser = new KXmlParser();
-                    parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-                    parser.setInput(new FileInputStream(xml), "UTF-8"); //$NON-NLS-1$);
+                    XmlPullParser parser = ParserFactory.create(xml);
 
                     // set the resource ref to have correct view cookies
                     mBridgeInflater.setResourceReference(resource);
@@ -687,25 +691,25 @@
      */
     private BridgeTypedArray createStyleBasedTypedArray(StyleResourceValue style, int[] attrs)
             throws Resources.NotFoundException {
-        AtomicBoolean frameworkAttributes = new AtomicBoolean();
-        AtomicReference<String> attrName = new AtomicReference<String>();
-        TreeMap<Integer, String> styleNameMap = searchAttrs(attrs, frameworkAttributes, attrName);
 
         BridgeTypedArray ta = ((BridgeResources) mSystemResources).newTypeArray(attrs.length,
-                style.isFramework(), frameworkAttributes.get(), attrName.get());
+                false, true, null);
 
-        // loop through all the values in the style map, and init the TypedArray with
-        // the style we got from the dynamic id
-        for (Entry<Integer, String> styleAttribute : styleNameMap.entrySet()) {
-            int index = styleAttribute.getKey().intValue();
+        // for each attribute, get its name so that we can search it in the style
+        for (int i = 0 ; i < attrs.length ; i++) {
+            Pair<ResourceType, String> resolvedResource = Bridge.resolveResourceId(attrs[i]);
+            if (resolvedResource != null) {
+                String attrName = resolvedResource.getSecond();
+                // look for the value in the given style
+                ResourceValue resValue = mRenderResources.findItemInStyle(style, attrName);
 
-            String name = styleAttribute.getValue();
+                if (resValue != null) {
+                    // resolve it to make sure there are no references left.
+                    ta.bridgeSetValue(i, attrName, mRenderResources.resolveResValue(resValue));
 
-            // get the value from the style, or its parent styles.
-            ResourceValue resValue = mRenderResources.findItemInStyle(style, name);
-
-            // resolve it to make sure there are no references left.
-            ta.bridgeSetValue(index, name, mRenderResources.resolveResValue(resValue));
+                    resValue = mRenderResources.resolveResValue(resValue);
+                }
+            }
         }
 
         ta.sealArray();
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
index 7c90a31..4a6393d 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
@@ -22,10 +22,10 @@
 import com.android.ide.common.rendering.api.ResourceReference;
 import com.android.ide.common.rendering.api.ResourceValue;
 import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.ParserFactory;
 import com.android.resources.ResourceType;
 import com.android.util.Pair;
 
-import org.kxml2.io.KXmlParser;
 import org.xmlpull.v1.XmlPullParser;
 
 import android.content.Context;
@@ -36,7 +36,6 @@
 import android.view.ViewGroup;
 
 import java.io.File;
-import java.io.FileInputStream;
 
 /**
  * Custom implementation of {@link LayoutInflater} to handle custom views.
@@ -175,9 +174,7 @@
                 File f = new File(value.getValue());
                 if (f.isFile()) {
                     try {
-                        KXmlParser parser = new KXmlParser();
-                        parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-                        parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$
+                        XmlPullParser parser = ParserFactory.create(f);
 
                         BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser(
                                 parser, bridgeContext, false);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
index d0b90fb..1756496 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
@@ -21,12 +21,12 @@
 import com.android.ide.common.rendering.api.ResourceValue;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.BridgeConstants;
+import com.android.layoutlib.bridge.impl.ParserFactory;
 import com.android.layoutlib.bridge.impl.ResourceHelper;
 import com.android.ninepatch.NinePatch;
 import com.android.resources.ResourceType;
 import com.android.util.Pair;
 
-import org.kxml2.io.KXmlParser;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -131,14 +131,16 @@
                 platformStyleable, styleableName);
     }
 
-    private ResourceValue getResourceValue(int id, boolean[] platformResFlag_out) {
+    private Pair<String, ResourceValue> getResourceValue(int id, boolean[] platformResFlag_out) {
         // first get the String related to this id in the framework
         Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(id);
 
         if (resourceInfo != null) {
             platformResFlag_out[0] = true;
-            return mContext.getRenderResources().getFrameworkResource(
-                    resourceInfo.getFirst(), resourceInfo.getSecond());
+            String attributeName = resourceInfo.getSecond();
+
+            return Pair.of(attributeName, mContext.getRenderResources().getFrameworkResource(
+                    resourceInfo.getFirst(), attributeName));
         }
 
         // didn't find a match in the framework? look in the project.
@@ -147,8 +149,10 @@
 
             if (resourceInfo != null) {
                 platformResFlag_out[0] = false;
-                return mContext.getRenderResources().getProjectResource(
-                        resourceInfo.getFirst(), resourceInfo.getSecond());
+                String attributeName = resourceInfo.getSecond();
+
+                return Pair.of(attributeName, mContext.getRenderResources().getProjectResource(
+                        resourceInfo.getFirst(), attributeName));
             }
         }
 
@@ -157,10 +161,10 @@
 
     @Override
     public Drawable getDrawable(int id) throws NotFoundException {
-        ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
 
         if (value != null) {
-            return ResourceHelper.getDrawable(value, mContext);
+            return ResourceHelper.getDrawable(value.getSecond(), mContext);
         }
 
         // id was not found or not resolved. Throw a NotFoundException.
@@ -172,11 +176,11 @@
 
     @Override
     public int getColor(int id) throws NotFoundException {
-        ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
 
         if (value != null) {
             try {
-                return ResourceHelper.getColor(value.getValue());
+                return ResourceHelper.getColor(value.getSecond().getValue());
             } catch (NumberFormatException e) {
                 Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT, e.getMessage(), e,
                         null /*data*/);
@@ -193,10 +197,11 @@
 
     @Override
     public ColorStateList getColorStateList(int id) throws NotFoundException {
-        ResourceValue resValue = getResourceValue(id, mPlatformResourceFlag);
+        Pair<String, ResourceValue> resValue = getResourceValue(id, mPlatformResourceFlag);
 
         if (resValue != null) {
-            ColorStateList stateList = ResourceHelper.getColorStateList(resValue, mContext);
+            ColorStateList stateList = ResourceHelper.getColorStateList(resValue.getSecond(),
+                    mContext);
             if (stateList != null) {
                 return stateList;
             }
@@ -211,10 +216,10 @@
 
     @Override
     public CharSequence getText(int id) throws NotFoundException {
-        ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
 
         if (value != null) {
-            return value.getValue();
+            return value.getSecond().getValue();
         }
 
         // id was not found or not resolved. Throw a NotFoundException.
@@ -226,9 +231,10 @@
 
     @Override
     public XmlResourceParser getLayout(int id) throws NotFoundException {
-        ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+        Pair<String, ResourceValue> v = getResourceValue(id, mPlatformResourceFlag);
 
-        if (value != null) {
+        if (v != null) {
+            ResourceValue value = v.getSecond();
             XmlPullParser parser = null;
 
             try {
@@ -243,9 +249,7 @@
                     if (xml.isFile()) {
                         // we need to create a pull parser around the layout XML file, and then
                         // give that to our XmlBlockParser
-                        parser = new KXmlParser();
-                        parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-                        parser.setInput(new FileInputStream(xml), "UTF-8"); //$NON-NLS-1$);
+                        parser = ParserFactory.create(xml);
                     }
                 }
 
@@ -271,9 +275,10 @@
 
     @Override
     public XmlResourceParser getAnimation(int id) throws NotFoundException {
-        ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+        Pair<String, ResourceValue> v = getResourceValue(id, mPlatformResourceFlag);
 
-        if (value != null) {
+        if (v != null) {
+            ResourceValue value = v.getSecond();
             XmlPullParser parser = null;
 
             try {
@@ -281,9 +286,7 @@
                 if (xml.isFile()) {
                     // we need to create a pull parser around the layout XML file, and then
                     // give that to our XmlBlockParser
-                    parser = new KXmlParser();
-                    parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-                    parser.setInput(new FileInputStream(xml), "UTF-8"); //$NON-NLS-1$);
+                    parser = ParserFactory.create(xml);
 
                     return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]);
                 }
@@ -317,10 +320,10 @@
 
     @Override
     public float getDimension(int id) throws NotFoundException {
-        ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
 
         if (value != null) {
-            String v = value.getValue();
+            String v = value.getSecond().getValue();
 
             if (v != null) {
                 if (v.equals(BridgeConstants.MATCH_PARENT) ||
@@ -330,7 +333,8 @@
                     return LayoutParams.WRAP_CONTENT;
                 }
 
-                if (ResourceHelper.stringToFloat(v, mTmpValue) &&
+                if (ResourceHelper.parseFloatAttribute(
+                        value.getFirst(), v, mTmpValue, true /*requireUnit*/) &&
                         mTmpValue.type == TypedValue.TYPE_DIMENSION) {
                     return mTmpValue.getDimension(mMetrics);
                 }
@@ -346,13 +350,14 @@
 
     @Override
     public int getDimensionPixelOffset(int id) throws NotFoundException {
-        ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
 
         if (value != null) {
-            String v = value.getValue();
+            String v = value.getSecond().getValue();
 
             if (v != null) {
-                if (ResourceHelper.stringToFloat(v, mTmpValue) &&
+                if (ResourceHelper.parseFloatAttribute(
+                        value.getFirst(), v, mTmpValue, true /*requireUnit*/) &&
                         mTmpValue.type == TypedValue.TYPE_DIMENSION) {
                     return TypedValue.complexToDimensionPixelOffset(mTmpValue.data, mMetrics);
                 }
@@ -368,13 +373,14 @@
 
     @Override
     public int getDimensionPixelSize(int id) throws NotFoundException {
-        ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
 
         if (value != null) {
-            String v = value.getValue();
+            String v = value.getSecond().getValue();
 
             if (v != null) {
-                if (ResourceHelper.stringToFloat(v, mTmpValue) &&
+                if (ResourceHelper.parseFloatAttribute(
+                        value.getFirst(), v, mTmpValue, true /*requireUnit*/) &&
                         mTmpValue.type == TypedValue.TYPE_DIMENSION) {
                     return TypedValue.complexToDimensionPixelSize(mTmpValue.data, mMetrics);
                 }
@@ -390,10 +396,10 @@
 
     @Override
     public int getInteger(int id) throws NotFoundException {
-        ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
 
-        if (value != null && value.getValue() != null) {
-            String v = value.getValue();
+        if (value != null && value.getSecond().getValue() != null) {
+            String v = value.getSecond().getValue();
             int radix = 10;
             if (v.startsWith("0x")) {
                 v = v.substring(2);
@@ -445,10 +451,10 @@
 
     @Override
     public String getString(int id) throws NotFoundException {
-        ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
 
-        if (value != null && value.getValue() != null) {
-            return value.getValue();
+        if (value != null && value.getSecond().getValue() != null) {
+            return value.getSecond().getValue();
         }
 
         // id was not found or not resolved. Throw a NotFoundException.
@@ -461,13 +467,14 @@
     @Override
     public void getValue(int id, TypedValue outValue, boolean resolveRefs)
             throws NotFoundException {
-        ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
 
         if (value != null) {
-            String v = value.getValue();
+            String v = value.getSecond().getValue();
 
             if (v != null) {
-                if (ResourceHelper.stringToFloat(v, outValue)) {
+                if (ResourceHelper.parseFloatAttribute(value.getFirst(), v, outValue,
+                        false /*requireUnit*/)) {
                     return;
                 }
 
@@ -490,19 +497,17 @@
 
     @Override
     public XmlResourceParser getXml(int id) throws NotFoundException {
-        ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
 
         if (value != null) {
-            String v = value.getValue();
+            String v = value.getSecond().getValue();
 
             if (v != null) {
                 // check this is a file
-                File f = new File(value.getValue());
+                File f = new File(v);
                 if (f.isFile()) {
                     try {
-                        KXmlParser parser = new KXmlParser();
-                        parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-                        parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$);
+                        XmlPullParser parser = ParserFactory.create(f);
 
                         return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]);
                     } catch (XmlPullParserException e) {
@@ -535,9 +540,7 @@
 
         File f = new File(file);
         try {
-            KXmlParser parser = new KXmlParser();
-            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-            parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$);
+            XmlPullParser parser = ParserFactory.create(f);
 
             return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]);
         } catch (XmlPullParserException e) {
@@ -554,10 +557,10 @@
 
     @Override
     public InputStream openRawResource(int id) throws NotFoundException {
-        ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+        Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
 
         if (value != null) {
-            String path = value.getValue();
+            String path = value.getSecond().getValue();
 
             if (path != null) {
                 // check this is a file
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
index b1fbf08..260cdc8 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
@@ -24,10 +24,10 @@
 import com.android.internal.util.XmlUtils;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.BridgeConstants;
+import com.android.layoutlib.bridge.impl.ParserFactory;
 import com.android.layoutlib.bridge.impl.ResourceHelper;
 import com.android.resources.ResourceType;
 
-import org.kxml2.io.KXmlParser;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -41,7 +41,6 @@
 import android.view.ViewGroup.LayoutParams;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.util.Arrays;
 import java.util.Map;
 
@@ -211,7 +210,7 @@
         Map<String, Integer> map = null;
         if (mPlatformStyleable) {
             map = Bridge.getEnumValues(mNames[index]);
-        } else {
+        } else if (mStyleableName != null) {
             // get the styleable matching the resolved name
             RenderResources res = mContext.getRenderResources();
             ResourceValue styleable = res.getProjectResource(ResourceType.DECLARE_STYLEABLE,
@@ -331,9 +330,7 @@
         File f = new File(value);
         if (f.isFile()) {
             try {
-                KXmlParser parser = new KXmlParser();
-                parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-                parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$);
+                XmlPullParser parser = ParserFactory.create(f);
 
                 BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
                         parser, mContext, resValue.isFramework());
@@ -377,26 +374,7 @@
      */
     @Override
     public int getInteger(int index, int defValue) {
-        if (mResourceData[index] == null) {
-            return defValue;
-        }
-
-        String s = mResourceData[index].getValue();
-
-        if (s != null) {
-            try {
-                return Integer.parseInt(s);
-            } catch (NumberFormatException e) {
-                Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
-                        String.format(
-                            "\"%s\" in attribute \"%2$s\" cannont be converted to an integer.",
-                            s, mNames[index]), null /*data*/);
-
-                // The default value is returned below.
-            }
-        }
-
-        return defValue;
+        return getInt(index, defValue);
     }
 
     /**
@@ -434,7 +412,7 @@
             return defValue;
         }
 
-        if (ResourceHelper.stringToFloat(s, mValue)) {
+        if (ResourceHelper.parseFloatAttribute(mNames[index], s, mValue, true /*requireUnit*/)) {
             return mValue.getDimension(mBridgeResources.mMetrics);
         }
 
@@ -561,7 +539,7 @@
             throw new RuntimeException();
         }
 
-        if (ResourceHelper.stringToFloat(s, mValue)) {
+        if (ResourceHelper.parseFloatAttribute(mNames[index], s, mValue, true /*requireUnit*/)) {
             float f = mValue.getDimension(mBridgeResources.mMetrics);
 
             final int res = (int)(f+0.5f);
@@ -599,14 +577,15 @@
             return defValue;
         }
 
-        if (ResourceHelper.stringToFloat(value, mValue)) {
+        if (ResourceHelper.parseFloatAttribute(mNames[index], value, mValue,
+                false /*requireUnit*/)) {
             return mValue.getFraction(base, pbase);
         }
 
         // looks like we were unable to resolve the fraction value
         Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
                 String.format(
-                    "\"%1$s\" in attribute \"%2$s\" cannont be converted to a fraction.",
+                    "\"%1$s\" in attribute \"%2$s\" cannot be converted to a fraction.",
                     value, mNames[index]), null /*data*/);
 
         return defValue;
@@ -803,7 +782,8 @@
 
         String s = mResourceData[index].getValue();
 
-        return ResourceHelper.stringToFloat(s, outValue);
+        return ResourceHelper.parseFloatAttribute(mNames[index], s, outValue,
+                false /*requireUnit*/);
     }
 
     /**
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java
index 70dbaa4..1016b32 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java
@@ -18,6 +18,7 @@
 
 
 import com.android.ide.common.rendering.api.ILayoutPullParser;
+import com.android.layoutlib.bridge.impl.ParserFactory;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -54,6 +55,10 @@
      * @param platformFile Indicates whether the the file is a platform file or not.
      */
     public BridgeXmlBlockParser(XmlPullParser parser, BridgeContext context, boolean platformFile) {
+        if (ParserFactory.LOG_PARSER) {
+            System.out.println("CRTE " + parser.toString());
+        }
+
         mParser = parser;
         mContext = context;
         mPlatformFile = platformFile;
@@ -65,6 +70,10 @@
         }
     }
 
+    public XmlPullParser getParser() {
+        return mParser;
+    }
+
     public boolean isPlatformFile() {
         return mPlatformFile;
     }
@@ -247,18 +256,63 @@
     public int next() throws XmlPullParserException, IOException {
         if (!mStarted) {
             mStarted = true;
+
+            if (ParserFactory.LOG_PARSER) {
+                System.out.println("STRT " + mParser.toString());
+            }
+
             return START_DOCUMENT;
         }
+
         int ev = mParser.next();
 
+        if (ParserFactory.LOG_PARSER) {
+            System.out.println("NEXT " + mParser.toString() + " " +
+                    eventTypeToString(mEventType) + " -> " + eventTypeToString(ev));
+        }
+
         if (ev == END_TAG && mParser.getDepth() == 1) {
             // done with parser remove it from the context stack.
             ensurePopped();
+
+            if (ParserFactory.LOG_PARSER) {
+                System.out.println("");
+            }
         }
+
         mEventType = ev;
         return ev;
     }
 
+    public static String eventTypeToString(int eventType) {
+        switch (eventType) {
+            case START_DOCUMENT:
+                return "START_DOC";
+            case END_DOCUMENT:
+                return "END_DOC";
+            case START_TAG:
+                return "START_TAG";
+            case END_TAG:
+                return "END_TAG";
+            case TEXT:
+                return "TEXT";
+            case CDSECT:
+                return "CDSECT";
+            case ENTITY_REF:
+                return "ENTITY_REF";
+            case IGNORABLE_WHITESPACE:
+                return "IGNORABLE_WHITESPACE";
+            case PROCESSING_INSTRUCTION:
+                return "PROCESSING_INSTRUCTION";
+            case COMMENT:
+                return "COMMENT";
+            case DOCDECL:
+                return "DOCDECL";
+        }
+
+        return "????";
+    }
+
     public void require(int type, String namespace, String name)
             throws XmlPullParserException {
         if (type != getEventType()
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
index 060e6ee..df701d5 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
@@ -22,11 +22,11 @@
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.android.BridgeContext;
 import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
+import com.android.layoutlib.bridge.impl.ParserFactory;
 import com.android.layoutlib.bridge.impl.ResourceHelper;
 import com.android.resources.Density;
 import com.android.resources.ResourceType;
 
-import org.kxml2.io.KXmlParser;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -60,7 +60,7 @@
 
     protected abstract TextView getStyleableTextView();
 
-    protected CustomBar(Context context, Density density, String layoutPath)
+    protected CustomBar(Context context, Density density, String layoutPath, String name)
             throws XmlPullParserException {
         super(context);
         setOrientation(LinearLayout.HORIZONTAL);
@@ -69,11 +69,8 @@
         LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
 
-        KXmlParser parser = new KXmlParser();
-        parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-        parser.setInput(
-                getClass().getResourceAsStream(layoutPath),
-                "UTF8"); //$NON-NLS-1$
+        XmlPullParser parser = ParserFactory.create(getClass().getResourceAsStream(layoutPath),
+                name);
 
         BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser(
                 parser, (BridgeContext) context, false /*platformFile*/);
@@ -230,7 +227,8 @@
 
                 if (textSize != null) {
                     TypedValue out = new TypedValue();
-                    if (ResourceHelper.stringToFloat(textSize.getValue(), out)) {
+                    if (ResourceHelper.parseFloatAttribute("textSize", textSize.getValue(), out,
+                            true /*requireUnit*/)) {
                         textView.setTextSize(
                                 out.getDimension(bridgeContext.getResources().mMetrics));
                     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java
index 3af4e3a..f6edea4 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java
@@ -29,7 +29,7 @@
 
     public FakeActionBar(Context context, Density density, String label, String icon)
             throws XmlPullParserException {
-        super(context, density, "/bars/action_bar.xml");
+        super(context, density, "/bars/action_bar.xml", "action_bar.xml");
 
         // Cannot access the inside items through id because no R.id values have been
         // created for them.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java
index 9fab51a..5569e06 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java
@@ -30,7 +30,7 @@
 public class PhoneSystemBar extends CustomBar {
 
     public PhoneSystemBar(Context context, Density density) throws XmlPullParserException {
-        super(context, density, "/bars/phone_system_bar.xml");
+        super(context, density, "/bars/phone_system_bar.xml", "phone_system_bar.xml");
 
         setGravity(mGravity | Gravity.RIGHT);
         setBackgroundColor(0xFF000000);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TabletSystemBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TabletSystemBar.java
index 5ca68fa..456ddb4 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TabletSystemBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TabletSystemBar.java
@@ -29,7 +29,7 @@
 public class TabletSystemBar extends CustomBar {
 
     public TabletSystemBar(Context context, Density density) throws XmlPullParserException {
-        super(context, density, "/bars/tablet_system_bar.xml");
+        super(context, density, "/bars/tablet_system_bar.xml", "tablet_system_bar.xml");
 
         setBackgroundColor(0xFF000000);
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TitleBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TitleBar.java
index d7401d9..5f5ebc4 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TitleBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TitleBar.java
@@ -29,7 +29,7 @@
 
     public TitleBar(Context context, Density density, String label)
             throws XmlPullParserException {
-        super(context, density, "/bars/title_bar.xml");
+        super(context, density, "/bars/title_bar.xml", "title_bar.xml");
 
         // Cannot access the inside items through id because no R.id values have been
         // created for them.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java
new file mode 100644
index 0000000..a235ec3
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge.impl;
+
+
+import org.kxml2.io.KXmlParser;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+
+/**
+ * A factory for {@link XmlPullParser}.
+ *
+ */
+public class ParserFactory {
+
+    private final static String ENCODING = "UTF-8"; //$NON-NLS-1$
+
+    public final static boolean LOG_PARSER = false;
+
+    public static XmlPullParser create(File f)
+            throws XmlPullParserException, FileNotFoundException {
+        KXmlParser parser = instantiateParser(f.getName());
+        parser.setInput(new FileInputStream(f), ENCODING);
+        return parser;
+    }
+
+    public static XmlPullParser create(InputStream stream, String name)
+            throws XmlPullParserException {
+        KXmlParser parser = instantiateParser(name);
+        parser.setInput(stream, ENCODING);
+        return parser;
+    }
+
+    private static KXmlParser instantiateParser(String name) throws XmlPullParserException {
+        KXmlParser parser;
+        if (name != null) {
+            parser = new CustomParser(name);
+        } else {
+            parser = new KXmlParser();
+        }
+        parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
+        return parser;
+    }
+
+    private static class CustomParser extends KXmlParser {
+        private final String mName;
+
+        CustomParser(String name) {
+            super();
+            mName = name;
+        }
+
+        @Override
+        public String toString() {
+            return mName;
+        }
+    }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index b800519..aa30e29 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -984,7 +984,8 @@
                         "status_bar_height");
 
                 if (value != null) {
-                    TypedValue typedValue = ResourceHelper.getValue(value.getValue());
+                    TypedValue typedValue = ResourceHelper.getValue("status_bar_height",
+                            value.getValue(), true /*requireUnit*/);
                     if (typedValue != null) {
                         // compute the pixel value based on the display metrics
                         mStatusBarSize = (int)typedValue.getDimension(metrics);
@@ -1016,7 +1017,8 @@
 
             if (value != null) {
                 // get the numerical value, if available
-                TypedValue typedValue = ResourceHelper.getValue(value.getValue());
+                TypedValue typedValue = ResourceHelper.getValue("actionBarSize", value.getValue(),
+                        true /*requireUnit*/);
                 if (typedValue != null) {
                     // compute the pixel value based on the display metrics
                     mActionBarSize = (int)typedValue.getDimension(metrics);
@@ -1040,7 +1042,8 @@
 
                 if (value != null) {
                     // get the numerical value, if available
-                    TypedValue typedValue = ResourceHelper.getValue(value.getValue());
+                    TypedValue typedValue = ResourceHelper.getValue("windowTitleSize",
+                            value.getValue(), true /*requireUnit*/);
                     if (typedValue != null) {
                         // compute the pixel value based on the display metrics
                         mTitleBarSize = (int)typedValue.getDimension(metrics);
@@ -1062,7 +1065,8 @@
                     "status_bar_height");
 
             if (value != null) {
-                TypedValue typedValue = ResourceHelper.getValue(value.getValue());
+                TypedValue typedValue = ResourceHelper.getValue("status_bar_height",
+                        value.getValue(), true /*requireUnit*/);
                 if (typedValue != null) {
                     // compute the pixel value based on the display metrics
                     mSystemBarSize = (int)typedValue.getDimension(metrics);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
index e5efa4e..6dcb693 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
@@ -27,7 +27,6 @@
 import com.android.ninepatch.NinePatchChunk;
 import com.android.resources.Density;
 
-import org.kxml2.io.KXmlParser;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -121,9 +120,7 @@
                 try {
                     // let the framework inflate the ColorStateList from the XML file, by
                     // providing an XmlPullParser
-                    KXmlParser parser = new KXmlParser();
-                    parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-                    parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$);
+                    XmlPullParser parser = ParserFactory.create(f);
 
                     BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
                             parser, context, resValue.isFramework());
@@ -203,9 +200,7 @@
             if (f.isFile()) {
                 try {
                     // let the framework inflate the Drawable from the XML file.
-                    KXmlParser parser = new KXmlParser();
-                    parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-                    parser.setInput(new FileInputStream(f), "UTF-8"); //$NON-NLS-1$);
+                    XmlPullParser parser = ParserFactory.create(f);
 
                     BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
                             parser, context, value.isFramework());
@@ -341,11 +336,11 @@
     };
 
     /**
-     * Returns the raw value from the given string.
+     * Returns the raw value from the given attribute float-type value string.
      * This object is only valid until the next call on to {@link ResourceHelper}.
      */
-    public static TypedValue getValue(String s) {
-        if (stringToFloat(s, mValue)) {
+    public static TypedValue getValue(String attribute, String value, boolean requireUnit) {
+        if (parseFloatAttribute(attribute, value, mValue, requireUnit)) {
             return mValue;
         }
 
@@ -353,22 +348,27 @@
     }
 
     /**
-     * Convert the string into a {@link TypedValue}.
-     * @param s
-     * @param outValue
+     * Parse a float attribute and return the parsed value into a given TypedValue.
+     * @param attribute the name of the attribute. Can be null if <var>requireUnit</var> is false.
+     * @param value the string value of the attribute
+     * @param outValue the TypedValue to receive the parsed value
+     * @param requireUnit whether the value is expected to contain a unit.
      * @return true if success.
      */
-    public static boolean stringToFloat(String s, TypedValue outValue) {
+    public static boolean parseFloatAttribute(String attribute, String value,
+            TypedValue outValue, boolean requireUnit) {
+        assert requireUnit == false || attribute != null;
+
         // remove the space before and after
-        s = s.trim();
-        int len = s.length();
+        value = value.trim();
+        int len = value.length();
 
         if (len <= 0) {
             return false;
         }
 
         // check that there's no non ascii characters.
-        char[] buf = s.toCharArray();
+        char[] buf = value.toCharArray();
         for (int i = 0 ; i < len ; i++) {
             if (buf[i] > 255) {
                 return false;
@@ -381,7 +381,7 @@
         }
 
         // now look for the string that is after the float...
-        Matcher m = sFloatPattern.matcher(s);
+        Matcher m = sFloatPattern.matcher(value);
         if (m.matches()) {
             String f_str = m.group(1);
             String end = m.group(2);
@@ -397,45 +397,7 @@
             if (end.length() > 0 && end.charAt(0) != ' ') {
                 // Might be a unit...
                 if (parseUnit(end, outValue, sFloatOut)) {
-
-                    f *= sFloatOut[0];
-                    boolean neg = f < 0;
-                    if (neg) {
-                        f = -f;
-                    }
-                    long bits = (long)(f*(1<<23)+.5f);
-                    int radix;
-                    int shift;
-                    if ((bits&0x7fffff) == 0) {
-                        // Always use 23p0 if there is no fraction, just to make
-                        // things easier to read.
-                        radix = TypedValue.COMPLEX_RADIX_23p0;
-                        shift = 23;
-                    } else if ((bits&0xffffffffff800000L) == 0) {
-                        // Magnitude is zero -- can fit in 0 bits of precision.
-                        radix = TypedValue.COMPLEX_RADIX_0p23;
-                        shift = 0;
-                    } else if ((bits&0xffffffff80000000L) == 0) {
-                        // Magnitude can fit in 8 bits of precision.
-                        radix = TypedValue.COMPLEX_RADIX_8p15;
-                        shift = 8;
-                    } else if ((bits&0xffffff8000000000L) == 0) {
-                        // Magnitude can fit in 16 bits of precision.
-                        radix = TypedValue.COMPLEX_RADIX_16p7;
-                        shift = 16;
-                    } else {
-                        // Magnitude needs entire range, so no fractional part.
-                        radix = TypedValue.COMPLEX_RADIX_23p0;
-                        shift = 23;
-                    }
-                    int mantissa = (int)(
-                        (bits>>shift) & TypedValue.COMPLEX_MANTISSA_MASK);
-                    if (neg) {
-                        mantissa = (-mantissa) & TypedValue.COMPLEX_MANTISSA_MASK;
-                    }
-                    outValue.data |=
-                        (radix<<TypedValue.COMPLEX_RADIX_SHIFT)
-                        | (mantissa<<TypedValue.COMPLEX_MANTISSA_SHIFT);
+                    computeTypedValue(outValue, f, sFloatOut[0]);
                     return true;
                 }
                 return false;
@@ -446,8 +408,20 @@
 
             if (end.length() == 0) {
                 if (outValue != null) {
-                    outValue.type = TypedValue.TYPE_FLOAT;
-                    outValue.data = Float.floatToIntBits(f);
+                    if (requireUnit == false) {
+                        outValue.type = TypedValue.TYPE_FLOAT;
+                        outValue.data = Float.floatToIntBits(f);
+                    } else {
+                        // no unit when required? Use dp and out an error.
+                        applyUnit(sUnitNames[1], outValue, sFloatOut);
+                        computeTypedValue(outValue, f, sFloatOut[0]);
+
+                        Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE,
+                                String.format(
+                                        "Dimension \"%1$s\" in attribute \"%2$s\" is missing unit!",
+                                        value, attribute),
+                                null);
+                    }
                     return true;
                 }
             }
@@ -456,20 +430,64 @@
         return false;
     }
 
+    private static void computeTypedValue(TypedValue outValue, float value, float scale) {
+        value *= scale;
+        boolean neg = value < 0;
+        if (neg) {
+            value = -value;
+        }
+        long bits = (long)(value*(1<<23)+.5f);
+        int radix;
+        int shift;
+        if ((bits&0x7fffff) == 0) {
+            // Always use 23p0 if there is no fraction, just to make
+            // things easier to read.
+            radix = TypedValue.COMPLEX_RADIX_23p0;
+            shift = 23;
+        } else if ((bits&0xffffffffff800000L) == 0) {
+            // Magnitude is zero -- can fit in 0 bits of precision.
+            radix = TypedValue.COMPLEX_RADIX_0p23;
+            shift = 0;
+        } else if ((bits&0xffffffff80000000L) == 0) {
+            // Magnitude can fit in 8 bits of precision.
+            radix = TypedValue.COMPLEX_RADIX_8p15;
+            shift = 8;
+        } else if ((bits&0xffffff8000000000L) == 0) {
+            // Magnitude can fit in 16 bits of precision.
+            radix = TypedValue.COMPLEX_RADIX_16p7;
+            shift = 16;
+        } else {
+            // Magnitude needs entire range, so no fractional part.
+            radix = TypedValue.COMPLEX_RADIX_23p0;
+            shift = 23;
+        }
+        int mantissa = (int)(
+            (bits>>shift) & TypedValue.COMPLEX_MANTISSA_MASK);
+        if (neg) {
+            mantissa = (-mantissa) & TypedValue.COMPLEX_MANTISSA_MASK;
+        }
+        outValue.data |=
+            (radix<<TypedValue.COMPLEX_RADIX_SHIFT)
+            | (mantissa<<TypedValue.COMPLEX_MANTISSA_SHIFT);
+    }
+
     private static boolean parseUnit(String str, TypedValue outValue, float[] outScale) {
         str = str.trim();
 
         for (UnitEntry unit : sUnitNames) {
             if (unit.name.equals(str)) {
-                outValue.type = unit.type;
-                outValue.data = unit.unit << TypedValue.COMPLEX_UNIT_SHIFT;
-                outScale[0] = unit.scale;
-
+                applyUnit(unit, outValue, outScale);
                 return true;
             }
         }
 
         return false;
     }
+
+    private static void applyUnit(UnitEntry unit, TypedValue outValue, float[] outScale) {
+        outValue.type = unit.type;
+        outValue.data = unit.unit << TypedValue.COMPLEX_UNIT_SHIFT;
+        outScale[0] = unit.scale;
+    }
 }
 
diff --git a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
index e6dc646..98f8529 100644
--- a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
+++ b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
@@ -44,6 +44,16 @@
     // --- Native methods accessing ICU's database.
 
     @LayoutlibDelegate
+    /*package*/ static String getIcuVersion() {
+        return "unknown_layoutlib";
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static String getUnicodeVersion() {
+        return "5.2";
+    }
+
+    @LayoutlibDelegate
     /*package*/ static String[] getAvailableBreakIteratorLocalesNative() {
         return new String[0];
     }
@@ -74,17 +84,27 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static String getCurrencyCodeNative(String locale) {
+    /*package*/ static String[] getAvailableCurrencyCodes() {
+        return new String[0];
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static String getCurrencyCode(String locale) {
         return "";
     }
 
     @LayoutlibDelegate
-    /*package*/ static int getCurrencyFractionDigitsNative(String currencyCode) {
+    /*package*/ static String getCurrencyDisplayName(String locale, String currencyCode) {
+        return "";
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static int getCurrencyFractionDigits(String currencyCode) {
         return 0;
     }
 
     @LayoutlibDelegate
-    /*package*/ static String getCurrencySymbolNative(String locale, String currencyCode) {
+    /*package*/ static String getCurrencySymbol(String locale, String currencyCode) {
         return "";
     }
 
@@ -114,6 +134,12 @@
     }
 
     @LayoutlibDelegate
+    /*package*/ static String addLikelySubtags(String locale) {
+        return "";
+    }
+
+
+    @LayoutlibDelegate
     /*package*/ static String[] getISOLanguagesNative() {
         return Locale.getISOLanguages();
     }
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java
index 70d5446..96436fe 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java
@@ -16,14 +16,11 @@
 
 package com.android.layoutlib.bridge.android;
 
-import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
+import com.android.layoutlib.bridge.impl.ParserFactory;
 
-import org.kxml2.io.KXmlParser;
 import org.w3c.dom.Node;
 import org.xmlpull.v1.XmlPullParser;
 
-import java.io.InputStream;
-
 import junit.framework.TestCase;
 
 public class BridgeXmlBlockParserTest extends TestCase {
@@ -39,12 +36,12 @@
     }
 
     public void testXmlBlockParser() throws Exception {
-        XmlPullParser parser = new KXmlParser();
-        parser = new BridgeXmlBlockParser(parser, null, false /* platformResourceFlag */);
 
-        InputStream input = this.getClass().getClassLoader().getResourceAsStream(
-            "com/android/layoutlib/testdata/layout1.xml");
-        parser.setInput(input, "UTF-8"); //$NON-NLS-1$
+        XmlPullParser parser = ParserFactory.create(
+                getClass().getResourceAsStream("com/android/layoutlib/testdata/layout1.xml"),
+                        "layout1.xml");
+
+        parser = new BridgeXmlBlockParser(parser, null, false /* platformResourceFlag */);
 
         assertEquals(XmlPullParser.START_DOCUMENT, parser.next());
 
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 3df3736..2a033d1 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -1028,9 +1028,6 @@
         boolean wifiTethered = false;
         boolean wifiAvailable = false;
 
-        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
-        INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
-
         if (mCm == null) {
             mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
         }
@@ -1043,14 +1040,14 @@
 
                     InterfaceConfiguration ifcg = null;
                     try {
-                        ifcg = service.getInterfaceConfig(intf);
+                        ifcg = nwService.getInterfaceConfig(intf);
                         if (ifcg != null) {
                             /* IP/netmask: 192.168.43.1/255.255.255.0 */
                             ifcg.addr = new LinkAddress(NetworkUtils.numericToInetAddress(
                                     "192.168.43.1"), 24);
                             ifcg.interfaceFlags = "[up]";
 
-                            service.setInterfaceConfig(intf, ifcg);
+                            nwService.setInterfaceConfig(intf, ifcg);
                         }
                     } catch (Exception e) {
                         Log.e(TAG, "Error configuring interface " + intf + ", :" + e);
@@ -1374,7 +1371,7 @@
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
                 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
         intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, mNetworkInfo);
-        intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, mLinkProperties);
+        intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties (mLinkProperties));
         if (bssid != null)
             intent.putExtra(WifiManager.EXTRA_BSSID, bssid);
         mContext.sendStickyBroadcast(intent);
@@ -1390,7 +1387,7 @@
     private void sendLinkConfigurationChangedBroadcast() {
         Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-        intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, mLinkProperties);
+        intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties));
         mContext.sendBroadcast(intent);
     }
 
@@ -1438,7 +1435,6 @@
             /* BSSID is valid only in ASSOCIATING state */
             mWifiInfo.setBSSID(stateChangeResult.BSSID);
         }
-        setNetworkDetailedState(WifiInfo.getDetailedStateOf(state));
 
         mSupplicantStateTracker.sendMessage(Message.obtain(message));
         mWpsStateMachine.sendMessage(Message.obtain(message));
@@ -1451,19 +1447,23 @@
      * using the interface, stopping DHCP & disabling interface
      */
     private void handleNetworkDisconnect() {
-        Log.d(TAG, "Reset connections and stopping DHCP");
+        Log.d(TAG, "Stopping DHCP and clearing IP");
 
         /*
-         * Reset connections & stop DHCP
+         * stop DHCP
          */
-        NetworkUtils.resetConnections(mInterfaceName);
-
         if (mDhcpStateMachine != null) {
             mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
             mDhcpStateMachine.quit();
             mDhcpStateMachine = null;
         }
 
+        try {
+            nwService.clearInterfaceAddresses(mInterfaceName);
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to clear IP addresses on disconnect" + e);
+        }
+
         /* Reset data structures */
         mWifiInfo.setInetAddress(null);
         mWifiInfo.setBSSID(null);
@@ -1547,7 +1547,6 @@
             if (!linkProperties.equals(mLinkProperties)) {
                 Log.d(TAG, "Link configuration changed for netId: " + mLastNetworkId
                     + " old: " + mLinkProperties + "new: " + linkProperties);
-                NetworkUtils.resetConnections(mInterfaceName);
                 mLinkProperties = linkProperties;
                 sendLinkConfigurationChangedBroadcast();
             }
@@ -2660,13 +2659,11 @@
             } else {
                 DhcpInfoInternal dhcpInfoInternal = WifiConfigStore.getIpConfiguration(
                         mLastNetworkId);
-                IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
-                INetworkManagementService netd = INetworkManagementService.Stub.asInterface(b);
                 InterfaceConfiguration ifcg = new InterfaceConfiguration();
                 ifcg.addr = dhcpInfoInternal.makeLinkAddress();
                 ifcg.interfaceFlags = "[up]";
                 try {
-                    netd.setInterfaceConfig(mInterfaceName, ifcg);
+                    nwService.setInterfaceConfig(mInterfaceName, ifcg);
                     Log.v(TAG, "Static IP configuration succeeded");
                     sendMessage(CMD_STATIC_IP_SUCCESS, dhcpInfoInternal);
                 } catch (RemoteException re) {
@@ -2820,7 +2817,6 @@
                     if (mWifiInfo.getNetworkId() == result.getNetworkId()) {
                         if (result.hasIpChanged()) {
                             Log.d(TAG,"Reconfiguring IP on connection");
-                            NetworkUtils.resetConnections(mInterfaceName);
                             transitionTo(mConnectingState);
                         }
                         if (result.hasProxyChanged()) {
@@ -2979,7 +2975,12 @@
                     /* Ignore network disconnect */
                 case NETWORK_DISCONNECTION_EVENT:
                     break;
-               case CMD_START_SCAN:
+                case SUPPLICANT_STATE_CHANGE_EVENT:
+                    StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
+                    setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state));
+                    /* ConnectModeState does the rest of the handling */
+                    return NOT_HANDLED;
+                case CMD_START_SCAN:
                     /* Disable background scan temporarily during a regular scan */
                     if (mEnableBackgroundScan) {
                         WifiNative.enableBackgroundScanCommand(false);