Merge "Revert "Split libmedia into libmedia and libmedia_native""
diff --git a/api/current.txt b/api/current.txt
index 665b054..4398ea3 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3694,6 +3694,7 @@
 
   public static class Notification.Builder {
     ctor public Notification.Builder(android.content.Context);
+    method public android.app.Notification.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent);
     method public android.app.Notification.Builder addKind(java.lang.String);
     method public android.app.Notification getNotification();
     method public android.app.Notification.Builder setAutoCancel(boolean);
@@ -5203,6 +5204,7 @@
     field public static final java.lang.String LAYOUT_INFLATER_SERVICE = "layout_inflater";
     field public static final java.lang.String LOCATION_SERVICE = "location";
     field public static final int MODE_APPEND = 32768; // 0x8000
+    field public static final int MODE_ENABLE_WRITE_AHEAD_LOGGING = 8; // 0x8
     field public static final int MODE_MULTI_PROCESS = 4; // 0x4
     field public static final int MODE_PRIVATE = 0; // 0x0
     field public static final int MODE_WORLD_READABLE = 1; // 0x1
@@ -7312,6 +7314,7 @@
     method public static android.database.sqlite.SQLiteDatabase create(android.database.sqlite.SQLiteDatabase.CursorFactory);
     method public int delete(java.lang.String, java.lang.String, java.lang.String[]);
     method public static boolean deleteDatabase(java.io.File);
+    method public void disableWriteAheadLogging();
     method public boolean enableWriteAheadLogging();
     method public void endTransaction();
     method public void execSQL(java.lang.String) throws android.database.SQLException;
@@ -7332,6 +7335,7 @@
     method public deprecated boolean isDbLockedByOtherThreads();
     method public boolean isOpen();
     method public boolean isReadOnly();
+    method public boolean isWriteAheadLoggingEnabled();
     method public deprecated void markTableSyncable(java.lang.String, java.lang.String);
     method public deprecated void markTableSyncable(java.lang.String, java.lang.String, java.lang.String);
     method public boolean needUpgrade(int);
@@ -7373,6 +7377,7 @@
     field public static final int CONFLICT_REPLACE = 5; // 0x5
     field public static final int CONFLICT_ROLLBACK = 1; // 0x1
     field public static final int CREATE_IF_NECESSARY = 268435456; // 0x10000000
+    field public static final int ENABLE_WRITE_AHEAD_LOGGING = 536870912; // 0x20000000
     field public static final int MAX_SQL_CACHE_SIZE = 100; // 0x64
     field public static final int NO_LOCALIZED_COLLATORS = 16; // 0x10
     field public static final int OPEN_READONLY = 1; // 0x1
@@ -7436,6 +7441,7 @@
     method public void onDowngrade(android.database.sqlite.SQLiteDatabase, int, int);
     method public void onOpen(android.database.sqlite.SQLiteDatabase);
     method public abstract void onUpgrade(android.database.sqlite.SQLiteDatabase, int, int);
+    method public void setWriteAheadLoggingEnabled(boolean);
   }
 
   public class SQLiteOutOfMemoryException extends android.database.sqlite.SQLiteException {
@@ -23175,6 +23181,7 @@
     method public void buildLayer();
     method public boolean callOnClick();
     method public boolean canResolveLayoutDirection();
+    method public boolean canResolveTextDirection();
     method public boolean canScrollHorizontally(int);
     method public boolean canScrollVertically(int);
     method public void cancelLongPress();
@@ -23566,7 +23573,6 @@
     method public boolean willNotCacheDrawing();
     method public boolean willNotDraw();
     field public static final android.util.Property ALPHA;
-    field protected static int DEFAULT_TEXT_DIRECTION;
     field public static final int DRAWING_CACHE_QUALITY_AUTO = 0; // 0x0
     field public static final int DRAWING_CACHE_QUALITY_HIGH = 1048576; // 0x100000
     field public static final int DRAWING_CACHE_QUALITY_LOW = 524288; // 0x80000
@@ -23600,10 +23606,10 @@
     field public static final int LAYER_TYPE_HARDWARE = 2; // 0x2
     field public static final int LAYER_TYPE_NONE = 0; // 0x0
     field public static final int LAYER_TYPE_SOFTWARE = 1; // 0x1
-    field public static final int LAYOUT_DIRECTION_INHERIT = 4; // 0x4
-    field public static final int LAYOUT_DIRECTION_LOCALE = 8; // 0x8
-    field public static final int LAYOUT_DIRECTION_LTR = 1; // 0x1
-    field public static final int LAYOUT_DIRECTION_RTL = 2; // 0x2
+    field public static final int LAYOUT_DIRECTION_INHERIT = 2; // 0x2
+    field public static final int LAYOUT_DIRECTION_LOCALE = 3; // 0x3
+    field public static final int LAYOUT_DIRECTION_LTR = 0; // 0x0
+    field public static final int LAYOUT_DIRECTION_RTL = 1; // 0x1
     field public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; // 0x10
     field public static final int MEASURED_SIZE_MASK = 16777215; // 0xffffff
     field public static final int MEASURED_STATE_MASK = -16777216; // 0xff000000
@@ -23650,6 +23656,7 @@
     field public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 1; // 0x1
     field public static final int SYSTEM_UI_FLAG_VISIBLE = 0; // 0x0
     field public static final int TEXT_DIRECTION_ANY_RTL = 2; // 0x2
+    field protected static int TEXT_DIRECTION_DEFAULT;
     field public static final int TEXT_DIRECTION_FIRST_STRONG = 1; // 0x1
     field public static final int TEXT_DIRECTION_INHERIT = 0; // 0x0
     field public static final int TEXT_DIRECTION_LOCALE = 5; // 0x5
@@ -25899,6 +25906,7 @@
     ctor public AbsSeekBar(android.content.Context, android.util.AttributeSet);
     ctor public AbsSeekBar(android.content.Context, android.util.AttributeSet, int);
     method public int getKeyProgressIncrement();
+    method public android.graphics.drawable.Drawable getThumb();
     method public int getThumbOffset();
     method public void setKeyProgressIncrement(int);
     method public void setThumb(android.graphics.drawable.Drawable);
@@ -26621,8 +26629,14 @@
     ctor public GridView(android.content.Context, android.util.AttributeSet);
     ctor public GridView(android.content.Context, android.util.AttributeSet, int);
     method public android.widget.ListAdapter getAdapter();
+    method public int getColumnWidth();
+    method public int getGravity();
+    method public int getHorizontalSpacing();
     method public int getNumColumns();
+    method public int getRequestedColumnWidth();
+    method public int getRequestedHorizontalSpacing();
     method public int getStretchMode();
+    method public int getVerticalSpacing();
     method public void setColumnWidth(int);
     method public void setGravity(int);
     method public void setHorizontalSpacing(int);
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index c15c49f..53a0186 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -62,6 +62,7 @@
     private boolean mStopOption = false;
 
     private int mRepeat = 0;
+    private int mUserId = 0;
 
     private String mProfileFile;
 
@@ -135,7 +136,7 @@
             runToUri(false);
         } else if (op.equals("to-intent-uri")) {
             runToUri(true);
-        } else if (op.equals("switch-profile")) {
+        } else if (op.equals("switch-user")) {
             runSwitchUser();
         } else {
             throw new IllegalArgumentException("Unknown command: " + op);
@@ -152,6 +153,7 @@
         mStopOption = false;
         mRepeat = 0;
         mProfileFile = null;
+        mUserId = 0;
         Uri data = null;
         String type = null;
 
@@ -308,6 +310,8 @@
                 mStopOption = true;
             } else if (opt.equals("--opengl-trace")) {
                 mStartFlags |= ActivityManager.START_FLAG_OPENGL_TRACES;
+            } else if (opt.equals("--user")) {
+                mUserId = Integer.parseInt(nextArgRequired());
             } else {
                 System.err.println("Error: Unknown option: " + opt);
                 showUsage();
@@ -407,7 +411,8 @@
                         System.err.println("Error: Package manager not running; aborting");
                         return;
                     }
-                    List<ResolveInfo> activities = pm.queryIntentActivities(intent, mimeType, 0);
+                    List<ResolveInfo> activities = pm.queryIntentActivities(intent, mimeType, 0,
+                            mUserId);
                     if (activities == null || activities.size() <= 0) {
                         System.err.println("Error: Intent does not match any activities: "
                                 + intent);
@@ -550,7 +555,7 @@
         IntentReceiver receiver = new IntentReceiver();
         System.out.println("Broadcasting: " + intent);
         mAm.broadcastIntent(null, intent, null, receiver, 0, null, null, null, true, false,
-                Binder.getOrigCallingUser());
+                mUserId);
         receiver.waitForFinish();
     }
 
@@ -1294,6 +1299,7 @@
                 "       am display-size [reset|MxN]\n" +
                 "       am to-uri [INTENT]\n" +
                 "       am to-intent-uri [INTENT]\n" +
+                "       am switch-user <USER_ID>\n" +
                 "\n" +
                 "am start: start an Activity.  Options are:\n" +
                 "    -D: enable debugging\n" +
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index ac5bffe..4d638d0 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -146,18 +146,18 @@
             return;
         }
 
-        if ("create-profile".equals(op)) {
-            runCreateProfile();
+        if ("create-user".equals(op)) {
+            runCreateUser();
             return;
         }
 
-        if ("remove-profile".equals(op)) {
-            runRemoveProfile();
+        if ("remove-user".equals(op)) {
+            runRemoveUser();
             return;
         }
 
-        if ("list-profiles".equals(op)) {
-            runListProfiles();
+        if ("list-users".equals(op)) {
+            runListUsers();
             return;
         }
 
@@ -215,6 +215,8 @@
             runListLibraries();
         } else if ("instrumentation".equals(type)) {
             runListInstrumentation();
+        } else if ("users".equals(type)) {
+            runListUsers();
         } else {
             System.err.println("Error: unknown list type '" + type + "'");
             showUsage();
@@ -832,10 +834,10 @@
         }
     }
 
-    public void runCreateProfile() {
+    public void runCreateUser() {
         // Need to be run as root
         if (Process.myUid() != ROOT_UID) {
-            System.err.println("Error: create-profile must be run as root");
+            System.err.println("Error: create-user must be run as root");
             return;
         }
         String name;
@@ -848,7 +850,7 @@
         name = arg;
         try {
             if (mPm.createUser(name, 0) == null) {
-                System.err.println("Error: couldn't create profile.");
+                System.err.println("Error: couldn't create User.");
                 showUsage();
             }
         } catch (RemoteException e) {
@@ -858,10 +860,10 @@
 
     }
 
-    public void runRemoveProfile() {
+    public void runRemoveUser() {
         // Need to be run as root
         if (Process.myUid() != ROOT_UID) {
-            System.err.println("Error: remove-profile must be run as root");
+            System.err.println("Error: remove-user must be run as root");
             return;
         }
         int userId;
@@ -880,7 +882,7 @@
         }
         try {
             if (!mPm.removeUser(userId)) {
-                System.err.println("Error: couldn't remove profile.");
+                System.err.println("Error: couldn't remove user.");
                 showUsage();
             }
         } catch (RemoteException e) {
@@ -889,10 +891,10 @@
         }
     }
 
-    public void runListProfiles() {
+    public void runListUsers() {
         // Need to be run as root
         if (Process.myUid() != ROOT_UID) {
-            System.err.println("Error: list-profiles must be run as root");
+            System.err.println("Error: list-users must be run as root");
             return;
         }
         try {
@@ -1029,7 +1031,29 @@
         return "unknown";
     }
 
+    private boolean isNumber(String s) {
+        try {
+            Integer.parseInt(s);
+        } catch (NumberFormatException nfe) {
+            return false;
+        }
+        return true;
+    }
+
     private void runSetEnabledSetting(int state) {
+        int userId = 0;
+        String option = nextOption();
+        if (option != null && option.equals("--user")) {
+            String optionData = nextOptionData();
+            if (optionData == null || !isNumber(optionData)) {
+                System.err.println("Error: no USER_ID specified");
+                showUsage();
+                return;
+            } else {
+                userId = Integer.parseInt(optionData);
+            }
+        }
+
         String pkg = nextArg();
         if (pkg == null) {
             System.err.println("Error: no package or component specified");
@@ -1039,20 +1063,20 @@
         ComponentName cn = ComponentName.unflattenFromString(pkg);
         if (cn == null) {
             try {
-                mPm.setApplicationEnabledSetting(pkg, state, 0);
+                mPm.setApplicationEnabledSetting(pkg, state, 0, userId);
                 System.err.println("Package " + pkg + " new state: "
                         + enabledSettingToString(
-                                mPm.getApplicationEnabledSetting(pkg)));
+                        mPm.getApplicationEnabledSetting(pkg, userId)));
             } catch (RemoteException e) {
                 System.err.println(e.toString());
                 System.err.println(PM_NOT_RUNNING_ERR);
             }
         } else {
             try {
-                mPm.setComponentEnabledSetting(cn, state, 0);
+                mPm.setComponentEnabledSetting(cn, state, 0, userId);
                 System.err.println("Component " + cn.toShortString() + " new state: "
                         + enabledSettingToString(
-                                mPm.getComponentEnabledSetting(cn)));
+                        mPm.getComponentEnabledSetting(cn, userId)));
             } catch (RemoteException e) {
                 System.err.println(e.toString());
                 System.err.println(PM_NOT_RUNNING_ERR);
@@ -1096,7 +1120,7 @@
      */
     private void displayPackageFilePath(String pckg) {
         try {
-            PackageInfo info = mPm.getPackageInfo(pckg, 0);
+            PackageInfo info = mPm.getPackageInfo(pckg, 0, 0);
             if (info != null && info.applicationInfo != null) {
                 System.out.print("package:");
                 System.out.println(info.applicationInfo.sourceDir);
@@ -1112,7 +1136,7 @@
         if (res != null) return res;
 
         try {
-            ApplicationInfo ai = mPm.getApplicationInfo(pii.packageName, 0);
+            ApplicationInfo ai = mPm.getApplicationInfo(pii.packageName, 0, 0);
             AssetManager am = new AssetManager();
             am.addAssetPath(ai.publicSourceDir);
             res = new Resources(am, null, null);
@@ -1178,19 +1202,20 @@
         System.err.println("       pm list instrumentation [-f] [TARGET-PACKAGE]");
         System.err.println("       pm list features");
         System.err.println("       pm list libraries");
+        System.err.println("       pm list users");
         System.err.println("       pm path PACKAGE");
         System.err.println("       pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f] PATH");
         System.err.println("       pm uninstall [-k] PACKAGE");
         System.err.println("       pm clear PACKAGE");
-        System.err.println("       pm enable PACKAGE_OR_COMPONENT");
-        System.err.println("       pm disable PACKAGE_OR_COMPONENT");
-        System.err.println("       pm disable-user PACKAGE_OR_COMPONENT");
+        System.err.println("       pm enable [--user USER_ID] PACKAGE_OR_COMPONENT");
+        System.err.println("       pm disable [--user USER_ID] PACKAGE_OR_COMPONENT");
+        System.err.println("       pm disable-user [--user USER_ID] PACKAGE_OR_COMPONENT");
         System.err.println("       pm grant PACKAGE PERMISSION");
         System.err.println("       pm revoke PACKAGE PERMISSION");
         System.err.println("       pm set-install-location [0/auto] [1/internal] [2/external]");
         System.err.println("       pm get-install-location");
-        System.err.println("       pm create-profile USER_NAME");
-        System.err.println("       pm remove-profile USER_ID");
+        System.err.println("       pm create-user USER_NAME");
+        System.err.println("       pm remove-user USER_ID");
         System.err.println("");
         System.err.println("pm list packages: prints all packages, optionally only");
         System.err.println("  those whose package name contains the text in FILTER.  Options:");
diff --git a/cmds/stagefright/sf2.cpp b/cmds/stagefright/sf2.cpp
index e47cdc0..64df5d1 100644
--- a/cmds/stagefright/sf2.cpp
+++ b/cmds/stagefright/sf2.cpp
@@ -176,8 +176,9 @@
                     }
 
                     onDrainThisBuffer(msg);
-                } else if (what == ACodec::kWhatEOS) {
-                    printf("$\n");
+                } else if (what == ACodec::kWhatEOS
+                        || what == ACodec::kWhatError) {
+                    printf((what == ACodec::kWhatEOS) ? "$\n" : "E\n");
 
                     int64_t delayUs = ALooper::GetNowUs() - mStartTimeUs;
 
@@ -412,7 +413,8 @@
         sp<AMessage> reply;
         CHECK(msg->findMessage("reply", &reply));
 
-        if (mSeekState == SEEK_FLUSHING) {
+        if (mSource == NULL || mSeekState == SEEK_FLUSHING) {
+            reply->setInt32("err", ERROR_END_OF_STREAM);
             reply->post();
             return;
         }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 2a3e213..0860890 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1586,7 +1586,7 @@
         ApplicationInfo ai = null;
         try {
             ai = getPackageManager().getApplicationInfo(packageName,
-                    PackageManager.GET_SHARED_LIBRARY_FILES);
+                    PackageManager.GET_SHARED_LIBRARY_FILES, UserId.myUserId());
         } catch (RemoteException e) {
             // Ignore
         }
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 758ce09..f38540c 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -49,6 +49,7 @@
 import android.net.Uri;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.UserId;
 import android.util.Log;
 
 import java.lang.ref.WeakReference;
@@ -67,7 +68,7 @@
     public PackageInfo getPackageInfo(String packageName, int flags)
             throws NameNotFoundException {
         try {
-            PackageInfo pi = mPM.getPackageInfo(packageName, flags);
+            PackageInfo pi = mPM.getPackageInfo(packageName, flags, UserId.myUserId());
             if (pi != null) {
                 return pi;
             }
@@ -197,7 +198,7 @@
     public ApplicationInfo getApplicationInfo(String packageName, int flags)
             throws NameNotFoundException {
         try {
-            ApplicationInfo ai = mPM.getApplicationInfo(packageName, flags);
+            ApplicationInfo ai = mPM.getApplicationInfo(packageName, flags, UserId.myUserId());
             if (ai != null) {
                 return ai;
             }
@@ -212,7 +213,7 @@
     public ActivityInfo getActivityInfo(ComponentName className, int flags)
             throws NameNotFoundException {
         try {
-            ActivityInfo ai = mPM.getActivityInfo(className, flags);
+            ActivityInfo ai = mPM.getActivityInfo(className, flags, UserId.myUserId());
             if (ai != null) {
                 return ai;
             }
@@ -227,7 +228,7 @@
     public ActivityInfo getReceiverInfo(ComponentName className, int flags)
             throws NameNotFoundException {
         try {
-            ActivityInfo ai = mPM.getReceiverInfo(className, flags);
+            ActivityInfo ai = mPM.getReceiverInfo(className, flags, UserId.myUserId());
             if (ai != null) {
                 return ai;
             }
@@ -242,7 +243,7 @@
     public ServiceInfo getServiceInfo(ComponentName className, int flags)
             throws NameNotFoundException {
         try {
-            ServiceInfo si = mPM.getServiceInfo(className, flags);
+            ServiceInfo si = mPM.getServiceInfo(className, flags, UserId.myUserId());
             if (si != null) {
                 return si;
             }
@@ -257,7 +258,7 @@
     public ProviderInfo getProviderInfo(ComponentName className, int flags)
             throws NameNotFoundException {
         try {
-            ProviderInfo pi = mPM.getProviderInfo(className, flags);
+            ProviderInfo pi = mPM.getProviderInfo(className, flags, UserId.myUserId());
             if (pi != null) {
                 return pi;
             }
@@ -422,6 +423,7 @@
     @SuppressWarnings("unchecked")
     @Override
     public List<ApplicationInfo> getInstalledApplications(int flags) {
+        int userId = UserId.getUserId(Process.myUid());
         try {
             final List<ApplicationInfo> applicationInfos = new ArrayList<ApplicationInfo>();
             ApplicationInfo lastItem = null;
@@ -429,7 +431,7 @@
 
             do {
                 final String lastKey = lastItem != null ? lastItem.packageName : null;
-                slice = mPM.getInstalledApplications(flags, lastKey);
+                slice = mPM.getInstalledApplications(flags, lastKey, userId);
                 lastItem = slice.populateList(applicationInfos, ApplicationInfo.CREATOR);
             } while (!slice.isLastSlice());
 
@@ -445,7 +447,7 @@
             return mPM.resolveIntent(
                 intent,
                 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
-                flags);
+                    flags, UserId.myUserId());
         } catch (RemoteException e) {
             throw new RuntimeException("Package manager has died", e);
         }
@@ -458,7 +460,8 @@
             return mPM.queryIntentActivities(
                 intent,
                 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
-                flags);
+                flags,
+                UserId.myUserId());
         } catch (RemoteException e) {
             throw new RuntimeException("Package manager has died", e);
         }
@@ -490,7 +493,7 @@
         try {
             return mPM.queryIntentActivityOptions(caller, specifics,
                                                   specificTypes, intent, intent.resolveTypeIfNeeded(resolver),
-                                                  flags);
+                                                  flags, UserId.myUserId());
         } catch (RemoteException e) {
             throw new RuntimeException("Package manager has died", e);
         }
@@ -502,7 +505,8 @@
             return mPM.queryIntentReceivers(
                 intent,
                 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
-                flags);
+                flags,
+                UserId.myUserId());
         } catch (RemoteException e) {
             throw new RuntimeException("Package manager has died", e);
         }
@@ -514,7 +518,8 @@
             return mPM.resolveService(
                 intent,
                 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
-                flags);
+                flags,
+                UserId.myUserId());
         } catch (RemoteException e) {
             throw new RuntimeException("Package manager has died", e);
         }
@@ -526,7 +531,8 @@
             return mPM.queryIntentServices(
                 intent,
                 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
-                flags);
+                flags,
+                UserId.myUserId());
         } catch (RemoteException e) {
             throw new RuntimeException("Package manager has died", e);
         }
@@ -536,7 +542,7 @@
     public ProviderInfo resolveContentProvider(String name,
                                                int flags) {
         try {
-            return mPM.resolveContentProvider(name, flags);
+            return mPM.resolveContentProvider(name, flags, UserId.myUserId());
         } catch (RemoteException e) {
             throw new RuntimeException("Package manager has died", e);
         }
@@ -1026,7 +1032,7 @@
     public void clearApplicationUserData(String packageName,
                                          IPackageDataObserver observer) {
         try {
-            mPM.clearApplicationUserData(packageName, observer);
+            mPM.clearApplicationUserData(packageName, observer, UserId.myUserId());
         } catch (RemoteException e) {
             // Should never happen!
         }
@@ -1139,7 +1145,7 @@
     public void setComponentEnabledSetting(ComponentName componentName,
                                            int newState, int flags) {
         try {
-            mPM.setComponentEnabledSetting(componentName, newState, flags);
+            mPM.setComponentEnabledSetting(componentName, newState, flags, UserId.myUserId());
         } catch (RemoteException e) {
             // Should never happen!
         }
@@ -1148,7 +1154,7 @@
     @Override
     public int getComponentEnabledSetting(ComponentName componentName) {
         try {
-            return mPM.getComponentEnabledSetting(componentName);
+            return mPM.getComponentEnabledSetting(componentName, UserId.myUserId());
         } catch (RemoteException e) {
             // Should never happen!
         }
@@ -1159,7 +1165,7 @@
     public void setApplicationEnabledSetting(String packageName,
                                              int newState, int flags) {
         try {
-            mPM.setApplicationEnabledSetting(packageName, newState, flags);
+            mPM.setApplicationEnabledSetting(packageName, newState, flags, UserId.myUserId());
         } catch (RemoteException e) {
             // Should never happen!
         }
@@ -1168,7 +1174,7 @@
     @Override
     public int getApplicationEnabledSetting(String packageName) {
         try {
-            return mPM.getApplicationEnabledSetting(packageName);
+            return mPM.getApplicationEnabledSetting(packageName, UserId.myUserId());
         } catch (RemoteException e) {
             // Should never happen!
         }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 7043a73..d758ecae 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -766,17 +766,18 @@
 
     @Override
     public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory) {
-        File f = validateFilePath(name, true);
-        SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(f, factory);
-        setFilePermissionsFromMode(f.getPath(), mode, 0);
-        return db;
+        return openOrCreateDatabase(name, mode, factory, null);
     }
 
     @Override
     public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory,
             DatabaseErrorHandler errorHandler) {
         File f = validateFilePath(name, true);
-        SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(f.getPath(), factory, errorHandler);
+        int flags = SQLiteDatabase.CREATE_IF_NECESSARY;
+        if ((mode & MODE_ENABLE_WRITE_AHEAD_LOGGING) != 0) {
+            flags |= SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING;
+        }
+        SQLiteDatabase db = SQLiteDatabase.openDatabase(f.getPath(), factory, flags, errorHandler);
         setFilePermissionsFromMode(f.getPath(), mode, 0);
         return db;
     }
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index de9470e..5340fbb 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -194,7 +194,7 @@
         ApplicationInfo ai = null;
         try {
             ai = ActivityThread.getPackageManager().getApplicationInfo(packageName,
-                    PackageManager.GET_SHARED_LIBRARY_FILES);
+                    PackageManager.GET_SHARED_LIBRARY_FILES, UserId.myUserId());
         } catch (RemoteException e) {
             throw new AssertionError(e);
         }
@@ -351,7 +351,7 @@
         IPackageManager pm = ActivityThread.getPackageManager();
         android.content.pm.PackageInfo pi;
         try {
-            pi = pm.getPackageInfo(mPackageName, 0);
+            pi = pm.getPackageInfo(mPackageName, 0, UserId.myUserId());
         } catch (RemoteException e) {
             throw new AssertionError(e);
         }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 5325af0..04ab407 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -23,9 +23,11 @@
 import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
+import android.util.IntProperty;
 import android.view.View;
 import android.widget.ProgressBar;
 import android.widget.RemoteViews;
@@ -185,6 +187,13 @@
      */
     public RemoteViews contentView;
 
+
+    /**
+     * The view that will represent this notification in the pop-up "intruder alert" dialog.
+     * @hide
+     */
+    public RemoteViews intruderView;
+
     /**
      * The bitmap that may escape the bounds of the panel and bar.
      */
@@ -418,6 +427,64 @@
     private Bundle extras;
 
     /**
+     * Structure to encapsulate an "action", including title and icon, that can be attached to a Notification.
+     * @hide
+     */
+    private static class Action implements Parcelable {
+        public int icon;
+        public CharSequence title;
+        public PendingIntent actionIntent;
+        @SuppressWarnings("unused")
+        public Action() { }
+        private Action(Parcel in) {
+            icon = in.readInt();
+            title = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+            if (in.readInt() == 1) {
+                actionIntent = PendingIntent.CREATOR.createFromParcel(in);
+            }
+        }
+        public Action(int icon_, CharSequence title_, PendingIntent intent_) {
+            this.icon = icon_;
+            this.title = title_;
+            this.actionIntent = intent_;
+        }
+        @Override
+        public Action clone() {
+            return new Action(
+                this.icon,
+                this.title.toString(),
+                this.actionIntent // safe to alias
+            );
+        }
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeInt(icon);
+            TextUtils.writeToParcel(title, out, flags);
+            if (actionIntent != null) {
+                out.writeInt(1);
+                actionIntent.writeToParcel(out, flags);
+            } else {
+                out.writeInt(0);
+            }
+        }
+        public static final Parcelable.Creator<Action> CREATOR
+        = new Parcelable.Creator<Action>() {
+            public Action createFromParcel(Parcel in) {
+                return new Action(in);
+            }
+            public Action[] newArray(int size) {
+                return new Action[size];
+            }
+        };
+    }
+
+    private Action[] actions;
+
+    /**
      * Constructs a Notification object with default values.
      * You might want to consider using {@link Builder} instead.
      */
@@ -506,12 +573,17 @@
         }
 
         priority = parcel.readInt();
-        
+
         kind = parcel.createStringArray(); // may set kind to null
 
         if (parcel.readInt() != 0) {
             extras = parcel.readBundle();
         }
+
+        actions = parcel.createTypedArray(Action.CREATOR);
+        if (parcel.readInt() != 0) {
+            intruderView = RemoteViews.CREATOR.createFromParcel(parcel);
+        }
     }
 
     @Override
@@ -571,6 +643,14 @@
 
         }
 
+        that.actions = new Action[this.actions.length];
+        for(int i=0; i<this.actions.length; i++) {
+            that.actions[i] = this.actions[i].clone();
+        }
+        if (this.intruderView != null) {
+            that.intruderView = this.intruderView.clone();
+        }
+
         return that;
     }
 
@@ -658,6 +738,15 @@
         } else {
             parcel.writeInt(0);
         }
+
+        parcel.writeTypedArray(actions, 0);
+
+        if (intruderView != null) {
+            parcel.writeInt(1);
+            intruderView.writeToParcel(parcel, 0);
+        } else {
+            parcel.writeInt(0);
+        }
     }
 
     /**
@@ -769,7 +858,14 @@
                 sb.append(this.kind[i]);
             }
         }
-        sb.append("])");
+        sb.append("]");
+        if (actions != null) {
+            sb.append(" ");
+            sb.append(actions.length);
+            sb.append(" action");
+            if (actions.length > 1) sb.append("s");
+        }
+        sb.append(")");
         return sb.toString();
     }
 
@@ -821,6 +917,7 @@
         private ArrayList<String> mKindList = new ArrayList<String>(1);
         private Bundle mExtras;
         private int mPriority;
+        private ArrayList<Action> mActions = new ArrayList<Action>(3);
 
         /**
          * Constructs a new Builder with the defaults:
@@ -1203,6 +1300,19 @@
             return this;
         }
 
+        /**
+         * Add an action to this notification. Actions are typically displayed by
+         * the system as a button adjacent to the notification content.
+         *
+         * @param icon Resource ID of a drawable that represents the action.
+         * @param title Text describing the action.
+         * @param intent PendingIntent to be fired when the action is invoked.
+         */
+        public Builder addAction(int icon, CharSequence title, PendingIntent intent) {
+            mActions.add(new Action(icon, title, intent));
+            return this;
+        }
+
         private void setFlag(int mask, boolean value) {
             if (value) {
                 mFlags |= mask;
@@ -1284,6 +1394,44 @@
             }
         }
 
+        private RemoteViews makeIntruderView() {
+            RemoteViews intruderView = new RemoteViews(mContext.getPackageName(),
+                    R.layout.notification_intruder_content);
+            if (mLargeIcon != null) {
+                intruderView.setImageViewBitmap(R.id.icon, mLargeIcon);
+                intruderView.setViewVisibility(R.id.icon, View.VISIBLE);
+            } else if (mSmallIcon != 0) {
+                intruderView.setImageViewResource(R.id.icon, mSmallIcon);
+                intruderView.setViewVisibility(R.id.icon, View.VISIBLE);
+            } else {
+                intruderView.setViewVisibility(R.id.icon, View.GONE);
+            }
+            if (mContentTitle != null) {
+                intruderView.setTextViewText(R.id.title, mContentTitle);
+            }
+            if (mContentText != null) {
+                intruderView.setTextViewText(R.id.text, mContentText);
+            }
+            if (mActions.size() > 0) {
+                intruderView.setViewVisibility(R.id.actions, View.VISIBLE);
+                int N = mActions.size();
+                if (N>3) N=3;
+                final int[] BUTTONS = { R.id.action0, R.id.action1, R.id.action2 };
+                for (int i=0; i<N; i++) {
+                    final Action action = mActions.get(i);
+                    final int buttonId = BUTTONS[i];
+
+                    intruderView.setViewVisibility(buttonId, View.VISIBLE);
+                    intruderView.setImageViewResource(buttonId, action.icon);
+                    intruderView.setContentDescription(buttonId, action.title);
+                    intruderView.setOnClickPendingIntent(buttonId, action.actionIntent);
+                }
+            } else {
+                intruderView.setViewVisibility(R.id.actions, View.GONE);
+            }
+            return intruderView;
+        }
+
         /**
          * Combine all of the options that have been set and return a new {@link Notification}
          * object.
@@ -1309,6 +1457,7 @@
             n.ledOffMS = mLedOffMs;
             n.defaults = mDefaults;
             n.flags = mFlags;
+            n.intruderView = makeIntruderView();
             if (mLedOnMs != 0 && mLedOffMs != 0) {
                 n.flags |= FLAG_SHOW_LIGHTS;
             }
@@ -1323,6 +1472,10 @@
             }
             n.priority = mPriority;
             n.extras = mExtras != null ? new Bundle(mExtras) : null;
+            if (mActions.size() > 0) {
+                n.actions = new Action[mActions.size()];
+                mActions.toArray(n.actions);
+            }
             return n;
         }
     }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 741a6e9..2902504 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -99,6 +99,16 @@
     public static final int MODE_MULTI_PROCESS = 0x0004;
 
     /**
+     * Database open flag: when set, the database is opened with write-ahead
+     * logging enabled by default.
+     *
+     * @see #openOrCreateDatabase(String, int, CursorFactory)
+     * @see #openOrCreateDatabase(String, int, CursorFactory, DatabaseErrorHandler)
+     * @see SQLiteDatabase#enableWriteAheadLogging
+     */
+    public static final int MODE_ENABLE_WRITE_AHEAD_LOGGING = 0x0008;
+
+    /**
      * Flag for {@link #bindService}: automatically create the service as long
      * as the binding exists.  Note that while this will create the service,
      * its {@link android.app.Service#onStartCommand}
@@ -691,6 +701,7 @@
      * @param mode Operating mode.  Use 0 or {@link #MODE_PRIVATE} for the
      *     default operation, {@link #MODE_WORLD_READABLE}
      *     and {@link #MODE_WORLD_WRITEABLE} to control permissions.
+     *     Use {@link #MODE_ENABLE_WRITE_AHEAD_LOGGING} to enable write-ahead logging by default.
      * @param factory An optional factory class that is called to instantiate a
      *     cursor when query is called.
      *
@@ -700,6 +711,7 @@
      * @see #MODE_PRIVATE
      * @see #MODE_WORLD_READABLE
      * @see #MODE_WORLD_WRITEABLE
+     * @see #MODE_ENABLE_WRITE_AHEAD_LOGGING
      * @see #deleteDatabase
      */
     public abstract SQLiteDatabase openOrCreateDatabase(String name,
@@ -716,6 +728,7 @@
      * @param mode Operating mode.  Use 0 or {@link #MODE_PRIVATE} for the
      *     default operation, {@link #MODE_WORLD_READABLE}
      *     and {@link #MODE_WORLD_WRITEABLE} to control permissions.
+     *     Use {@link #MODE_ENABLE_WRITE_AHEAD_LOGGING} to enable write-ahead logging by default.
      * @param factory An optional factory class that is called to instantiate a
      *     cursor when query is called.
      * @param errorHandler the {@link DatabaseErrorHandler} to be used when sqlite reports database
@@ -726,6 +739,7 @@
      * @see #MODE_PRIVATE
      * @see #MODE_WORLD_READABLE
      * @see #MODE_WORLD_WRITEABLE
+     * @see #MODE_ENABLE_WRITE_AHEAD_LOGGING
      * @see #deleteDatabase
      */
     public abstract SQLiteDatabase openOrCreateDatabase(String name,
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 9bd1940..d89d2de 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -49,8 +49,8 @@
  *  {@hide}
  */
 interface IPackageManager {
-    PackageInfo getPackageInfo(String packageName, int flags);
-    int getPackageUid(String packageName);
+    PackageInfo getPackageInfo(String packageName, int flags, int userId);
+    int getPackageUid(String packageName, int userId);
     int[] getPackageGids(String packageName);
     
     String[] currentToCanonicalPackageNames(in String[] names);
@@ -64,15 +64,15 @@
     
     List<PermissionGroupInfo> getAllPermissionGroups(int flags);
     
-    ApplicationInfo getApplicationInfo(String packageName, int flags);
+    ApplicationInfo getApplicationInfo(String packageName, int flags ,int userId);
 
-    ActivityInfo getActivityInfo(in ComponentName className, int flags);
+    ActivityInfo getActivityInfo(in ComponentName className, int flags, int userId);
 
-    ActivityInfo getReceiverInfo(in ComponentName className, int flags);
+    ActivityInfo getReceiverInfo(in ComponentName className, int flags, int userId);
 
-    ServiceInfo getServiceInfo(in ComponentName className, int flags);
+    ServiceInfo getServiceInfo(in ComponentName className, int flags, int userId);
 
-    ProviderInfo getProviderInfo(in ComponentName className, int flags);
+    ProviderInfo getProviderInfo(in ComponentName className, int flags, int userId);
 
     int checkPermission(String permName, String pkgName);
     
@@ -98,24 +98,24 @@
     
     int getUidForSharedUser(String sharedUserName);
     
-    ResolveInfo resolveIntent(in Intent intent, String resolvedType, int flags);
+    ResolveInfo resolveIntent(in Intent intent, String resolvedType, int flags, int userId);
 
     List<ResolveInfo> queryIntentActivities(in Intent intent, 
-            String resolvedType, int flags);
+            String resolvedType, int flags, int userId);
 
     List<ResolveInfo> queryIntentActivityOptions(
             in ComponentName caller, in Intent[] specifics,
             in String[] specificTypes, in Intent intent,
-            String resolvedType, int flags);
+            String resolvedType, int flags, int userId);
 
     List<ResolveInfo> queryIntentReceivers(in Intent intent,
-            String resolvedType, int flags);
+            String resolvedType, int flags, int userId);
 
     ResolveInfo resolveService(in Intent intent,
-            String resolvedType, int flags);
+            String resolvedType, int flags, int userId);
 
     List<ResolveInfo> queryIntentServices(in Intent intent,
-            String resolvedType, int flags);
+            String resolvedType, int flags, int userId);
 
     /**
      * This implements getInstalledPackages via a "last returned row"
@@ -131,7 +131,7 @@
      * limit that kicks in when flags are included that bloat up the data
      * returned.
      */
-    ParceledListSlice getInstalledApplications(int flags, in String lastRead);
+    ParceledListSlice getInstalledApplications(int flags, in String lastRead, int userId);
 
     /**
      * Retrieve all applications that are marked as persistent.
@@ -141,7 +141,7 @@
      */
     List<ApplicationInfo> getPersistentApplications(int flags);
 
-    ProviderInfo resolveContentProvider(String name, int flags);
+    ProviderInfo resolveContentProvider(String name, int flags, int userId);
 
     /**
      * Retrieve sync information for all content providers.
@@ -212,28 +212,28 @@
      * As per {@link android.content.pm.PackageManager#setComponentEnabledSetting}.
      */
     void setComponentEnabledSetting(in ComponentName componentName,
-            in int newState, in int flags);
+            in int newState, in int flags, int userId);
 
     /**
      * As per {@link android.content.pm.PackageManager#getComponentEnabledSetting}.
      */
-    int getComponentEnabledSetting(in ComponentName componentName);
+    int getComponentEnabledSetting(in ComponentName componentName, int userId);
     
     /**
      * As per {@link android.content.pm.PackageManager#setApplicationEnabledSetting}.
      */
-    void setApplicationEnabledSetting(in String packageName, in int newState, int flags);
+    void setApplicationEnabledSetting(in String packageName, in int newState, int flags, int userId);
     
     /**
      * As per {@link android.content.pm.PackageManager#getApplicationEnabledSetting}.
      */
-    int getApplicationEnabledSetting(in String packageName);
+    int getApplicationEnabledSetting(in String packageName, int userId);
     
     /**
      * Set whether the given package should be considered stopped, making
      * it not visible to implicit intents that filter out stopped packages.
      */
-    void setPackageStoppedState(String packageName, boolean stopped);
+    void setPackageStoppedState(String packageName, boolean stopped, int userId);
 
     /**
      * Free storage by deleting LRU sorted list of cache files across
@@ -296,7 +296,7 @@
      * files need to be deleted
      * @param observer a callback used to notify when the operation is completed.
      */
-    void clearApplicationUserData(in String packageName, IPackageDataObserver observer);
+    void clearApplicationUserData(in String packageName, IPackageDataObserver observer, int userId);
     
    /**
      * Get package statistics including the code, data and cache size for
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 207f077..07d231a 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -240,7 +240,13 @@
             int gids[], int flags, long firstInstallTime, long lastUpdateTime,
             HashSet<String> grantedPermissions) {
 
-        final int userId = Binder.getOrigCallingUser();
+        return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime,
+                grantedPermissions, UserId.getCallingUserId());
+    }
+
+    static PackageInfo generatePackageInfo(PackageParser.Package p,
+            int gids[], int flags, long firstInstallTime, long lastUpdateTime,
+            HashSet<String> grantedPermissions, int userId) {
 
         PackageInfo pi = new PackageInfo();
         pi.packageName = p.packageName;
@@ -3350,7 +3356,7 @@
     }
 
     public static ApplicationInfo generateApplicationInfo(Package p, int flags) {
-        return generateApplicationInfo(p, flags, UserId.getUserId(Binder.getCallingUid()));
+        return generateApplicationInfo(p, flags, UserId.getCallingUserId());
     }
 
     public static ApplicationInfo generateApplicationInfo(Package p, int flags, int userId) {
@@ -3366,6 +3372,13 @@
             } else {
                 p.applicationInfo.flags &= ~ApplicationInfo.FLAG_STOPPED;
             }
+            if (p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
+                p.applicationInfo.enabled = true;
+            } else if (p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+                    || p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
+                p.applicationInfo.enabled = false;
+            }
+            p.applicationInfo.enabledSetting = p.mSetEnabled;
             return p.applicationInfo;
         }
 
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index e2c222b..e999316 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -211,8 +211,7 @@
                 SQLiteDebug.DEBUG_SQL_STATEMENTS, SQLiteDebug.DEBUG_SQL_TIME);
 
         setPageSize();
-        setSyncModeFromConfiguration();
-        setJournalModeFromConfiguration();
+        setWalModeFromConfiguration();
         setJournalSizeLimit();
         setAutoCheckpointInterval();
         setLocaleFromConfiguration();
@@ -268,28 +267,69 @@
         }
     }
 
-    private void setSyncModeFromConfiguration() {
+    private void setWalModeFromConfiguration() {
         if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) {
-            final String newValue = mConfiguration.syncMode;
-            String value = executeForString("PRAGMA synchronous", null, null);
-            if (!value.equalsIgnoreCase(newValue)) {
-                execute("PRAGMA synchronous=" + newValue, null, null);
+            if ((mConfiguration.openFlags & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0) {
+                setJournalMode("WAL");
+                setSyncMode(SQLiteGlobal.getWALSyncMode());
+            } else {
+                setJournalMode(SQLiteGlobal.getDefaultJournalMode());
+                setSyncMode(SQLiteGlobal.getDefaultSyncMode());
             }
         }
     }
 
-    private void setJournalModeFromConfiguration() {
-        if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) {
-            final String newValue = mConfiguration.journalMode;
-            String value = executeForString("PRAGMA journal_mode", null, null);
-            if (!value.equalsIgnoreCase(newValue)) {
-                value = executeForString("PRAGMA journal_mode=" + newValue, null, null);
-                if (!value.equalsIgnoreCase(newValue)) {
-                    Log.e(TAG, "setting journal_mode to " + newValue
-                            + " failed for db: " + mConfiguration.label
-                            + " (on pragma set journal_mode, sqlite returned:" + value);
+    private void setSyncMode(String newValue) {
+        String value = executeForString("PRAGMA synchronous", null, null);
+        if (!canonicalizeSyncMode(value).equalsIgnoreCase(
+                canonicalizeSyncMode(newValue))) {
+            execute("PRAGMA synchronous=" + newValue, null, null);
+        }
+    }
+
+    private static String canonicalizeSyncMode(String value) {
+        if (value.equals("0")) {
+            return "OFF";
+        } else if (value.equals("1")) {
+            return "NORMAL";
+        } else if (value.equals("2")) {
+            return "FULL";
+        }
+        return value;
+    }
+
+    private void setJournalMode(String newValue) {
+        String value = executeForString("PRAGMA journal_mode", null, null);
+        if (!value.equalsIgnoreCase(newValue)) {
+            try {
+                String result = executeForString("PRAGMA journal_mode=" + newValue, null, null);
+                if (result.equalsIgnoreCase(newValue)) {
+                    return;
                 }
+                // PRAGMA journal_mode silently fails and returns the original journal
+                // mode in some cases if the journal mode could not be changed.
+            } catch (SQLiteDatabaseLockedException ex) {
+                // This error (SQLITE_BUSY) occurs if one connection has the database
+                // open in WAL mode and another tries to change it to non-WAL.
             }
+            // Because we always disable WAL mode when a database is first opened
+            // (even if we intend to re-enable it), we can encounter problems if
+            // there is another open connection to the database somewhere.
+            // This can happen for a variety of reasons such as an application opening
+            // the same database in multiple processes at the same time or if there is a
+            // crashing content provider service that the ActivityManager has
+            // removed from its registry but whose process hasn't quite died yet
+            // by the time it is restarted in a new process.
+            //
+            // If we don't change the journal mode, nothing really bad happens.
+            // In the worst case, an application that enables WAL might not actually
+            // get it, although it can still use connection pooling.
+            Log.w(TAG, "Could not change the database journal mode of '"
+                    + mConfiguration.label + "' from '" + value + "' to '" + newValue
+                    + "' because the database is locked.  This usually means that "
+                    + "there are other open connections to the database which prevents "
+                    + "the database from enabling or disabling write-ahead logging mode.  "
+                    + "Proceeding without changing the journal mode.");
         }
     }
 
@@ -349,10 +389,8 @@
         }
 
         // Remember what changed.
-        boolean syncModeChanged = !configuration.syncMode.equalsIgnoreCase(
-                mConfiguration.syncMode);
-        boolean journalModeChanged = !configuration.journalMode.equalsIgnoreCase(
-                mConfiguration.journalMode);
+        boolean walModeChanged = ((configuration.openFlags ^ mConfiguration.openFlags)
+                & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0;
         boolean localeChanged = !configuration.locale.equals(mConfiguration.locale);
 
         // Update configuration parameters.
@@ -361,14 +399,9 @@
         // Update prepared statement cache size.
         mPreparedStatementCache.resize(configuration.maxSqlCacheSize);
 
-        // Update sync mode.
-        if (syncModeChanged) {
-            setSyncModeFromConfiguration();
-        }
-
-        // Update journal mode.
-        if (journalModeChanged) {
-            setJournalModeFromConfiguration();
+        // Update WAL.
+        if (walModeChanged) {
+            setWalModeFromConfiguration();
         }
 
         // Update locale.
diff --git a/core/java/android/database/sqlite/SQLiteConnectionPool.java b/core/java/android/database/sqlite/SQLiteConnectionPool.java
index 3562e89..0538ce4 100644
--- a/core/java/android/database/sqlite/SQLiteConnectionPool.java
+++ b/core/java/android/database/sqlite/SQLiteConnectionPool.java
@@ -81,6 +81,7 @@
     private final Object mLock = new Object();
     private final AtomicBoolean mConnectionLeaked = new AtomicBoolean();
     private final SQLiteDatabaseConfiguration mConfiguration;
+    private int mMaxConnectionPoolSize;
     private boolean mIsOpen;
     private int mNextConnectionId;
 
@@ -146,6 +147,7 @@
 
     private SQLiteConnectionPool(SQLiteDatabaseConfiguration configuration) {
         mConfiguration = new SQLiteDatabaseConfiguration(configuration);
+        setMaxConnectionPoolSizeLocked();
     }
 
     @Override
@@ -257,7 +259,32 @@
         synchronized (mLock) {
             throwIfClosedLocked();
 
+            boolean walModeChanged = ((configuration.openFlags ^ mConfiguration.openFlags)
+                    & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0;
+            if (walModeChanged) {
+                // WAL mode can only be changed if there are no acquired connections
+                // because we need to close all but the primary connection first.
+                if (!mAcquiredConnections.isEmpty()) {
+                    throw new IllegalStateException("Write Ahead Logging (WAL) mode cannot "
+                            + "be enabled or disabled while there are transactions in "
+                            + "progress.  Finish all transactions and release all active "
+                            + "database connections first.");
+                }
+
+                // Close all non-primary connections.  This should happen immediately
+                // because none of them are in use.
+                closeAvailableNonPrimaryConnectionsAndLogExceptionsLocked();
+                assert mAvailableNonPrimaryConnections.isEmpty();
+            }
+
             if (mConfiguration.openFlags != configuration.openFlags) {
+                // If we are changing open flags and WAL mode at the same time, then
+                // we have no choice but to close the primary connection beforehand
+                // because there can only be one connection open when we change WAL mode.
+                if (walModeChanged) {
+                    closeAvailableConnectionsAndLogExceptionsLocked();
+                }
+
                 // Try to reopen the primary connection using the new open flags then
                 // close and discard all existing connections.
                 // This might throw if the database is corrupt or cannot be opened in
@@ -270,9 +297,11 @@
 
                 mAvailablePrimaryConnection = newPrimaryConnection;
                 mConfiguration.updateParametersFrom(configuration);
+                setMaxConnectionPoolSizeLocked();
             } else {
                 // Reconfigure the database connections in place.
                 mConfiguration.updateParametersFrom(configuration);
+                setMaxConnectionPoolSizeLocked();
 
                 closeExcessConnectionsAndLogExceptionsLocked();
                 reconfigureAllConnectionsLocked();
@@ -334,8 +363,7 @@
                     mAvailablePrimaryConnection = connection;
                 }
                 wakeConnectionWaitersLocked();
-            } else if (mAvailableNonPrimaryConnections.size() >=
-                    mConfiguration.maxConnectionPoolSize - 1) {
+            } else if (mAvailableNonPrimaryConnections.size() >= mMaxConnectionPoolSize - 1) {
                 closeConnectionAndLogExceptionsLocked(connection);
             } else {
                 if (recycleConnectionLocked(connection, status)) {
@@ -453,11 +481,7 @@
 
     // Can't throw.
     private void closeAvailableConnectionsAndLogExceptionsLocked() {
-        final int count = mAvailableNonPrimaryConnections.size();
-        for (int i = 0; i < count; i++) {
-            closeConnectionAndLogExceptionsLocked(mAvailableNonPrimaryConnections.get(i));
-        }
-        mAvailableNonPrimaryConnections.clear();
+        closeAvailableNonPrimaryConnectionsAndLogExceptionsLocked();
 
         if (mAvailablePrimaryConnection != null) {
             closeConnectionAndLogExceptionsLocked(mAvailablePrimaryConnection);
@@ -466,9 +490,18 @@
     }
 
     // Can't throw.
+    private void closeAvailableNonPrimaryConnectionsAndLogExceptionsLocked() {
+        final int count = mAvailableNonPrimaryConnections.size();
+        for (int i = 0; i < count; i++) {
+            closeConnectionAndLogExceptionsLocked(mAvailableNonPrimaryConnections.get(i));
+        }
+        mAvailableNonPrimaryConnections.clear();
+    }
+
+    // Can't throw.
     private void closeExcessConnectionsAndLogExceptionsLocked() {
         int availableCount = mAvailableNonPrimaryConnections.size();
-        while (availableCount-- > mConfiguration.maxConnectionPoolSize - 1) {
+        while (availableCount-- > mMaxConnectionPoolSize - 1) {
             SQLiteConnection connection =
                     mAvailableNonPrimaryConnections.remove(availableCount);
             closeConnectionAndLogExceptionsLocked(connection);
@@ -843,7 +876,7 @@
         if (mAvailablePrimaryConnection != null) {
             openConnections += 1;
         }
-        if (openConnections >= mConfiguration.maxConnectionPoolSize) {
+        if (openConnections >= mMaxConnectionPoolSize) {
             return null;
         }
         connection = openConnectionLocked(mConfiguration,
@@ -895,6 +928,18 @@
         return (connectionFlags & CONNECTION_FLAG_INTERACTIVE) != 0 ? 1 : 0;
     }
 
+    private void setMaxConnectionPoolSizeLocked() {
+        if ((mConfiguration.openFlags & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0) {
+            mMaxConnectionPoolSize = SQLiteGlobal.getWALConnectionPoolSize();
+        } else {
+            // TODO: We don't actually need to restrict the connection pool size to 1
+            // for non-WAL databases.  There might be reasons to use connection pooling
+            // with other journal modes.  For now, enabling connection pooling and
+            // using WAL are the same thing in the API.
+            mMaxConnectionPoolSize = 1;
+        }
+    }
+
     private void throwIfClosedLocked() {
         if (!mIsOpen) {
             throw new IllegalStateException("Cannot perform this operation "
@@ -941,7 +986,7 @@
         synchronized (mLock) {
             printer.println("Connection pool for " + mConfiguration.path + ":");
             printer.println("  Open: " + mIsOpen);
-            printer.println("  Max connections: " + mConfiguration.maxConnectionPoolSize);
+            printer.println("  Max connections: " + mMaxConnectionPoolSize);
 
             printer.println("  Available primary connection:");
             if (mAvailablePrimaryConnection != null) {
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index bf32ea7..049a615 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -127,10 +127,6 @@
     // INVARIANT: Guarded by mLock.
     private boolean mHasAttachedDbsLocked;
 
-    // True if the database is in WAL mode.
-    // INVARIANT: Guarded by mLock.
-    private boolean mIsWALEnabledLocked;
-
     /**
      * When a constraint violation occurs, an immediate ROLLBACK occurs,
      * thus ending the current transaction, and the command aborts with a
@@ -236,6 +232,18 @@
     public static final int CREATE_IF_NECESSARY = 0x10000000;     // update native code if changing
 
     /**
+     * Open flag: Flag for {@link #openDatabase} to open the database file with
+     * write-ahead logging enabled by default.  Using this flag is more efficient
+     * than calling {@link #enableWriteAheadLogging}.
+     *
+     * Write-ahead logging cannot be used with read-only databases so the value of
+     * this flag is ignored if the database is opened read-only.
+     *
+     * @see #enableWriteAheadLogging
+     */
+    public static final int ENABLE_WRITE_AHEAD_LOGGING = 0x20000000;
+
+    /**
      * Absolute max value that can be set by {@link #setMaxSqlCacheSize(int)}.
      *
      * Each prepared-statement is between 1K - 6K, depending on the complexity of the
@@ -658,7 +666,7 @@
      * @throws SQLiteException if the database cannot be opened
      */
     public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags) {
-        return openDatabase(path, factory, flags, new DefaultDatabaseErrorHandler());
+        return openDatabase(path, factory, flags, null);
     }
 
     /**
@@ -698,7 +706,7 @@
      * Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY).
      */
     public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory) {
-        return openDatabase(path, factory, CREATE_IF_NECESSARY);
+        return openDatabase(path, factory, CREATE_IF_NECESSARY, null);
     }
 
     /**
@@ -834,8 +842,14 @@
 
         synchronized (mLock) {
             throwIfNotOpenLocked();
+
             mConfigurationLocked.customFunctions.add(wrapper);
-            mConnectionPoolLocked.reconfigure(mConfigurationLocked);
+            try {
+                mConnectionPoolLocked.reconfigure(mConfigurationLocked);
+            } catch (RuntimeException ex) {
+                mConfigurationLocked.customFunctions.remove(wrapper);
+                throw ex;
+            }
         }
     }
 
@@ -1733,8 +1747,15 @@
 
         synchronized (mLock) {
             throwIfNotOpenLocked();
+
+            final Locale oldLocale = mConfigurationLocked.locale;
             mConfigurationLocked.locale = locale;
-            mConnectionPoolLocked.reconfigure(mConfigurationLocked);
+            try {
+                mConnectionPoolLocked.reconfigure(mConfigurationLocked);
+            } catch (RuntimeException ex) {
+                mConfigurationLocked.locale = oldLocale;
+                throw ex;
+            }
         }
     }
 
@@ -1759,58 +1780,97 @@
 
         synchronized (mLock) {
             throwIfNotOpenLocked();
+
+            final int oldMaxSqlCacheSize = mConfigurationLocked.maxSqlCacheSize;
             mConfigurationLocked.maxSqlCacheSize = cacheSize;
-            mConnectionPoolLocked.reconfigure(mConfigurationLocked);
+            try {
+                mConnectionPoolLocked.reconfigure(mConfigurationLocked);
+            } catch (RuntimeException ex) {
+                mConfigurationLocked.maxSqlCacheSize = oldMaxSqlCacheSize;
+                throw ex;
+            }
         }
     }
 
     /**
-     * This method enables parallel execution of queries from multiple threads on the same database.
-     * It does this by opening multiple handles to the database and using a different
-     * database handle for each query.
+     * This method enables parallel execution of queries from multiple threads on the
+     * same database.  It does this by opening multiple connections to the database
+     * and using a different database connection for each query.  The database
+     * journal mode is also changed to enable writes to proceed concurrently with reads.
      * <p>
-     * If a transaction is in progress on one connection handle and say, a table is updated in the
-     * transaction, then query on the same table on another connection handle will block for the
-     * transaction to complete. But this method enables such queries to execute by having them
-     * return old version of the data from the table. Most often it is the data that existed in the
-     * table prior to the above transaction updates on that table.
-     * <p>
-     * Maximum number of simultaneous handles used to execute queries in parallel is
+     * When write-ahead logging is not enabled (the default), it is not possible for
+     * reads and writes to occur on the database at the same time.  Before modifying the
+     * database, the writer implicitly acquires an exclusive lock on the database which
+     * prevents readers from accessing the database until the write is completed.
+     * </p><p>
+     * In contrast, when write-ahead logging is enabled (by calling this method), write
+     * operations occur in a separate log file which allows reads to proceed concurrently.
+     * While a write is in progress, readers on other threads will perceive the state
+     * of the database as it was before the write began.  When the write completes, readers
+     * on other threads will then perceive the new state of the database.
+     * </p><p>
+     * It is a good idea to enable write-ahead logging whenever a database will be
+     * concurrently accessed and modified by multiple threads at the same time.
+     * However, write-ahead logging uses significantly more memory than ordinary
+     * journaling because there are multiple connections to the same database.
+     * So if a database will only be used by a single thread, or if optimizing
+     * concurrency is not very important, then write-ahead logging should be disabled.
+     * </p><p>
+     * After calling this method, execution of queries in parallel is enabled as long as
+     * the database remains open.  To disable execution of queries in parallel, either
+     * call {@link #disableWriteAheadLogging} or close the database and reopen it.
+     * </p><p>
+     * The maximum number of connections used to execute queries in parallel is
      * dependent upon the device memory and possibly other properties.
-     * <p>
-     * After calling this method, execution of queries in parallel is enabled as long as this
-     * database handle is open. To disable execution of queries in parallel, database should
-     * be closed and reopened.
-     * <p>
+     * </p><p>
      * If a query is part of a transaction, then it is executed on the same database handle the
      * transaction was begun.
-     * <p>
-     * If the database has any attached databases, then execution of queries in paralel is NOT
-     * possible. In such cases, a message is printed to logcat and false is returned.
-     * <p>
-     * This feature is not available for :memory: databases. In such cases,
-     * a message is printed to logcat and false is returned.
-     * <p>
-     * A typical way to use this method is the following:
-     * <pre>
-     *     SQLiteDatabase db = SQLiteDatabase.openDatabase("db_filename", cursorFactory,
-     *             CREATE_IF_NECESSARY, myDatabaseErrorHandler);
-     *     db.enableWriteAheadLogging();
-     * </pre>
-     * <p>
+     * </p><p>
      * Writers should use {@link #beginTransactionNonExclusive()} or
      * {@link #beginTransactionWithListenerNonExclusive(SQLiteTransactionListener)}
-     * to start a trsnsaction.
-     * Non-exclusive mode allows database file to be in readable by threads executing queries.
+     * to start a transaction.  Non-exclusive mode allows database file to be in readable
+     * by other threads executing queries.
+     * </p><p>
+     * If the database has any attached databases, then execution of queries in parallel is NOT
+     * possible.  Likewise, write-ahead logging is not supported for read-only databases
+     * or memory databases.  In such cases, {@link #enableWriteAheadLogging} returns false.
+     * </p><p>
+     * The best way to enable write-ahead logging is to pass the
+     * {@link #ENABLE_WRITE_AHEAD_LOGGING} flag to {@link #openDatabase}.  This is
+     * more efficient than calling {@link #enableWriteAheadLogging}.
+     * <code><pre>
+     *     SQLiteDatabase db = SQLiteDatabase.openDatabase("db_filename", cursorFactory,
+     *             SQLiteDatabase.CREATE_IF_NECESSARY | SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING,
+     *             myDatabaseErrorHandler);
+     *     db.enableWriteAheadLogging();
+     * </pre></code>
+     * </p><p>
+     * Another way to enable write-ahead logging is to call {@link #enableWriteAheadLogging}
+     * after opening the database.
+     * <code><pre>
+     *     SQLiteDatabase db = SQLiteDatabase.openDatabase("db_filename", cursorFactory,
+     *             SQLiteDatabase.CREATE_IF_NECESSARY, myDatabaseErrorHandler);
+     *     db.enableWriteAheadLogging();
+     * </pre></code>
+     * </p><p>
+     * See also <a href="http://sqlite.org/wal.html">SQLite Write-Ahead Logging</a> for
+     * more details about how write-ahead logging works.
      * </p>
      *
-     * @return true if write-ahead-logging is set. false otherwise
+     * @return True if write-ahead logging is enabled.
+     *
+     * @throws IllegalStateException if there are transactions in progress at the
+     * time this method is called.  WAL mode can only be changed when there are no
+     * transactions in progress.
+     *
+     * @see #ENABLE_WRITE_AHEAD_LOGGING
+     * @see #disableWriteAheadLogging
      */
     public boolean enableWriteAheadLogging() {
         synchronized (mLock) {
             throwIfNotOpenLocked();
 
-            if (mIsWALEnabledLocked) {
+            if ((mConfigurationLocked.openFlags & ENABLE_WRITE_AHEAD_LOGGING) != 0) {
                 return true;
             }
 
@@ -1835,32 +1895,57 @@
                 return false;
             }
 
-            mIsWALEnabledLocked = true;
-            mConfigurationLocked.maxConnectionPoolSize = SQLiteGlobal.getWALConnectionPoolSize();
-            mConfigurationLocked.syncMode = SQLiteGlobal.getWALSyncMode();
-            mConfigurationLocked.journalMode = "WAL";
-            mConnectionPoolLocked.reconfigure(mConfigurationLocked);
+            mConfigurationLocked.openFlags |= ENABLE_WRITE_AHEAD_LOGGING;
+            try {
+                mConnectionPoolLocked.reconfigure(mConfigurationLocked);
+            } catch (RuntimeException ex) {
+                mConfigurationLocked.openFlags &= ~ENABLE_WRITE_AHEAD_LOGGING;
+                throw ex;
+            }
         }
         return true;
     }
 
     /**
      * This method disables the features enabled by {@link #enableWriteAheadLogging()}.
-     * @hide
+     *
+     * @throws IllegalStateException if there are transactions in progress at the
+     * time this method is called.  WAL mode can only be changed when there are no
+     * transactions in progress.
+     *
+     * @see #enableWriteAheadLogging
      */
     public void disableWriteAheadLogging() {
         synchronized (mLock) {
             throwIfNotOpenLocked();
 
-            if (!mIsWALEnabledLocked) {
+            if ((mConfigurationLocked.openFlags & ENABLE_WRITE_AHEAD_LOGGING) == 0) {
                 return;
             }
 
-            mIsWALEnabledLocked = false;
-            mConfigurationLocked.maxConnectionPoolSize = 1;
-            mConfigurationLocked.syncMode = SQLiteGlobal.getDefaultSyncMode();
-            mConfigurationLocked.journalMode = SQLiteGlobal.getDefaultJournalMode();
-            mConnectionPoolLocked.reconfigure(mConfigurationLocked);
+            mConfigurationLocked.openFlags &= ~ENABLE_WRITE_AHEAD_LOGGING;
+            try {
+                mConnectionPoolLocked.reconfigure(mConfigurationLocked);
+            } catch (RuntimeException ex) {
+                mConfigurationLocked.openFlags |= ENABLE_WRITE_AHEAD_LOGGING;
+                throw ex;
+            }
+        }
+    }
+
+    /**
+     * Returns true if write-ahead logging has been enabled for this database.
+     *
+     * @return True if write-ahead logging has been enabled for this database.
+     *
+     * @see #enableWriteAheadLogging
+     * @see #ENABLE_WRITE_AHEAD_LOGGING
+     */
+    public boolean isWriteAheadLoggingEnabled() {
+        synchronized (mLock) {
+            throwIfNotOpenLocked();
+
+            return (mConfigurationLocked.openFlags & ENABLE_WRITE_AHEAD_LOGGING) != 0;
         }
     }
 
diff --git a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
index efbcaca..123c2c6 100644
--- a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
+++ b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
@@ -62,14 +62,6 @@
     public int openFlags;
 
     /**
-     * The maximum number of connections to retain in the connection pool.
-     * Must be at least 1.
-     *
-     * Default is 1.
-     */
-    public int maxConnectionPoolSize;
-
-    /**
      * The maximum size of the prepared statement cache for each database connection.
      * Must be non-negative.
      *
@@ -85,20 +77,6 @@
     public Locale locale;
 
     /**
-     * The database synchronization mode.
-     *
-     * Default is {@link SQLiteGlobal#getDefaultSyncMode()}.
-     */
-    public String syncMode;
-
-    /**
-     * The database journal mode.
-     *
-     * Default is {@link SQLiteGlobal#getDefaultJournalMode()}.
-     */
-    public String journalMode;
-
-    /**
      * The custom functions to register.
      */
     public final ArrayList<SQLiteCustomFunction> customFunctions =
@@ -121,11 +99,8 @@
         this.openFlags = openFlags;
 
         // Set default values for optional parameters.
-        maxConnectionPoolSize = 1;
         maxSqlCacheSize = 25;
         locale = Locale.getDefault();
-        syncMode = SQLiteGlobal.getDefaultSyncMode();
-        journalMode = SQLiteGlobal.getDefaultJournalMode();
     }
 
     /**
@@ -159,11 +134,8 @@
         }
 
         openFlags = other.openFlags;
-        maxConnectionPoolSize = other.maxConnectionPoolSize;
         maxSqlCacheSize = other.maxSqlCacheSize;
         locale = other.locale;
-        syncMode = other.syncMode;
-        journalMode = other.journalMode;
         customFunctions.clear();
         customFunctions.addAll(other.customFunctions);
     }
diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java
index ffa4663..fe37b8f 100644
--- a/core/java/android/database/sqlite/SQLiteOpenHelper.java
+++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java
@@ -58,6 +58,7 @@
 
     private SQLiteDatabase mDatabase;
     private boolean mIsInitializing;
+    private boolean mEnableWriteAheadLogging;
     private final DatabaseErrorHandler mErrorHandler;
 
     /**
@@ -74,7 +75,7 @@
      *     newer, {@link #onDowngrade} will be used to downgrade the database
      */
     public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) {
-        this(context, name, factory, version, new DefaultDatabaseErrorHandler());
+        this(context, name, factory, version, null);
     }
 
     /**
@@ -92,14 +93,11 @@
      *     {@link #onUpgrade} will be used to upgrade the database; if the database is
      *     newer, {@link #onDowngrade} will be used to downgrade the database
      * @param errorHandler the {@link DatabaseErrorHandler} to be used when sqlite reports database
-     * corruption.
+     * corruption, or null to use the default error handler.
      */
     public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version,
             DatabaseErrorHandler errorHandler) {
         if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version);
-        if (errorHandler == null) {
-            throw new IllegalArgumentException("DatabaseErrorHandler param value can't be null.");
-        }
 
         mContext = context;
         mName = name;
@@ -117,6 +115,32 @@
     }
 
     /**
+     * Enables or disables the use of write-ahead logging for the database.
+     *
+     * Write-ahead logging cannot be used with read-only databases so the value of
+     * this flag is ignored if the database is opened read-only.
+     *
+     * @param enabled True if write-ahead logging should be enabled, false if it
+     * should be disabled.
+     *
+     * @see SQLiteDatabase#enableWriteAheadLogging()
+     */
+    public void setWriteAheadLoggingEnabled(boolean enabled) {
+        synchronized (this) {
+            if (mEnableWriteAheadLogging != enabled) {
+                if (mDatabase != null && mDatabase.isOpen() && !mDatabase.isReadOnly()) {
+                    if (enabled) {
+                        mDatabase.enableWriteAheadLogging();
+                    } else {
+                        mDatabase.disableWriteAheadLogging();
+                    }
+                }
+                mEnableWriteAheadLogging = enabled;
+            }
+        }
+    }
+
+    /**
      * Create and/or open a database that will be used for reading and writing.
      * The first time this is called, the database will be opened and
      * {@link #onCreate}, {@link #onUpgrade} and/or {@link #onOpen} will be
@@ -197,7 +221,9 @@
                         db = SQLiteDatabase.openDatabase(path, mFactory,
                                 SQLiteDatabase.OPEN_READONLY, mErrorHandler);
                     } else {
-                        db = mContext.openOrCreateDatabase(mName, 0, mFactory, mErrorHandler);
+                        db = mContext.openOrCreateDatabase(mName, mEnableWriteAheadLogging ?
+                                Context.MODE_ENABLE_WRITE_AHEAD_LOGGING : 0,
+                                mFactory, mErrorHandler);
                     }
                 } catch (SQLiteException ex) {
                     if (writable) {
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 442535a..89c9c36 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -30,8 +30,8 @@
 interface INetworkPolicyManager {
 
     /** Control UID policies. */
-    void setUidPolicy(int uid, int policy);
-    int getUidPolicy(int uid);
+    void setAppPolicy(int appId, int policy);
+    int getAppPolicy(int appId);
 
     boolean isUidForeground(int uid);
 
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 7173751..c09c676 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -88,21 +88,21 @@
     }
 
     /**
-     * Set policy flags for specific UID.
+     * Set policy flags for specific application.
      *
      * @param policy {@link #POLICY_NONE} or combination of flags like
      *            {@link #POLICY_REJECT_METERED_BACKGROUND}.
      */
-    public void setUidPolicy(int uid, int policy) {
+    public void setAppPolicy(int appId, int policy) {
         try {
-            mService.setUidPolicy(uid, policy);
+            mService.setAppPolicy(appId, policy);
         } catch (RemoteException e) {
         }
     }
 
-    public int getUidPolicy(int uid) {
+    public int getAppPolicy(int appId) {
         try {
-            return mService.getUidPolicy(uid);
+            return mService.getAppPolicy(appId);
         } catch (RemoteException e) {
             return POLICY_NONE;
         }
@@ -203,6 +203,7 @@
      * Check if given UID can have a {@link #setUidPolicy(int, int)} defined,
      * usually to protect critical system services.
      */
+    @Deprecated
     public static boolean isUidValidForPolicy(Context context, int uid) {
         // first, quick-reject non-applications
         if (uid < android.os.Process.FIRST_APPLICATION_UID
diff --git a/core/java/android/os/UserId.java b/core/java/android/os/UserId.java
index 0da67d63..8bf6c6e 100644
--- a/core/java/android/os/UserId.java
+++ b/core/java/android/os/UserId.java
@@ -61,6 +61,15 @@
         return uid >= Process.FIRST_ISOLATED_UID && uid <= Process.LAST_ISOLATED_UID;
     }
 
+    public static boolean isApp(int uid) {
+        if (uid > 0) {
+            uid = UserId.getAppId(uid);
+            return uid >= Process.FIRST_APPLICATION_UID && uid <= Process.LAST_APPLICATION_UID;
+        } else {
+            return false;
+        }
+    }
+
     /**
      * Returns the user id for a given uid.
      * @hide
@@ -96,4 +105,12 @@
     public static final int getAppId(int uid) {
         return uid % PER_USER_RANGE;
     }
+
+    /**
+     * Returns the user id of the current process
+     * @return user id of the current process
+     */
+    public static final int myUserId() {
+        return getUserId(Process.myUid());
+    }
 }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index fbb3273..d74ccb8 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -793,6 +793,7 @@
             MOVED_TO_SECURE.add(Secure.HTTP_PROXY);
             MOVED_TO_SECURE.add(Secure.INSTALL_NON_MARKET_APPS);
             MOVED_TO_SECURE.add(Secure.LOCATION_PROVIDERS_ALLOWED);
+            MOVED_TO_SECURE.add(Secure.LOCK_BIOMETRIC_WEAK_FLAGS);
             MOVED_TO_SECURE.add(Secure.LOCK_PATTERN_ENABLED);
             MOVED_TO_SECURE.add(Secure.LOCK_PATTERN_VISIBLE);
             MOVED_TO_SECURE.add(Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED);
@@ -2657,6 +2658,13 @@
         public static final String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed";
 
         /**
+         * A flag containing settings used for biometric weak
+         * @hide
+         */
+        public static final String LOCK_BIOMETRIC_WEAK_FLAGS =
+                "lock_biometric_weak_flags";
+
+        /**
          * Whether autolock is enabled (0 = false, 1 = true)
          */
         public static final String LOCK_PATTERN_ENABLED = "lock_pattern_autolock";
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index fecc8f9..850349b 100755
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -46,6 +46,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.SharedPreferences;
+import android.content.res.Resources;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
@@ -554,12 +555,15 @@
     private synchronized void updateSdpRecords() {
         ArrayList<ParcelUuid> uuids = new ArrayList<ParcelUuid>();
 
-        // Add the default records
-        uuids.add(BluetoothUuid.HSP_AG);
-        uuids.add(BluetoothUuid.ObexObjectPush);
+        Resources R = mContext.getResources();
 
-        if (mContext.getResources().
-                getBoolean(com.android.internal.R.bool.config_voice_capable)) {
+        // Add the default records
+        if (R.getBoolean(com.android.internal.R.bool.config_bluetooth_default_profiles)) {
+            uuids.add(BluetoothUuid.HSP_AG);
+            uuids.add(BluetoothUuid.ObexObjectPush);
+        }
+
+        if (R.getBoolean(com.android.internal.R.bool.config_voice_capable)) {
             uuids.add(BluetoothUuid.Handsfree_AG);
             uuids.add(BluetoothUuid.PBAP_PSE);
         }
@@ -567,14 +571,16 @@
         // Add SDP records for profiles maintained by Android userspace
         addReservedSdpRecords(uuids);
 
-        // Enable profiles maintained by Bluez userspace.
-        setBluetoothTetheringNative(true, BluetoothPanProfileHandler.NAP_ROLE,
-                BluetoothPanProfileHandler.NAP_BRIDGE);
+        if (R.getBoolean(com.android.internal.R.bool.config_bluetooth_default_profiles)) {
+            // Enable profiles maintained by Bluez userspace.
+            setBluetoothTetheringNative(true, BluetoothPanProfileHandler.NAP_ROLE,
+                   BluetoothPanProfileHandler.NAP_BRIDGE);
 
-        // Add SDP records for profiles maintained by Bluez userspace
-        uuids.add(BluetoothUuid.AudioSource);
-        uuids.add(BluetoothUuid.AvrcpTarget);
-        uuids.add(BluetoothUuid.NAP);
+            // Add SDP records for profiles maintained by Bluez userspace
+            uuids.add(BluetoothUuid.AudioSource);
+            uuids.add(BluetoothUuid.AvrcpTarget);
+            uuids.add(BluetoothUuid.NAP);
+        }
 
         // Cannot cast uuids.toArray directly since ParcelUuid is parcelable
         mAdapterUuids = new ParcelUuid[uuids.size()];
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
index 1dabad2..a50f09f 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -16,8 +16,6 @@
 
 package android.view;
 
-import android.os.Handler;
-
 /**
  * A display lists records a series of graphics related operation and can replay
  * them later. Display lists are usually built by recording operations on a
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index b98257c..1f140e95 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -464,8 +464,8 @@
         static final Object[] sEglLock = new Object[0];
         int mWidth = -1, mHeight = -1;
 
-        static final ThreadLocal<Gl20Renderer.Gl20RendererEglContext> sEglContextStorage
-                = new ThreadLocal<Gl20Renderer.Gl20RendererEglContext>();
+        static final ThreadLocal<ManagedEGLContext> sEglContextStorage
+                = new ThreadLocal<ManagedEGLContext>();
 
         EGLContext mEglContext;
         Thread mEglThread;
@@ -622,7 +622,7 @@
             }
         }
 
-        abstract GLES20Canvas createCanvas();
+        abstract HardwareCanvas createCanvas();
 
         abstract int[] getConfig(boolean dirtyRegions);
 
@@ -662,16 +662,18 @@
                 }
             }
 
-            Gl20Renderer.Gl20RendererEglContext managedContext = sEglContextStorage.get();
+            ManagedEGLContext managedContext = sEglContextStorage.get();
             mEglContext = managedContext != null ? managedContext.getContext() : null;
             mEglThread = Thread.currentThread();
 
             if (mEglContext == null) {
                 mEglContext = createContext(sEgl, sEglDisplay, sEglConfig);
-                sEglContextStorage.set(new Gl20Renderer.Gl20RendererEglContext(mEglContext));
+                sEglContextStorage.set(createManagedContext(mEglContext));
             }
         }
 
+        abstract ManagedEGLContext createManagedContext(EGLContext eglContext);
+
         private EGLConfig chooseEglConfig() {
             EGLConfig[] configs = new EGLConfig[1];
             int[] configsCount = new int[1];
@@ -1103,7 +1105,8 @@
                 // Make sure we do this on the correct thread.
                 if (mHandler.getLooper() != Looper.myLooper()) {
                     mHandler.post(new Runnable() {
-                        @Override public void run() {
+                        @Override
+                        public void run() {
                             onTerminate(eglContext);
                         }
                     });
@@ -1142,11 +1145,16 @@
         }
 
         @Override
-        GLES20Canvas createCanvas() {
+        HardwareCanvas createCanvas() {
             return mGlCanvas = new GLES20Canvas(mTranslucent);
         }
 
         @Override
+        ManagedEGLContext createManagedContext(EGLContext eglContext) {
+            return new Gl20Renderer.Gl20RendererEglContext(mEglContext);
+        }
+
+        @Override
         int[] getConfig(boolean dirtyRegions) {
             return new int[] {
                     EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
@@ -1249,7 +1257,8 @@
                 if (isEnabled() && checkCurrent() != SURFACE_STATE_ERROR) needsContext = false;
 
                 if (needsContext) {
-                    Gl20RendererEglContext managedContext = sEglContextStorage.get();
+                    Gl20RendererEglContext managedContext =
+                            (Gl20RendererEglContext) sEglContextStorage.get();
                     if (managedContext == null) return;
                     usePbufferSurface(managedContext.getContext());
                 }
@@ -1282,7 +1291,8 @@
         static void trimMemory(int level) {
             if (sEgl == null || sEglConfig == null) return;
 
-            Gl20RendererEglContext managedContext = sEglContextStorage.get();
+            Gl20RendererEglContext managedContext =
+                    (Gl20RendererEglContext) sEglContextStorage.get();
             // We do not have OpenGL objects
             if (managedContext == null) {
                 return;
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 92e8f4e..77fd8d2 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -1654,14 +1654,22 @@
             }
         }
     }
-    
+
     /**
-     * Scales down the coordination of this event by the given scale.
+     * Applies a scale factor to all points within this event.
      *
+     * This method is used to adjust touch events to simulate different density
+     * displays for compatibility mode.  The values returned by {@link #getRawX()},
+     * {@link #getRawY()}, {@link #getXPrecision()} and {@link #getYPrecision()}
+     * are also affected by the scale factor.
+     *
+     * @param scale The scale factor to apply.
      * @hide
      */
     public final void scale(float scale) {
-        nativeScale(mNativePtr, scale);
+        if (scale != 1.0f) {
+            nativeScale(mNativePtr, scale);
+        }
     }
 
     /** {@inheritDoc} */
@@ -2631,7 +2639,9 @@
      * @param deltaY Amount to add to the current Y coordinate of the event.
      */
     public final void offsetLocation(float deltaX, float deltaY) {
-        nativeOffsetLocation(mNativePtr, deltaX, deltaY);
+        if (deltaX != 0.0f || deltaY != 0.0f) {
+            nativeOffsetLocation(mNativePtr, deltaX, deltaY);
+        }
     }
 
     /**
@@ -2644,7 +2654,7 @@
     public final void setLocation(float x, float y) {
         float oldX = getX();
         float oldY = getY();
-        nativeOffsetLocation(mNativePtr, x - oldX, y - oldY);
+        offsetLocation(x - oldX, y - oldY);
     }
     
     /**
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index edaa262..eb80290d 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -20,6 +20,7 @@
 import android.graphics.*;
 import android.os.Parcelable;
 import android.os.Parcel;
+import android.os.SystemProperties;
 import android.util.Log;
 
 /**
@@ -35,6 +36,15 @@
     public static final int ROTATION_180     = 2;
     public static final int ROTATION_270     = 3;
 
+    private static final boolean headless = "1".equals(
+        SystemProperties.get("ro.config.headless", "0"));
+
+    private static void checkHeadless() {
+        if(headless) {
+            throw new UnsupportedOperationException("Device is headless");
+        }
+    }
+
     /**
      * Create Surface from a {@link SurfaceTexture}.
      *
@@ -46,6 +56,8 @@
      * Surface.
      */
     public Surface(SurfaceTexture surfaceTexture) {
+        checkHeadless();
+
         if (DEBUG_RELEASE) {
             mCreationStack = new Exception();
         }
@@ -244,6 +256,8 @@
     public Surface(SurfaceSession s,
             int pid, int display, int w, int h, int format, int flags)
         throws OutOfResourcesException {
+        checkHeadless();
+
         if (DEBUG_RELEASE) {
             mCreationStack = new Exception();
         }
@@ -255,6 +269,8 @@
     public Surface(SurfaceSession s,
             int pid, String name, int display, int w, int h, int format, int flags)
         throws OutOfResourcesException {
+        checkHeadless();
+
         if (DEBUG_RELEASE) {
             mCreationStack = new Exception();
         }
@@ -269,6 +285,8 @@
      * @hide
      */
     public Surface() {
+        checkHeadless();
+
         if (DEBUG_RELEASE) {
             mCreationStack = new Exception();
         }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 6c195c4..770d899 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1459,7 +1459,7 @@
      * apps.
      * @hide
      */
-    public static final boolean USE_DISPLAY_LIST_PROPERTIES = true;
+    public static final boolean USE_DISPLAY_LIST_PROPERTIES = false;
 
     /**
      * Map used to store views' tags.
@@ -1707,25 +1707,25 @@
      * Horizontal layout direction of this view is from Left to Right.
      * Use with {@link #setLayoutDirection}.
      */
-    public static final int LAYOUT_DIRECTION_LTR = 0x00000001;
+    public static final int LAYOUT_DIRECTION_LTR = 0;
 
     /**
      * Horizontal layout direction of this view is from Right to Left.
      * Use with {@link #setLayoutDirection}.
      */
-    public static final int LAYOUT_DIRECTION_RTL = 0x00000002;
+    public static final int LAYOUT_DIRECTION_RTL = 1;
 
     /**
      * Horizontal layout direction of this view is inherited from its parent.
      * Use with {@link #setLayoutDirection}.
      */
-    public static final int LAYOUT_DIRECTION_INHERIT = 0x00000004;
+    public static final int LAYOUT_DIRECTION_INHERIT = 2;
 
     /**
      * Horizontal layout direction of this view is from deduced from the default language
      * script for the locale. Use with {@link #setLayoutDirection}.
      */
-    public static final int LAYOUT_DIRECTION_LOCALE = 0x00000008;
+    public static final int LAYOUT_DIRECTION_LOCALE = 3;
 
     /**
      * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED)
@@ -1737,34 +1737,38 @@
      * Mask for use with private flags indicating bits used for horizontal layout direction.
      * @hide
      */
-    static final int LAYOUT_DIRECTION_MASK = 0x0000000F << LAYOUT_DIRECTION_MASK_SHIFT;
+    static final int LAYOUT_DIRECTION_MASK = 0x00000003 << LAYOUT_DIRECTION_MASK_SHIFT;
 
     /**
      * Indicates whether the view horizontal layout direction has been resolved and drawn to the
      * right-to-left direction.
      * @hide
      */
-    static final int LAYOUT_DIRECTION_RESOLVED_RTL = 0x00000010 << LAYOUT_DIRECTION_MASK_SHIFT;
+    static final int LAYOUT_DIRECTION_RESOLVED_RTL = 4 << LAYOUT_DIRECTION_MASK_SHIFT;
 
     /**
      * Indicates whether the view horizontal layout direction has been resolved.
      * @hide
      */
-    static final int LAYOUT_DIRECTION_RESOLVED = 0x00000020 << LAYOUT_DIRECTION_MASK_SHIFT;
+    static final int LAYOUT_DIRECTION_RESOLVED = 8 << LAYOUT_DIRECTION_MASK_SHIFT;
 
     /**
      * Mask for use with private flags indicating bits used for resolved horizontal layout direction.
      * @hide
      */
-    static final int LAYOUT_DIRECTION_RESOLVED_MASK = 0x00000030 << LAYOUT_DIRECTION_MASK_SHIFT;
+    static final int LAYOUT_DIRECTION_RESOLVED_MASK = 0x0000000C << LAYOUT_DIRECTION_MASK_SHIFT;
 
     /*
      * Array of horizontal layout direction flags for mapping attribute "layoutDirection" to correct
      * flag value.
      * @hide
      */
-    private static final int[] LAYOUT_DIRECTION_FLAGS = {LAYOUT_DIRECTION_LTR,
-            LAYOUT_DIRECTION_RTL, LAYOUT_DIRECTION_INHERIT, LAYOUT_DIRECTION_LOCALE};
+    private static final int[] LAYOUT_DIRECTION_FLAGS = {
+            LAYOUT_DIRECTION_LTR,
+            LAYOUT_DIRECTION_RTL,
+            LAYOUT_DIRECTION_INHERIT,
+            LAYOUT_DIRECTION_LOCALE
+    };
 
     /**
      * Default horizontal layout direction.
@@ -1783,6 +1787,97 @@
     static final int HAS_TRANSIENT_STATE = 0x00000100;
 
 
+    /**
+     * Text direction is inherited thru {@link ViewGroup}
+     */
+    public static final int TEXT_DIRECTION_INHERIT = 0;
+
+    /**
+     * Text direction is using "first strong algorithm". The first strong directional character
+     * determines the paragraph direction. If there is no strong directional character, the
+     * paragraph direction is the view's resolved layout direction.
+     */
+    public static final int TEXT_DIRECTION_FIRST_STRONG = 1;
+
+    /**
+     * Text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains
+     * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters.
+     * If there are neither, the paragraph direction is the view's resolved layout direction.
+     */
+    public static final int TEXT_DIRECTION_ANY_RTL = 2;
+
+    /**
+     * Text direction is forced to LTR.
+     */
+    public static final int TEXT_DIRECTION_LTR = 3;
+
+    /**
+     * Text direction is forced to RTL.
+     */
+    public static final int TEXT_DIRECTION_RTL = 4;
+
+    /**
+     * Text direction is coming from the system Locale.
+     */
+    public static final int TEXT_DIRECTION_LOCALE = 5;
+
+    /**
+     * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED)
+     * @hide
+     */
+    static final int TEXT_DIRECTION_MASK_SHIFT = 6;
+
+    /**
+     * Default text direction is inherited
+     */
+    protected static int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT;
+
+    /**
+     * Mask for use with private flags indicating bits used for text direction.
+     * @hide
+     */
+    static final int TEXT_DIRECTION_MASK = 0x00000007 << TEXT_DIRECTION_MASK_SHIFT;
+
+    /**
+     * Array of text direction flags for mapping attribute "textDirection" to correct
+     * flag value.
+     * @hide
+     */
+    private static final int[] TEXT_DIRECTION_FLAGS = {
+            TEXT_DIRECTION_INHERIT << TEXT_DIRECTION_MASK_SHIFT,
+            TEXT_DIRECTION_FIRST_STRONG << TEXT_DIRECTION_MASK_SHIFT,
+            TEXT_DIRECTION_ANY_RTL << TEXT_DIRECTION_MASK_SHIFT,
+            TEXT_DIRECTION_LTR << TEXT_DIRECTION_MASK_SHIFT,
+            TEXT_DIRECTION_RTL << TEXT_DIRECTION_MASK_SHIFT,
+            TEXT_DIRECTION_LOCALE << TEXT_DIRECTION_MASK_SHIFT
+    };
+
+    /**
+     * Indicates whether the view text direction has been resolved.
+     * @hide
+     */
+    static final int TEXT_DIRECTION_RESOLVED = 0x00000008 << TEXT_DIRECTION_MASK_SHIFT;
+
+    /**
+     * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED)
+     * @hide
+     */
+    static final int TEXT_DIRECTION_RESOLVED_MASK_SHIFT = 10;
+
+    /**
+     * Mask for use with private flags indicating bits used for resolved text direction.
+     * @hide
+     */
+    static final int TEXT_DIRECTION_RESOLVED_MASK = 0x00000007 << TEXT_DIRECTION_RESOLVED_MASK_SHIFT;
+
+    /**
+     * Indicates whether the view text direction has been resolved to the "first strong" heuristic.
+     * @hide
+     */
+    static final int TEXT_DIRECTION_RESOLVED_DEFAULT =
+            TEXT_DIRECTION_FIRST_STRONG << TEXT_DIRECTION_RESOLVED_MASK_SHIFT;
+
+
     /* End of masks for mPrivateFlags2 */
 
     static final int DRAG_MASK = DRAG_CAN_ACCEPT | DRAG_HOVERED;
@@ -2657,82 +2752,6 @@
     AccessibilityDelegate mAccessibilityDelegate;
 
     /**
-     * Text direction is inherited thru {@link ViewGroup}
-     */
-    public static final int TEXT_DIRECTION_INHERIT = 0;
-
-    /**
-     * Text direction is using "first strong algorithm". The first strong directional character
-     * determines the paragraph direction. If there is no strong directional character, the
-     * paragraph direction is the view's resolved layout direction.
-     *
-     */
-    public static final int TEXT_DIRECTION_FIRST_STRONG = 1;
-
-    /**
-     * Text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains
-     * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters.
-     * If there are neither, the paragraph direction is the view's resolved layout direction.
-     *
-     */
-    public static final int TEXT_DIRECTION_ANY_RTL = 2;
-
-    /**
-     * Text direction is forced to LTR.
-     *
-     */
-    public static final int TEXT_DIRECTION_LTR = 3;
-
-    /**
-     * Text direction is forced to RTL.
-     *
-     */
-    public static final int TEXT_DIRECTION_RTL = 4;
-
-    /**
-     * Text direction is coming from the system Locale.
-     *
-     */
-    public static final int TEXT_DIRECTION_LOCALE = 5;
-
-    /**
-     * Default text direction is inherited
-     *
-     */
-    protected static int DEFAULT_TEXT_DIRECTION = TEXT_DIRECTION_INHERIT;
-
-    /**
-     * The text direction that has been defined by {@link #setTextDirection(int)}.
-     *
-     */
-    @ViewDebug.ExportedProperty(category = "text", mapping = {
-            @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"),
-            @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"),
-            @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"),
-            @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"),
-            @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"),
-            @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE")
-    })
-    private int mTextDirection = DEFAULT_TEXT_DIRECTION;
-
-    /**
-     * The resolved text direction.  This needs resolution if the value is
-     * TEXT_DIRECTION_INHERIT.  The resolution matches mTextDirection if it is
-     * not TEXT_DIRECTION_INHERIT, otherwise resolution proceeds up the parent
-     * chain of the view.
-     *
-     */
-    @ViewDebug.ExportedProperty(category = "text", mapping = {
-            @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"),
-            @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"),
-            @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"),
-            @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"),
-            @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"),
-            @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE")
-    })
-    private int mResolvedTextDirection = TEXT_DIRECTION_INHERIT;
-
-    /**
      * Consistency verifier for debugging purposes.
      * @hide
      */
@@ -2750,7 +2769,9 @@
         mContext = context;
         mResources = context != null ? context.getResources() : null;
         mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED;
-        mPrivateFlags2 |= (LAYOUT_DIRECTION_DEFAULT << LAYOUT_DIRECTION_MASK_SHIFT);
+        // Set layout and text direction defaults
+        mPrivateFlags2 = (LAYOUT_DIRECTION_DEFAULT << LAYOUT_DIRECTION_MASK_SHIFT) |
+                (TEXT_DIRECTION_DEFAULT << TEXT_DIRECTION_MASK_SHIFT);
         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
         setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS);
         mUserPaddingStart = -1;
@@ -3110,7 +3131,13 @@
                     setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null);
                     break;
                 case R.styleable.View_textDirection:
-                    mTextDirection = a.getInt(attr, DEFAULT_TEXT_DIRECTION);
+                    // Clear any text direction flag already set
+                    mPrivateFlags2 &= ~TEXT_DIRECTION_MASK;
+                    // Set the text direction flags depending on the value of the attribute
+                    final int textDirection = a.getInt(attr, -1);
+                    if (textDirection != -1) {
+                        mPrivateFlags2 |= TEXT_DIRECTION_FLAGS[textDirection];
+                    }
                     break;
             }
         }
@@ -11489,7 +11516,7 @@
                 layerType != LAYER_TYPE_HARDWARE;
 
         int restoreTo = -1;
-        if (!useDisplayListProperties) {
+        if (!useDisplayListProperties || transformToApply != null) {
             restoreTo = canvas.save();
         }
         if (offsetForScroll) {
@@ -11523,11 +11550,9 @@
                     if (concatMatrix) {
                         // Undo the scroll translation, apply the transformation matrix,
                         // then redo the scroll translate to get the correct result.
-                        if (!useDisplayListProperties) {
-                            canvas.translate(-transX, -transY);
-                            canvas.concat(transformToApply.getMatrix());
-                            canvas.translate(transX, transY);
-                        }
+                        canvas.translate(-transX, -transY);
+                        canvas.concat(transformToApply.getMatrix());
+                        canvas.translate(transX, transY);
                         parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;
                     }
 
@@ -11556,12 +11581,10 @@
                             layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
                         }
                         if (layerType == LAYER_TYPE_NONE) {
-                            if (!useDisplayListProperties) {
-                                final int scrollX = hasDisplayList ? 0 : sx;
-                                final int scrollY = hasDisplayList ? 0 : sy;
-                                canvas.saveLayerAlpha(scrollX, scrollY, scrollX + mRight - mLeft,
-                                        scrollY + mBottom - mTop, multipliedAlpha, layerFlags);
-                            }
+                            final int scrollX = hasDisplayList ? 0 : sx;
+                            final int scrollY = hasDisplayList ? 0 : sy;
+                            canvas.saveLayerAlpha(scrollX, scrollY, scrollX + mRight - mLeft,
+                                    scrollY + mBottom - mTop, multipliedAlpha, layerFlags);
                         }
                     } else {
                         // Alpha is handled by the child directly, clobber the layer's alpha
@@ -14495,8 +14518,16 @@
      * {@link #TEXT_DIRECTION_RTL},
      * {@link #TEXT_DIRECTION_LOCALE},
      */
+    @ViewDebug.ExportedProperty(category = "text", mapping = {
+            @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"),
+            @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"),
+            @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"),
+            @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"),
+            @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"),
+            @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE")
+    })
     public int getTextDirection() {
-        return mTextDirection;
+        return (mPrivateFlags2 & TEXT_DIRECTION_MASK) >> TEXT_DIRECTION_MASK_SHIFT;
     }
 
     /**
@@ -14512,9 +14543,14 @@
      * {@link #TEXT_DIRECTION_LOCALE},
      */
     public void setTextDirection(int textDirection) {
-        if (textDirection != mTextDirection) {
-            mTextDirection = textDirection;
+        if (getTextDirection() != textDirection) {
+            // Reset the current text direction
+            mPrivateFlags2 &= ~TEXT_DIRECTION_MASK;
+            // Set the new text direction
+            mPrivateFlags2 |= ((textDirection << TEXT_DIRECTION_MASK_SHIFT) & TEXT_DIRECTION_MASK);
+            // Reset the current resolved text direction
             resetResolvedTextDirection();
+            // Ask for a layout pass
             requestLayout();
         }
     }
@@ -14522,7 +14558,12 @@
     /**
      * Return the resolved text direction.
      *
-     * @return the resolved text direction. Return one of:
+     * This needs resolution if the value is TEXT_DIRECTION_INHERIT. The resolution matches
+     * {@link #getTextDirection()}if it is not TEXT_DIRECTION_INHERIT, otherwise resolution proceeds
+     * up the parent chain of the view. if there is no parent, then it will return the default
+     * {@link #TEXT_DIRECTION_FIRST_STRONG}.
+     *
+     * @return the resolved text direction. Returns one of:
      *
      * {@link #TEXT_DIRECTION_FIRST_STRONG}
      * {@link #TEXT_DIRECTION_ANY_RTL},
@@ -14531,10 +14572,11 @@
      * {@link #TEXT_DIRECTION_LOCALE},
      */
     public int getResolvedTextDirection() {
-        if (mResolvedTextDirection == TEXT_DIRECTION_INHERIT) {
+        // The text direction is not inherited so return it back
+        if ((mPrivateFlags2 & TEXT_DIRECTION_RESOLVED) != TEXT_DIRECTION_RESOLVED) {
             resolveTextDirection();
         }
-        return mResolvedTextDirection;
+        return (mPrivateFlags2 & TEXT_DIRECTION_RESOLVED_MASK) >> TEXT_DIRECTION_RESOLVED_MASK_SHIFT;
     }
 
     /**
@@ -14542,17 +14584,51 @@
      * resolution is done.
      */
     public void resolveTextDirection() {
-        if (mResolvedTextDirection != TEXT_DIRECTION_INHERIT) {
-            // Resolution has already been done.
-            return;
+        // Reset any previous text direction resolution
+        mPrivateFlags2 &= ~(TEXT_DIRECTION_RESOLVED | TEXT_DIRECTION_RESOLVED_MASK);
+
+        // Set resolved text direction flag depending on text direction flag
+        final int textDirection = getTextDirection();
+        switch(textDirection) {
+            case TEXT_DIRECTION_INHERIT:
+                if (canResolveTextDirection()) {
+                    ViewGroup viewGroup = ((ViewGroup) mParent);
+
+                    // Set current resolved direction to the same value as the parent's one
+                    final int parentResolvedDirection = viewGroup.getResolvedTextDirection();
+                    switch (parentResolvedDirection) {
+                        case TEXT_DIRECTION_FIRST_STRONG:
+                        case TEXT_DIRECTION_ANY_RTL:
+                        case TEXT_DIRECTION_LTR:
+                        case TEXT_DIRECTION_RTL:
+                        case TEXT_DIRECTION_LOCALE:
+                            mPrivateFlags2 |=
+                                    (parentResolvedDirection << TEXT_DIRECTION_RESOLVED_MASK_SHIFT);
+                            break;
+                        default:
+                            // Default resolved direction is "first strong" heuristic
+                            mPrivateFlags2 |= TEXT_DIRECTION_RESOLVED_DEFAULT;
+                    }
+                } else {
+                    // We cannot do the resolution if there is no parent, so use the default one
+                    mPrivateFlags2 |= TEXT_DIRECTION_RESOLVED_DEFAULT;
+                }
+                break;
+            case TEXT_DIRECTION_FIRST_STRONG:
+            case TEXT_DIRECTION_ANY_RTL:
+            case TEXT_DIRECTION_LTR:
+            case TEXT_DIRECTION_RTL:
+            case TEXT_DIRECTION_LOCALE:
+                // Resolved direction is the same as text direction
+                mPrivateFlags2 |= (textDirection << TEXT_DIRECTION_RESOLVED_MASK_SHIFT);
+                break;
+            default:
+                // Default resolved direction is "first strong" heuristic
+                mPrivateFlags2 |= TEXT_DIRECTION_RESOLVED_DEFAULT;
         }
-        if (mTextDirection != TEXT_DIRECTION_INHERIT) {
-            mResolvedTextDirection = mTextDirection;
-        } else if (mParent != null && mParent instanceof ViewGroup) {
-            mResolvedTextDirection = ((ViewGroup) mParent).getResolvedTextDirection();
-        } else {
-            mResolvedTextDirection = TEXT_DIRECTION_FIRST_STRONG;
-        }
+
+        // Set to resolved
+        mPrivateFlags2 |= TEXT_DIRECTION_RESOLVED;
         onResolvedTextDirectionChanged();
     }
 
@@ -14566,12 +14642,26 @@
     }
 
     /**
+     * Check if text direction resolution can be done.
+     *
+     * @return true if text direction resolution can be done otherwise return false.
+     */
+    public boolean canResolveTextDirection() {
+        switch (getTextDirection()) {
+            case TEXT_DIRECTION_INHERIT:
+                return (mParent != null) && (mParent instanceof ViewGroup);
+            default:
+                return true;
+        }
+    }
+
+    /**
      * Reset resolved text direction. Text direction can be resolved with a call to
      * getResolvedTextDirection(). Will call {@link View#onResolvedTextDirectionReset} when
      * reset is done.
      */
     public void resetResolvedTextDirection() {
-        mResolvedTextDirection = TEXT_DIRECTION_INHERIT;
+        mPrivateFlags2 &= ~(TEXT_DIRECTION_RESOLVED | TEXT_DIRECTION_RESOLVED_MASK);
         onResolvedTextDirectionReset();
     }
 
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 4eb70ab..14b8084 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1919,7 +1919,9 @@
     }
 
     private void performDraw() {
-        if (!mAttachInfo.mScreenOn) return;
+        if (!mAttachInfo.mScreenOn && !mReportNextDraw) {
+            return;
+        }
 
         final long drawStartTime;
         if (ViewDebug.DEBUG_LATENCY) {
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 0e5ff20..17dbde8 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -403,6 +403,9 @@
                                 mIInputContext.finishComposingText();
                             } catch (RemoteException e) {
                             }
+                            // Check focus again in case that "onWindowFocus" is called before
+                            // handling this message.
+                            checkFocus(mHasBeenInactive);
                         }
                     }
                     return;
@@ -1173,13 +1176,17 @@
         }
     }
 
+    private void checkFocus(boolean forceNewFocus) {
+        if (checkFocusNoStartInput(forceNewFocus)) {
+            startInputInner(null, 0, 0, 0);
+        }
+    }
+
     /**
      * @hide
      */
     public void checkFocus() {
-        if (checkFocusNoStartInput(false)) {
-            startInputInner(null, 0, 0, 0);
-        }
+        checkFocus(false);
     }
 
     private boolean checkFocusNoStartInput(boolean forceNewFocus) {
diff --git a/core/java/android/webkit/WebSettingsClassic.java b/core/java/android/webkit/WebSettingsClassic.java
index 7e38570..c41bc00 100644
--- a/core/java/android/webkit/WebSettingsClassic.java
+++ b/core/java/android/webkit/WebSettingsClassic.java
@@ -121,9 +121,6 @@
     private boolean         mForceUserScalable = false;
 
     // AutoFill Profile data
-    /**
-     * @hide for now, pending API council approval.
-     */
     public static class AutoFillProfile {
         private int mUniqueId;
         private String mFullName;
@@ -644,7 +641,6 @@
     /**
      * Set the double-tap zoom of the page in percent. Default is 100.
      * @param doubleTapZoom A percent value for increasing or decreasing the double-tap zoom.
-     * @hide
      */
     public void setDoubleTapZoom(int doubleTapZoom) {
         if (mDoubleTapZoom != doubleTapZoom) {
@@ -656,7 +652,6 @@
     /**
      * Get the double-tap zoom of the page in percent.
      * @return A percent value describing the double-tap zoom.
-     * @hide
      */
     public int getDoubleTapZoom() {
         return mDoubleTapZoom;
@@ -1012,7 +1007,6 @@
     /**
      * Set the number of pages cached by the WebKit for the history navigation.
      * @param size A non-negative integer between 0 (no cache) and 20 (max).
-     * @hide
      */
     public synchronized void setPageCacheCapacity(int size) {
         if (size < 0) size = 0;
@@ -1108,7 +1102,6 @@
     /**
      * Tell the WebView to use Skia's hardware accelerated rendering path
      * @param flag True if the WebView should use Skia's hw-accel path
-     * @hide
      */
     public synchronized void setHardwareAccelSkiaEnabled(boolean flag) {
         if (mHardwareAccelSkia != flag) {
@@ -1119,7 +1112,6 @@
 
     /**
      * @return True if the WebView is using hardware accelerated skia
-     * @hide
      */
     public synchronized boolean getHardwareAccelSkiaEnabled() {
         return mHardwareAccelSkia;
@@ -1128,7 +1120,6 @@
     /**
      * Tell the WebView to show the visual indicator
      * @param flag True if the WebView should show the visual indicator
-     * @hide
      */
     public synchronized void setShowVisualIndicator(boolean flag) {
         if (mShowVisualIndicator != flag) {
@@ -1139,7 +1130,6 @@
 
     /**
      * @return True if the WebView is showing the visual indicator
-     * @hide
      */
     public synchronized boolean getShowVisualIndicator() {
         return mShowVisualIndicator;
@@ -1283,7 +1273,6 @@
      * @param flag True if the WebView should enable WebWorkers.
      * Note that this flag only affects V8. JSC does not have
      * an equivalent setting.
-     * @hide
      */
     public synchronized void setWorkersEnabled(boolean flag) {
         if (mWorkersEnabled != flag) {
@@ -1305,8 +1294,8 @@
 
     /**
      * Sets whether XSS Auditor is enabled.
+     * Only used by LayoutTestController.
      * @param flag Whether XSS Auditor should be enabled.
-     * @hide Only used by LayoutTestController.
      */
     public synchronized void setXSSAuditorEnabled(boolean flag) {
         if (mXSSAuditorEnabled != flag) {
@@ -1507,7 +1496,6 @@
      * of an HTML page to fit the screen. This conflicts with attempts by
      * the UI to zoom in and out of an image, so it is set false by default.
      * @param shrink Set true to let webkit shrink the standalone image to fit.
-     * {@hide}
      */
     public void setShrinksStandaloneImagesToFit(boolean shrink) {
         if (mShrinksStandaloneImagesToFit != shrink) {
@@ -1520,7 +1508,6 @@
      * Specify the maximum decoded image size. The default is
      * 2 megs for small memory devices and 8 megs for large memory devices.
      * @param size The maximum decoded size, or zero to set to the default.
-     * @hide
      */
     public void setMaximumDecodedImageSize(long size) {
         if (mMaximumDecodedImageSize != size) {
@@ -1562,7 +1549,6 @@
 
     /**
      * Returns whether the viewport metatag can disable zooming
-     * @hide
      */
     public boolean forceUserScalable() {
         return mForceUserScalable;
@@ -1571,7 +1557,6 @@
     /**
      * Sets whether viewport metatag can disable zooming.
      * @param flag Whether or not to forceably enable user scalable.
-     * @hide
      */
     public synchronized void setForceUserScalable(boolean flag) {
         mForceUserScalable = flag;
@@ -1584,9 +1569,6 @@
         }
     }
 
-    /**
-     * @hide
-     */
     public synchronized void setAutoFillEnabled(boolean enabled) {
         // AutoFill is always disabled in private browsing mode.
         boolean autoFillEnabled = enabled && !mPrivateBrowsingEnabled;
@@ -1596,16 +1578,10 @@
         }
     }
 
-    /**
-     * @hide
-     */
     public synchronized boolean getAutoFillEnabled() {
         return mAutoFillEnabled;
     }
 
-    /**
-     * @hide
-     */
     public synchronized void setAutoFillProfile(AutoFillProfile profile) {
         if (mAutoFillProfile != profile) {
             mAutoFillProfile = profile;
@@ -1613,9 +1589,6 @@
         }
     }
 
-    /**
-     * @hide
-     */
     public synchronized AutoFillProfile getAutoFillProfile() {
         return mAutoFillProfile;
     }
@@ -1633,18 +1606,12 @@
         }
     }
 
-    /**
-     * @hide
-     */
     public void setProperty(String key, String value) {
         if (mWebView.nativeSetProperty(key, value)) {
             mWebView.invalidate();
         }
     }
 
-    /**
-     * @hide
-     */
     public String getProperty(String key) {
         return mWebView.nativeGetProperty(key);
     }
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index 13a2c94..03329b8 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -348,8 +348,6 @@
  *
  * @hide
  */
-// TODO: Remove duplicated API documentation and @hide from fields and methods, and
-// checkThread() call. (All left in for now to ease branch merging.)
 // TODO: Check if any WebView published API methods are called from within here, and if so
 // we should bounce the call out via the proxy to enable any sub-class to override it.
 @Widget
@@ -1255,6 +1253,7 @@
     static final int AUTOFILL_FORM                      = 148;
     static final int ANIMATE_TEXT_SCROLL                = 149;
     static final int EDIT_TEXT_SIZE_CHANGED             = 150;
+    static final int SHOW_CARET_HANDLE                  = 151;
 
     private static final int FIRST_PACKAGE_MSG_ID = SCROLL_TO_MSG_ID;
     private static final int LAST_PACKAGE_MSG_ID = HIT_TEST_RESULT;
@@ -1463,8 +1462,6 @@
      */
     @Override
     public void init(Map<String, Object> javaScriptInterfaces, boolean privateBrowsing) {
-        checkThread();
-
         Context context = mContext;
 
         // Used by the chrome stack to find application paths
@@ -1496,8 +1493,7 @@
         mEditTextScroller = new Scroller(context);
     }
 
-    // === START: WebView Proxy binding ===
-    // Keep the webview proxy / SPI related stuff in this section, to minimize merge conflicts.
+    // WebViewProvider bindings
 
     static class Factory implements WebViewFactoryProvider,  WebViewFactoryProvider.Statics {
         @Override
@@ -1586,8 +1582,6 @@
         mWebViewPrivate.setScrollYRaw(mScrollY);
     }
 
-    // === END: WebView Proxy binding ===
-
     private static class TrustStorageListener extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -1968,7 +1962,6 @@
      */
     @Override
     public void setHorizontalScrollbarOverlay(boolean overlay) {
-        checkThread();
         mOverlayHorizontalScrollbar = overlay;
     }
 
@@ -1977,7 +1970,6 @@
      */
     @Override
     public void setVerticalScrollbarOverlay(boolean overlay) {
-        checkThread();
         mOverlayVerticalScrollbar = overlay;
     }
 
@@ -1986,7 +1978,6 @@
      */
     @Override
     public boolean overlayHorizontalScrollbar() {
-        checkThread();
         return mOverlayHorizontalScrollbar;
     }
 
@@ -1995,7 +1986,6 @@
      */
     @Override
     public boolean overlayVerticalScrollbar() {
-        checkThread();
         return mOverlayVerticalScrollbar;
     }
 
@@ -2021,7 +2011,6 @@
     /**
      * Returns the height (in pixels) of the embedded title bar (if any). Does not care about
      * scrolling
-     * @hide
      */
     protected int getTitleHeight() {
         if (mWebView instanceof TitleBarDelegate) {
@@ -2038,7 +2027,6 @@
     public int getVisibleTitleHeight() {
         // Actually, this method returns the height of the embedded title bar if one is set via the
         // hidden setEmbeddedTitleBar method.
-        checkThread();
         return getVisibleTitleHeightImpl();
     }
 
@@ -2084,7 +2072,6 @@
      */
     @Override
     public SslCertificate getCertificate() {
-        checkThread();
         return mCertificate;
     }
 
@@ -2093,7 +2080,6 @@
      */
     @Override
     public void setCertificate(SslCertificate certificate) {
-        checkThread();
         if (DebugFlags.WEB_VIEW) {
             Log.v(LOGTAG, "setCertificate=" + certificate);
         }
@@ -2110,7 +2096,6 @@
      */
     @Override
     public void savePassword(String host, String username, String password) {
-        checkThread();
         mDatabase.setUsernamePassword(host, username, password);
     }
 
@@ -2120,7 +2105,6 @@
     @Override
     public void setHttpAuthUsernamePassword(String host, String realm,
             String username, String password) {
-        checkThread();
         mDatabase.setHttpAuthUsernamePassword(host, realm, username, password);
     }
 
@@ -2129,7 +2113,6 @@
      */
     @Override
     public String[] getHttpAuthUsernamePassword(String host, String realm) {
-        checkThread();
         return mDatabase.getHttpAuthUsernamePassword(host, realm);
     }
 
@@ -2169,7 +2152,6 @@
      */
     @Override
     public void destroy() {
-        checkThread();
         destroyImpl();
     }
 
@@ -2202,7 +2184,6 @@
      */
     @Deprecated
     public static void enablePlatformNotifications() {
-        checkThread();
         synchronized (WebViewClassic.class) {
             sNotificationsEnabled = true;
             Context context = JniUtil.getContext();
@@ -2216,7 +2197,6 @@
      */
     @Deprecated
     public static void disablePlatformNotifications() {
-        checkThread();
         synchronized (WebViewClassic.class) {
             sNotificationsEnabled = false;
             Context context = JniUtil.getContext();
@@ -2230,10 +2210,9 @@
      *
      * @param flags JS engine flags in a String
      *
-     * @hide This is an implementation detail.
+     * This is an implementation detail.
      */
     public void setJsFlags(String flags) {
-        checkThread();
         mWebViewCore.sendMessage(EventHub.SET_JS_FLAGS, flags);
     }
 
@@ -2242,17 +2221,14 @@
      */
     @Override
     public void setNetworkAvailable(boolean networkUp) {
-        checkThread();
         mWebViewCore.sendMessage(EventHub.SET_NETWORK_STATE,
                 networkUp ? 1 : 0, 0);
     }
 
     /**
      * Inform WebView about the current network type.
-     * {@hide}
      */
     public void setNetworkType(String type, String subtype) {
-        checkThread();
         Map<String, String> map = new HashMap<String, String>();
         map.put("type", type);
         map.put("subtype", subtype);
@@ -2264,7 +2240,6 @@
      */
     @Override
     public WebBackForwardList saveState(Bundle outState) {
-        checkThread();
         if (outState == null) {
             return null;
         }
@@ -2316,7 +2291,6 @@
     @Override
     @Deprecated
     public boolean savePicture(Bundle b, final File dest) {
-        checkThread();
         if (dest == null || b == null) {
             return false;
         }
@@ -2378,7 +2352,6 @@
     @Override
     @Deprecated
     public boolean restorePicture(Bundle b, File src) {
-        checkThread();
         if (src == null || b == null) {
             return false;
         }
@@ -2424,7 +2397,6 @@
      * of WebView.
      * @param stream The {@link OutputStream} to save to
      * @return True if saved successfully
-     * @hide
      */
     public boolean saveViewState(OutputStream stream) {
         try {
@@ -2440,7 +2412,6 @@
      * {@link #saveViewState(OutputStream)} for more information.
      * @param stream The {@link InputStream} to load from
      * @return True if loaded successfully
-     * @hide
      */
     public boolean loadViewState(InputStream stream) {
         try {
@@ -2470,7 +2441,6 @@
      */
     @Override
     public WebBackForwardList restoreState(Bundle inState) {
-        checkThread();
         WebBackForwardList returnList = null;
         if (inState == null) {
             return returnList;
@@ -2527,7 +2497,6 @@
      */
     @Override
     public void loadUrl(String url, Map<String, String> additionalHttpHeaders) {
-        checkThread();
         loadUrlImpl(url, additionalHttpHeaders);
     }
 
@@ -2545,7 +2514,6 @@
      */
     @Override
     public void loadUrl(String url) {
-        checkThread();
         loadUrlImpl(url);
     }
 
@@ -2561,7 +2529,6 @@
      */
     @Override
     public void postUrl(String url, byte[] postData) {
-        checkThread();
         if (URLUtil.isNetworkUrl(url)) {
             switchOutDrawHistory();
             WebViewCore.PostUrlData arg = new WebViewCore.PostUrlData();
@@ -2579,7 +2546,6 @@
      */
     @Override
     public void loadData(String data, String mimeType, String encoding) {
-        checkThread();
         loadDataImpl(data, mimeType, encoding);
     }
 
@@ -2600,7 +2566,6 @@
     @Override
     public void loadDataWithBaseURL(String baseUrl, String data,
             String mimeType, String encoding, String historyUrl) {
-        checkThread();
 
         if (baseUrl != null && baseUrl.toLowerCase().startsWith("data:")) {
             loadDataImpl(data, mimeType, encoding);
@@ -2622,7 +2587,6 @@
      */
     @Override
     public void saveWebArchive(String filename) {
-        checkThread();
         saveWebArchiveImpl(filename, false, null);
     }
 
@@ -2644,7 +2608,6 @@
      */
     @Override
     public void saveWebArchive(String basename, boolean autoname, ValueCallback<String> callback) {
-        checkThread();
         saveWebArchiveImpl(basename, autoname, callback);
     }
 
@@ -2659,7 +2622,6 @@
      */
     @Override
     public void stopLoading() {
-        checkThread();
         // TODO: should we clear all the messages in the queue before sending
         // STOP_LOADING?
         switchOutDrawHistory();
@@ -2671,7 +2633,6 @@
      */
     @Override
     public void reload() {
-        checkThread();
         clearHelpers();
         switchOutDrawHistory();
         mWebViewCore.sendMessage(EventHub.RELOAD);
@@ -2682,7 +2643,6 @@
      */
     @Override
     public boolean canGoBack() {
-        checkThread();
         WebBackForwardList l = mCallbackProxy.getBackForwardList();
         synchronized (l) {
             if (l.getClearPending()) {
@@ -2698,7 +2658,6 @@
      */
     @Override
     public void goBack() {
-        checkThread();
         goBackOrForwardImpl(-1);
     }
 
@@ -2707,7 +2666,6 @@
      */
     @Override
     public boolean canGoForward() {
-        checkThread();
         WebBackForwardList l = mCallbackProxy.getBackForwardList();
         synchronized (l) {
             if (l.getClearPending()) {
@@ -2723,7 +2681,6 @@
      */
     @Override
     public void goForward() {
-        checkThread();
         goBackOrForwardImpl(1);
     }
 
@@ -2732,7 +2689,6 @@
      */
     @Override
     public boolean canGoBackOrForward(int steps) {
-        checkThread();
         WebBackForwardList l = mCallbackProxy.getBackForwardList();
         synchronized (l) {
             if (l.getClearPending()) {
@@ -2749,7 +2705,6 @@
      */
     @Override
     public void goBackOrForward(int steps) {
-        checkThread();
         goBackOrForwardImpl(steps);
     }
 
@@ -2770,7 +2725,6 @@
      */
     @Override
     public boolean isPrivateBrowsingEnabled() {
-        checkThread();
         return getSettings().isPrivateBrowsingEnabled();
     }
 
@@ -2792,7 +2746,6 @@
      */
     @Override
     public boolean pageUp(boolean top) {
-        checkThread();
         if (mNativeClass == 0) {
             return false;
         }
@@ -2817,7 +2770,6 @@
      */
     @Override
     public boolean pageDown(boolean bottom) {
-        checkThread();
         if (mNativeClass == 0) {
             return false;
         }
@@ -2841,7 +2793,6 @@
      */
     @Override
     public void clearView() {
-        checkThread();
         mContentWidth = 0;
         mContentHeight = 0;
         setBaseLayer(0, null, false, false);
@@ -2853,7 +2804,6 @@
      */
     @Override
     public Picture capturePicture() {
-        checkThread();
         if (mNativeClass == 0) return null;
         Picture result = new Picture();
         nativeCopyBaseContentToPicture(result);
@@ -2865,7 +2815,6 @@
      */
     @Override
     public float getScale() {
-        checkThread();
         return mZoomManager.getScale();
     }
 
@@ -2883,7 +2832,6 @@
      */
     @Override
     public void setInitialScale(int scaleInPercent) {
-        checkThread();
         mZoomManager.setInitialScaleInPercent(scaleInPercent);
     }
 
@@ -2892,7 +2840,6 @@
      */
     @Override
     public void invokeZoomPicker() {
-        checkThread();
         if (!getSettings().supportZoom()) {
             Log.w(LOGTAG, "This WebView doesn't support zoom.");
             return;
@@ -2906,7 +2853,6 @@
      */
     @Override
     public HitTestResult getHitTestResult() {
-        checkThread();
         return mInitialHitTestResult;
     }
 
@@ -2942,7 +2888,6 @@
      */
     @Override
     public void requestFocusNodeHref(Message hrefMsg) {
-        checkThread();
         if (hrefMsg == null) {
             return;
         }
@@ -2965,7 +2910,6 @@
      */
     @Override
     public void requestImageRef(Message msg) {
-        checkThread();
         if (0 == mNativeClass) return; // client isn't initialized
         String url = mFocusedNode != null ? mFocusedNode.mImageUrl : null;
         Bundle data = msg.getData();
@@ -3019,7 +2963,6 @@
      * along with it vertically, while remaining in view horizontally. Pass
      * null to remove the title bar from the WebView, and return to drawing
      * the WebView normally without translating to account for the title bar.
-     * @hide
      */
     public void setEmbeddedTitleBar(View v) {
         if (mWebView instanceof TitleBarDelegate) {
@@ -3041,7 +2984,6 @@
      * Set where to render the embedded title bar
      * NO_GRAVITY at the top of the page
      * TOP        at the top of the screen
-     * @hide
      */
     public void setTitleBarGravity(int gravity) {
         mTitleGravity = gravity;
@@ -3421,7 +3363,6 @@
         return getViewHeight();
     }
 
-    /** @hide */
     @Override
     public void onDrawVerticalScrollBar(Canvas canvas,
                                            Drawable scrollBar,
@@ -3470,7 +3411,6 @@
      */
     @Override
     public String getUrl() {
-        checkThread();
         WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
         return h != null ? h.getUrl() : null;
     }
@@ -3480,7 +3420,6 @@
      */
     @Override
     public String getOriginalUrl() {
-        checkThread();
         WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
         return h != null ? h.getOriginalUrl() : null;
     }
@@ -3490,7 +3429,6 @@
      */
     @Override
     public String getTitle() {
-        checkThread();
         WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
         return h != null ? h.getTitle() : null;
     }
@@ -3500,7 +3438,6 @@
      */
     @Override
     public Bitmap getFavicon() {
-        checkThread();
         WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
         return h != null ? h.getFavicon() : null;
     }
@@ -3519,7 +3456,6 @@
      */
     @Override
     public int getProgress() {
-        checkThread();
         return mCallbackProxy.getProgress();
     }
 
@@ -3528,7 +3464,6 @@
      */
     @Override
     public int getContentHeight() {
-        checkThread();
         return mContentHeight;
     }
 
@@ -3540,9 +3475,6 @@
         return mContentWidth;
     }
 
-    /**
-     * @hide
-     */
     public int getPageBackgroundColor() {
         return nativeGetBackgroundColor();
     }
@@ -3552,7 +3484,6 @@
      */
     @Override
     public void pauseTimers() {
-        checkThread();
         mWebViewCore.sendMessage(EventHub.PAUSE_TIMERS);
     }
 
@@ -3561,7 +3492,6 @@
      */
     @Override
     public void resumeTimers() {
-        checkThread();
         mWebViewCore.sendMessage(EventHub.RESUME_TIMERS);
     }
 
@@ -3570,7 +3500,6 @@
      */
     @Override
     public void onPause() {
-        checkThread();
         if (!mIsPaused) {
             mIsPaused = true;
             mWebViewCore.sendMessage(EventHub.ON_PAUSE);
@@ -3609,7 +3538,6 @@
      */
     @Override
     public void onResume() {
-        checkThread();
         if (mIsPaused) {
             mIsPaused = false;
             mWebViewCore.sendMessage(EventHub.ON_RESUME);
@@ -3641,7 +3569,6 @@
      */
     @Override
     public void freeMemory() {
-        checkThread();
         mWebViewCore.sendMessage(EventHub.FREE_MEMORY);
     }
 
@@ -3650,7 +3577,6 @@
      */
     @Override
     public void clearCache(boolean includeDiskFiles) {
-        checkThread();
         // Note: this really needs to be a static method as it clears cache for all
         // WebView. But we need mWebViewCore to send message to WebCore thread, so
         // we can't make this static.
@@ -3663,7 +3589,6 @@
      */
     @Override
     public void clearFormData() {
-        checkThread();
         if (mAutoCompletePopup != null) {
             mAutoCompletePopup.clearAdapter();
         }
@@ -3674,7 +3599,6 @@
      */
     @Override
     public void clearHistory() {
-        checkThread();
         mCallbackProxy.getBackForwardList().setClearPending();
         mWebViewCore.sendMessage(EventHub.CLEAR_HISTORY);
     }
@@ -3684,7 +3608,6 @@
      */
     @Override
     public void clearSslPreferences() {
-        checkThread();
         mWebViewCore.sendMessage(EventHub.CLEAR_SSL_PREF_TABLE);
     }
 
@@ -3693,7 +3616,6 @@
      */
     @Override
     public WebBackForwardList copyBackForwardList() {
-        checkThread();
         return mCallbackProxy.getBackForwardList().clone();
     }
 
@@ -3704,7 +3626,6 @@
      * @param listener An implementation of FindListener
      */
      public void setFindListener(FindListener listener) {
-         checkThread();
          mFindListener = listener;
      }
 
@@ -3713,7 +3634,6 @@
      */
     @Override
     public void findNext(boolean forward) {
-        checkThread();
         if (0 == mNativeClass) return; // client isn't initialized
         mWebViewCore.sendMessage(EventHub.FIND_NEXT, forward ? 1 : 0);
     }
@@ -3726,15 +3646,11 @@
         return findAllBody(find, false);
     }
 
-    /**
-     * @hide
-     */
     public void findAllAsync(String find) {
         findAllBody(find, true);
     }
 
     private int findAllBody(String find, boolean isAsync) {
-        checkThread();
         if (0 == mNativeClass) return 0; // client isn't initialized
         mLastFind = find;
         if (find == null) return 0;
@@ -3771,7 +3687,6 @@
      * @return boolean True if the find dialog is shown, false otherwise.
      */
     public boolean showFindDialog(String text, boolean showIme) {
-        checkThread();
         FindActionModeCallback callback = new FindActionModeCallback(mContext);
         if (mWebView.getParent() == null || mWebView.startActionMode(callback) == null) {
             // Could not start the action mode, so end Find on page
@@ -3840,12 +3755,10 @@
      * @return the address, or if no address is found, return null.
      */
     public static String findAddress(String addr) {
-        checkThread();
         return findAddress(addr, false);
     }
 
     /**
-     * @hide
      * Return the first substring consisting of the address of a physical
      * location. Currently, only addresses in the United States are detected,
      * and consist of:
@@ -3875,7 +3788,6 @@
      */
     @Override
     public void clearMatches() {
-        checkThread();
         if (mNativeClass == 0)
             return;
         mWebViewCore.removeMessages(EventHub.FIND_ALL);
@@ -3905,7 +3817,6 @@
      */
     @Override
     public void documentHasImages(Message response) {
-        checkThread();
         if (response == null) {
             return;
         }
@@ -3914,8 +3825,6 @@
 
     /**
      * Request the scroller to abort any ongoing animation
-     *
-     * @hide
      */
     public void stopScroll() {
         mScroller.forceFinished(true);
@@ -4339,7 +4248,6 @@
      */
     @Override
     public void setWebViewClient(WebViewClient client) {
-        checkThread();
         mCallbackProxy.setWebViewClient(client);
     }
 
@@ -4347,7 +4255,7 @@
      * Gets the WebViewClient
      * @return the current WebViewClient instance.
      *
-     * @hide This is an implementation detail.
+     * This is an implementation detail.
      */
     public WebViewClient getWebViewClient() {
         return mCallbackProxy.getWebViewClient();
@@ -4358,7 +4266,6 @@
      */
     @Override
     public void setDownloadListener(DownloadListener listener) {
-        checkThread();
         mCallbackProxy.setDownloadListener(listener);
     }
 
@@ -4367,7 +4274,6 @@
      */
     @Override
     public void setWebChromeClient(WebChromeClient client) {
-        checkThread();
         mCallbackProxy.setWebChromeClient(client);
     }
 
@@ -4375,7 +4281,7 @@
      * Gets the chrome handler.
      * @return the current WebChromeClient instance.
      *
-     * @hide This is an implementation detail.
+     * This is an implementation detail.
      */
     public WebChromeClient getWebChromeClient() {
         return mCallbackProxy.getWebChromeClient();
@@ -4386,7 +4292,6 @@
      * WebBackForwardListClient for handling new items and changes in the
      * history index.
      * @param client An implementation of WebBackForwardListClient.
-     * {@hide}
      */
     public void setWebBackForwardListClient(WebBackForwardListClient client) {
         mCallbackProxy.setWebBackForwardListClient(client);
@@ -4394,7 +4299,6 @@
 
     /**
      * Gets the WebBackForwardListClient.
-     * {@hide}
      */
     public WebBackForwardListClient getWebBackForwardListClient() {
         return mCallbackProxy.getWebBackForwardListClient();
@@ -4406,21 +4310,14 @@
     @Override
     @Deprecated
     public void setPictureListener(PictureListener listener) {
-        checkThread();
         mPictureListener = listener;
     }
 
-    /**
-     * {@hide}
-     */
     /* FIXME: Debug only! Remove for SDK! */
     public void externalRepresentation(Message callback) {
         mWebViewCore.sendMessage(EventHub.REQUEST_EXT_REPRESENTATION, callback);
     }
 
-    /**
-     * {@hide}
-     */
     /* FIXME: Debug only! Remove for SDK! */
     public void documentAsText(Message callback) {
         mWebViewCore.sendMessage(EventHub.REQUEST_DOC_AS_TEXT, callback);
@@ -4431,7 +4328,6 @@
      */
     @Override
     public void addJavascriptInterface(Object object, String name) {
-        checkThread();
         if (object == null) {
             return;
         }
@@ -4446,7 +4342,6 @@
      */
     @Override
     public void removeJavascriptInterface(String interfaceName) {
-        checkThread();
         if (mWebViewCore != null) {
             WebViewCore.JSInterfaceData arg = new WebViewCore.JSInterfaceData();
             arg.mInterfaceName = interfaceName;
@@ -4461,7 +4356,6 @@
      */
     @Override
     public WebSettingsClassic getSettings() {
-        checkThread();
         return (mWebViewCore != null) ? mWebViewCore.getSettings() : null;
     }
 
@@ -4470,7 +4364,6 @@
      */
     @Deprecated
     public static synchronized PluginList getPluginList() {
-        checkThread();
         return new PluginList();
     }
 
@@ -4479,7 +4372,6 @@
      */
     @Deprecated
     public void refreshPlugins(boolean reloadOpenPages) {
-        checkThread();
     }
 
     //-------------------------------------------------------------------------
@@ -4783,7 +4675,7 @@
     /**
      * Select the word at the last click point.
      *
-     * @hide This is an implementation detail.
+     * This is an implementation detail.
      */
     public boolean selectText() {
         int x = viewToContentX(mLastTouchX + getScrollX());
@@ -4923,7 +4815,7 @@
      * startX, startY, endX, endY
      */
     private void getSelectionHandles(int[] handles) {
-        handles[0] = mSelectCursorBase.right;
+        handles[0] = mSelectCursorBase.left;
         handles[1] = mSelectCursorBase.bottom;
         handles[2] = mSelectCursorExtent.left;
         handles[3] = mSelectCursorExtent.bottom;
@@ -5134,7 +5026,7 @@
     /**
      * Dump the display tree to "/sdcard/displayTree.txt"
      *
-     * @hide debug only
+     * debug only
      */
     public void dumpDisplayTree() {
         nativeDumpDisplayTree(getUrl());
@@ -5144,7 +5036,7 @@
      * Dump the dom tree to adb shell if "toFile" is False, otherwise dump it to
      * "/sdcard/domTree.txt"
      *
-     * @hide debug only
+     * debug only
      */
     public void dumpDomTree(boolean toFile) {
         mWebViewCore.sendMessage(EventHub.DUMP_DOMTREE, toFile ? 1 : 0, 0);
@@ -5154,7 +5046,7 @@
      * Dump the render tree to adb shell if "toFile" is False, otherwise dump it
      * to "/sdcard/renderTree.txt"
      *
-     * @hide debug only
+     * debug only
      */
     public void dumpRenderTree(boolean toFile) {
         mWebViewCore.sendMessage(EventHub.DUMP_RENDERTREE, toFile ? 1 : 0, 0);
@@ -5163,7 +5055,7 @@
     /**
      * Called by DRT on UI thread, need to proxy to WebCore thread.
      *
-     * @hide debug only
+     * debug only
      */
     public void useMockDeviceOrientation() {
         mWebViewCore.sendMessage(EventHub.USE_MOCK_DEVICE_ORIENTATION);
@@ -5172,7 +5064,7 @@
     /**
      * Called by DRT on WebCore thread.
      *
-     * @hide debug only
+     * debug only
      */
     public void setMockDeviceOrientation(boolean canProvideAlpha, double alpha,
             boolean canProvideBeta, double beta, boolean canProvideGamma, double gamma) {
@@ -5468,9 +5360,7 @@
 
     private boolean setupWebkitSelect() {
         syncSelectionCursors();
-        if (mIsCaretSelection) {
-            showPasteWindow();
-        } else if (!startSelectActionMode()) {
+        if (!mIsCaretSelection && !startSelectActionMode()) {
             selectionDone();
             return false;
         }
@@ -5511,13 +5401,12 @@
     @Override
     @Deprecated
     public void emulateShiftHeld() {
-        checkThread();
     }
 
     /**
      * Select all of the text in this WebView.
      *
-     * @hide This is an implementation detail.
+     * This is an implementation detail.
      */
     public void selectAll() {
         mWebViewCore.sendMessage(EventHub.SELECT_ALL);
@@ -5539,7 +5428,6 @@
             if (!mIsCaretSelection) {
                 updateWebkitSelection();
             }
-            mIsCaretSelection = false;
             invalidate(); // redraw without selection
             mAutoScrollX = 0;
             mAutoScrollY = 0;
@@ -5550,7 +5438,7 @@
     /**
      * Copy the selection to the clipboard
      *
-     * @hide This is an implementation detail.
+     * This is an implementation detail.
      */
     public boolean copySelection() {
         boolean copiedSomething = false;
@@ -5577,7 +5465,7 @@
     /**
      * Cut the selected text into the clipboard
      *
-     * @hide This is an implementation detail
+     * This is an implementation detail
      */
     public void cutSelection() {
         copySelection();
@@ -5589,7 +5477,7 @@
     /**
      * Paste text from the clipboard to the cursor position.
      *
-     * @hide This is an implementation detail
+     * This is an implementation detail
      */
     public void pasteFromClipboard() {
         ClipboardManager cm = (ClipboardManager)mContext
@@ -5605,7 +5493,7 @@
     }
 
     /**
-     * @hide This is an implementation detail.
+     * This is an implementation detail.
      */
     public SearchBox getSearchBox() {
         if ((mWebViewCore == null) || (mWebViewCore.getBrowserFrame() == null)) {
@@ -5781,9 +5669,6 @@
                 mVisibleContentRect, getScale());
     }
 
-    /**
-     * @hide
-     */
     @Override
     public boolean setFrame(int left, int top, int right, int bottom) {
         boolean changed = mWebViewPrivate.super_setFrame(left, top, right, bottom);
@@ -6378,8 +6263,15 @@
             case MotionEvent.ACTION_UP: {
                 mGestureDetector.onTouchEvent(ev);
                 if (mTouchInEditText && mConfirmMove) {
+                    stopTouch();
                     break; // We've been scrolling the edit text.
                 }
+                if (!mConfirmMove && mIsEditingText && mSelectionStarted &&
+                        mIsCaretSelection) {
+                    showPasteWindow();
+                    stopTouch();
+                    break;
+                }
                 // pass the touch events from UI thread to WebCore thread
                 if (shouldForwardTouchEvent()) {
                     TouchEventData ted = new TouchEventData();
@@ -6765,7 +6657,6 @@
             syncSelectionCursors();
             if (mIsCaretSelection) {
                 resetCaretTimer();
-                showPasteWindow();
             }
             invalidate();
         }
@@ -6857,7 +6748,6 @@
     private DrawData mLoadedPicture;
 
     public void setMapTrackballToArrowKeys(boolean setMap) {
-        checkThread();
         mMapTrackballToArrowKeys = setMap;
     }
 
@@ -7084,7 +6974,6 @@
     }
 
     public void flingScroll(int vx, int vy) {
-        checkThread();
         mScroller.fling(getScrollX(), getScrollY(), vx, vy, 0, computeMaxScrollX(), 0,
                 computeMaxScrollY(), mOverflingDistance, mOverflingDistance);
         invalidate();
@@ -7206,7 +7095,6 @@
     @Override
     @Deprecated
     public View getZoomControls() {
-        checkThread();
         if (!getSettings().supportZoom()) {
             Log.w(LOGTAG, "This WebView doesn't support zoom.");
             return null;
@@ -7235,7 +7123,6 @@
      */
     @Override
     public boolean canZoomIn() {
-        checkThread();
         return mZoomManager.canZoomIn();
     }
 
@@ -7244,7 +7131,6 @@
      */
     @Override
     public boolean canZoomOut() {
-        checkThread();
         return mZoomManager.canZoomOut();
     }
 
@@ -7253,7 +7139,6 @@
      */
     @Override
     public boolean zoomIn() {
-        checkThread();
         return mZoomManager.zoomIn();
     }
 
@@ -7262,7 +7147,6 @@
      */
     @Override
     public boolean zoomOut() {
-        checkThread();
         return mZoomManager.zoomOut();
     }
 
@@ -7552,9 +7436,6 @@
         mWebViewCore.sendMessageDelayed(EventHub.SAVE_DOCUMENT_STATE, null, 1000);
     }
 
-    /**
-     * @hide
-     */
     public synchronized WebViewCore getWebViewCore() {
         return mWebViewCore;
     }
@@ -8524,6 +8405,14 @@
                     }
                     break;
 
+                case SHOW_CARET_HANDLE:
+                    if (!mSelectingText && mIsEditingText && mIsCaretSelection) {
+                        setupWebkitSelect();
+                        resetCaretTimer();
+                        showPasteWindow();
+                    }
+                    break;
+
                 default:
                     super.handleMessage(msg);
                     break;
@@ -8728,7 +8617,7 @@
         void onPageSwapOccurred(boolean notifyAnimationStarted);
     }
 
-    /** @hide Called by JNI when pages are swapped (only occurs with hardware
+    /** Called by JNI when pages are swapped (only occurs with hardware
      * acceleration) */
     protected void pageSwapCallback(boolean notifyAnimationStarted) {
         mWebViewCore.resumeWebKitDraw();
@@ -8823,13 +8712,20 @@
                 (data.mStart != data.mEnd ||
                 (mFieldPointer == nodePointer && mFieldPointer != 0))) {
             mIsCaretSelection = (data.mStart == data.mEnd);
-            if (!mSelectingText) {
-                setupWebkitSelect();
-            } else if (!mSelectionStarted) {
-                syncSelectionCursors();
-            }
-            if (mIsCaretSelection) {
-                resetCaretTimer();
+            if (mIsCaretSelection &&
+                    (mInputConnection == null ||
+                    mInputConnection.getEditable().length() == 0)) {
+                // There's no text, don't show caret handle.
+                selectionDone();
+            } else {
+                if (!mSelectingText) {
+                    setupWebkitSelect();
+                } else if (!mSelectionStarted) {
+                    syncSelectionCursors();
+                }
+                if (mIsCaretSelection) {
+                    resetCaretTimer();
+                }
             }
         } else {
             selectionDone();
@@ -9111,8 +9007,10 @@
                         // after the page regains focus.
                         mListBoxMessage = Message.obtain(null,
                                 EventHub.SINGLE_LISTBOX_CHOICE, (int) id, 0);
-                        mListBoxDialog.dismiss();
-                        mListBoxDialog = null;
+                        if (mListBoxDialog != null) {
+                            mListBoxDialog.dismiss();
+                            mListBoxDialog = null;
+                        }
                     }
                 });
                 if (mSelection != -1) {
@@ -9287,7 +9185,7 @@
      * view-specific zoom, scroll offset, or other changes. It does not draw
      * any view-specific chrome, such as progress or URL bars.
      *
-     * @hide only needs to be accessible to Browser and testing
+     * only needs to be accessible to Browser and testing
      */
     public void drawPage(Canvas canvas) {
         calcOurContentVisibleRectF(mVisibleContentRect);
@@ -9297,7 +9195,7 @@
     /**
      * Enable the communication b/t the webView and VideoViewProxy
      *
-     * @hide only used by the Browser
+     * only used by the Browser
      */
     public void setHTML5VideoViewProxy(HTML5VideoViewProxy proxy) {
         mHTML5VideoViewProxy = proxy;
@@ -9307,7 +9205,7 @@
      * Set the time to wait between passing touches to WebCore. See also the
      * TOUCH_SENT_INTERVAL member for further discussion.
      *
-     * @hide This is only used by the DRT test application.
+     * This is only used by the DRT test application.
      */
     public void setTouchInterval(int interval) {
         mCurrentTouchInterval = interval;
@@ -9334,26 +9232,14 @@
         return mViewManager;
     }
 
-    private static void checkThread() {
-        if (Looper.myLooper() != Looper.getMainLooper()) {
-            Throwable throwable = new Throwable(
-                    "Warning: A WebView method was called on thread '" +
-                    Thread.currentThread().getName() + "'. " +
-                    "All WebView methods must be called on the UI thread. " +
-                    "Future versions of WebView may not support use on other threads.");
-            Log.w(LOGTAG, Log.getStackTraceString(throwable));
-            StrictMode.onWebViewMethodCalledOnWrongThread(throwable);
-        }
-    }
-
-    /** @hide send content invalidate */
+    /** send content invalidate */
     protected void contentInvalidateAll() {
         if (mWebViewCore != null && !mBlockWebkitViewMessages) {
             mWebViewCore.sendMessage(EventHub.CONTENT_INVALIDATE_ALL);
         }
     }
 
-    /** @hide discard all textures from tiles. Used in Profiled WebView */
+    /** discard all textures from tiles. Used in Profiled WebView */
     public void discardAllTextures() {
         nativeDiscardAllTextures();
     }
@@ -9385,7 +9271,7 @@
     /**
      * Begin collecting per-tile profiling data
      *
-     * @hide only used by profiling tests
+     * only used by profiling tests
      */
     public void tileProfilingStart() {
         nativeTileProfilingStart();
@@ -9393,29 +9279,29 @@
     /**
      * Return per-tile profiling data
      *
-     * @hide only used by profiling tests
+     * only used by profiling tests
      */
     public float tileProfilingStop() {
         return nativeTileProfilingStop();
     }
 
-    /** @hide only used by profiling tests */
+    /** only used by profiling tests */
     public void tileProfilingClear() {
         nativeTileProfilingClear();
     }
-    /** @hide only used by profiling tests */
+    /** only used by profiling tests */
     public int tileProfilingNumFrames() {
         return nativeTileProfilingNumFrames();
     }
-    /** @hide only used by profiling tests */
+    /** only used by profiling tests */
     public int tileProfilingNumTilesInFrame(int frame) {
         return nativeTileProfilingNumTilesInFrame(frame);
     }
-    /** @hide only used by profiling tests */
+    /** only used by profiling tests */
     public int tileProfilingGetInt(int frame, int tile, String key) {
         return nativeTileProfilingGetInt(frame, tile, key);
     }
-    /** @hide only used by profiling tests */
+    /** only used by profiling tests */
     public float tileProfilingGetFloat(int frame, int tile, String key) {
         return nativeTileProfilingGetFloat(frame, tile, key);
     }
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index a36ce06..b47f71d 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -1778,7 +1778,10 @@
                         case SELECT_WORD_AT: {
                             int x = msg.arg1;
                             int y = msg.arg2;
-                            nativeSelectWordAt(mNativeClass, x, y);
+                            if (!nativeSelectWordAt(mNativeClass, x, y)) {
+                                mWebViewClassic.mPrivateHandler.obtainMessage(WebViewClassic.SHOW_CARET_HANDLE)
+                                    .sendToTarget();
+                            }
                             break;
                         }
                         case SELECT_ALL:
@@ -3120,7 +3123,7 @@
     private native void nativeSelectText(int nativeClass,
             int startX, int startY, int endX, int endY);
     private native void nativeClearTextSelection(int nativeClass);
-    private native void nativeSelectWordAt(int nativeClass, int x, int y);
+    private native boolean nativeSelectWordAt(int nativeClass, int x, int y);
     private native void nativeSelectAll(int nativeClass);
 
     private static native void nativeCertTrustChanged();
diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java
index 757a619..6c35f19 100644
--- a/core/java/android/webkit/WebViewDatabase.java
+++ b/core/java/android/webkit/WebViewDatabase.java
@@ -144,7 +144,6 @@
                         null);
             }
         }
-        mDatabase.enableWriteAheadLogging();
 
         // mDatabase should not be null,
         // the only case is RequestAPI test has problem to create db
@@ -163,11 +162,6 @@
                 mDatabase.endTransaction();
             }
         }
-
-        // use per table Mutex lock, turn off database lock, this
-        // improves performance as database's ReentrantLock is
-        // expansive
-        mDatabase.setLockingEnabled(false);
     }
 
     private static void upgradeDatabase() {
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index e36afa3..ca5648a 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -133,6 +133,16 @@
     }
 
     /**
+     * Return the drawable used to represent the scroll thumb - the component that
+     * the user can drag back and forth indicating the current value by its position.
+     *
+     * @return The current thumb drawable
+     */
+    public Drawable getThumb() {
+        return mThumb;
+    }
+
+    /**
      * @see #setThumbOffset(int)
      */
     public int getThumbOffset() {
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index 739bcce..0f1dab5 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -1908,7 +1908,8 @@
     }
 
     /**
-     * Describes how the child views are horizontally aligned. Defaults to Gravity.LEFT
+     * Set the gravity for this grid. Gravity describes how the child views
+     * are horizontally aligned. Defaults to Gravity.LEFT
      *
      * @param gravity the gravity to apply to this grid's children
      *
@@ -1922,6 +1923,17 @@
     }
 
     /**
+     * Describes how the child views are horizontally aligned. Defaults to Gravity.LEFT
+     *
+     * @return the gravity that will be applied to this grid's children
+     *
+     * @attr ref android.R.styleable#GridView_gravity
+     */
+    public int getGravity() {
+        return mGravity;
+    }
+
+    /**
      * Set the amount of horizontal (x) spacing to place between each item
      * in the grid.
      *
@@ -1937,6 +1949,44 @@
         }
     }
 
+    /**
+     * Returns the amount of horizontal spacing currently used between each item in the grid.
+     *
+     * <p>This is only accurate for the current layout. If {@link #setHorizontalSpacing(int)}
+     * has been called but layout is not yet complete, this method may return a stale value.
+     * To get the horizontal spacing that was explicitly requested use
+     * {@link #getRequestedHorizontalSpacing()}.</p>
+     *
+     * @return Current horizontal spacing between each item in pixels
+     *
+     * @see #setHorizontalSpacing(int)
+     * @see #getRequestedHorizontalSpacing()
+     *
+     * @attr ref android.R.styleable#GridView_horizontalSpacing
+     */
+    public int getHorizontalSpacing() {
+        return mHorizontalSpacing;
+    }
+
+    /**
+     * Returns the requested amount of horizontal spacing between each item in the grid.
+     *
+     * <p>The value returned may have been supplied during inflation as part of a style,
+     * the default GridView style, or by a call to {@link #setHorizontalSpacing(int)}.
+     * If layout is not yet complete or if GridView calculated a different horizontal spacing
+     * from what was requested, this may return a different value from
+     * {@link #getHorizontalSpacing()}.</p>
+     *
+     * @return The currently requested horizontal spacing between items, in pixels
+     *
+     * @see #setHorizontalSpacing(int)
+     * @see #getHorizontalSpacing()
+     *
+     * @attr ref android.R.styleable#GridView_horizontalSpacing
+     */
+    public int getRequestedHorizontalSpacing() {
+        return mRequestedHorizontalSpacing;
+    }
 
     /**
      * Set the amount of vertical (y) spacing to place between each item
@@ -1945,6 +1995,8 @@
      * @param verticalSpacing The amount of vertical space between items,
      * in pixels.
      *
+     * @see #getVerticalSpacing()
+     *
      * @attr ref android.R.styleable#GridView_verticalSpacing
      */
     public void setVerticalSpacing(int verticalSpacing) {
@@ -1955,6 +2007,19 @@
     }
 
     /**
+     * Returns the amount of vertical spacing between each item in the grid.
+     *
+     * @return The vertical spacing between items in pixels
+     *
+     * @see #setVerticalSpacing(int)
+     *
+     * @attr ref android.R.styleable#GridView_verticalSpacing
+     */
+    public int getVerticalSpacing() {
+        return mVerticalSpacing;
+    }
+
+    /**
      * Control how items are stretched to fill their space.
      *
      * @param stretchMode Either {@link #NO_STRETCH},
@@ -1988,6 +2053,39 @@
     }
 
     /**
+     * Return the width of a column in the grid.
+     *
+     * <p>This may not be valid yet if a layout is pending.</p>
+     *
+     * @return The column width in pixels
+     *
+     * @see #setColumnWidth(int)
+     * @see #getRequestedColumnWidth()
+     *
+     * @attr ref android.R.styleable#GridView_columnWidth
+     */
+    public int getColumnWidth() {
+        return mColumnWidth;
+    }
+
+    /**
+     * Return the requested width of a column in the grid.
+     *
+     * <p>This may not be the actual column width used. Use {@link #getColumnWidth()}
+     * to retrieve the current real width of a column.</p>
+     *
+     * @return The requested column width in pixels
+     *
+     * @see #setColumnWidth(int)
+     * @see #getColumnWidth()
+     *
+     * @attr ref android.R.styleable#GridView_columnWidth
+     */
+    public int getRequestedColumnWidth() {
+        return mRequestedColumnWidth;
+    }
+
+    /**
      * Set the number of columns in the grid
      *
      * @param numColumns The desired number of columns.
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 0563846..af722a8 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -33,14 +33,17 @@
 import android.os.Bundle;
 import android.os.PatternMatcher;
 import android.util.Log;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.LayoutInflater;
+import android.widget.AdapterView;
 import android.widget.BaseAdapter;
 import android.widget.CheckBox;
 import android.widget.CompoundButton;
 import android.widget.ImageView;
+import android.widget.ListView;
 import android.widget.TextView;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
@@ -122,6 +125,11 @@
         }
 
         setupAlert();
+
+        ListView lv = mAlert.getListView();
+        if (lv != null) {
+            lv.setOnItemLongClickListener(new ItemLongClickListener());
+        }
     }
 
     @Override
@@ -489,5 +497,18 @@
             mClearDefaultHint.setVisibility(View.GONE);
         }
     }
+
+    class ItemLongClickListener implements AdapterView.OnItemLongClickListener {
+
+        @Override
+        public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
+            ResolveInfo ri = mAdapter.resolveInfoForPosition(position);
+            Intent in = new Intent().setAction("android.settings.APPLICATION_DETAILS_SETTINGS")
+                    .setData(Uri.fromParts("package", ri.activityInfo.packageName, null));
+            startActivity(in);
+            return true;
+        }
+
+    }
 }
 
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index acc3c1c..5a7d519 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -105,6 +105,12 @@
      */
     public static final int MIN_PATTERN_REGISTER_FAIL = MIN_LOCK_PATTERN_SIZE;
 
+    /**
+     * The bit in LOCK_BIOMETRIC_WEAK_FLAGS to be used to indicate whether liveliness should
+     * be used
+     */
+    public static final int FLAG_BIOMETRIC_WEAK_LIVELINESS = 0x1;
+
     private final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
     private final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
     private final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
@@ -878,6 +884,28 @@
     }
 
     /**
+     * Set whether biometric weak liveliness is enabled.
+     */
+    public void setBiometricWeakLivelinessEnabled(boolean enabled) {
+        long currentFlag = getLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, 0L);
+        long newFlag;
+        if (enabled) {
+            newFlag = currentFlag | FLAG_BIOMETRIC_WEAK_LIVELINESS;
+        } else {
+            newFlag = currentFlag & ~FLAG_BIOMETRIC_WEAK_LIVELINESS;
+        }
+        setLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, newFlag);
+    }
+
+    /**
+     * @return Whether the biometric weak liveliness is enabled.
+     */
+    public boolean isBiometricWeakLivelinessEnabled() {
+        long currentFlag = getLong(Settings.Secure.LOCK_BIOMETRIC_WEAK_FLAGS, 0L);
+        return ((currentFlag & FLAG_BIOMETRIC_WEAK_LIVELINESS) != 0);
+    }
+
+    /**
      * Set whether the lock pattern is enabled.
      */
     public void setLockPatternEnabled(boolean enabled) {
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index afbcfc2..8d6fab4 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -20,8 +20,8 @@
 #include <android_runtime/AndroidRuntime.h>
 
 #include <utils/Log.h>
+#include <utils/ZipFileRO.h>
 #include <ScopedUtfChars.h>
-#include <androidfw/ZipFileRO.h>
 
 #include <zlib.h>
 
diff --git a/core/res/res/layout/notification_intruder_content.xml b/core/res/res/layout/notification_intruder_content.xml
new file mode 100644
index 0000000..61be5f5
--- /dev/null
+++ b/core/res/res/layout/notification_intruder_content.xml
@@ -0,0 +1,69 @@
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:background="#FF333333"
+    android:padding="4dp"
+    >
+    <ImageView android:id="@+id/icon"
+        android:layout_width="32dp"
+        android:layout_height="32dp"
+        android:scaleType="center"
+        android:padding="4dp"
+        />
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="40dp"
+        android:layout_marginLeft="40dp"
+        android:orientation="vertical"
+        >
+        <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"
+            />
+        <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="-4dp"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal"
+            />
+    </LinearLayout>
+    <LinearLayout
+        android:id="@+id/actions"
+        android:layout_width="match_parent"
+        android:layout_height="40dp"
+        android:layout_marginTop="48dp"
+        android:orientation="horizontal"
+        android:visibility="gone"
+        >
+        <ImageView
+            android:id="@+id/action0"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:visibility="gone"
+            />
+        <ImageView
+            android:id="@+id/action1"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:visibility="gone"
+            />
+        <ImageView
+            android:id="@+id/action2"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:visibility="gone"
+            />
+    </LinearLayout>
+</FrameLayout>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index f020f5d..fd32c8e 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Voeg rekening by"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Verhoging"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Verminder"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> raak en hou."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Skuif op om by te tel en af om af te trek."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Tel \'n minuut by"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Trek \'n minuut af"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index f1379f7..50b6c67 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"መለያ አክል"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"ጨምር"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"ቀንስ"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> ንካ እና ያዝ።"</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"ለመጨመር ወደላይ ለመቀነስ ወደታች አንሸራት"</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"ደቂቃዎች ጨምር"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"ደቂቃ ቀንስ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index a156e64..9bd3ab2 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"إضافة حساب"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"زيادة"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"تناقص"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> المس مع الاستمرار."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"مرر لأعلى للزيادة ولأسفل للإنقاص."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"زيادة دقيقة"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"إنقاص دقيقة"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 0178764..2526bcd 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Дадаць уліковы запіс"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Інкрэмент"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Дэкрэмент"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Націсніце і ўтрымлівайце <xliff:g id="VALUE">%s</xliff:g>."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Перасуньце палец уверх, каб павялiчыць адрэзак, або ўніз, каб паменшыць."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"На хвiлiну больш"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"На хвiлiну менш"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 479e118..b34de19 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Добавяне на профил"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Увеличаване"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Намаляване"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Докоснете <xliff:g id="VALUE">%s</xliff:g> път/и и задръжте."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Плъзнете нагоре за увеличаване и надолу за намаляване."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Увеличаване на минутите"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Намаляване на минутите"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 64d0f87..675a4ba 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Afegeix un compte"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Incrementa"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Disminueix"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Mantén premut <xliff:g id="VALUE">%s</xliff:g>."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Fes lliscar el dit cap amunt per incrementar i cap avall per disminuir."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Incrementa els minuts"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Disminueix els minuts"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 8125ee3..b11f852 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Přidat účet"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Zvýšení"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Snížení"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> dotkněte se a podržte."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Chcete-li přičítat, přejeďte prstem nahoru, chcete-li odečítat, přejeďte prstem dolů."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Přičíst minutu"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Odečíst minutu"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index b139e5e..89f3451 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Tilføj konto"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Optælling"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Nedtælling"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Tryk <xliff:g id="VALUE">%s</xliff:g> gange, og hold inde."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Glid op for at tilføje, og glid ned for at fjerne."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Tilføj minut"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Fjern minut"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index baf3e40..2de5212 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Konto hinzufügen"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Erhöhen"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Verringern"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> berühren und gedrückt halten"</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Zum Vorstellen nach oben und zum Zurückstellen nach unten ziehen"</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Minute vorstellen"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Minute zurückstellen"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index ad840e3..4906812 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Προσθήκη λογαριασμού"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Αύξηση"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Μείωση"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Πατήστε παρατεταμένα το <xliff:g id="VALUE">%s</xliff:g>."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Πραγματοποιήστε κύλιση προς τα πάνω για αύξηση και προς τα κάτω για μείωση."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Αύξηση λεπτού"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Μείωση λεπτού"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index de92665..d8dac7c 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Add account"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Increment"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Decrement"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> touch and hold."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Slide up to increment and down to decrease."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Increment minute"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Decrement minute"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 8761ca9..0071e0a 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Agregar una cuenta"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Incremento"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Decremento"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Mantén presionado <xliff:g id="VALUE">%s</xliff:g>."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Deslízate hacia arriba para aumentar y hacia abajo para disminuir."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Aumentar minutos"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Disminuir minutos"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 9ede6a0..05b837d 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Añadir cuenta"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Aumentar"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Disminuir"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Mantén pulsado <xliff:g id="VALUE">%s</xliff:g>."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Desliza el dedo hacia arriba para aumentar y hacia abajo para disminuir."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Aumentar minuto"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Disminuir minuto"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index b68944e..22de35d 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Lisa konto"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Suurenda"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Vähenda"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> puudutage ja hoidke."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Suurendamiseks lohistage üles, vähendamiseks alla."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Minutite arvu suurendamine"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Minutite arvu vähendamine"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 5a536e6..dd6a016 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -338,7 +338,7 @@
     <string name="permlab_readCallLog" msgid="3478133184624102739">"خواندن گزارش تماس"</string>
     <string name="permdesc_readCallLog" product="tablet" msgid="3995157599976515002">"به برنامه اجازه می‌دهد گزارشات تماس رایانه لوحی شما، از جمله داده‌هایی درمورد تماس‎های ورودی و خروجی را بخواند. برنامه‌های مخرب ممکن است از این ویژگی برای ارسال داده‌های شما به دیگران استفاده کنند."</string>
     <string name="permdesc_readCallLog" product="default" msgid="3452017559804750758">"به برنامه اجازه می‌دهد گزارشات تماس تلفنی شما، از جمله داده‌هایی درمورد تماس‎های ورودی و خروجی را بخواند. برنامه‌های مخرب ممکن است از این ویژگی برای ارسال داده‌های شما به دیگران استفاده کنند."</string>
-    <string name="permlab_writeCallLog" msgid="8552045664743499354">"نوشتن در گزارش تماس"</string>
+    <string name="permlab_writeCallLog" msgid="8552045664743499354">"نوشتن گزارش تماس"</string>
     <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"به برنامه اجازه می‌دهد گزارشات تماس رایانه لوحی شما، از جمله داده‌هایی درمورد تماس‎های ورودی و خروجی را تغییر دهد. برنامه‌های مخرب ممکن است از این ویژگی برای پاک کردن یا تغییر گزارش تماس شما استفاده کنند."</string>
     <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"به برنامه اجازه می‌دهد گزارشات تماس تلفنی شما، از جمله داده‌هایی درمورد تماس‎های ورودی و خروجی را تغییر دهد. برنامه‌های مخرب ممکن است از این ویژگی برای پاک کردن یا تغییر گزارش تماس شما استفاده کنند."</string>
     <string name="permlab_readProfile" msgid="6824681438529842282">"خواندن داده‌های نمایه شما"</string>
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"افزودن حساب"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"افزایش"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"کاهش"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> لمس کرده و نگه دارید."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"برای افزایش به بالا و برای کاهش به پایین بلغزانید."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">" افزایش دقیقه"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"کاهش دقیقه"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index b1009a5..c744479 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Lisää tili"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Lisää"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Vähennä"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> kosketa pitkään."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Kasvata tai pienennä arvoa liu\'uttamalla ylös tai alas."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Kasvata minuuttia"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Pienennä minuuttia"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index d044a70..62fe768 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Ajouter un compte"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Augmenter"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Diminuer"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> appuyez de manière prolongée."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Faire glisser vers le haut pour augmenter et vers le bas pour diminuer"</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Minute suivante"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Minute précédente"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index bd8863f..bfc2f71 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"खाता जोड़ें"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"वृद्धि"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"कमी"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> को स्‍पर्श करके रखें."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"बढ़ते क्रम के लिए ऊपर और घटते क्रम के लिए नीचे की ओर स्‍लाइड करें."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"बढ़ते क्रम में मिनट"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"घटते क्रम में मिनट"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 749012b..77c5a10 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Dodaj račun"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Povećaj"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Smanji"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> pritisnite i držite."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Klizite prema gore za pomak unaprijed, a prema dolje za pomak unatrag."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Pomak unaprijed za jednu minutu"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Pomak unatrag za jednu minutu"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 24a70d7..466cb3a 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Fiók hozzáadása"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Növelés"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Csökkentés"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> érintse meg és tartsa lenyomva."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Csúsztassa fel a növeléshez és le a csökkentéshez."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Percek növelése"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Percek csökkentése"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index d2b4f04..2ad73a4 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -396,7 +396,7 @@
     <string name="permdesc_asec_destroy" msgid="7218749286145526537">"Mengizinkan apl merusak penyimpanan internal."</string>
     <string name="permlab_asec_mount_unmount" msgid="8877998101944999386">"memasang/melepas penyimpanan internal"</string>
     <string name="permdesc_asec_mount_unmount" msgid="3451360114902490929">"Mengizinkan apl memasang/melepas penyimpanan internal."</string>
-    <string name="permlab_asec_rename" msgid="7496633954080472417">"ubah nama penyimpanan internal"</string>
+    <string name="permlab_asec_rename" msgid="7496633954080472417">"ganti nama penyimpanan internal"</string>
     <string name="permdesc_asec_rename" msgid="1794757588472127675">"Mengizinkan apl mengganti nama penyimpanan internal."</string>
     <string name="permlab_vibrate" msgid="7768356019980849603">"mengontrol penggetar"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Mengizinkan aplikasi untuk mengendalikan vibrator."</string>
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Tambahkan akun"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Penambahan"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Pengurangan"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> sentuh dan tahan."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Geser ke atas untuk menambah dan ke bawah untuk mengurangi."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Menit penambahan"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Menit pengurangan"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 75ed4e8..1eb3be4 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Aggiungi account"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Aumenta"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Diminuisci"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Tocca e tieni premuto il numero <xliff:g id="VALUE">%s</xliff:g>."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Scorri verso l\'alto per aumentare il valore e verso il basso per diminuirlo."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Aumenta minuto"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Diminuisci minuto"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index f51f232..8edf115 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"הוסף חשבון"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"הגדל"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"הפחת"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> גע והחזק."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"הסט מעלה כדי להוסיף ומטה כדי להפחית."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"הוסף דקה"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"הפחת דקה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 549c1e2..fba0304 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"アカウントを追加"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"増やす"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"減らす"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g>回タップして押し続けます。"</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"上にスライドで大きく、下にスライドで小さくなります。"</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"1分進める"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"1分戻す"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index fc8e7b1..211c79c 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"계정 추가"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"올리기"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"줄이기"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> 길게 터치하세요."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"올리려면 위로 슬라이드하고 줄이려면 아래로 슬라이드합니다."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"\'분\'을 올립니다."</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"\'분\'을 줄입니다."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 5e9d3f4..9ceaa1d 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Pridėti paskyrą"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Padidinti"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Sumažinti"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Palieskite <xliff:g id="VALUE">%s</xliff:g> ir laikykite."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Slinkite aukštyn, kad būtų parodytas padidėjimas, ir žemyn, kad būtų parodytas sumažėjimas."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Padidėjimo minutė"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Sumažėjimo minutė"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index a568c3b..6ebc733 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Pievienot kontu"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Palielināt"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Samazināt"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g>: pieskarieties un turiet nospiestu."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Bīdiet uz augšu, lai palielinātu vērtību, un uz leju, lai to samazinātu."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Palielināt minūtes vērtību"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Samazināt minūtes vērtību"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 363832d..2b7fc36 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Tambah akaun"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Kenaikan"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Penyusutan"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> sentuh terus."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Luncurkan ke atas untuk kenaikan dan ke bawah untuk penyusutan."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Minit kenaikan"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Minit penyusutan"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 384fdac..580d30c 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Legg til konto"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Øke"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Senke"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> – trykk og hold inne."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Skyv opp for å øke og ned for å redusere."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Endre minutter (fremover)"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Endre minutter (bakover)"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 030222d..010a4d8 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Account toevoegen"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Hoger"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Lager"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> blijven aanraken."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Schuif omhoog om te verhogen en omlaag om te verlagen."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Minuten verhogen"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Minuten verlagen"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 9e4cbf3..3d58076 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Dodaj konto"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Zwiększ"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Zmniejsz"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> dotknij i przytrzymaj."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Przesuń w górę, aby zwiększyć wartość, lub w dół, aby ją zmniejszyć."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Następna minuta"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Poprzednia minuta"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index abe1454..3e4c31b 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Adicionar conta"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Aumentar"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Diminuir"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Toque sem soltar em <xliff:g id="VALUE">%s</xliff:g>."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Deslize lentamente para cima para aumentar e para baixo para diminuir."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Aumentar minuto"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Diminuir minuto"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 3ae566c..0af0052 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Adicionar conta"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Incremento"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Redução"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> toque e mantenha pressionado."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Deslize para cima para aumentar e para baixo para diminuir."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Aumentar minuto"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Diminuir minuto"</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index fc6a510..f14b247 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -1746,8 +1746,6 @@
     <skip />
     <!-- no translation found for number_picker_decrement_button (2576606679160067262) -->
     <skip />
-    <!-- no translation found for number_picker_increment_scroll_mode (3073101067441638428) -->
-    <skip />
     <!-- no translation found for number_picker_increment_scroll_action (4628981789985093179) -->
     <skip />
     <!-- no translation found for time_picker_increment_minute_button (2843066823236250329) -->
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index d443d1d..32d25c1 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Adăugaţi un cont"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Incrementaţi"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Decrementaţi"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Atingeţi şi ţineţi apăsat <xliff:g id="VALUE">%s</xliff:g>."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Glisaţi în sus pentru incrementare şi în jos pentru decrementare."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Incrementaţi valoarea pentru minut"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Decrementaţi valoarea pentru minut"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 5ed4c2e..989be4a 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Добавить аккаунт"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Увеличить"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Уменьшить"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Нажмите и удерживайте <xliff:g id="VALUE">%s</xliff:g>."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Проведите вверх, чтобы увеличить значение, и вниз, чтобы уменьшить его."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"На минуту вперед"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"На минуту назад"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 2e97b82..4a1fe20 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Pridať účet"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Zvýšenie"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Zníženie"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Dotknite sa a podržte <xliff:g id="VALUE">%s</xliff:g>."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Ak chcete pripočítať, potiahnite prst nahor. Ak chcete odpočítať, potiahnite prst nadol."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Pripočítať minútu"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Odpočítať minútu"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index f66cabb..e079147 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Dodaj račun"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Povečaj"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Zmanjšaj"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Dotaknite se vrednosti <xliff:g id="VALUE">%s</xliff:g> in jo pridržite."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Povlecite gor za povečanje in dol za zmanjšanje."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Povečaj minute"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Zmanjšaj minute"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 66c0561..273a3ac 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Додај налог"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Повећање"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Смањење"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> додирните и задржите."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Превуците нагоре за повећање, а надоле за смањење."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Повећај минуте"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Смањи минуте"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index eee0d80..291f36b 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1169,7 +1169,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Lägg till konto"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Öka"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Minska"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> tryck länge."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Skjut uppåt för att öka och nedåt för att minska."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Öka minuter"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Minska minuter"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 3b870cf..dfdeb2f 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -335,12 +335,12 @@
     <string name="permlab_writeContacts" msgid="644616215860933284">"andika data ya anwani"</string>
     <string name="permdesc_writeContacts" product="tablet" msgid="988969759110632978">"Inaruhusu programu kurekebisha data ya mwasiliani(anwani) iliyohifadhiwa kwenye kompyuta yako ki. programu hasidi zinaweza tumia hii kufuta au kurekebisha data yako ya mwasiliani."</string>
     <string name="permdesc_writeContacts" product="default" msgid="5075164818647934067">"Inaruhusu programu kurekebisha data ya mwasiliani(anwani) iliyohifadhiwa kwenye simu yako. Programu hasidi zinaweza kutumia hii kufuta au kurekebisha data yako ya mwasiliani."</string>
-    <string name="permlab_readCallLog" msgid="3478133184624102739">"soma kumbukumbu ya simu"</string>
-    <string name="permdesc_readCallLog" product="tablet" msgid="3995157599976515002">"Huruhusu programu kusoma kumbukumbu ya kompyuta kibao yako, ikiwa ni pamoja na simu zinazoingia na kutoka. Huenda programu hasidi zikatumia hii ili kutuma data yako kwa watu wengine."</string>
-    <string name="permdesc_readCallLog" product="default" msgid="3452017559804750758">"Huruhusu programu kusoma kumbukumbu ya simu yako, ikiwa ni pamoja na simu zinazoingia na kutoka. Huenda programu hasidi zikatumia hii ili kutuma data yako kwa watu wengine."</string>
-    <string name="permlab_writeCallLog" msgid="8552045664743499354">"andika kumbukumbu ya simu"</string>
-    <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Huruhusu programu kusoma kumbukumbu ya kompyuta kibao yako, ikiwa ni pamoja na simu zinazoingia na kutoka. Huenda programu hasidi zikatumia hii ili kufuta au kurekebisha kumbukumbu ya simu yako."</string>
-    <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Huruhusu programu kusoma kumbukumbu ya simu yako, ikiwa ni pamoja na simu zinazoingia na kutoka. Huenda programu hasidi zikatumia hii ili kufuta au kurekebisha kumbukumbu ya simu yako."</string>
+    <string name="permlab_readCallLog" msgid="3478133184624102739">"soma rajisi ya simu"</string>
+    <string name="permdesc_readCallLog" product="tablet" msgid="3995157599976515002">"Huruhusu programu kusoma rajisi ya simu ya kompyuta kibao yako, ikiwa ni pamoja na simu zinazoingia na kutoka. Huenda programu hasidi zikatumia hii ili kutuma data yako kwa watu wengine."</string>
+    <string name="permdesc_readCallLog" product="default" msgid="3452017559804750758">"Huruhusu programu kusoma rajisi ya simu yako, ikiwa ni pamoja na data kuhusu simu zinazoingia na kutoka. Huenda programu hasidi zikatumia hii ili kutuma data yako kwa watu wengine."</string>
+    <string name="permlab_writeCallLog" msgid="8552045664743499354">"andika rajisi ya simu"</string>
+    <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Huruhusu programu kurekebisha rajisi ya kompyuta kibao yako, ikiwa ni pamoja na simu zinazoingia na kutoka. Huenda programu hasidi zikatumia hii ili kufuta au kurekebisha rajisi ya simu yako."</string>
+    <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Huruhusu programu kurekebisha rajisi ya simu yako, ikiwa ni pamoja na simu zinazoingia na kutoka. Huenda programu hasidi zikatumia hii ili kufuta au kurekebisha rajisi ya simu yako."</string>
     <string name="permlab_readProfile" msgid="6824681438529842282">"soma data ya maelezo yako mafupi"</string>
     <string name="permdesc_readProfile" product="default" msgid="94520753797630679">"Inaruhusu programu kusoma maelezo mafupi ya kibinafsi yaliyohifadhiwa kwenye kifaa chako, kama vile jina lako na taarifa ya kuwasiliana. Hii ina maanisha programu inaweza kukutambua na kutuma taarifa yako fupi ya kibinafsi kwa wengine."</string>
     <string name="permlab_writeProfile" msgid="4679878325177177400">"andika kwenye data ya maelezo yako mafupi"</string>
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Ongeza akaunti"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Ongezeko"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Punguza"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> gusa na ushikilie."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Nyiririsha juu kuongeza na chini kupunguza."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Dakika ya nyongeza"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Dakika pungufu"</string>
diff --git a/core/res/res/values-sw600dp/config.xml b/core/res/res/values-sw600dp/config.xml
index 7fa7658..49c8893 100644
--- a/core/res/res/values-sw600dp/config.xml
+++ b/core/res/res/values-sw600dp/config.xml
@@ -21,7 +21,7 @@
      for different hardware and product builds. -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- see comment in values/config.xml -->
-    <integer name="config_longPressOnPowerBehavior">2</integer>
+    <integer name="config_longPressOnPowerBehavior">1</integer>
 
     <!-- Enable lockscreen rotation -->
     <bool name="config_enableLockScreenRotation">true</bool>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 4b59923..ebd2a31 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"เพิ่มบัญชี"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"การเพิ่ม"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"การลด"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"แตะ <xliff:g id="VALUE">%s</xliff:g> ค้างไว้"</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"เลื่อนขึ้นเพื่อเพิ่มและเลื่อนลงเพื่อลด"</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"เพิ่มนาที"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"ลดนาที"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index dc22a08..0cc2b1f 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Magdagdag ng account"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Taasan"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Babaan"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> pindutin nang matagal."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"I-slide pataas upang magdagdag at pababa upang magbawas."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Minuto ng pagdaragdag"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Minuto ng pagbawas"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 419ae96..c4a5e83 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Hesap ekle"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Artır"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Azalt"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> rakamına dokunun ve basılı tutun."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Artırmak için yukarı, azaltmak için aşağı kaydırın."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Dakika değerini artır"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Dakika değerini azalt"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 13311f1..ac04bc2 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Додати облік. запис"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Додати"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Відняти"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> – торкніться й утримуйте."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Перемістіть угору, щоб додати, і вниз, щоб відняти."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Додати хвилину"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Відняти хвилину"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index b94f104..7fa924b 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Thêm tài khoản"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Tăng dần"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Giảm dần"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Chạm và giữ <xliff:g id="VALUE">%s</xliff:g>."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Trượt lên để tăng và trượt xuống để giảm."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Phút tăng dần"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Phút giảm dần"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 81d0ec6..53baaef 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"添加帐户"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"增加"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"减少"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"触摸 <xliff:g id="VALUE">%s</xliff:g> 次并按住。"</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"向上滑动可增加值,向下滑动可减少值。"</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"增加分钟数"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"减少分钟数"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index e81e393..e5a15de 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -336,11 +336,11 @@
     <string name="permdesc_writeContacts" product="tablet" msgid="988969759110632978">"允許應用程式修改平板電腦上儲存的聯絡人 (地址) 資料。請注意,惡意應用程式可能利用此功能清除或修改您的聯絡人資料。"</string>
     <string name="permdesc_writeContacts" product="default" msgid="5075164818647934067">"允許應用程式修改手機上儲存的聯絡人 (地址) 資料。請注意,惡意應用程式可能利用此功能清除或修改您的聯絡人資料。"</string>
     <string name="permlab_readCallLog" msgid="3478133184624102739">"讀取通話紀錄"</string>
-    <string name="permdesc_readCallLog" product="tablet" msgid="3995157599976515002">"允許應用程式讀取平板電腦的通話紀錄,包括來電和已撥電話相關資料。請注意,惡意應用程式可能利用此功能將您的資料傳送給他人。"</string>
-    <string name="permdesc_readCallLog" product="default" msgid="3452017559804750758">"允許應用程式讀取手機的通話紀錄,包括來電和已撥電話相關資料。請注意,惡意應用程式可能利用此功能將您的資料傳送給他人。"</string>
+    <string name="permdesc_readCallLog" product="tablet" msgid="3995157599976515002">"允許應用程式讀取平板電腦的通話紀錄,包括來電和已撥電話相關資料。請注意,惡意應用程式可能濫用此功能將您的資料傳送給他人。"</string>
+    <string name="permdesc_readCallLog" product="default" msgid="3452017559804750758">"允許應用程式讀取手機的通話紀錄,包括來電和已撥電話相關資料。請注意,惡意應用程式可能濫用此功能將您的資料傳送給他人。"</string>
     <string name="permlab_writeCallLog" msgid="8552045664743499354">"寫入通話紀錄"</string>
-    <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"允許應用程式修改平板電腦的通話紀錄,包括來電和已撥電話相關資料。請注意,惡意應用程式可能利用此功能刪除或修改您的通話記錄。"</string>
-    <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"允許應用程式修改手機的通話紀錄,包括來電和已撥電話相關資料。請注意,惡意應用程式可能利用此功能刪除或修改您的通話記錄。"</string>
+    <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"允許應用程式修改平板電腦的通話紀錄,包括來電和已撥電話相關資料。請注意,惡意應用程式可能濫用此功能刪除或修改您的通話紀錄。"</string>
+    <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"允許應用程式修改手機的通話紀錄,包括來電和已撥電話相關資料。請注意,惡意應用程式可能濫用此功能刪除或修改您的通話紀錄。"</string>
     <string name="permlab_readProfile" msgid="6824681438529842282">"讀取您的個人資料"</string>
     <string name="permdesc_readProfile" product="default" msgid="94520753797630679">"允許應用程式讀取裝置上儲存的個人資料,例如您的姓名和聯絡資訊。這表示應用程式可以識別您的身分,並將您的個人資料傳送給他人。"</string>
     <string name="permlab_writeProfile" msgid="4679878325177177400">"寫入您的個人資料"</string>
@@ -1169,7 +1169,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"新增帳戶"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"增加"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"減少"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> 輕觸並按住。"</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"向上滑動即可增加,向下滑動即可減少。"</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"增加分鐘數"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"減少分鐘數"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index f43835f..c50a1a8 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1168,7 +1168,6 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Engeza i-akhawunti"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Nciphisa"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Decrement"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> thinta bese ucindezela."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Shishilizisa kwenyuke kuye ekwenyusweni kwehle kuye ekwehlisweni."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Iminithi wokwenyusa"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Iminithi yokwehlisa"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 4d9b043a..4fde018 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -284,6 +284,10 @@
          point on the move. A value of 0 means no periodic scans will be used in the framework. -->
     <integer translatable="false" name="config_wifi_framework_scan_interval">300000</integer>
 
+    <!-- Wifi driver stop delay, in milliseconds.
+         Default value is 2 minutes. -->
+    <integer translatable="false" name="config_wifi_driver_stop_delay">120000</integer>
+
     <!-- Flag indicating whether the keyguard should be bypassed when
          the slider is open.  This can be set or unset depending how easily
          the slider can be opened (for example, in a pocket or purse). -->
@@ -304,6 +308,9 @@
     <!-- If this is true, the screen will fade off. -->
     <bool name="config_animateScreenLights">true</bool>
 
+    <!-- If this is true, key chords can be used to take a screenshot on the device. -->
+    <bool name="config_enableScreenshotChord">true</bool>
+
     <!-- If true, the screen can be rotated via the accelerometer in all 4
          rotations as the default behavior. -->
     <bool name="config_allowAllRotations">false</bool>
@@ -628,6 +635,10 @@
                cell broadcasting sms, and MMS. -->
     <bool name="config_sms_capable">true</bool>
 
+    <!-- Enable/disable default bluetooth profiles:
+        HSP_AG, ObexObjectPush, Audio, NAP -->
+    <bool name="config_bluetooth_default_profiles">true</bool>
+
     <!-- IP address of the dns server to use if nobody else suggests one -->
     <string name="config_default_dns_server" translatable="false">8.8.8.8</string>
 
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index ea1a70a..e1bc33b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -194,6 +194,10 @@
   <java-symbol type="id" name="zoomIn" />
   <java-symbol type="id" name="zoomMagnify" />
   <java-symbol type="id" name="zoomOut" />
+  <java-symbol type="id" name="actions" />
+  <java-symbol type="id" name="action0" />
+  <java-symbol type="id" name="action1" />
+  <java-symbol type="id" name="action2" />
 
   <java-symbol type="attr" name="actionModeShareDrawable" />
   <java-symbol type="attr" name="alertDialogCenterButtons" />
@@ -240,6 +244,8 @@
   <java-symbol type="bool" name="config_useMasterVolume" />
   <java-symbol type="bool" name="config_enableWallpaperService" />
   <java-symbol type="bool" name="config_sendAudioBecomingNoisy" />
+  <java-symbol type="bool" name="config_enableScreenshotChord" />
+  <java-symbol type="bool" name="config_bluetooth_default_profiles" />
 
   <java-symbol type="integer" name="config_cursorWindowSize" />
   <java-symbol type="integer" name="config_longPressOnPowerBehavior" />
@@ -251,6 +257,7 @@
   <java-symbol type="integer" name="db_journal_size_limit" />
   <java-symbol type="integer" name="db_wal_autocheckpoint" />
   <java-symbol type="integer" name="max_action_buttons" />
+  <java-symbol type="integer" name="config_wifi_driver_stop_delay" />
 
   <java-symbol type="color" name="tab_indicator_text_v4" />
 
@@ -1062,6 +1069,7 @@
   <java-symbol type="layout" name="zoom_container" />
   <java-symbol type="layout" name="zoom_controls" />
   <java-symbol type="layout" name="zoom_magnify" />
+  <java-symbol type="layout" name="notification_intruder_content" />
 
   <java-symbol type="anim" name="slide_in_child_bottom" />
   <java-symbol type="anim" name="slide_in_right" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index f6125f00..7799f74 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3190,6 +3190,8 @@
     <string name="number_picker_increment_button">Increment</string>
     <!-- Description of the button to decrement the NumberPicker value. [CHAR LIMIT=NONE] -->
     <string name="number_picker_decrement_button">Decrement</string>
+    <!-- Description of the tap and hold action to get into scroll mode in NumberPicker. [CHAR LIMIT=NONE] -->
+    <string name="number_picker_increment_scroll_mode"><xliff:g id="value" example="3">%s</xliff:g> touch and hold.</string>
     <!-- Description of the scrolling action in NumberPicker. [CHAR LIMIT=NONE] -->
     <string name="number_picker_increment_scroll_action">Slide up to increment and down to decrement.</string>
 
diff --git a/core/tests/coretests/src/android/content/pm/AppCacheTest.java b/core/tests/coretests/src/android/content/pm/AppCacheTest.java
index 2982816..0c31e2d 100755
--- a/core/tests/coretests/src/android/content/pm/AppCacheTest.java
+++ b/core/tests/coretests/src/android/content/pm/AppCacheTest.java
@@ -24,6 +24,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.StatFs;
+import android.os.UserId;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.test.suitebuilder.annotation.MediumTest;
@@ -674,7 +675,7 @@
             PackageDataObserver observer = new PackageDataObserver();
             //wait on observer
             synchronized(observer) {
-                getPm().clearApplicationUserData(packageName, observer);
+                getPm().clearApplicationUserData(packageName, observer, 0 /* TODO: Other users */);
                 long waitTime = 0;
                 while(!observer.isDone() || (waitTime > MAX_WAIT_TIME)) {
                     observer.wait(WAIT_TIME_INCR);
@@ -717,7 +718,8 @@
     
     File getDataDir() {
         try {
-            ApplicationInfo appInfo = getPm().getApplicationInfo(mContext.getPackageName(), 0);
+            ApplicationInfo appInfo = getPm().getApplicationInfo(mContext.getPackageName(), 0,
+                    UserId.myUserId());
             return new File(appInfo.dataDir);
         } catch (RemoteException e) {
             throw new RuntimeException("Pacakge manager dead", e);
@@ -746,7 +748,7 @@
     
     @LargeTest
     public void testClearApplicationUserDataNoObserver() throws Exception {
-        getPm().clearApplicationUserData(mContext.getPackageName(), null);
+        getPm().clearApplicationUserData(mContext.getPackageName(), null, UserId.myUserId());
         //sleep for 1 minute
         Thread.sleep(60*1000);
         //confirm files dont exist
diff --git a/data/fonts/vendor_fonts.xml b/data/fonts/vendor_fonts.xml
index c1116d0..5850f94 100644
--- a/data/fonts/vendor_fonts.xml
+++ b/data/fonts/vendor_fonts.xml
@@ -3,7 +3,12 @@
     Vendor-provided fallback fonts
 
     This file can be edited to add references to fonts that are not installed or referenced in the
-    default system. The file should then be placed in /vendor/etc/fallback_fonts.xml.
+    default system. The file should then be placed in /vendor/etc/fallback_fonts.xml. Note
+    that in your makefile, this directory should be referenced as $(TARGET_COPY_OUT_VENDOR)/etc/:
+
+        PRODUCT_COPY_FILES += \
+            frameworks/base/data/fonts/vendor_fonts.xml:$(TARGET_COPY_OUT_VENDOR)/etc/fallback_fonts.xml \
+            frameworks/base/data/fonts/vendor_fonts-ja.xml:$(TARGET_COPY_OUT_VENDOR)/etc/fallback_fonts-ja.xml
 
     For example, vendors might want to build configurations for locales that are
     better served by fonts which either handle glyphs not supported in the default fonts or which
@@ -28,11 +33,31 @@
     Han languages (Chinese, Japanese, and Korean) share a common range of unicode characters;
     their ordering in the fallback or vendor files gives priority to the first in the list.
     Locale-specific ordering can be configured by adding language and region codes to the end
-    of the filename (e.g. /system/etc/fallback_fonts-ja.xml). When no region code is used,
+    of the filename (e.g. /vendor/etc/fallback_fonts-ja.xml). When no region code is used,
     as with this example, all regions are matched. Use separate files for each supported locale.
     The standard fallback file (fallback_fonts.xml) is used when a locale does not have its own
     file. All fallback files must contain the same complete set of fonts; only their ordering
-    can differ.
+    can differ. For example, on a device supporting Japanese, but with English as the default,
+    /vendor/etc/fallback_fonts.xml might contain:
+
+        <familyset>
+            <family>
+                <fileset>
+                    <file>DroidSansJapanese.ttf</file>
+                </fileset>
+            </family>
+        </familyset>
+
+    placing the Japanese font at the end of the fallback sequence for English, with a corresponding
+    /system/vendor/etc/fallback_fonts-ja.xml, placing it at the front of the list.
+
+        <familyset>
+            <family order="0">
+                <fileset>
+                    <file>DroidSansJapanese.ttf</file>
+                </fileset>
+            </family>
+        </familyset>
 
     The sample configuration below is an example of how one might provide two families of fonts
     that get inserted at the first and second (0  and 1) position in the overall fallback fonts.
diff --git a/docs/html/sdk/eclipse-adt.jd b/docs/html/sdk/eclipse-adt.jd
index c8bf12d..3019544 100644
--- a/docs/html/sdk/eclipse-adt.jd
+++ b/docs/html/sdk/eclipse-adt.jd
@@ -135,7 +135,9 @@
           <li>Added feature to automatically setup JAR dependencies. Any {@code .jar} files in the
           {@code /libs} folder are added to the build configuration (similar to how the Ant build
           system works). Also, {@code .jar} files needed by library projects are also automatically
-          added to projects that depend on those library projects.</li>
+          added to projects that depend on those library projects.
+          (<a href="http://tools.android.com/recent/dealingwithdependenciesinandroidprojects">more
+          info</a>)</li>
           <li>Added a feature that allows you to run some code only in debug mode. Builds now
 generate a class called {@code BuildConfig} containing a {@code DEBUG} constant that is
 automatically set according to your build type. You can check the ({@code BuildConfig.DEBUG})
diff --git a/docs/html/sdk/tools-notes.jd b/docs/html/sdk/tools-notes.jd
index bbbca81..dea0c38 100644
--- a/docs/html/sdk/tools-notes.jd
+++ b/docs/html/sdk/tools-notes.jd
@@ -128,7 +128,8 @@
 automatically set according to your build type. You can check the ({@code BuildConfig.DEBUG})
 constant in your code to run debug-only functions.</li>
             <li>Fixed issue when a project and its libraries include the same jar file in their libs
-              folder.</li>
+              folder. (<a href="http://tools.android.com/recent/dealingwithdependenciesinandroidprojects">more
+              info</a>)</li>
             <li>Added support for custom views with custom attributes in libraries. Layouts using
 custom attributes must use the namespace URI {@code http://schemas.android.com/apk/res-auto} instead
 of the URI that includes the app package name. This URI is replaced with the app specific one at
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 6698d31..383fe71 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -575,6 +575,11 @@
     @Override
     public Drawable mutate() {
         if (!mMutated && super.mutate() == this) {
+            if (!mLayerState.canConstantState()) {
+                throw new IllegalStateException("One or more children of this LayerDrawable does " +
+                        "not have constant state; this drawable cannot be mutated.");
+            }
+            mLayerState = new LayerState(mLayerState, this, null);
             final ChildDrawable[] array = mLayerState.mChildren;
             final int N = mLayerState.mNum;
             for (int i = 0; i < N; i++) {
@@ -694,7 +699,7 @@
             return stateful;
         }
 
-        public synchronized boolean canConstantState() {
+        public boolean canConstantState() {
             if (!mCheckedConstantState && mChildren != null) {
                 mCanConstantState = true;
                 final int N = mNum;
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 6539ff3..adeeaca 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -131,22 +131,13 @@
     public static final int USAGE_GRAPHICS_RENDER_TARGET = 0x0010;
 
     /**
-     * USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE The allocation
-     * will be used as a SurfaceTexture graphics consumer. This
-     * usage may only be used with USAGE_GRAPHICS_TEXTURE.
-     *
-     * @hide
-     */
-    public static final int USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE = 0x0020;
-
-    /**
      * USAGE_IO_INPUT The allocation will be used as SurfaceTexture
      * consumer.  This usage will cause the allocation to be created
      * read only.
      *
      * @hide
      */
-    public static final int USAGE_IO_INPUT = 0x0040;
+    public static final int USAGE_IO_INPUT = 0x0020;
 
     /**
      * USAGE_IO_OUTPUT The allocation will be used as a
@@ -155,7 +146,7 @@
      *
      * @hide
      */
-    public static final int USAGE_IO_OUTPUT = 0x0080;
+    public static final int USAGE_IO_OUTPUT = 0x0040;
 
     /**
      * Controls mipmap behavior when using the bitmap creation and
@@ -217,17 +208,15 @@
                        USAGE_GRAPHICS_VERTEX |
                        USAGE_GRAPHICS_CONSTANTS |
                        USAGE_GRAPHICS_RENDER_TARGET |
-                       USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE |
                        USAGE_IO_INPUT |
                        USAGE_IO_OUTPUT)) != 0) {
             throw new RSIllegalArgumentException("Unknown usage specified.");
         }
 
-        if ((usage & (USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE | USAGE_IO_INPUT)) != 0) {
+        if ((usage & USAGE_IO_INPUT) != 0) {
             mWriteAllowed = false;
 
-            if ((usage & ~(USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE |
-                           USAGE_IO_INPUT |
+            if ((usage & ~(USAGE_IO_INPUT |
                            USAGE_GRAPHICS_TEXTURE |
                            USAGE_SCRIPT)) != 0) {
                 throw new RSIllegalArgumentException("Invalid usage combination.");
@@ -348,7 +337,7 @@
     public void ioGetInput() {
         if ((mUsage & USAGE_IO_INPUT) == 0) {
             throw new RSIllegalArgumentException(
-                "Can only send buffer if IO_OUTPUT usage specified.");
+                "Can only receive if IO_INPUT usage specified.");
         }
         mRS.validate();
         mRS.nAllocationIoReceive(getID());
@@ -1134,13 +1123,15 @@
      *
      */
     public SurfaceTexture getSurfaceTexture() {
-        if ((mUsage & USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE) == 0) {
+        if ((mUsage & USAGE_IO_INPUT) == 0) {
             throw new RSInvalidStateException("Allocation is not a surface texture.");
         }
 
         int id = mRS.nAllocationGetSurfaceTextureID(getID());
-        return new SurfaceTexture(id);
+        SurfaceTexture st = new SurfaceTexture(id);
+        mRS.nAllocationGetSurfaceTextureID2(getID(), st);
 
+        return st;
     }
 
     /**
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 6921f37..ab6ba54 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -16,8 +16,8 @@
 
 package android.renderscript;
 
-import java.lang.reflect.Field;
 import java.io.File;
+import java.lang.reflect.Field;
 
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -294,6 +294,11 @@
         validate();
         return rsnAllocationGetSurfaceTextureID(mContext, alloc);
     }
+    native void rsnAllocationGetSurfaceTextureID2(int con, int alloc, SurfaceTexture st);
+    synchronized void nAllocationGetSurfaceTextureID2(int alloc, SurfaceTexture st) {
+        validate();
+        rsnAllocationGetSurfaceTextureID2(mContext, alloc, st);
+    }
     native void rsnAllocationSetSurfaceTexture(int con, int alloc, SurfaceTexture sur);
     synchronized void nAllocationSetSurfaceTexture(int alloc, SurfaceTexture sur) {
         validate();
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 9fc4fd4..9d4c64f 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -477,6 +477,15 @@
 }
 
 static void
+nAllocationGetSurfaceTextureID2(JNIEnv *_env, jobject _this, RsContext con, jint a, jobject jst)
+{
+    LOG_API("nAllocationGetSurfaceTextureID2, con(%p), a(%p)", con, (RsAllocation)a);
+    sp<SurfaceTexture> st = SurfaceTexture_getSurfaceTexture(_env, jst);
+
+    rsAllocationGetSurfaceTextureID2(con, (RsAllocation)a, st.get(), sizeof(SurfaceTexture *));
+}
+
+static void
 nAllocationSetSurfaceTexture(JNIEnv *_env, jobject _this, RsContext con,
                              RsAllocation alloc, jobject sur)
 {
@@ -1352,7 +1361,8 @@
 
 {"rsnAllocationSyncAll",             "(III)V",                                (void*)nAllocationSyncAll },
 {"rsnAllocationGetSurfaceTextureID", "(II)I",                                 (void*)nAllocationGetSurfaceTextureID },
-{"rsnAllocationSetSurfaceTexture",   "(IILandroid/graphics/SurfaceTexture;)V", (void*)nAllocationSetSurfaceTexture },
+{"rsnAllocationGetSurfaceTextureID2","(IILandroid/graphics/SurfaceTexture;)V",(void*)nAllocationGetSurfaceTextureID2 },
+{"rsnAllocationSetSurfaceTexture",   "(IILandroid/graphics/SurfaceTexture;)V",(void*)nAllocationSetSurfaceTexture },
 {"rsnAllocationIoSend",              "(II)V",                                 (void*)nAllocationIoSend },
 {"rsnAllocationIoReceive",           "(II)V",                                 (void*)nAllocationIoReceive },
 {"rsnAllocationData1D",              "(IIIII[II)V",                           (void*)nAllocationData1D_i },
diff --git a/include/androidfw/AssetManager.h b/include/androidfw/AssetManager.h
index d95b45e..d153c31 100644
--- a/include/androidfw/AssetManager.h
+++ b/include/androidfw/AssetManager.h
@@ -22,13 +22,13 @@
 
 #include <androidfw/Asset.h>
 #include <androidfw/AssetDir.h>
-#include <androidfw/ZipFileRO.h>
 #include <utils/KeyedVector.h>
 #include <utils/SortedVector.h>
 #include <utils/String16.h>
 #include <utils/String8.h>
 #include <utils/threads.h>
 #include <utils/Vector.h>
+#include <utils/ZipFileRO.h>
 
 /*
  * Native-app access is via the opaque typedef struct AAssetManager in the C namespace.
diff --git a/include/androidfw/ZipFileCRO.h b/include/androidfw/ZipFileCRO.h
deleted file mode 100644
index 3e42a95..0000000
--- a/include/androidfw/ZipFileCRO.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.
- */
-
-//
-// C API for ead-only access to Zip archives, with minimal heap allocation.
-//
-#ifndef __LIBS_ZIPFILECRO_H
-#define __LIBS_ZIPFILECRO_H
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <utils/Compat.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Trivial typedef to ensure that ZipFileCRO is not treated as a simple integer.
- */
-typedef void* ZipFileCRO;
-
-/*
- * Trivial typedef to ensure that ZipEntryCRO is not treated as a simple
- * integer.  We use NULL to indicate an invalid value.
- */
-typedef void* ZipEntryCRO;
-
-extern ZipFileCRO ZipFileXRO_open(const char* path);
-
-extern void ZipFileCRO_destroy(ZipFileCRO zip);
-
-extern ZipEntryCRO ZipFileCRO_findEntryByName(ZipFileCRO zip,
-        const char* fileName);
-
-extern bool ZipFileCRO_getEntryInfo(ZipFileCRO zip, ZipEntryCRO entry,
-        int* pMethod, size_t* pUncompLen,
-        size_t* pCompLen, off64_t* pOffset, long* pModWhen, long* pCrc32);
-
-extern bool ZipFileCRO_uncompressEntry(ZipFileCRO zip, ZipEntryCRO entry, int fd);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /*__LIBS_ZIPFILECRO_H*/
diff --git a/include/androidfw/ZipFileRO.h b/include/androidfw/ZipFileRO.h
deleted file mode 100644
index 547e36a..0000000
--- a/include/androidfw/ZipFileRO.h
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * 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.
- */
-
-/*
- * Read-only access to Zip archives, with minimal heap allocation.
- *
- * This is similar to the more-complete ZipFile class, but no attempt
- * has been made to make them interchangeable.  This class operates under
- * a very different set of assumptions and constraints.
- *
- * One such assumption is that if you're getting file descriptors for
- * use with this class as a child of a fork() operation, you must be on
- * a pread() to guarantee correct operation. This is because pread() can
- * atomically read at a file offset without worrying about a lock around an
- * lseek() + read() pair.
- */
-#ifndef __LIBS_ZIPFILERO_H
-#define __LIBS_ZIPFILERO_H
-
-#include <utils/Compat.h>
-#include <utils/Errors.h>
-#include <utils/FileMap.h>
-#include <utils/threads.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <time.h>
-
-namespace android {
-
-/*
- * Trivial typedef to ensure that ZipEntryRO is not treated as a simple
- * integer.  We use NULL to indicate an invalid value.
- */
-typedef void* ZipEntryRO;
-
-/*
- * Open a Zip archive for reading.
- *
- * We want "open" and "find entry by name" to be fast operations, and we
- * want to use as little memory as possible.  We memory-map the file,
- * and load a hash table with pointers to the filenames (which aren't
- * null-terminated).  The other fields are at a fixed offset from the
- * filename, so we don't need to extract those (but we do need to byte-read
- * and endian-swap them every time we want them).
- *
- * To speed comparisons when doing a lookup by name, we could make the mapping
- * "private" (copy-on-write) and null-terminate the filenames after verifying
- * the record structure.  However, this requires a private mapping of
- * every page that the Central Directory touches.  Easier to tuck a copy
- * of the string length into the hash table entry.
- *
- * NOTE: If this is used on file descriptors inherited from a fork() operation,
- * you must be on a platform that implements pread() to guarantee correctness
- * on the shared file descriptors.
- */
-class ZipFileRO {
-public:
-    ZipFileRO()
-        : mFd(-1), mFileName(NULL), mFileLength(-1),
-          mDirectoryMap(NULL),
-          mNumEntries(-1), mDirectoryOffset(-1),
-          mHashTableSize(-1), mHashTable(NULL)
-        {}
-
-    ~ZipFileRO();
-
-    /*
-     * Open an archive.
-     */
-    status_t open(const char* zipFileName);
-
-    /*
-     * Find an entry, by name.  Returns the entry identifier, or NULL if
-     * not found.
-     *
-     * If two entries have the same name, one will be chosen at semi-random.
-     */
-    ZipEntryRO findEntryByName(const char* fileName) const;
-
-    /*
-     * Return the #of entries in the Zip archive.
-     */
-    int getNumEntries(void) const {
-        return mNumEntries;
-    }
-
-    /*
-     * Return the Nth entry.  Zip file entries are not stored in sorted
-     * order, and updated entries may appear at the end, so anyone walking
-     * the archive needs to avoid making ordering assumptions.  We take
-     * that further by returning the Nth non-empty entry in the hash table
-     * rather than the Nth entry in the archive.
-     *
-     * Valid values are [0..numEntries).
-     *
-     * [This is currently O(n).  If it needs to be fast we can allocate an
-     * additional data structure or provide an iterator interface.]
-     */
-    ZipEntryRO findEntryByIndex(int idx) const;
-
-    /*
-     * Copy the filename into the supplied buffer.  Returns 0 on success,
-     * -1 if "entry" is invalid, or the filename length if it didn't fit.  The
-     * length, and the returned string, include the null-termination.
-     */
-    int getEntryFileName(ZipEntryRO entry, char* buffer, int bufLen) const;
-
-    /*
-     * Get the vital stats for an entry.  Pass in NULL pointers for anything
-     * you don't need.
-     *
-     * "*pOffset" holds the Zip file offset of the entry's data.
-     *
-     * Returns "false" if "entry" is bogus or if the data in the Zip file
-     * appears to be bad.
-     */
-    bool getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen,
-        size_t* pCompLen, off64_t* pOffset, long* pModWhen, long* pCrc32) const;
-
-    /*
-     * Create a new FileMap object that maps a subset of the archive.  For
-     * an uncompressed entry this effectively provides a pointer to the
-     * actual data, for a compressed entry this provides the input buffer
-     * for inflate().
-     */
-    FileMap* createEntryFileMap(ZipEntryRO entry) const;
-
-    /*
-     * Uncompress the data into a buffer.  Depending on the compression
-     * format, this is either an "inflate" operation or a memcpy.
-     *
-     * Use "uncompLen" from getEntryInfo() to determine the required
-     * buffer size.
-     *
-     * Returns "true" on success.
-     */
-    bool uncompressEntry(ZipEntryRO entry, void* buffer) const;
-
-    /*
-     * Uncompress the data to an open file descriptor.
-     */
-    bool uncompressEntry(ZipEntryRO entry, int fd) const;
-
-    /* Zip compression methods we support */
-    enum {
-        kCompressStored     = 0,        // no compression
-        kCompressDeflated   = 8,        // standard deflate
-    };
-
-    /*
-     * Utility function: uncompress deflated data, buffer to buffer.
-     */
-    static bool inflateBuffer(void* outBuf, const void* inBuf,
-        size_t uncompLen, size_t compLen);
-
-    /*
-     * Utility function: uncompress deflated data, buffer to fd.
-     */
-    static bool inflateBuffer(int fd, const void* inBuf,
-        size_t uncompLen, size_t compLen);
-
-    /*
-     * Utility function to convert ZIP's time format to a timespec struct.
-     */
-    static inline void zipTimeToTimespec(long when, struct tm* timespec) {
-        const long date = when >> 16;
-        timespec->tm_year = ((date >> 9) & 0x7F) + 80; // Zip is years since 1980
-        timespec->tm_mon = (date >> 5) & 0x0F;
-        timespec->tm_mday = date & 0x1F;
-
-        timespec->tm_hour = (when >> 11) & 0x1F;
-        timespec->tm_min = (when >> 5) & 0x3F;
-        timespec->tm_sec = (when & 0x1F) << 1;
-    }
-
-    /*
-     * Some basic functions for raw data manipulation.  "LE" means
-     * Little Endian.
-     */
-    static inline unsigned short get2LE(const unsigned char* buf) {
-        return buf[0] | (buf[1] << 8);
-    }
-    static inline unsigned long get4LE(const unsigned char* buf) {
-        return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
-    }
-
-private:
-    /* these are private and not defined */ 
-    ZipFileRO(const ZipFileRO& src);
-    ZipFileRO& operator=(const ZipFileRO& src);
-
-    /* locate and parse the central directory */
-    bool mapCentralDirectory(void);
-
-    /* parse the archive, prepping internal structures */
-    bool parseZipArchive(void);
-
-    /* add a new entry to the hash table */
-    void addToHash(const char* str, int strLen, unsigned int hash);
-
-    /* compute string hash code */
-    static unsigned int computeHash(const char* str, int len);
-
-    /* convert a ZipEntryRO back to a hash table index */
-    int entryToIndex(const ZipEntryRO entry) const;
-
-    /*
-     * One entry in the hash table.
-     */
-    typedef struct HashEntry {
-        const char*     name;
-        unsigned short  nameLen;
-        //unsigned int    hash;
-    } HashEntry;
-
-    /* open Zip archive */
-    int         mFd;
-
-    /* Lock for handling the file descriptor (seeks, etc) */
-    mutable Mutex mFdLock;
-
-    /* zip file name */
-    char*       mFileName;
-
-    /* length of file */
-    size_t      mFileLength;
-
-    /* mapped file */
-    FileMap*    mDirectoryMap;
-
-    /* number of entries in the Zip archive */
-    int         mNumEntries;
-
-    /* CD directory offset in the Zip archive */
-    off64_t     mDirectoryOffset;
-
-    /*
-     * We know how many entries are in the Zip archive, so we have a
-     * fixed-size hash table.  We probe for an empty slot.
-     */
-    int         mHashTableSize;
-    HashEntry*  mHashTable;
-};
-
-}; // namespace android
-
-#endif /*__LIBS_ZIPFILERO_H*/
diff --git a/include/androidfw/ZipUtils.h b/include/androidfw/ZipUtils.h
deleted file mode 100644
index 42c42b6..0000000
--- a/include/androidfw/ZipUtils.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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.
- */
-
-//
-// Miscellaneous zip/gzip utility functions.
-//
-#ifndef __LIBS_ZIPUTILS_H
-#define __LIBS_ZIPUTILS_H
-
-#include <stdio.h>
-
-namespace android {
-
-/*
- * Container class for utility functions, primarily for namespace reasons.
- */
-class ZipUtils {
-public:
-    /*
-     * General utility function for uncompressing "deflate" data from a file
-     * to a buffer.
-     */
-    static bool inflateToBuffer(int fd, void* buf, long uncompressedLen,
-        long compressedLen);
-    static bool inflateToBuffer(FILE* fp, void* buf, long uncompressedLen,
-        long compressedLen);
-
-    /*
-     * Someday we might want to make this generic and handle bzip2 ".bz2"
-     * files too.
-     *
-     * We could declare gzip to be a sub-class of zip that has exactly
-     * one always-compressed entry, but we currently want to treat Zip
-     * and gzip as distinct, so there's no value.
-     *
-     * The zlib library has some gzip utilities, but it has no interface
-     * for extracting the uncompressed length of the file (you do *not*
-     * want to gzseek to the end).
-     *
-     * Pass in a seeked file pointer for the gzip file.  If this is a gzip
-     * file, we set our return values appropriately and return "true" with
-     * the file seeked to the start of the compressed data.
-     */
-    static bool examineGzip(FILE* fp, int* pCompressionMethod,
-        long* pUncompressedLen, long* pCompressedLen, unsigned long* pCRC32);
-
-private:
-    ZipUtils() {}
-    ~ZipUtils() {}
-};
-
-}; // namespace android
-
-#endif /*__LIBS_ZIPUTILS_H*/
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index ad27a1e..7d5d772 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -476,8 +476,7 @@
                                  int frameCount,
                                  audio_policy_output_flags_t flags,
                                  const sp<IMemory>& sharedBuffer,
-                                 audio_io_handle_t output,
-                                 bool enforceFrameCount);
+                                 audio_io_handle_t output);
             void flush_l();
             status_t setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount);
             audio_io_handle_t getOutput_l();
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 00b8679..c3ccb56 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -24,6 +24,7 @@
 
 #include <utils/RefBase.h>
 #include <utils/KeyedVector.h>
+#include <utils/String8.h>
 
 namespace android {
 
@@ -180,6 +181,8 @@
     bool findData(uint32_t key, uint32_t *type,
                   const void **data, size_t *size) const;
 
+    void dumpToLog() const;
+
 protected:
     virtual ~MetaData();
 
@@ -194,6 +197,7 @@
         void clear();
         void setData(uint32_t type, const void *data, size_t size);
         void getData(uint32_t *type, const void **data, size_t *size) const;
+        String8 asString() const;
 
     private:
         uint32_t mType;
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 392ea87..7c612ba 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -30,6 +30,7 @@
 class MemoryDealer;
 struct OMXCodecObserver;
 struct CodecProfileLevel;
+class SkipCutBuffer;
 
 struct OMXCodec : public MediaSource,
                   public MediaBufferObserver {
@@ -201,6 +202,7 @@
     ReadOptions::SeekMode mSeekMode;
     int64_t mTargetTimeUs;
     bool mOutputPortSettingsChangedPending;
+    SkipCutBuffer *mSkipCutBuffer;
 
     MediaBuffer *mLeftOverBuffer;
 
@@ -378,6 +380,7 @@
         const char *mimeType, bool queryDecoders,
         Vector<CodecCapabilities> *results);
 
+
 }  // namespace android
 
 #endif  // OMX_CODEC_H_
diff --git a/include/media/stagefright/SkipCutBuffer.h b/include/media/stagefright/SkipCutBuffer.h
new file mode 100644
index 0000000..5c7cd47
--- /dev/null
+++ b/include/media/stagefright/SkipCutBuffer.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2012 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 SKIP_CUT_BUFFER_H_
+
+#define SKIP_CUT_BUFFER_H_
+
+#include <media/stagefright/MediaBuffer.h>
+
+namespace android {
+
+/**
+ * utility class to cut the start and end off a stream of data in MediaBuffers
+ *
+ */
+class SkipCutBuffer {
+ public:
+    // 'skip' is the number of bytes to skip from the beginning
+    // 'cut' is the number of bytes to cut from the end
+    // 'output_size' is the size in bytes of the MediaBuffers that will be used
+    SkipCutBuffer(int32_t skip, int32_t cut, int32_t output_size);
+    virtual ~SkipCutBuffer();
+
+    // Submit one MediaBuffer for skipping and cutting. This may consume all or
+    // some of the data in the buffer, or it may add data to it.
+    // After this, the caller should continue processing the buffer as usual.
+    void submit(MediaBuffer *buffer);
+    void clear();
+    size_t size(); // how many bytes are currently stored in the buffer
+
+ private:
+    void write(const char *src, size_t num);
+    size_t read(char *dst, size_t num);
+    int32_t mFrontPadding;
+    int32_t mBackPadding;
+    int32_t mWriteHead;
+    int32_t mReadHead;
+    int32_t mCapacity;
+    char* mCutBuffer;
+    DISALLOW_EVIL_CONSTRUCTORS(SkipCutBuffer);
+};
+
+}  // namespace android
+
+#endif  // OMX_CODEC_H_
diff --git a/libs/androidfw/Android.mk b/libs/androidfw/Android.mk
index 4e89d87..a3f92cb 100644
--- a/libs/androidfw/Android.mk
+++ b/libs/androidfw/Android.mk
@@ -24,10 +24,7 @@
     AssetManager.cpp \
     ObbFile.cpp \
     ResourceTypes.cpp \
-    StreamingZipInflater.cpp \
-    ZipFileCRO.cpp \
-    ZipFileRO.cpp \
-    ZipUtils.cpp
+    StreamingZipInflater.cpp
 
 # formerly in libui
 commonUiSources:= \
diff --git a/libs/androidfw/Asset.cpp b/libs/androidfw/Asset.cpp
index cb7628d..fd5b3e4 100644
--- a/libs/androidfw/Asset.cpp
+++ b/libs/androidfw/Asset.cpp
@@ -23,11 +23,11 @@
 
 #include <androidfw/Asset.h>
 #include <androidfw/StreamingZipInflater.h>
-#include <androidfw/ZipFileRO.h>
-#include <androidfw/ZipUtils.h>
 #include <utils/Atomic.h>
 #include <utils/FileMap.h>
 #include <utils/Log.h>
+#include <utils/ZipFileRO.h>
+#include <utils/ZipUtils.h>
 #include <utils/threads.h>
 
 #include <assert.h>
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 4829add..8d59d8e 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -25,13 +25,13 @@
 #include <androidfw/AssetDir.h>
 #include <androidfw/AssetManager.h>
 #include <androidfw/ResourceTypes.h>
-#include <androidfw/ZipFileRO.h>
 #include <utils/Atomic.h>
 #include <utils/Log.h>
 #include <utils/String8.h>
 #include <utils/String8.h>
 #include <utils/threads.h>
 #include <utils/Timers.h>
+#include <utils/ZipFileRO.h>
 
 #include <assert.h>
 #include <dirent.h>
diff --git a/libs/androidfw/ZipFileCRO.cpp b/libs/androidfw/ZipFileCRO.cpp
deleted file mode 100644
index c8df845..0000000
--- a/libs/androidfw/ZipFileCRO.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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.
- */
-
-#include <androidfw/ZipFileCRO.h>
-#include <androidfw/ZipFileRO.h>
-
-using namespace android;
-
-ZipFileCRO ZipFileXRO_open(const char* path) {
-    ZipFileRO* zip = new ZipFileRO();
-    if (zip->open(path) == NO_ERROR) {
-        return (ZipFileCRO)zip;
-    }
-    return NULL;
-}
-
-void ZipFileCRO_destroy(ZipFileCRO zipToken) {
-    ZipFileRO* zip = (ZipFileRO*)zipToken;
-    delete zip;
-}
-
-ZipEntryCRO ZipFileCRO_findEntryByName(ZipFileCRO zipToken,
-        const char* fileName) {
-    ZipFileRO* zip = (ZipFileRO*)zipToken;
-    return (ZipEntryCRO)zip->findEntryByName(fileName);
-}
-
-bool ZipFileCRO_getEntryInfo(ZipFileCRO zipToken, ZipEntryRO entryToken,
-        int* pMethod, size_t* pUncompLen,
-        size_t* pCompLen, off64_t* pOffset, long* pModWhen, long* pCrc32) {
-    ZipFileRO* zip = (ZipFileRO*)zipToken;
-    ZipEntryRO entry = (ZipEntryRO)entryToken;
-    return zip->getEntryInfo(entry, pMethod, pUncompLen, pCompLen, pOffset,
-            pModWhen, pCrc32);
-}
-
-bool ZipFileCRO_uncompressEntry(ZipFileCRO zipToken, ZipEntryRO entryToken, int fd) {
-    ZipFileRO* zip = (ZipFileRO*)zipToken;
-    ZipEntryRO entry = (ZipEntryRO)entryToken;
-    return zip->uncompressEntry(entry, fd);
-}
diff --git a/libs/androidfw/ZipFileRO.cpp b/libs/androidfw/ZipFileRO.cpp
deleted file mode 100644
index 4b7f1e7..0000000
--- a/libs/androidfw/ZipFileRO.cpp
+++ /dev/null
@@ -1,931 +0,0 @@
-/*
- * 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.
- */
-
-//
-// Read-only access to Zip archives, with minimal heap allocation.
-//
-#define LOG_TAG "zipro"
-//#define LOG_NDEBUG 0
-#include <androidfw/ZipFileRO.h>
-#include <utils/Log.h>
-#include <utils/misc.h>
-#include <utils/threads.h>
-
-#include <zlib.h>
-
-#include <string.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <assert.h>
-#include <unistd.h>
-
-#if HAVE_PRINTF_ZD
-#  define ZD "%zd"
-#  define ZD_TYPE ssize_t
-#else
-#  define ZD "%ld"
-#  define ZD_TYPE long
-#endif
-
-/*
- * We must open binary files using open(path, ... | O_BINARY) under Windows.
- * Otherwise strange read errors will happen.
- */
-#ifndef O_BINARY
-#  define O_BINARY  0
-#endif
-
-/*
- * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
- * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
- * not already defined, then define it here.
- */
-#ifndef TEMP_FAILURE_RETRY
-/* Used to retry syscalls that can return EINTR. */
-#define TEMP_FAILURE_RETRY(exp) ({         \
-    typeof (exp) _rc;                      \
-    do {                                   \
-        _rc = (exp);                       \
-    } while (_rc == -1 && errno == EINTR); \
-    _rc; })
-#endif
-
-using namespace android;
-
-/*
- * Zip file constants.
- */
-#define kEOCDSignature      0x06054b50
-#define kEOCDLen            22
-#define kEOCDNumEntries     8               // offset to #of entries in file
-#define kEOCDSize           12              // size of the central directory
-#define kEOCDFileOffset     16              // offset to central directory
-
-#define kMaxCommentLen      65535           // longest possible in ushort
-#define kMaxEOCDSearch      (kMaxCommentLen + kEOCDLen)
-
-#define kLFHSignature       0x04034b50
-#define kLFHLen             30              // excluding variable-len fields
-#define kLFHNameLen         26              // offset to filename length
-#define kLFHExtraLen        28              // offset to extra length
-
-#define kCDESignature       0x02014b50
-#define kCDELen             46              // excluding variable-len fields
-#define kCDEMethod          10              // offset to compression method
-#define kCDEModWhen         12              // offset to modification timestamp
-#define kCDECRC             16              // offset to entry CRC
-#define kCDECompLen         20              // offset to compressed length
-#define kCDEUncompLen       24              // offset to uncompressed length
-#define kCDENameLen         28              // offset to filename length
-#define kCDEExtraLen        30              // offset to extra length
-#define kCDECommentLen      32              // offset to comment length
-#define kCDELocalOffset     42              // offset to local hdr
-
-/*
- * The values we return for ZipEntryRO use 0 as an invalid value, so we
- * want to adjust the hash table index by a fixed amount.  Using a large
- * value helps insure that people don't mix & match arguments, e.g. to
- * findEntryByIndex().
- */
-#define kZipEntryAdj        10000
-
-ZipFileRO::~ZipFileRO() {
-    free(mHashTable);
-    if (mDirectoryMap)
-        mDirectoryMap->release();
-    if (mFd >= 0)
-        TEMP_FAILURE_RETRY(close(mFd));
-    if (mFileName)
-        free(mFileName);
-}
-
-/*
- * Convert a ZipEntryRO to a hash table index, verifying that it's in a
- * valid range.
- */
-int ZipFileRO::entryToIndex(const ZipEntryRO entry) const
-{
-    long ent = ((long) entry) - kZipEntryAdj;
-    if (ent < 0 || ent >= mHashTableSize || mHashTable[ent].name == NULL) {
-        ALOGW("Invalid ZipEntryRO %p (%ld)\n", entry, ent);
-        return -1;
-    }
-    return ent;
-}
-
-
-/*
- * Open the specified file read-only.  We memory-map the entire thing and
- * close the file before returning.
- */
-status_t ZipFileRO::open(const char* zipFileName)
-{
-    int fd = -1;
-
-    assert(mDirectoryMap == NULL);
-
-    /*
-     * Open and map the specified file.
-     */
-    fd = ::open(zipFileName, O_RDONLY | O_BINARY);
-    if (fd < 0) {
-        ALOGW("Unable to open zip '%s': %s\n", zipFileName, strerror(errno));
-        return NAME_NOT_FOUND;
-    }
-
-    mFileLength = lseek64(fd, 0, SEEK_END);
-    if (mFileLength < kEOCDLen) {
-        TEMP_FAILURE_RETRY(close(fd));
-        return UNKNOWN_ERROR;
-    }
-
-    if (mFileName != NULL) {
-        free(mFileName);
-    }
-    mFileName = strdup(zipFileName);
-
-    mFd = fd;
-
-    /*
-     * Find the Central Directory and store its size and number of entries.
-     */
-    if (!mapCentralDirectory()) {
-        goto bail;
-    }
-
-    /*
-     * Verify Central Directory and create data structures for fast access.
-     */
-    if (!parseZipArchive()) {
-        goto bail;
-    }
-
-    return OK;
-
-bail:
-    free(mFileName);
-    mFileName = NULL;
-    TEMP_FAILURE_RETRY(close(fd));
-    return UNKNOWN_ERROR;
-}
-
-/*
- * Parse the Zip archive, verifying its contents and initializing internal
- * data structures.
- */
-bool ZipFileRO::mapCentralDirectory(void)
-{
-    ssize_t readAmount = kMaxEOCDSearch;
-    if (readAmount > (ssize_t) mFileLength)
-        readAmount = mFileLength;
-
-    unsigned char* scanBuf = (unsigned char*) malloc(readAmount);
-    if (scanBuf == NULL) {
-        ALOGW("couldn't allocate scanBuf: %s", strerror(errno));
-        free(scanBuf);
-        return false;
-    }
-
-    /*
-     * Make sure this is a Zip archive.
-     */
-    if (lseek64(mFd, 0, SEEK_SET) != 0) {
-        ALOGW("seek to start failed: %s", strerror(errno));
-        free(scanBuf);
-        return false;
-    }
-
-    ssize_t actual = TEMP_FAILURE_RETRY(read(mFd, scanBuf, sizeof(int32_t)));
-    if (actual != (ssize_t) sizeof(int32_t)) {
-        ALOGI("couldn't read first signature from zip archive: %s", strerror(errno));
-        free(scanBuf);
-        return false;
-    }
-
-    {
-        unsigned int header = get4LE(scanBuf);
-        if (header == kEOCDSignature) {
-            ALOGI("Found Zip archive, but it looks empty\n");
-            free(scanBuf);
-            return false;
-        } else if (header != kLFHSignature) {
-            ALOGV("Not a Zip archive (found 0x%08x)\n", header);
-            free(scanBuf);
-            return false;
-        }
-    }
-
-    /*
-     * Perform the traditional EOCD snipe hunt.
-     *
-     * We're searching for the End of Central Directory magic number,
-     * which appears at the start of the EOCD block.  It's followed by
-     * 18 bytes of EOCD stuff and up to 64KB of archive comment.  We
-     * need to read the last part of the file into a buffer, dig through
-     * it to find the magic number, parse some values out, and use those
-     * to determine the extent of the CD.
-     *
-     * We start by pulling in the last part of the file.
-     */
-    off64_t searchStart = mFileLength - readAmount;
-
-    if (lseek64(mFd, searchStart, SEEK_SET) != searchStart) {
-        ALOGW("seek %ld failed: %s\n",  (long) searchStart, strerror(errno));
-        free(scanBuf);
-        return false;
-    }
-    actual = TEMP_FAILURE_RETRY(read(mFd, scanBuf, readAmount));
-    if (actual != (ssize_t) readAmount) {
-        ALOGW("Zip: read " ZD ", expected " ZD ". Failed: %s\n",
-            (ZD_TYPE) actual, (ZD_TYPE) readAmount, strerror(errno));
-        free(scanBuf);
-        return false;
-    }
-
-    /*
-     * Scan backward for the EOCD magic.  In an archive without a trailing
-     * comment, we'll find it on the first try.  (We may want to consider
-     * doing an initial minimal read; if we don't find it, retry with a
-     * second read as above.)
-     */
-    int i;
-    for (i = readAmount - kEOCDLen; i >= 0; i--) {
-        if (scanBuf[i] == 0x50 && get4LE(&scanBuf[i]) == kEOCDSignature) {
-            ALOGV("+++ Found EOCD at buf+%d\n", i);
-            break;
-        }
-    }
-    if (i < 0) {
-        ALOGD("Zip: EOCD not found, %s is not zip\n", mFileName);
-        free(scanBuf);
-        return false;
-    }
-
-    off64_t eocdOffset = searchStart + i;
-    const unsigned char* eocdPtr = scanBuf + i;
-
-    assert(eocdOffset < mFileLength);
-
-    /*
-     * Grab the CD offset and size, and the number of entries in the
-     * archive. After that, we can release our EOCD hunt buffer.
-     */
-    unsigned int numEntries = get2LE(eocdPtr + kEOCDNumEntries);
-    unsigned int dirSize = get4LE(eocdPtr + kEOCDSize);
-    unsigned int dirOffset = get4LE(eocdPtr + kEOCDFileOffset);
-    free(scanBuf);
-
-    // Verify that they look reasonable.
-    if ((long long) dirOffset + (long long) dirSize > (long long) eocdOffset) {
-        ALOGW("bad offsets (dir %ld, size %u, eocd %ld)\n",
-            (long) dirOffset, dirSize, (long) eocdOffset);
-        return false;
-    }
-    if (numEntries == 0) {
-        ALOGW("empty archive?\n");
-        return false;
-    }
-
-    ALOGV("+++ numEntries=%d dirSize=%d dirOffset=%d\n",
-        numEntries, dirSize, dirOffset);
-
-    mDirectoryMap = new FileMap();
-    if (mDirectoryMap == NULL) {
-        ALOGW("Unable to create directory map: %s", strerror(errno));
-        return false;
-    }
-
-    if (!mDirectoryMap->create(mFileName, mFd, dirOffset, dirSize, true)) {
-        ALOGW("Unable to map '%s' (" ZD " to " ZD "): %s\n", mFileName,
-                (ZD_TYPE) dirOffset, (ZD_TYPE) (dirOffset + dirSize), strerror(errno));
-        return false;
-    }
-
-    mNumEntries = numEntries;
-    mDirectoryOffset = dirOffset;
-
-    return true;
-}
-
-bool ZipFileRO::parseZipArchive(void)
-{
-    bool result = false;
-    const unsigned char* cdPtr = (const unsigned char*) mDirectoryMap->getDataPtr();
-    size_t cdLength = mDirectoryMap->getDataLength();
-    int numEntries = mNumEntries;
-
-    /*
-     * Create hash table.  We have a minimum 75% load factor, possibly as
-     * low as 50% after we round off to a power of 2.
-     */
-    mHashTableSize = roundUpPower2(1 + (numEntries * 4) / 3);
-    mHashTable = (HashEntry*) calloc(mHashTableSize, sizeof(HashEntry));
-
-    /*
-     * Walk through the central directory, adding entries to the hash
-     * table.
-     */
-    const unsigned char* ptr = cdPtr;
-    for (int i = 0; i < numEntries; i++) {
-        if (get4LE(ptr) != kCDESignature) {
-            ALOGW("Missed a central dir sig (at %d)\n", i);
-            goto bail;
-        }
-        if (ptr + kCDELen > cdPtr + cdLength) {
-            ALOGW("Ran off the end (at %d)\n", i);
-            goto bail;
-        }
-
-        long localHdrOffset = (long) get4LE(ptr + kCDELocalOffset);
-        if (localHdrOffset >= mDirectoryOffset) {
-            ALOGW("bad LFH offset %ld at entry %d\n", localHdrOffset, i);
-            goto bail;
-        }
-
-        unsigned int fileNameLen, extraLen, commentLen, hash;
-
-        fileNameLen = get2LE(ptr + kCDENameLen);
-        extraLen = get2LE(ptr + kCDEExtraLen);
-        commentLen = get2LE(ptr + kCDECommentLen);
-
-        /* add the CDE filename to the hash table */
-        hash = computeHash((const char*)ptr + kCDELen, fileNameLen);
-        addToHash((const char*)ptr + kCDELen, fileNameLen, hash);
-
-        ptr += kCDELen + fileNameLen + extraLen + commentLen;
-        if ((size_t)(ptr - cdPtr) > cdLength) {
-            ALOGW("bad CD advance (%d vs " ZD ") at entry %d\n",
-                (int) (ptr - cdPtr), (ZD_TYPE) cdLength, i);
-            goto bail;
-        }
-    }
-    ALOGV("+++ zip good scan %d entries\n", numEntries);
-    result = true;
-
-bail:
-    return result;
-}
-
-/*
- * Simple string hash function for non-null-terminated strings.
- */
-/*static*/ unsigned int ZipFileRO::computeHash(const char* str, int len)
-{
-    unsigned int hash = 0;
-
-    while (len--)
-        hash = hash * 31 + *str++;
-
-    return hash;
-}
-
-/*
- * Add a new entry to the hash table.
- */
-void ZipFileRO::addToHash(const char* str, int strLen, unsigned int hash)
-{
-    int ent = hash & (mHashTableSize-1);
-
-    /*
-     * We over-allocate the table, so we're guaranteed to find an empty slot.
-     */
-    while (mHashTable[ent].name != NULL)
-        ent = (ent + 1) & (mHashTableSize-1);
-
-    mHashTable[ent].name = str;
-    mHashTable[ent].nameLen = strLen;
-}
-
-/*
- * Find a matching entry.
- *
- * Returns NULL if not found.
- */
-ZipEntryRO ZipFileRO::findEntryByName(const char* fileName) const
-{
-    /*
-     * If the ZipFileRO instance is not initialized, the entry number will
-     * end up being garbage since mHashTableSize is -1.
-     */
-    if (mHashTableSize <= 0) {
-        return NULL;
-    }
-
-    int nameLen = strlen(fileName);
-    unsigned int hash = computeHash(fileName, nameLen);
-    int ent = hash & (mHashTableSize-1);
-
-    while (mHashTable[ent].name != NULL) {
-        if (mHashTable[ent].nameLen == nameLen &&
-            memcmp(mHashTable[ent].name, fileName, nameLen) == 0)
-        {
-            /* match */
-            return (ZipEntryRO)(long)(ent + kZipEntryAdj);
-        }
-
-        ent = (ent + 1) & (mHashTableSize-1);
-    }
-
-    return NULL;
-}
-
-/*
- * Find the Nth entry.
- *
- * This currently involves walking through the sparse hash table, counting
- * non-empty entries.  If we need to speed this up we can either allocate
- * a parallel lookup table or (perhaps better) provide an iterator interface.
- */
-ZipEntryRO ZipFileRO::findEntryByIndex(int idx) const
-{
-    if (idx < 0 || idx >= mNumEntries) {
-        ALOGW("Invalid index %d\n", idx);
-        return NULL;
-    }
-
-    for (int ent = 0; ent < mHashTableSize; ent++) {
-        if (mHashTable[ent].name != NULL) {
-            if (idx-- == 0)
-                return (ZipEntryRO) (ent + kZipEntryAdj);
-        }
-    }
-
-    return NULL;
-}
-
-/*
- * Get the useful fields from the zip entry.
- *
- * Returns "false" if the offsets to the fields or the contents of the fields
- * appear to be bogus.
- */
-bool ZipFileRO::getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen,
-    size_t* pCompLen, off64_t* pOffset, long* pModWhen, long* pCrc32) const
-{
-    bool ret = false;
-
-    const int ent = entryToIndex(entry);
-    if (ent < 0)
-        return false;
-
-    HashEntry hashEntry = mHashTable[ent];
-
-    /*
-     * Recover the start of the central directory entry from the filename
-     * pointer.  The filename is the first entry past the fixed-size data,
-     * so we can just subtract back from that.
-     */
-    const unsigned char* ptr = (const unsigned char*) hashEntry.name;
-    off64_t cdOffset = mDirectoryOffset;
-
-    ptr -= kCDELen;
-
-    int method = get2LE(ptr + kCDEMethod);
-    if (pMethod != NULL)
-        *pMethod = method;
-
-    if (pModWhen != NULL)
-        *pModWhen = get4LE(ptr + kCDEModWhen);
-    if (pCrc32 != NULL)
-        *pCrc32 = get4LE(ptr + kCDECRC);
-
-    size_t compLen = get4LE(ptr + kCDECompLen);
-    if (pCompLen != NULL)
-        *pCompLen = compLen;
-    size_t uncompLen = get4LE(ptr + kCDEUncompLen);
-    if (pUncompLen != NULL)
-        *pUncompLen = uncompLen;
-
-    /*
-     * If requested, determine the offset of the start of the data.  All we
-     * have is the offset to the Local File Header, which is variable size,
-     * so we have to read the contents of the struct to figure out where
-     * the actual data starts.
-     *
-     * We also need to make sure that the lengths are not so large that
-     * somebody trying to map the compressed or uncompressed data runs
-     * off the end of the mapped region.
-     *
-     * Note we don't verify compLen/uncompLen if they don't request the
-     * dataOffset, because dataOffset is expensive to determine.  However,
-     * if they don't have the file offset, they're not likely to be doing
-     * anything with the contents.
-     */
-    if (pOffset != NULL) {
-        long localHdrOffset = get4LE(ptr + kCDELocalOffset);
-        if (localHdrOffset + kLFHLen >= cdOffset) {
-            ALOGE("ERROR: bad local hdr offset in zip\n");
-            return false;
-        }
-
-        unsigned char lfhBuf[kLFHLen];
-
-#ifdef HAVE_PREAD
-        /*
-         * This file descriptor might be from zygote's preloaded assets,
-         * so we need to do an pread64() instead of a lseek64() + read() to
-         * guarantee atomicity across the processes with the shared file
-         * descriptors.
-         */
-        ssize_t actual =
-                TEMP_FAILURE_RETRY(pread64(mFd, lfhBuf, sizeof(lfhBuf), localHdrOffset));
-
-        if (actual != sizeof(lfhBuf)) {
-            ALOGW("failed reading lfh from offset %ld\n", localHdrOffset);
-            return false;
-        }
-
-        if (get4LE(lfhBuf) != kLFHSignature) {
-            ALOGW("didn't find signature at start of lfh; wanted: offset=%ld data=0x%08x; "
-                    "got: data=0x%08lx\n",
-                    localHdrOffset, kLFHSignature, get4LE(lfhBuf));
-            return false;
-        }
-#else /* HAVE_PREAD */
-        /*
-         * For hosts don't have pread64() we cannot guarantee atomic reads from
-         * an offset in a file. Android should never run on those platforms.
-         * File descriptors inherited from a fork() share file offsets and
-         * there would be nothing to protect from two different processes
-         * calling lseek64() concurrently.
-         */
-
-        {
-            AutoMutex _l(mFdLock);
-
-            if (lseek64(mFd, localHdrOffset, SEEK_SET) != localHdrOffset) {
-                ALOGW("failed seeking to lfh at offset %ld\n", localHdrOffset);
-                return false;
-            }
-
-            ssize_t actual =
-                    TEMP_FAILURE_RETRY(read(mFd, lfhBuf, sizeof(lfhBuf)));
-            if (actual != sizeof(lfhBuf)) {
-                ALOGW("failed reading lfh from offset %ld\n", localHdrOffset);
-                return false;
-            }
-
-            if (get4LE(lfhBuf) != kLFHSignature) {
-                off64_t actualOffset = lseek64(mFd, 0, SEEK_CUR);
-                ALOGW("didn't find signature at start of lfh; wanted: offset=%ld data=0x%08x; "
-                        "got: offset=" ZD " data=0x%08lx\n",
-                        localHdrOffset, kLFHSignature, (ZD_TYPE) actualOffset, get4LE(lfhBuf));
-                return false;
-            }
-        }
-#endif /* HAVE_PREAD */
-
-        off64_t dataOffset = localHdrOffset + kLFHLen
-            + get2LE(lfhBuf + kLFHNameLen) + get2LE(lfhBuf + kLFHExtraLen);
-        if (dataOffset >= cdOffset) {
-            ALOGW("bad data offset %ld in zip\n", (long) dataOffset);
-            return false;
-        }
-
-        /* check lengths */
-        if ((off64_t)(dataOffset + compLen) > cdOffset) {
-            ALOGW("bad compressed length in zip (%ld + " ZD " > %ld)\n",
-                (long) dataOffset, (ZD_TYPE) compLen, (long) cdOffset);
-            return false;
-        }
-
-        if (method == kCompressStored &&
-            (off64_t)(dataOffset + uncompLen) > cdOffset)
-        {
-            ALOGE("ERROR: bad uncompressed length in zip (%ld + " ZD " > %ld)\n",
-                (long) dataOffset, (ZD_TYPE) uncompLen, (long) cdOffset);
-            return false;
-        }
-
-        *pOffset = dataOffset;
-    }
-
-    return true;
-}
-
-/*
- * Copy the entry's filename to the buffer.
- */
-int ZipFileRO::getEntryFileName(ZipEntryRO entry, char* buffer, int bufLen)
-    const
-{
-    int ent = entryToIndex(entry);
-    if (ent < 0)
-        return -1;
-
-    int nameLen = mHashTable[ent].nameLen;
-    if (bufLen < nameLen+1)
-        return nameLen+1;
-
-    memcpy(buffer, mHashTable[ent].name, nameLen);
-    buffer[nameLen] = '\0';
-    return 0;
-}
-
-/*
- * Create a new FileMap object that spans the data in "entry".
- */
-FileMap* ZipFileRO::createEntryFileMap(ZipEntryRO entry) const
-{
-    /*
-     * TODO: the efficient way to do this is to modify FileMap to allow
-     * sub-regions of a file to be mapped.  A reference-counting scheme
-     * can manage the base memory mapping.  For now, we just create a brand
-     * new mapping off of the Zip archive file descriptor.
-     */
-
-    FileMap* newMap;
-    size_t compLen;
-    off64_t offset;
-
-    if (!getEntryInfo(entry, NULL, NULL, &compLen, &offset, NULL, NULL))
-        return NULL;
-
-    newMap = new FileMap();
-    if (!newMap->create(mFileName, mFd, offset, compLen, true)) {
-        newMap->release();
-        return NULL;
-    }
-
-    return newMap;
-}
-
-/*
- * Uncompress an entry, in its entirety, into the provided output buffer.
- *
- * This doesn't verify the data's CRC, which might be useful for
- * uncompressed data.  The caller should be able to manage it.
- */
-bool ZipFileRO::uncompressEntry(ZipEntryRO entry, void* buffer) const
-{
-    const size_t kSequentialMin = 32768;
-    bool result = false;
-    int ent = entryToIndex(entry);
-    if (ent < 0)
-        return -1;
-
-    int method;
-    size_t uncompLen, compLen;
-    off64_t offset;
-    const unsigned char* ptr;
-
-    getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL);
-
-    FileMap* file = createEntryFileMap(entry);
-    if (file == NULL) {
-        goto bail;
-    }
-
-    ptr = (const unsigned char*) file->getDataPtr();
-
-    /*
-     * Experiment with madvise hint.  When we want to uncompress a file,
-     * we pull some stuff out of the central dir entry and then hit a
-     * bunch of compressed or uncompressed data sequentially.  The CDE
-     * visit will cause a limited amount of read-ahead because it's at
-     * the end of the file.  We could end up doing lots of extra disk
-     * access if the file we're prying open is small.  Bottom line is we
-     * probably don't want to turn MADV_SEQUENTIAL on and leave it on.
-     *
-     * So, if the compressed size of the file is above a certain minimum
-     * size, temporarily boost the read-ahead in the hope that the extra
-     * pair of system calls are negated by a reduction in page faults.
-     */
-    if (compLen > kSequentialMin)
-        file->advise(FileMap::SEQUENTIAL);
-
-    if (method == kCompressStored) {
-        memcpy(buffer, ptr, uncompLen);
-    } else {
-        if (!inflateBuffer(buffer, ptr, uncompLen, compLen))
-            goto unmap;
-    }
-
-    if (compLen > kSequentialMin)
-        file->advise(FileMap::NORMAL);
-
-    result = true;
-
-unmap:
-    file->release();
-bail:
-    return result;
-}
-
-/*
- * Uncompress an entry, in its entirety, to an open file descriptor.
- *
- * This doesn't verify the data's CRC, but probably should.
- */
-bool ZipFileRO::uncompressEntry(ZipEntryRO entry, int fd) const
-{
-    bool result = false;
-    int ent = entryToIndex(entry);
-    if (ent < 0)
-        return -1;
-
-    int method;
-    size_t uncompLen, compLen;
-    off64_t offset;
-    const unsigned char* ptr;
-
-    getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL);
-
-    FileMap* file = createEntryFileMap(entry);
-    if (file == NULL) {
-        goto bail;
-    }
-
-    ptr = (const unsigned char*) file->getDataPtr();
-
-    if (method == kCompressStored) {
-        ssize_t actual = write(fd, ptr, uncompLen);
-        if (actual < 0) {
-            ALOGE("Write failed: %s\n", strerror(errno));
-            goto unmap;
-        } else if ((size_t) actual != uncompLen) {
-            ALOGE("Partial write during uncompress (" ZD " of " ZD ")\n",
-                (ZD_TYPE) actual, (ZD_TYPE) uncompLen);
-            goto unmap;
-        } else {
-            ALOGI("+++ successful write\n");
-        }
-    } else {
-        if (!inflateBuffer(fd, ptr, uncompLen, compLen))
-            goto unmap;
-    }
-
-    result = true;
-
-unmap:
-    file->release();
-bail:
-    return result;
-}
-
-/*
- * Uncompress "deflate" data from one buffer to another.
- */
-/*static*/ bool ZipFileRO::inflateBuffer(void* outBuf, const void* inBuf,
-    size_t uncompLen, size_t compLen)
-{
-    bool result = false;
-    z_stream zstream;
-    int zerr;
-
-    /*
-     * Initialize the zlib stream struct.
-     */
-    memset(&zstream, 0, sizeof(zstream));
-    zstream.zalloc = Z_NULL;
-    zstream.zfree = Z_NULL;
-    zstream.opaque = Z_NULL;
-    zstream.next_in = (Bytef*)inBuf;
-    zstream.avail_in = compLen;
-    zstream.next_out = (Bytef*) outBuf;
-    zstream.avail_out = uncompLen;
-    zstream.data_type = Z_UNKNOWN;
-
-    /*
-     * Use the undocumented "negative window bits" feature to tell zlib
-     * that there's no zlib header waiting for it.
-     */
-    zerr = inflateInit2(&zstream, -MAX_WBITS);
-    if (zerr != Z_OK) {
-        if (zerr == Z_VERSION_ERROR) {
-            ALOGE("Installed zlib is not compatible with linked version (%s)\n",
-                ZLIB_VERSION);
-        } else {
-            ALOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr);
-        }
-        goto bail;
-    }
-
-    /*
-     * Expand data.
-     */
-    zerr = inflate(&zstream, Z_FINISH);
-    if (zerr != Z_STREAM_END) {
-        ALOGW("Zip inflate failed, zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)\n",
-            zerr, zstream.next_in, zstream.avail_in,
-            zstream.next_out, zstream.avail_out);
-        goto z_bail;
-    }
-
-    /* paranoia */
-    if (zstream.total_out != uncompLen) {
-        ALOGW("Size mismatch on inflated file (%ld vs " ZD ")\n",
-            zstream.total_out, (ZD_TYPE) uncompLen);
-        goto z_bail;
-    }
-
-    result = true;
-
-z_bail:
-    inflateEnd(&zstream);        /* free up any allocated structures */
-
-bail:
-    return result;
-}
-
-/*
- * Uncompress "deflate" data from one buffer to an open file descriptor.
- */
-/*static*/ bool ZipFileRO::inflateBuffer(int fd, const void* inBuf,
-    size_t uncompLen, size_t compLen)
-{
-    bool result = false;
-    const size_t kWriteBufSize = 32768;
-    unsigned char writeBuf[kWriteBufSize];
-    z_stream zstream;
-    int zerr;
-
-    /*
-     * Initialize the zlib stream struct.
-     */
-    memset(&zstream, 0, sizeof(zstream));
-    zstream.zalloc = Z_NULL;
-    zstream.zfree = Z_NULL;
-    zstream.opaque = Z_NULL;
-    zstream.next_in = (Bytef*)inBuf;
-    zstream.avail_in = compLen;
-    zstream.next_out = (Bytef*) writeBuf;
-    zstream.avail_out = sizeof(writeBuf);
-    zstream.data_type = Z_UNKNOWN;
-
-    /*
-     * Use the undocumented "negative window bits" feature to tell zlib
-     * that there's no zlib header waiting for it.
-     */
-    zerr = inflateInit2(&zstream, -MAX_WBITS);
-    if (zerr != Z_OK) {
-        if (zerr == Z_VERSION_ERROR) {
-            ALOGE("Installed zlib is not compatible with linked version (%s)\n",
-                ZLIB_VERSION);
-        } else {
-            ALOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr);
-        }
-        goto bail;
-    }
-
-    /*
-     * Loop while we have more to do.
-     */
-    do {
-        /*
-         * Expand data.
-         */
-        zerr = inflate(&zstream, Z_NO_FLUSH);
-        if (zerr != Z_OK && zerr != Z_STREAM_END) {
-            ALOGW("zlib inflate: zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)\n",
-                zerr, zstream.next_in, zstream.avail_in,
-                zstream.next_out, zstream.avail_out);
-            goto z_bail;
-        }
-
-        /* write when we're full or when we're done */
-        if (zstream.avail_out == 0 ||
-            (zerr == Z_STREAM_END && zstream.avail_out != sizeof(writeBuf)))
-        {
-            long writeSize = zstream.next_out - writeBuf;
-            int cc = write(fd, writeBuf, writeSize);
-            if (cc != (int) writeSize) {
-                ALOGW("write failed in inflate (%d vs %ld)\n", cc, writeSize);
-                goto z_bail;
-            }
-
-            zstream.next_out = writeBuf;
-            zstream.avail_out = sizeof(writeBuf);
-        }
-    } while (zerr == Z_OK);
-
-    assert(zerr == Z_STREAM_END);       /* other errors should've been caught */
-
-    /* paranoia */
-    if (zstream.total_out != uncompLen) {
-        ALOGW("Size mismatch on inflated file (%ld vs " ZD ")\n",
-            zstream.total_out, (ZD_TYPE) uncompLen);
-        goto z_bail;
-    }
-
-    result = true;
-
-z_bail:
-    inflateEnd(&zstream);        /* free up any allocated structures */
-
-bail:
-    return result;
-}
diff --git a/libs/androidfw/ZipUtils.cpp b/libs/androidfw/ZipUtils.cpp
deleted file mode 100644
index db3479d..0000000
--- a/libs/androidfw/ZipUtils.cpp
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- * 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.
- */
-
-//
-// Misc zip/gzip utility functions.
-//
-
-#define LOG_TAG "ziputil"
-
-#include <androidfw/ZipUtils.h>
-#include <androidfw/ZipFileRO.h>
-#include <utils/Log.h>
-
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-
-#include <zlib.h>
-
-using namespace android;
-
-/*
- * Utility function that expands zip/gzip "deflate" compressed data
- * into a buffer.
- *
- * "fd" is an open file positioned at the start of the "deflate" data
- * "buf" must hold at least "uncompressedLen" bytes.
- */
-/*static*/ bool ZipUtils::inflateToBuffer(int fd, void* buf,
-    long uncompressedLen, long compressedLen)
-{
-    bool result = false;
-	const unsigned long kReadBufSize = 32768;
-	unsigned char* readBuf = NULL;
-    z_stream zstream;
-    int zerr;
-    unsigned long compRemaining;
-
-    assert(uncompressedLen >= 0);
-    assert(compressedLen >= 0);
-
-	readBuf = new unsigned char[kReadBufSize];
-	if (readBuf == NULL)
-        goto bail;
-    compRemaining = compressedLen;
-
-    /*
-     * Initialize the zlib stream.
-     */
-	memset(&zstream, 0, sizeof(zstream));
-    zstream.zalloc = Z_NULL;
-    zstream.zfree = Z_NULL;
-    zstream.opaque = Z_NULL;
-    zstream.next_in = NULL;
-    zstream.avail_in = 0;
-    zstream.next_out = (Bytef*) buf;
-    zstream.avail_out = uncompressedLen;
-    zstream.data_type = Z_UNKNOWN;
-
-	/*
-	 * Use the undocumented "negative window bits" feature to tell zlib
-	 * that there's no zlib header waiting for it.
-	 */
-    zerr = inflateInit2(&zstream, -MAX_WBITS);
-    if (zerr != Z_OK) {
-        if (zerr == Z_VERSION_ERROR) {
-            ALOGE("Installed zlib is not compatible with linked version (%s)\n",
-                ZLIB_VERSION);
-        } else {
-            ALOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr);
-        }
-        goto bail;
-    }
-
-    /*
-     * Loop while we have data.
-     */
-    do {
-        unsigned long getSize;
-
-        /* read as much as we can */
-        if (zstream.avail_in == 0) {
-            getSize = (compRemaining > kReadBufSize) ?
-                        kReadBufSize : compRemaining;
-            ALOGV("+++ reading %ld bytes (%ld left)\n",
-                getSize, compRemaining);
-
-            int cc = read(fd, readBuf, getSize);
-            if (cc != (int) getSize) {
-                ALOGD("inflate read failed (%d vs %ld)\n",
-                    cc, getSize);
-                goto z_bail;
-            }
-
-            compRemaining -= getSize;
-
-            zstream.next_in = readBuf;
-            zstream.avail_in = getSize;
-        }
-
-        /* uncompress the data */
-        zerr = inflate(&zstream, Z_NO_FLUSH);
-        if (zerr != Z_OK && zerr != Z_STREAM_END) {
-            ALOGD("zlib inflate call failed (zerr=%d)\n", zerr);
-            goto z_bail;
-        }
-
-		/* output buffer holds all, so no need to write the output */
-    } while (zerr == Z_OK);
-
-    assert(zerr == Z_STREAM_END);       /* other errors should've been caught */
-
-    if ((long) zstream.total_out != uncompressedLen) {
-        ALOGW("Size mismatch on inflated file (%ld vs %ld)\n",
-            zstream.total_out, uncompressedLen);
-        goto z_bail;
-    }
-
-    // success!
-    result = true;
-
-z_bail:
-    inflateEnd(&zstream);        /* free up any allocated structures */
-
-bail:
-	delete[] readBuf;
-    return result;
-}
-
-/*
- * Utility function that expands zip/gzip "deflate" compressed data
- * into a buffer.
- *
- * (This is a clone of the previous function, but it takes a FILE* instead
- * of an fd.  We could pass fileno(fd) to the above, but we can run into
- * trouble when "fp" has a different notion of what fd's file position is.)
- *
- * "fp" is an open file positioned at the start of the "deflate" data
- * "buf" must hold at least "uncompressedLen" bytes.
- */
-/*static*/ bool ZipUtils::inflateToBuffer(FILE* fp, void* buf,
-    long uncompressedLen, long compressedLen)
-{
-    bool result = false;
-	const unsigned long kReadBufSize = 32768;
-	unsigned char* readBuf = NULL;
-    z_stream zstream;
-    int zerr;
-    unsigned long compRemaining;
-
-    assert(uncompressedLen >= 0);
-    assert(compressedLen >= 0);
-
-	readBuf = new unsigned char[kReadBufSize];
-	if (readBuf == NULL)
-        goto bail;
-    compRemaining = compressedLen;
-
-    /*
-     * Initialize the zlib stream.
-     */
-	memset(&zstream, 0, sizeof(zstream));
-    zstream.zalloc = Z_NULL;
-    zstream.zfree = Z_NULL;
-    zstream.opaque = Z_NULL;
-    zstream.next_in = NULL;
-    zstream.avail_in = 0;
-    zstream.next_out = (Bytef*) buf;
-    zstream.avail_out = uncompressedLen;
-    zstream.data_type = Z_UNKNOWN;
-
-	/*
-	 * Use the undocumented "negative window bits" feature to tell zlib
-	 * that there's no zlib header waiting for it.
-	 */
-    zerr = inflateInit2(&zstream, -MAX_WBITS);
-    if (zerr != Z_OK) {
-        if (zerr == Z_VERSION_ERROR) {
-            ALOGE("Installed zlib is not compatible with linked version (%s)\n",
-                ZLIB_VERSION);
-        } else {
-            ALOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr);
-        }
-        goto bail;
-    }
-
-    /*
-     * Loop while we have data.
-     */
-    do {
-        unsigned long getSize;
-
-        /* read as much as we can */
-        if (zstream.avail_in == 0) {
-            getSize = (compRemaining > kReadBufSize) ?
-                        kReadBufSize : compRemaining;
-            ALOGV("+++ reading %ld bytes (%ld left)\n",
-                getSize, compRemaining);
-
-            int cc = fread(readBuf, 1, getSize, fp);
-            if (cc != (int) getSize) {
-                ALOGD("inflate read failed (%d vs %ld)\n",
-                    cc, getSize);
-                goto z_bail;
-            }
-
-            compRemaining -= getSize;
-
-            zstream.next_in = readBuf;
-            zstream.avail_in = getSize;
-        }
-
-        /* uncompress the data */
-        zerr = inflate(&zstream, Z_NO_FLUSH);
-        if (zerr != Z_OK && zerr != Z_STREAM_END) {
-            ALOGD("zlib inflate call failed (zerr=%d)\n", zerr);
-            goto z_bail;
-        }
-
-		/* output buffer holds all, so no need to write the output */
-    } while (zerr == Z_OK);
-
-    assert(zerr == Z_STREAM_END);       /* other errors should've been caught */
-
-    if ((long) zstream.total_out != uncompressedLen) {
-        ALOGW("Size mismatch on inflated file (%ld vs %ld)\n",
-            zstream.total_out, uncompressedLen);
-        goto z_bail;
-    }
-
-    // success!
-    result = true;
-
-z_bail:
-    inflateEnd(&zstream);        /* free up any allocated structures */
-
-bail:
-	delete[] readBuf;
-    return result;
-}
-
-/*
- * Look at the contents of a gzip archive.  We want to know where the
- * data starts, and how long it will be after it is uncompressed.
- *
- * We expect to find the CRC and length as the last 8 bytes on the file.
- * This is a pretty reasonable thing to expect for locally-compressed
- * files, but there's a small chance that some extra padding got thrown
- * on (the man page talks about compressed data written to tape).  We
- * don't currently deal with that here.  If "gzip -l" whines, we're going
- * to fail too.
- *
- * On exit, "fp" is pointing at the start of the compressed data.
- */
-/*static*/ bool ZipUtils::examineGzip(FILE* fp, int* pCompressionMethod,
-    long* pUncompressedLen, long* pCompressedLen, unsigned long* pCRC32)
-{
-    enum {  // flags
-        FTEXT       = 0x01,
-        FHCRC       = 0x02,
-        FEXTRA      = 0x04,
-        FNAME       = 0x08,
-        FCOMMENT    = 0x10,
-    };
-    int ic;
-    int method, flags;
-    int i;
-
-    ic = getc(fp);
-    if (ic != 0x1f || getc(fp) != 0x8b)
-        return false;       // not gzip
-    method = getc(fp);
-    flags = getc(fp);
-
-    /* quick sanity checks */
-    if (method == EOF || flags == EOF)
-        return false;
-    if (method != ZipFileRO::kCompressDeflated)
-        return false;
-
-    /* skip over 4 bytes of mod time, 1 byte XFL, 1 byte OS */
-    for (i = 0; i < 6; i++)
-        (void) getc(fp);
-    /* consume "extra" field, if present */
-    if ((flags & FEXTRA) != 0) {
-        int len;
-
-        len = getc(fp);
-        len |= getc(fp) << 8;
-        while (len-- && getc(fp) != EOF)
-            ;
-    }
-    /* consume filename, if present */
-    if ((flags & FNAME) != 0) {
-        do {
-            ic = getc(fp);
-        } while (ic != 0 && ic != EOF);
-    }
-    /* consume comment, if present */
-    if ((flags & FCOMMENT) != 0) {
-        do {
-            ic = getc(fp);
-        } while (ic != 0 && ic != EOF);
-    }
-    /* consume 16-bit header CRC, if present */
-    if ((flags & FHCRC) != 0) {
-        (void) getc(fp);
-        (void) getc(fp);
-    }
-
-    if (feof(fp) || ferror(fp))
-        return false;
-
-    /* seek to the end; CRC and length are in the last 8 bytes */
-    long curPosn = ftell(fp);
-    unsigned char buf[8];
-    fseek(fp, -8, SEEK_END);
-    *pCompressedLen = ftell(fp) - curPosn;
-
-    if (fread(buf, 1, 8, fp) != 8)
-        return false;
-    /* seek back to start of compressed data */
-    fseek(fp, curPosn, SEEK_SET);
-
-    *pCompressionMethod = method;
-    *pCRC32 = ZipFileRO::get4LE(&buf[0]);
-    *pUncompressedLen = ZipFileRO::get4LE(&buf[4]);
-
-    return true;
-}
diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk
index d85009b..39009b8 100644
--- a/libs/androidfw/tests/Android.mk
+++ b/libs/androidfw/tests/Android.mk
@@ -7,8 +7,7 @@
     InputChannel_test.cpp \
     InputEvent_test.cpp \
     InputPublisherAndConsumer_test.cpp \
-    ObbFile_test.cpp \
-    ZipFileRO_test.cpp 
+    ObbFile_test.cpp
 
 shared_libraries := \
 	libandroidfw \
diff --git a/libs/androidfw/tests/ZipFileRO_test.cpp b/libs/androidfw/tests/ZipFileRO_test.cpp
deleted file mode 100644
index 344f974..0000000
--- a/libs/androidfw/tests/ZipFileRO_test.cpp
+++ /dev/null
@@ -1,64 +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.
- */
-
-#define LOG_TAG "ZipFileRO_test"
-#include <androidfw/ZipFileRO.h>
-#include <utils/Log.h>
-
-#include <gtest/gtest.h>
-
-#include <fcntl.h>
-#include <string.h>
-
-namespace android {
-
-class ZipFileROTest : public testing::Test {
-protected:
-    virtual void SetUp() {
-    }
-
-    virtual void TearDown() {
-    }
-};
-
-TEST_F(ZipFileROTest, ZipTimeConvertSuccess) {
-    struct tm t;
-
-    // 2011-06-29 14:40:40
-    long when = 0x3EDD7514;
-
-    ZipFileRO::zipTimeToTimespec(when, &t);
-
-    EXPECT_EQ(2011, t.tm_year + 1900)
-            << "Year was improperly converted.";
-
-    EXPECT_EQ(6, t.tm_mon)
-            << "Month was improperly converted.";
-
-    EXPECT_EQ(29, t.tm_mday)
-            << "Day was improperly converted.";
-
-    EXPECT_EQ(14, t.tm_hour)
-            << "Hour was improperly converted.";
-
-    EXPECT_EQ(40, t.tm_min)
-            << "Minute was improperly converted.";
-
-    EXPECT_EQ(40, t.tm_sec)
-            << "Second was improperly converted.";
-}
-
-}
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 38d0374..4bbb04f 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -51,7 +51,7 @@
 
 // Set to 1 to enable native processing of View properties. 0 by default. Eventually this
 // will go away and we will always use this approach for accelerated apps.
-#define USE_DISPLAY_LIST_PROPERTIES 1
+#define USE_DISPLAY_LIST_PROPERTIES 0
 
 #define TRANSLATION 0x0001
 #define ROTATION    0x0002
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 92a7573..d7937c7 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -518,6 +518,8 @@
     mCacheLines.clear();
 
     if (mInitialized) {
+        glDeleteBuffers(1, &mIndexBufferID);
+
         delete[] mTextMeshPtr;
         delete mCacheTextureSmall;
         delete mCacheTexture128;
diff --git a/libs/rs/Allocation.cpp b/libs/rs/Allocation.cpp
index d69c55f..e37d5de 100644
--- a/libs/rs/Allocation.cpp
+++ b/libs/rs/Allocation.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008-2012 The Android Open Source Project
+ * Copyright (C) 2012 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.
@@ -51,17 +51,14 @@
                    RS_ALLOCATION_USAGE_GRAPHICS_VERTEX |
                    RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS |
                    RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET |
-                   RS_ALLOCATION_USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE |
                    RS_ALLOCATION_USAGE_IO_INPUT |
                    RS_ALLOCATION_USAGE_IO_OUTPUT)) != 0) {
         ALOGE("Unknown usage specified.");
     }
 
-    if ((usage & (RS_ALLOCATION_USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE |
-                  RS_ALLOCATION_USAGE_IO_INPUT)) != 0) {
+    if ((usage & RS_ALLOCATION_USAGE_IO_INPUT) != 0) {
         mWriteAllowed = false;
-        if ((usage & ~(RS_ALLOCATION_USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE |
-                       RS_ALLOCATION_USAGE_IO_INPUT |
+        if ((usage & ~(RS_ALLOCATION_USAGE_IO_INPUT |
                        RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE |
                        RS_ALLOCATION_USAGE_SCRIPT)) != 0) {
             ALOGE("Invalid usage combination.");
diff --git a/libs/rs/driver/rsdAllocation.cpp b/libs/rs/driver/rsdAllocation.cpp
index fb93d82..f358f93 100644
--- a/libs/rs/driver/rsdAllocation.cpp
+++ b/libs/rs/driver/rsdAllocation.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2011-2012 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.
@@ -27,6 +27,7 @@
 #include "hardware/gralloc.h"
 #include "ui/Rect.h"
 #include "ui/GraphicBufferMapper.h"
+#include "gui/SurfaceTexture.h"
 
 #include <GLES/gl.h>
 #include <GLES2/gl2.h>
@@ -139,7 +140,7 @@
 static void UploadToTexture(const Context *rsc, const Allocation *alloc) {
     DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
 
-    if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE) {
+    if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_IO_INPUT) {
         if (!drv->textureID) {
             RSD_CALL_GL(glGenTextures, 1, &drv->textureID);
         }
@@ -475,7 +476,8 @@
 }
 
 void rsdAllocationIoReceive(const Context *rsc, Allocation *alloc) {
-    ALOGE("not implemented");
+    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
+    alloc->mHal.state.surfaceTexture->updateTexImage();
 }
 
 
diff --git a/libs/rs/driver/rsdCore.cpp b/libs/rs/driver/rsdCore.cpp
index 35a5c08..6a532e9 100644
--- a/libs/rs/driver/rsdCore.cpp
+++ b/libs/rs/driver/rsdCore.cpp
@@ -227,13 +227,13 @@
 
 
     int cpu = sysconf(_SC_NPROCESSORS_ONLN);
-    ALOGV("%p Launching thread(s), CPUs %i", rsc, cpu);
     if(rsc->props.mDebugMaxThreads && (cpu > (int)rsc->props.mDebugMaxThreads)) {
         cpu = rsc->props.mDebugMaxThreads;
     }
     if (cpu < 2) {
         cpu = 0;
     }
+    ALOGV("%p Launching thread(s), CPUs %i", rsc, cpu);
 
     dc->mWorkers.mCount = (uint32_t)cpu;
     dc->mWorkers.mThreadId = (pthread_t *) calloc(dc->mWorkers.mCount, sizeof(pthread_t));
diff --git a/libs/rs/driver/rsdProgram.cpp b/libs/rs/driver/rsdProgram.cpp
index fa4cb0f..30a4c5f 100644
--- a/libs/rs/driver/rsdProgram.cpp
+++ b/libs/rs/driver/rsdProgram.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2011-2012 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.
@@ -41,7 +41,7 @@
                                    textureNames, textureNamesCount, textureNamesLength);
     pv->mHal.drv = drv;
 
-    return drv->createShader();
+    return true;
 }
 
 static void SyncProgramConstants(const Context *rsc, const Program *p) {
@@ -88,7 +88,7 @@
                                    textureNames, textureNamesCount, textureNamesLength);
     pf->mHal.drv = drv;
 
-    return drv->createShader();
+    return true;
 }
 
 void rsdProgramFragmentSetActive(const Context *rsc, const ProgramFragment *pf) {
diff --git a/libs/rs/driver/rsdShader.cpp b/libs/rs/driver/rsdShader.cpp
index 1e73b95..a386735 100644
--- a/libs/rs/driver/rsdShader.cpp
+++ b/libs/rs/driver/rsdShader.cpp
@@ -39,7 +39,10 @@
     initMemberVars();
     initAttribAndUniformArray();
     init(textureNames, textureNamesCount, textureNamesLength);
-    createTexturesString(textureNames, textureNamesCount, textureNamesLength);
+
+    for(size_t i=0; i < textureNamesCount; i++) {
+        mTextureNames.push(String8(textureNames[i], textureNamesLength[i]));
+    }
 }
 
 RsdShader::~RsdShader() {
@@ -138,37 +141,42 @@
     }
 }
 
-void RsdShader::createTexturesString(const char** textureNames, size_t textureNamesCount,
-                                     const size_t *textureNamesLength) {
-    mShaderTextures.setTo("");
+void RsdShader::appendTextures() {
+
+    // TODO: this does not yet handle cases where the texture changes between IO
+    // input and local
+    bool appendUsing = true;
     for (uint32_t ct = 0; ct < mRSProgram->mHal.state.texturesCount; ct ++) {
         if (mRSProgram->mHal.state.textureTargets[ct] == RS_TEXTURE_2D) {
             Allocation *a = mRSProgram->mHal.state.textures[ct];
             if (a && a->mHal.state.surfaceTextureID) {
-                mShaderTextures.append("uniform samplerExternalOES UNI_");
+                if(appendUsing) {
+                    mShader.append("#extension GL_OES_EGL_image_external : require\n");
+                    appendUsing = false;
+                }
+                mShader.append("uniform samplerExternalOES UNI_");
+                mTextureTargets[ct] = GL_TEXTURE_EXTERNAL_OES;
             } else {
-                mShaderTextures.append("uniform sampler2D UNI_");
+                mShader.append("uniform sampler2D UNI_");
+                mTextureTargets[ct] = GL_TEXTURE_2D;
             }
-            mTextureTargets[ct] = GL_TEXTURE_2D;
         } else {
-            mShaderTextures.append("uniform samplerCube UNI_");
+            mShader.append("uniform samplerCube UNI_");
             mTextureTargets[ct] = GL_TEXTURE_CUBE_MAP;
         }
 
-        mShaderTextures.append(textureNames[ct], textureNamesLength[ct]);
-        mShaderTextures.append(";\n");
+        mShader.append(mTextureNames[ct]);
+        mShader.append(";\n");
     }
 }
 
 bool RsdShader::createShader() {
-
     if (mType == GL_FRAGMENT_SHADER) {
         mShader.append("precision mediump float;\n");
     }
     appendUserConstants();
     appendAttributes();
-    mShader.append(mShaderTextures);
-
+    appendTextures();
     mShader.append(mUserShader);
 
     return true;
@@ -178,6 +186,10 @@
     mShaderID = glCreateShader(mType);
     rsAssert(mShaderID);
 
+    if(!mShader.length()) {
+        createShader();
+    }
+
     if (rsc->props.mLogShaders) {
         ALOGV("Loading shader type %x, ID %i", mType, mShaderID);
         ALOGV("%s", mShader.string());
@@ -423,7 +435,9 @@
         }
 
         DrvAllocation *drvTex = (DrvAllocation *)mRSProgram->mHal.state.textures[ct]->mHal.drv;
-        if (drvTex->glTarget != GL_TEXTURE_2D && drvTex->glTarget != GL_TEXTURE_CUBE_MAP) {
+        if (drvTex->glTarget != GL_TEXTURE_2D &&
+            drvTex->glTarget != GL_TEXTURE_CUBE_MAP &&
+            drvTex->glTarget != GL_TEXTURE_EXTERNAL_OES) {
             ALOGE("Attempting to bind unknown texture to shader id %u, texture unit %u",
                   (uint)this, ct);
             rsc->setError(RS_ERROR_BAD_SHADER, "Non-texture allocation bound to a shader");
diff --git a/libs/rs/driver/rsdShader.h b/libs/rs/driver/rsdShader.h
index e32145f..6c0b616 100644
--- a/libs/rs/driver/rsdShader.h
+++ b/libs/rs/driver/rsdShader.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2011-2012 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.
@@ -81,15 +81,12 @@
 
     void appendAttributes();
     void appendTextures();
-    void createTexturesString(const char** textureNames, size_t textureNamesCount,
-                              const size_t *textureNamesLength);
 
     void initAttribAndUniformArray();
 
     mutable bool mDirty;
     android::String8 mShader;
     android::String8 mUserShader;
-    android::String8 mShaderTextures;
     uint32_t mShaderID;
     uint32_t mType;
 
@@ -101,6 +98,8 @@
     android::String8 *mUniformNames;
     uint32_t *mUniformArraySizes;
 
+    android::Vector<android::String8> mTextureNames;
+
     int32_t mTextureUniformIndexStart;
 
     void logUniform(const android::renderscript::Element *field,
diff --git a/libs/rs/driver/rsdShaderCache.cpp b/libs/rs/driver/rsdShaderCache.cpp
index 89d3c45..50cb9f9 100644
--- a/libs/rs/driver/rsdShaderCache.cpp
+++ b/libs/rs/driver/rsdShaderCache.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2011-2012 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.
@@ -119,7 +119,6 @@
     if (!vtx->getShaderID() || !frag->getShaderID()) {
         return false;
     }
-    //ALOGV("rsdShaderCache lookup  vtx %i, frag %i", vtx->getShaderID(), frag->getShaderID());
     uint32_t entryCount = mEntries.size();
     for (uint32_t ct = 0; ct < entryCount; ct ++) {
         if ((mEntries[ct]->vtx == vtx->getShaderID()) &&
@@ -134,8 +133,6 @@
         }
     }
 
-    //ALOGV("RsdShaderCache miss");
-    //ALOGE("e0 %x", glGetError());
     ProgramEntry *e = new ProgramEntry(vtx->getAttribCount(),
                                        vtx->getUniformCount(),
                                        frag->getUniformCount());
diff --git a/libs/rs/driver/rsdShaderCache.h b/libs/rs/driver/rsdShaderCache.h
index 0beecae..1192916 100644
--- a/libs/rs/driver/rsdShaderCache.h
+++ b/libs/rs/driver/rsdShaderCache.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2011-2012 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.
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index cf4a391..b373056 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -69,6 +69,12 @@
     ret int32_t
 }
 
+AllocationGetSurfaceTextureID2 {
+    param RsAllocation alloc
+    param void *st
+    sync
+}
+
 AllocationSetSurface {
     param RsAllocation alloc
     param RsNativeWindow sur
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index a404c49..cdff49c 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -20,6 +20,7 @@
 #include "rs_hal.h"
 
 #include "system/window.h"
+#include "gui/SurfaceTexture.h"
 
 using namespace android;
 using namespace android::renderscript;
@@ -64,6 +65,7 @@
 
 Allocation::~Allocation() {
     freeChildrenUnlocked();
+    setSurfaceTexture(mRSC, NULL);
     mRSC->mHal.funcs.allocation.destroy(mRSC, this);
 }
 
@@ -424,6 +426,18 @@
     return id;
 }
 
+void Allocation::setSurfaceTexture(const Context *rsc, SurfaceTexture *st) {
+    if(st != mHal.state.surfaceTexture) {
+        if(mHal.state.surfaceTexture != NULL) {
+            mHal.state.surfaceTexture->decStrong(NULL);
+        }
+        mHal.state.surfaceTexture = st;
+        if(mHal.state.surfaceTexture != NULL) {
+            mHal.state.surfaceTexture->incStrong(NULL);
+        }
+    }
+}
+
 void Allocation::setSurface(const Context *rsc, RsNativeWindow sur) {
     ANativeWindow *nw = (ANativeWindow *)sur;
     ANativeWindow *old = mHal.state.wndSurface;
@@ -696,6 +710,11 @@
     return alloc->getSurfaceTextureID(rsc);
 }
 
+void rsi_AllocationGetSurfaceTextureID2(Context *rsc, RsAllocation valloc, void *vst, size_t len) {
+    Allocation *alloc = static_cast<Allocation *>(valloc);
+    alloc->setSurfaceTexture(rsc, static_cast<SurfaceTexture *>(vst));
+}
+
 void rsi_AllocationSetSurface(Context *rsc, RsAllocation valloc, RsNativeWindow sur) {
     Allocation *alloc = static_cast<Allocation *>(valloc);
     alloc->setSurface(rsc, sur);
diff --git a/libs/rs/rsAllocation.h b/libs/rs/rsAllocation.h
index 58a6fca..e2783d2 100644
--- a/libs/rs/rsAllocation.h
+++ b/libs/rs/rsAllocation.h
@@ -23,6 +23,8 @@
 
 // ---------------------------------------------------------------------------
 namespace android {
+class SurfaceTexture;
+
 namespace renderscript {
 
 class Program;
@@ -60,6 +62,7 @@
             void * usrPtr;
             int32_t surfaceTextureID;
             ANativeWindow *wndSurface;
+            SurfaceTexture *surfaceTexture;
         };
         State state;
 
@@ -130,6 +133,7 @@
     }
 
     int32_t getSurfaceTextureID(const Context *rsc);
+    void setSurfaceTexture(const Context *rsc, SurfaceTexture *st);
     void setSurface(const Context *rsc, RsNativeWindow sur);
     void ioSend(const Context *rsc);
     void ioReceive(const Context *rsc);
diff --git a/libs/rs/rsDefines.h b/libs/rs/rsDefines.h
index 990ef26..0e0cd8d 100644
--- a/libs/rs/rsDefines.h
+++ b/libs/rs/rsDefines.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2007-2012 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.
@@ -100,9 +100,8 @@
     RS_ALLOCATION_USAGE_GRAPHICS_VERTEX = 0x0004,
     RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS = 0x0008,
     RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET = 0x0010,
-    RS_ALLOCATION_USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE = 0x0020,
-    RS_ALLOCATION_USAGE_IO_INPUT = 0x0040,
-    RS_ALLOCATION_USAGE_IO_OUTPUT = 0x0080,
+    RS_ALLOCATION_USAGE_IO_INPUT = 0x0020,
+    RS_ALLOCATION_USAGE_IO_OUTPUT = 0x0040,
 
     RS_ALLOCATION_USAGE_ALL = 0x00FF
 };
diff --git a/libs/rs/scriptc/rs_allocation.rsh b/libs/rs/scriptc/rs_allocation.rsh
index 89696b8..b0840a0 100644
--- a/libs/rs/scriptc/rs_allocation.rsh
+++ b/libs/rs/scriptc/rs_allocation.rsh
@@ -14,31 +14,6 @@
  * limitations under the License.
  */
 
-/*! \mainpage notitle
- *
- * Renderscript is a high-performance runtime that provides graphics rendering and
- * compute operations at the native level. Renderscript code is compiled on devices
- * at runtime to allow platform-independence as well.
- * This reference documentation describes the Renderscript runtime APIs, which you
- * can utilize to write Renderscript code in C99. The Renderscript header
- * files are automatically included for you, except for the rs_graphics.rsh header. If
- * you are doing graphics rendering, include the graphics header file like this:
- *
- * <code>#include "rs_graphics.rsh"</code>
- *
- * To use Renderscript, you need to utilize the Renderscript runtime APIs documented here
- * as well as the Android framework APIs for Renderscript.
- * For documentation on the Android framework APIs, see the <a target="_parent" href=
- * "http://developer.android.com/reference/android/renderscript/package-summary.html">
- * android.renderscript</a> package reference.
- * For more information on how to develop with Renderscript and how the runtime and
- * Android framework APIs interact, see the <a target="_parent" href=
- * "http://developer.android.com/guide/topics/renderscript/index.html">Renderscript
- * developer guide</a> and the <a target="_parent" href=
- * "http://developer.android.com/resources/samples/RenderScript/index.html">
- * Renderscript samples</a>.
- */
-
 /** @file rs_allocation.rsh
  *  \brief Allocation routines
  *
@@ -168,6 +143,8 @@
 extern const void * __attribute__((overloadable))
     rsGetElementAt(rs_allocation, uint32_t x, uint32_t y, uint32_t z);
 
+#if (defined(RS_VERSION) && (RS_VERSION >= 16))
+
 /**
  * @param a allocation to get data from
  * @return element describing allocation layout
@@ -176,129 +153,6 @@
     rsAllocationGetElement(rs_allocation a);
 
 /**
- * @param m mesh to get data from
- * @return number of allocations in the mesh that contain vertex
- *         data
- */
-extern uint32_t __attribute__((overloadable))
-    rsMeshGetVertexAllocationCount(rs_mesh m);
-
-/**
- * @param m mesh to get data from
- * @return number of primitive groups in the mesh. This would
- *         include simple primitives as well as allocations
- *         containing index data
- */
-extern uint32_t __attribute__((overloadable))
-    rsMeshGetPrimitiveCount(rs_mesh m);
-
-/**
- * @param m mesh to get data from
- * @param index index of the vertex allocation
- * @return allocation containing vertex data
- */
-extern rs_allocation __attribute__((overloadable))
-    rsMeshGetVertexAllocation(rs_mesh m, uint32_t index);
-
-/**
- * @param m mesh to get data from
- * @param index index of the index allocation
- * @return allocation containing index data
- */
-extern rs_allocation __attribute__((overloadable))
-    rsMeshGetIndexAllocation(rs_mesh m, uint32_t index);
-
-/**
- * @param m mesh to get data from
- * @param index index of the primitive
- * @return primitive describing how the mesh is rendered
- */
-extern rs_primitive __attribute__((overloadable))
-    rsMeshGetPrimitive(rs_mesh m, uint32_t index);
-
-/**
- * @param e element to get data from
- * @return number of sub-elements in this element
- */
-extern uint32_t __attribute__((overloadable))
-    rsElementGetSubElementCount(rs_element e);
-
-/**
- * @param e element to get data from
- * @param index index of the sub-element to return
- * @return sub-element in this element at given index
- */
-extern rs_element __attribute__((overloadable))
-    rsElementGetSubElement(rs_element, uint32_t index);
-
-/**
- * @param e element to get data from
- * @param index index of the sub-element to return
- * @return length of the sub-element name including the null
- *         terminator (size of buffer needed to write the name)
- */
-extern uint32_t __attribute__((overloadable))
-    rsElementGetSubElementNameLength(rs_element e, uint32_t index);
-
-/**
- * @param e element to get data from
- * @param index index of the sub-element
- * @param name array to store the name into
- * @param nameLength length of the provided name array
- * @return number of characters actually written, excluding the
- *         null terminator
- */
-extern uint32_t __attribute__((overloadable))
-    rsElementGetSubElementName(rs_element e, uint32_t index, char *name, uint32_t nameLength);
-
-/**
- * @param e element to get data from
- * @param index index of the sub-element
- * @return array size of sub-element in this element at given
- *         index
- */
-extern uint32_t __attribute__((overloadable))
-    rsElementGetSubElementArraySize(rs_element e, uint32_t index);
-
-/**
- * @param e element to get data from
- * @param index index of the sub-element
- * @return offset in bytes of sub-element in this element at
- *         given index
- */
-extern uint32_t __attribute__((overloadable))
-    rsElementGetSubElementOffsetBytes(rs_element e, uint32_t index);
-
-/**
- * @param e element to get data from
- * @return total size of the element in bytes
- */
-extern uint32_t __attribute__((overloadable))
-    rsElementGetSizeBytes(rs_element e);
-
-/**
- * @param e element to get data from
- * @return element's data type
- */
-extern rs_data_type __attribute__((overloadable))
-    rsElementGetDataType(rs_element e);
-
-/**
- * @param e element to get data from
- * @return element's data size
- */
-extern rs_data_kind __attribute__((overloadable))
-    rsElementGetDataKind(rs_element e);
-
-/**
- * @param e element to get data from
- * @return length of the element vector (for float2, float3,
- *         etc.)
- */
-extern uint32_t __attribute__((overloadable))
-    rsElementGetVectorSize(rs_element e);
-
-/**
  * Fetch allocation in a way described by the sampler
  * @param a 1D allocation to sample from
  * @param s sampler state
@@ -339,26 +193,7 @@
 extern const float4 __attribute__((overloadable))
     rsSample(rs_allocation a, rs_sampler s, float2 location, float lod);
 
-/**
- * Fetch allocation in a way described by the sampler
- * @param a 3D allocation to sample from
- * @param s sampler state
- * @param location to sample from
- */
-extern const float4 __attribute__((overloadable))
-    rsSample(rs_allocation a, rs_sampler s, float3 location);
-
-/**
- * Fetch allocation in a way described by the sampler
- * @param a 3D allocation to sample from
- * @param s sampler state
- * @param location to sample from
- * @param lod mip level to sample from, for fractional values
- *            mip levels will be interpolated if
- *            RS_SAMPLER_LINEAR_MIP_LINEAR is used
- */
-extern const float4 __attribute__((overloadable))
-    rsSample(rs_allocation a, rs_sampler s, float3 location, float lod);
+#endif // (defined(RS_VERSION) && (RS_VERSION >= 16))
 
 #endif
 
diff --git a/libs/rs/scriptc/rs_core.rsh b/libs/rs/scriptc/rs_core.rsh
index be900cb..1b0f9db 100644
--- a/libs/rs/scriptc/rs_core.rsh
+++ b/libs/rs/scriptc/rs_core.rsh
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2011-2012 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.
@@ -14,6 +14,31 @@
  * limitations under the License.
  */
 
+ /*! \mainpage notitle
+  *
+  * Renderscript is a high-performance runtime that provides graphics rendering and
+  * compute operations at the native level. Renderscript code is compiled on devices
+  * at runtime to allow platform-independence as well.
+  * This reference documentation describes the Renderscript runtime APIs, which you
+  * can utilize to write Renderscript code in C99. The Renderscript header
+  * files are automatically included for you, except for the rs_graphics.rsh header. If
+  * you are doing graphics rendering, include the graphics header file like this:
+  *
+  * <code>#include "rs_graphics.rsh"</code>
+  *
+  * To use Renderscript, you need to utilize the Renderscript runtime APIs documented here
+  * as well as the Android framework APIs for Renderscript.
+  * For documentation on the Android framework APIs, see the <a target="_parent" href=
+  * "http://developer.android.com/reference/android/renderscript/package-summary.html">
+  * android.renderscript</a> package reference.
+  * For more information on how to develop with Renderscript and how the runtime and
+  * Android framework APIs interact, see the <a target="_parent" href=
+  * "http://developer.android.com/guide/topics/renderscript/index.html">Renderscript
+  * developer guide</a> and the <a target="_parent" href=
+  * "http://developer.android.com/resources/samples/RenderScript/index.html">
+  * Renderscript samples</a>.
+  */
+
 /** @file rs_core.rsh
  *  \brief todo-jsams
  *
@@ -31,14 +56,14 @@
 #include "rs_atomic.rsh"
 #include "rs_cl.rsh"
 #include "rs_debug.rsh"
+#include "rs_element.rsh"
 #include "rs_math.rsh"
 #include "rs_matrix.rsh"
 #include "rs_object.rsh"
 #include "rs_quaternion.rsh"
+#include "rs_sampler.rsh"
 #include "rs_time.rsh"
 
-
-
 /**
  * Send a message back to the client.  Will not block and returns true
  * if the message was sendable and false if the fifo was full.
diff --git a/libs/rs/scriptc/rs_element.rsh b/libs/rs/scriptc/rs_element.rsh
new file mode 100644
index 0000000..1a4cdb75
--- /dev/null
+++ b/libs/rs/scriptc/rs_element.rsh
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/** @file rs_element.rsh
+ *  \brief Element routines
+ *
+ *
+ */
+
+#ifndef __RS_ELEMENT_RSH__
+#define __RS_ELEMENT_RSH__
+
+#if (defined(RS_VERSION) && (RS_VERSION >= 16))
+
+/**
+ * @param e element to get data from
+ * @return number of sub-elements in this element
+ */
+extern uint32_t __attribute__((overloadable))
+    rsElementGetSubElementCount(rs_element e);
+
+/**
+ * @param e element to get data from
+ * @param index index of the sub-element to return
+ * @return sub-element in this element at given index
+ */
+extern rs_element __attribute__((overloadable))
+    rsElementGetSubElement(rs_element, uint32_t index);
+
+/**
+ * @param e element to get data from
+ * @param index index of the sub-element to return
+ * @return length of the sub-element name including the null
+ *         terminator (size of buffer needed to write the name)
+ */
+extern uint32_t __attribute__((overloadable))
+    rsElementGetSubElementNameLength(rs_element e, uint32_t index);
+
+/**
+ * @param e element to get data from
+ * @param index index of the sub-element
+ * @param name array to store the name into
+ * @param nameLength length of the provided name array
+ * @return number of characters actually written, excluding the
+ *         null terminator
+ */
+extern uint32_t __attribute__((overloadable))
+    rsElementGetSubElementName(rs_element e, uint32_t index, char *name, uint32_t nameLength);
+
+/**
+ * @param e element to get data from
+ * @param index index of the sub-element
+ * @return array size of sub-element in this element at given
+ *         index
+ */
+extern uint32_t __attribute__((overloadable))
+    rsElementGetSubElementArraySize(rs_element e, uint32_t index);
+
+/**
+ * @param e element to get data from
+ * @param index index of the sub-element
+ * @return offset in bytes of sub-element in this element at
+ *         given index
+ */
+extern uint32_t __attribute__((overloadable))
+    rsElementGetSubElementOffsetBytes(rs_element e, uint32_t index);
+
+/**
+ * @param e element to get data from
+ * @return total size of the element in bytes
+ */
+extern uint32_t __attribute__((overloadable))
+    rsElementGetSizeBytes(rs_element e);
+
+/**
+ * @param e element to get data from
+ * @return element's data type
+ */
+extern rs_data_type __attribute__((overloadable))
+    rsElementGetDataType(rs_element e);
+
+/**
+ * @param e element to get data from
+ * @return element's data size
+ */
+extern rs_data_kind __attribute__((overloadable))
+    rsElementGetDataKind(rs_element e);
+
+/**
+ * @param e element to get data from
+ * @return length of the element vector (for float2, float3,
+ *         etc.)
+ */
+extern uint32_t __attribute__((overloadable))
+    rsElementGetVectorSize(rs_element e);
+
+#endif // (defined(RS_VERSION) && (RS_VERSION >= 16))
+
+#endif // __RS_ELEMENT_RSH__
+
diff --git a/libs/rs/scriptc/rs_graphics.rsh b/libs/rs/scriptc/rs_graphics.rsh
index e3fde828..44ee99f 100644
--- a/libs/rs/scriptc/rs_graphics.rsh
+++ b/libs/rs/scriptc/rs_graphics.rsh
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2011-2012 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.
@@ -23,6 +23,9 @@
 #ifndef __RS_GRAPHICS_RSH__
 #define __RS_GRAPHICS_RSH__
 
+#include "rs_mesh.rsh"
+#include "rs_program.rsh"
+
 #if (defined(RS_VERSION) && (RS_VERSION >= 14))
 /**
  * Set the color target used for all subsequent rendering calls
@@ -83,88 +86,6 @@
 extern void __attribute__((overloadable))
     rsgBindProgramStore(rs_program_store ps);
 
-
-/**
- * @hide
- * Get program store depth function
- *
- * @param ps
- */
-extern rs_depth_func __attribute__((overloadable))
-    rsgProgramStoreGetDepthFunc(rs_program_store ps);
-
-/**
- * @hide
- * Get program store depth mask
- *
- * @param ps
- */
-extern bool __attribute__((overloadable))
-    rsgProgramStoreGetDepthMask(rs_program_store ps);
-/**
- * @hide
- * Get program store red component color mask
- *
- * @param ps
- */
-extern bool __attribute__((overloadable))
-    rsgProgramStoreGetColorMaskR(rs_program_store ps);
-
-/**
- * @hide
- * Get program store green component color mask
- *
- * @param ps
- */
-extern bool __attribute__((overloadable))
-    rsgProgramStoreGetColorMaskG(rs_program_store ps);
-
-/**
- * @hide
- * Get program store blur component color mask
- *
- * @param ps
- */
-extern bool __attribute__((overloadable))
-    rsgProgramStoreGetColorMaskB(rs_program_store ps);
-
-/**
- * @hide
- * Get program store alpha component color mask
- *
- * @param ps
- */
-extern bool __attribute__((overloadable))
-    rsgProgramStoreGetColorMaskA(rs_program_store ps);
-
-/**
- * @hide
- * Get program store blend source function
- *
- * @param ps
- */
-extern rs_blend_src_func __attribute__((overloadable))
-        rsgProgramStoreGetBlendSrcFunc(rs_program_store ps);
-
-/**
- * @hide
- * Get program store blend destination function
- *
- * @param ps
- */
-extern rs_blend_dst_func __attribute__((overloadable))
-    rsgProgramStoreGetBlendDstFunc(rs_program_store ps);
-
-/**
- * @hide
- * Get program store dither state
- *
- * @param ps
- */
-extern bool __attribute__((overloadable))
-    rsgProgramStoreGetDitherEnabled(rs_program_store ps);
-
-
 /**
  * Bind a new ProgramVertex to the rendering context.
  *
@@ -182,24 +103,6 @@
     rsgBindProgramRaster(rs_program_raster pr);
 
 /**
- * @hide
- * Get program raster point sprite state
- *
- * @param pr
- */
-extern bool __attribute__((overloadable))
-    rsgProgramRasterGetPointSpriteEnabled(rs_program_raster pr);
-
-/**
- * @hide
- * Get program raster cull mode
- *
- * @param pr
- */
-extern rs_cull_mode __attribute__((overloadable))
-    rsgProgramRasterGetCullMode(rs_program_raster pr);
-
-/**
  * Bind a new Sampler object to a ProgramFragment.  The sampler will
  * operate on the texture bound at the matching slot.
  *
@@ -209,51 +112,6 @@
     rsgBindSampler(rs_program_fragment, uint slot, rs_sampler);
 
 /**
- * @hide
- * Get sampler minification value
- *
- * @param pr
- */
-extern rs_sampler_value __attribute__((overloadable))
-    rsgSamplerGetMinification(rs_sampler s);
-
-/**
- * @hide
- * Get sampler magnification value
- *
- * @param pr
- */
-extern rs_sampler_value __attribute__((overloadable))
-    rsgSamplerGetMagnification(rs_sampler s);
-
-/**
- * @hide
- * Get sampler wrap S value
- *
- * @param pr
- */
-extern rs_sampler_value __attribute__((overloadable))
-    rsgSamplerGetWrapS(rs_sampler s);
-
-/**
- * @hide
- * Get sampler wrap T value
- *
- * @param pr
- */
-extern rs_sampler_value __attribute__((overloadable))
-    rsgSamplerGetWrapT(rs_sampler s);
-
-/**
- * @hide
- * Get sampler anisotropy
- *
- * @param pr
- */
-extern float __attribute__((overloadable))
-    rsgSamplerGetAnisotropy(rs_sampler s);
-
-/**
  * Bind a new Allocation object to a ProgramFragment.  The
  * Allocation must be a valid texture for the Program.  The sampling
  * of the texture will be controled by the Sampler bound at the
diff --git a/libs/rs/scriptc/rs_mesh.rsh b/libs/rs/scriptc/rs_mesh.rsh
new file mode 100644
index 0000000..87ffd33
--- /dev/null
+++ b/libs/rs/scriptc/rs_mesh.rsh
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/** @file rs_mesh.rsh
+ *  \brief Mesh routines
+ *
+ *
+ */
+
+#ifndef __RS_MESH_RSH__
+#define __RS_MESH_RSH__
+
+#if (defined(RS_VERSION) && (RS_VERSION >= 16))
+
+/**
+ * @param m mesh to get data from
+ * @return number of allocations in the mesh that contain vertex
+ *         data
+ */
+extern uint32_t __attribute__((overloadable))
+    rsgMeshGetVertexAllocationCount(rs_mesh m);
+
+/**
+ * @param m mesh to get data from
+ * @return number of primitive groups in the mesh. This would
+ *         include simple primitives as well as allocations
+ *         containing index data
+ */
+extern uint32_t __attribute__((overloadable))
+    rsgMeshGetPrimitiveCount(rs_mesh m);
+
+/**
+ * @param m mesh to get data from
+ * @param index index of the vertex allocation
+ * @return allocation containing vertex data
+ */
+extern rs_allocation __attribute__((overloadable))
+    rsgMeshGetVertexAllocation(rs_mesh m, uint32_t index);
+
+/**
+ * @param m mesh to get data from
+ * @param index index of the index allocation
+ * @return allocation containing index data
+ */
+extern rs_allocation __attribute__((overloadable))
+    rsgMeshGetIndexAllocation(rs_mesh m, uint32_t index);
+
+/**
+ * @param m mesh to get data from
+ * @param index index of the primitive
+ * @return primitive describing how the mesh is rendered
+ */
+extern rs_primitive __attribute__((overloadable))
+    rsgMeshGetPrimitive(rs_mesh m, uint32_t index);
+
+#endif // (defined(RS_VERSION) && (RS_VERSION >= 16))
+
+#endif // __RS_MESH_RSH__
+
diff --git a/libs/rs/scriptc/rs_program.rsh b/libs/rs/scriptc/rs_program.rsh
new file mode 100644
index 0000000..6a9929e
--- /dev/null
+++ b/libs/rs/scriptc/rs_program.rsh
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/** @file rs_program.rsh
+ *  \brief Program object routines
+ *
+ *
+ */
+
+#ifndef __RS_PROGRAM_RSH__
+#define __RS_PROGRAM_RSH__
+
+#if (defined(RS_VERSION) && (RS_VERSION >= 16))
+
+/**
+ * @hide
+ * Get program store depth function
+ *
+ * @param ps
+ */
+extern rs_depth_func __attribute__((overloadable))
+    rsgProgramStoreGetDepthFunc(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store depth mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+    rsgProgramStoreGetDepthMask(rs_program_store ps);
+/**
+ * @hide
+ * Get program store red component color mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+    rsgProgramStoreGetColorMaskR(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store green component color mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+    rsgProgramStoreGetColorMaskG(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store blur component color mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+    rsgProgramStoreGetColorMaskB(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store alpha component color mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+    rsgProgramStoreGetColorMaskA(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store blend source function
+ *
+ * @param ps
+ */
+extern rs_blend_src_func __attribute__((overloadable))
+        rsgProgramStoreGetBlendSrcFunc(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store blend destination function
+ *
+ * @param ps
+ */
+extern rs_blend_dst_func __attribute__((overloadable))
+    rsgProgramStoreGetBlendDstFunc(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store dither state
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+    rsgProgramStoreGetDitherEnabled(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program raster point sprite state
+ *
+ * @param pr
+ */
+extern bool __attribute__((overloadable))
+    rsgProgramRasterGetPointSpriteEnabled(rs_program_raster pr);
+
+/**
+ * @hide
+ * Get program raster cull mode
+ *
+ * @param pr
+ */
+extern rs_cull_mode __attribute__((overloadable))
+    rsgProgramRasterGetCullMode(rs_program_raster pr);
+
+#endif // (defined(RS_VERSION) && (RS_VERSION >= 16))
+
+#endif // __RS_PROGRAM_RSH__
+
diff --git a/libs/rs/scriptc/rs_sampler.rsh b/libs/rs/scriptc/rs_sampler.rsh
new file mode 100644
index 0000000..c8948c7
--- /dev/null
+++ b/libs/rs/scriptc/rs_sampler.rsh
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/** @file rs_sampler.rsh
+ *  \brief Sampler routines
+ *
+ *
+ */
+
+#ifndef __RS_SAMPLER_RSH__
+#define __RS_SAMPLER_RSH__
+
+#if (defined(RS_VERSION) && (RS_VERSION >= 16))
+
+/**
+ * @hide
+ * Get sampler minification value
+ *
+ * @param pr
+ */
+extern rs_sampler_value __attribute__((overloadable))
+    rsSamplerGetMinification(rs_sampler s);
+
+/**
+ * @hide
+ * Get sampler magnification value
+ *
+ * @param pr
+ */
+extern rs_sampler_value __attribute__((overloadable))
+    rsSamplerGetMagnification(rs_sampler s);
+
+/**
+ * @hide
+ * Get sampler wrap S value
+ *
+ * @param pr
+ */
+extern rs_sampler_value __attribute__((overloadable))
+    rsSamplerGetWrapS(rs_sampler s);
+
+/**
+ * @hide
+ * Get sampler wrap T value
+ *
+ * @param pr
+ */
+extern rs_sampler_value __attribute__((overloadable))
+    rsSamplerGetWrapT(rs_sampler s);
+
+/**
+ * @hide
+ * Get sampler anisotropy
+ *
+ * @param pr
+ */
+extern float __attribute__((overloadable))
+    rsSamplerGetAnisotropy(rs_sampler s);
+
+#endif // (defined(RS_VERSION) && (RS_VERSION >= 16))
+
+#endif // __RS_SAMPLER_RSH__
+
diff --git a/libs/rs/scriptc/rs_types.rsh b/libs/rs/scriptc/rs_types.rsh
index f8c2657..10617d8 100644
--- a/libs/rs/scriptc/rs_types.rsh
+++ b/libs/rs/scriptc/rs_types.rsh
@@ -402,6 +402,8 @@
 
 #endif //defined(RS_VERSION) && (RS_VERSION >= 14)
 
+#if (defined(RS_VERSION) && (RS_VERSION >= 16))
+
 /**
  * Describes the way mesh vertex data is interpreted when rendering
  *
@@ -552,4 +554,6 @@
     RS_SAMPLER_INVALID              = 100,
 } rs_sampler_value;
 
-#endif
+#endif // (defined(RS_VERSION) && (RS_VERSION >= 16))
+
+#endif // __RS_TYPES_RSH__
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 9748d3b..82dd308 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -608,16 +608,15 @@
      * Adjusts the master volume for the device's audio amplifier.
      * <p>
      *
-     * @param direction The direction to adjust the volume. One of
-     *            {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
-     *            {@link #ADJUST_SAME}.
+     * @param steps The number of volume steps to adjust. A positive
+     *            value will raise the volume.
      * @param flags One or more flags.
      * @hide
      */
-    public void adjustMasterVolume(int direction, int flags) {
+    public void adjustMasterVolume(int steps, int flags) {
         IAudioService service = getService();
         try {
-            service.adjustMasterVolume(direction, flags);
+            service.adjustMasterVolume(steps, flags);
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in adjustMasterVolume", e);
         }
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index aa60d0a..5f6a61d 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -159,6 +159,9 @@
     // but to support integer based AudioManager API we translate it to 0 - 100
     private static final int MAX_MASTER_VOLUME = 100;
 
+    // Maximum volume adjust steps allowed in a single batch call.
+    private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4;
+
     /* Sound effect file names  */
     private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
     private static final String[] SOUND_EFFECT_FILES = new String[] {
@@ -619,29 +622,19 @@
     }
 
     /** @see AudioManager#adjustMasterVolume(int) */
-    public void adjustMasterVolume(int direction, int flags) {
-        ensureValidDirection(direction);
+    public void adjustMasterVolume(int steps, int flags) {
+        ensureValidSteps(steps);
         int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
         int delta = 0;
-        for (int i = 0; i < mMasterVolumeRamp.length; i += 2) {
-            int testVolume = mMasterVolumeRamp[i];
-            int testDelta =  mMasterVolumeRamp[i + 1];
-            if (direction == AudioManager.ADJUST_RAISE) {
-                if (volume >= testVolume) {
-                    delta = testDelta;
-                } else {
-                    break;
-                }
-            } else if (direction == AudioManager.ADJUST_LOWER) {
-                if (volume - testDelta >= testVolume) {
-                    delta = -testDelta;
-                } else {
-                    break;
-                }
-            }
+        int numSteps = Math.abs(steps);
+        int direction = steps > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER;
+        for (int i = 0; i < numSteps; ++i) {
+            delta = findVolumeDelta(direction, volume);
+            volume += delta;
         }
-//        Log.d(TAG, "adjustMasterVolume volume: " + volume + " delta: " + delta + " direction: " + direction);
-        setMasterVolume(volume + delta, flags);
+
+        //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps);
+        setMasterVolume(volume, flags);
     }
 
     /** @see AudioManager#setStreamVolume(int, int, int) */
@@ -682,6 +675,41 @@
         sendVolumeUpdate(streamType, oldIndex, index, flags);
     }
 
+    private int findVolumeDelta(int direction, int volume) {
+        int delta = 0;
+        if (direction == AudioManager.ADJUST_RAISE) {
+            if (volume == MAX_MASTER_VOLUME) {
+                return 0;
+            }
+            // This is the default value if we make it to the end
+            delta = mMasterVolumeRamp[1];
+            // If we're raising the volume move down the ramp array until we
+            // find the volume we're above and use that groups delta.
+            for (int i = mMasterVolumeRamp.length - 1; i > 1; i -= 2) {
+                if (volume >= mMasterVolumeRamp[i - 1]) {
+                    delta = mMasterVolumeRamp[i];
+                    break;
+                }
+            }
+        } else if (direction == AudioManager.ADJUST_LOWER){
+            if (volume == 0) {
+                return 0;
+            }
+            int length = mMasterVolumeRamp.length;
+            // This is the default value if we make it to the end
+            delta = -mMasterVolumeRamp[length - 1];
+            // If we're lowering the volume move up the ramp array until we
+            // find the volume we're below and use the group below it's delta
+            for (int i = 2; i < length; i += 2) {
+                if (volume <= mMasterVolumeRamp[i]) {
+                    delta = -mMasterVolumeRamp[i - 1];
+                    break;
+                }
+            }
+        }
+        return delta;
+    }
+
     // UI update and Broadcast Intent
     private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
         if (!mVoiceCapable && (streamType == AudioSystem.STREAM_RING)) {
@@ -1862,6 +1890,12 @@
         }
     }
 
+    private void ensureValidSteps(int steps) {
+        if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) {
+            throw new IllegalArgumentException("Bad volume adjust steps " + steps);
+        }
+    }
+
     private void ensureValidStreamType(int streamType) {
         if (streamType < 0 || streamType >= mStreamStates.length) {
             throw new IllegalArgumentException("Bad stream type " + streamType);
diff --git a/media/jni/mediaeditor/Android.mk b/media/jni/mediaeditor/Android.mk
index 688e180..d1cf8b5 100755
--- a/media/jni/mediaeditor/Android.mk
+++ b/media/jni/mediaeditor/Android.mk
@@ -38,12 +38,12 @@
     $(call include-path-for, corecg graphics) \
     $(TOP)/frameworks/native/include/media/editor \
     $(TOP)/frameworks/base/core/jni/mediaeditor \
-    $(TOP)/frameworks/media/libvideoeditor/vss/inc \
-    $(TOP)/frameworks/media/libvideoeditor/vss/common/inc \
-    $(TOP)/frameworks/media/libvideoeditor/vss/mcs/inc \
-    $(TOP)/frameworks/media/libvideoeditor/vss/stagefrightshells/inc \
-    $(TOP)/frameworks/media/libvideoeditor/lvpp \
-    $(TOP)/frameworks/media/libvideoeditor/osal/inc \
+    $(TOP)/frameworks/av/libvideoeditor/vss/inc \
+    $(TOP)/frameworks/av/libvideoeditor/vss/common/inc \
+    $(TOP)/frameworks/av/libvideoeditor/vss/mcs/inc \
+    $(TOP)/frameworks/av/libvideoeditor/vss/stagefrightshells/inc \
+    $(TOP)/frameworks/av/libvideoeditor/lvpp \
+    $(TOP)/frameworks/av/libvideoeditor/osal/inc \
     $(TOP)/frameworks/native/include/media/openmax
 
 LOCAL_SHARED_LIBRARIES := \
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 55cd3ad..50fbf36 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -261,8 +261,7 @@
                                   frameCount,
                                   flags,
                                   sharedBuffer,
-                                  output,
-                                  true);
+                                  output);
 
     if (status != NO_ERROR) {
         return status;
@@ -741,8 +740,7 @@
         int frameCount,
         audio_policy_output_flags_t flags,
         const sp<IMemory>& sharedBuffer,
-        audio_io_handle_t output,
-        bool enforceFrameCount)
+        audio_io_handle_t output)
 {
     status_t status;
     const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
@@ -789,7 +787,8 @@
                 mNotificationFramesAct = frameCount/2;
             }
             if (frameCount < minFrameCount) {
-                ALOGW_IF(enforceFrameCount, "Minimum buffer size corrected from %d to %d",
+                // not ALOGW because it happens all the time when playing key clicks over A2DP
+                ALOGV("Minimum buffer size corrected from %d to %d",
                          frameCount, minFrameCount);
                 frameCount = minFrameCount;
             }
@@ -1249,8 +1248,7 @@
                                mFrameCount,
                                mFlags,
                                mSharedBuffer,
-                               getOutput_l(),
-                               false);
+                               getOutput_l());
 
         if (result == NO_ERROR) {
             uint32_t user = cblk->user;
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 148018d..840e475 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -541,6 +541,12 @@
 }
 
 static player_type getDefaultPlayerType() {
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("media.stagefright.use-nuplayer", value, NULL)
+            && (!strcmp("1", value) || !strcasecmp("true", value))) {
+        return NU_PLAYER;
+    }
+
     return STAGEFRIGHT_PLAYER;
 }
 
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index 7dbb57f..776d288 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -87,6 +87,7 @@
     sp<MediaMetadataRetrieverBase> p;
     switch (playerType) {
         case STAGEFRIGHT_PLAYER:
+        case NU_PLAYER:
         {
             p = new StagefrightMetadataRetriever;
             break;
diff --git a/media/libmediaplayerservice/nuplayer/Android.mk b/media/libmediaplayerservice/nuplayer/Android.mk
index 9b485d7..73336ef 100644
--- a/media/libmediaplayerservice/nuplayer/Android.mk
+++ b/media/libmediaplayerservice/nuplayer/Android.mk
@@ -2,6 +2,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=                       \
+        GenericSource.cpp               \
         HTTPLiveSource.cpp              \
         NuPlayer.cpp                    \
         NuPlayerDecoder.cpp             \
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
new file mode 100644
index 0000000..99569c9
--- /dev/null
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2012 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 "GenericSource.h"
+
+#include "AnotherPacketSource.h"
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/FileSource.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+NuPlayer::GenericSource::GenericSource(
+        const char *url,
+        const KeyedVector<String8, String8> *headers,
+        bool uidValid,
+        uid_t uid)
+    : mDurationUs(0ll),
+      mAudioIsVorbis(false) {
+    DataSource::RegisterDefaultSniffers();
+
+    sp<DataSource> dataSource =
+        DataSource::CreateFromURI(url, headers);
+    CHECK(dataSource != NULL);
+
+    initFromDataSource(dataSource);
+}
+
+NuPlayer::GenericSource::GenericSource(
+        int fd, int64_t offset, int64_t length)
+    : mDurationUs(0ll),
+      mAudioIsVorbis(false) {
+    DataSource::RegisterDefaultSniffers();
+
+    sp<DataSource> dataSource = new FileSource(dup(fd), offset, length);
+
+    initFromDataSource(dataSource);
+}
+
+void NuPlayer::GenericSource::initFromDataSource(
+        const sp<DataSource> &dataSource) {
+    sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
+
+    CHECK(extractor != NULL);
+
+    for (size_t i = 0; i < extractor->countTracks(); ++i) {
+        sp<MetaData> meta = extractor->getTrackMetaData(i);
+
+        const char *mime;
+        CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+        sp<MediaSource> track;
+
+        if (!strncasecmp(mime, "audio/", 6)) {
+            if (mAudioTrack.mSource == NULL) {
+                mAudioTrack.mSource = track = extractor->getTrack(i);
+
+                if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
+                    mAudioIsVorbis = true;
+                } else {
+                    mAudioIsVorbis = false;
+                }
+            }
+        } else if (!strncasecmp(mime, "video/", 6)) {
+            if (mVideoTrack.mSource == NULL) {
+                mVideoTrack.mSource = track = extractor->getTrack(i);
+            }
+        }
+
+        if (track != NULL) {
+            int64_t durationUs;
+            if (meta->findInt64(kKeyDuration, &durationUs)) {
+                if (durationUs > mDurationUs) {
+                    mDurationUs = durationUs;
+                }
+            }
+        }
+    }
+}
+
+NuPlayer::GenericSource::~GenericSource() {
+}
+
+void NuPlayer::GenericSource::start() {
+    ALOGI("start");
+
+    if (mAudioTrack.mSource != NULL) {
+        CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK);
+
+        mAudioTrack.mPackets =
+            new AnotherPacketSource(mAudioTrack.mSource->getFormat());
+
+        readBuffer(true /* audio */);
+    }
+
+    if (mVideoTrack.mSource != NULL) {
+        CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK);
+
+        mVideoTrack.mPackets =
+            new AnotherPacketSource(mVideoTrack.mSource->getFormat());
+
+        readBuffer(false /* audio */);
+    }
+}
+
+status_t NuPlayer::GenericSource::feedMoreTSData() {
+    return OK;
+}
+
+sp<MetaData> NuPlayer::GenericSource::getFormat(bool audio) {
+    sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
+
+    if (source == NULL) {
+        return NULL;
+    }
+
+    return source->getFormat();
+}
+
+status_t NuPlayer::GenericSource::dequeueAccessUnit(
+        bool audio, sp<ABuffer> *accessUnit) {
+    Track *track = audio ? &mAudioTrack : &mVideoTrack;
+
+    if (track->mSource == NULL) {
+        return -EWOULDBLOCK;
+    }
+
+    status_t finalResult;
+    if (!track->mPackets->hasBufferAvailable(&finalResult)) {
+        return finalResult == OK ? -EWOULDBLOCK : finalResult;
+    }
+
+    status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
+
+    readBuffer(audio, -1ll);
+
+    return result;
+}
+
+status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
+    *durationUs = mDurationUs;
+    return OK;
+}
+
+status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) {
+    if (mVideoTrack.mSource != NULL) {
+        int64_t actualTimeUs;
+        readBuffer(false /* audio */, seekTimeUs, &actualTimeUs);
+
+        seekTimeUs = actualTimeUs;
+    }
+
+    if (mAudioTrack.mSource != NULL) {
+        readBuffer(true /* audio */, seekTimeUs);
+    }
+
+    return OK;
+}
+
+void NuPlayer::GenericSource::readBuffer(
+        bool audio, int64_t seekTimeUs, int64_t *actualTimeUs) {
+    Track *track = audio ? &mAudioTrack : &mVideoTrack;
+    CHECK(track->mSource != NULL);
+
+    if (actualTimeUs) {
+        *actualTimeUs = seekTimeUs;
+    }
+
+    MediaSource::ReadOptions options;
+
+    bool seeking = false;
+
+    if (seekTimeUs >= 0) {
+        options.setSeekTo(seekTimeUs);
+        seeking = true;
+    }
+
+    for (;;) {
+        MediaBuffer *mbuf;
+        status_t err = track->mSource->read(&mbuf, &options);
+
+        options.clearSeekTo();
+
+        if (err == OK) {
+            size_t outLength = mbuf->range_length();
+
+            if (audio && mAudioIsVorbis) {
+                outLength += sizeof(int32_t);
+            }
+
+            sp<ABuffer> buffer = new ABuffer(outLength);
+
+            memcpy(buffer->data(),
+                   (const uint8_t *)mbuf->data() + mbuf->range_offset(),
+                   mbuf->range_length());
+
+            if (audio && mAudioIsVorbis) {
+                int32_t numPageSamples;
+                if (!mbuf->meta_data()->findInt32(
+                            kKeyValidSamples, &numPageSamples)) {
+                    numPageSamples = -1;
+                }
+
+                memcpy(buffer->data() + mbuf->range_length(),
+                       &numPageSamples,
+                       sizeof(numPageSamples));
+            }
+
+            int64_t timeUs;
+            CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
+
+            buffer->meta()->setInt64("timeUs", timeUs);
+
+            if (actualTimeUs) {
+                *actualTimeUs = timeUs;
+            }
+
+            mbuf->release();
+            mbuf = NULL;
+
+            if (seeking) {
+                track->mPackets->queueDiscontinuity(
+                        ATSParser::DISCONTINUITY_SEEK, NULL);
+            }
+
+            track->mPackets->queueAccessUnit(buffer);
+            break;
+        } else if (err == INFO_FORMAT_CHANGED) {
+#if 0
+            track->mPackets->queueDiscontinuity(
+                    ATSParser::DISCONTINUITY_FORMATCHANGE, NULL);
+#endif
+        } else {
+            track->mPackets->signalEOS(err);
+            break;
+        }
+    }
+}
+
+bool NuPlayer::GenericSource::isSeekable() {
+    return true;
+}
+
+}  // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
new file mode 100644
index 0000000..aaa5876
--- /dev/null
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2012 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 GENERIC_SOURCE_H_
+
+#define GENERIC_SOURCE_H_
+
+#include "NuPlayer.h"
+#include "NuPlayerSource.h"
+
+#include "ATSParser.h"
+
+namespace android {
+
+struct AnotherPacketSource;
+struct ARTSPController;
+struct DataSource;
+struct MediaSource;
+
+struct NuPlayer::GenericSource : public NuPlayer::Source {
+    GenericSource(
+            const char *url,
+            const KeyedVector<String8, String8> *headers,
+            bool uidValid = false,
+            uid_t uid = 0);
+
+    GenericSource(int fd, int64_t offset, int64_t length);
+
+    virtual void start();
+
+    virtual status_t feedMoreTSData();
+
+    virtual sp<MetaData> getFormat(bool audio);
+    virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
+
+    virtual status_t getDuration(int64_t *durationUs);
+    virtual status_t seekTo(int64_t seekTimeUs);
+    virtual bool isSeekable();
+
+protected:
+    virtual ~GenericSource();
+
+private:
+    struct Track {
+        sp<MediaSource> mSource;
+        sp<AnotherPacketSource> mPackets;
+    };
+
+    Track mAudioTrack;
+    Track mVideoTrack;
+
+    int64_t mDurationUs;
+    bool mAudioIsVorbis;
+
+    void initFromDataSource(const sp<DataSource> &dataSource);
+
+    void readBuffer(
+            bool audio,
+            int64_t seekTimeUs = -1ll, int64_t *actualTimeUs = NULL);
+
+    DISALLOW_EVIL_CONSTRUCTORS(GenericSource);
+};
+
+}  // namespace android
+
+#endif  // GENERIC_SOURCE_H_
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 526120a..544d501 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -27,6 +27,7 @@
 #include "NuPlayerSource.h"
 #include "RTSPSource.h"
 #include "StreamingSource.h"
+#include "GenericSource.h"
 
 #include "ATSParser.h"
 
@@ -84,18 +85,44 @@
     msg->post();
 }
 
+static bool IsHTTPLiveURL(const char *url) {
+    if (!strncasecmp("http://", url, 7)
+            || !strncasecmp("https://", url, 8)) {
+        size_t len = strlen(url);
+        if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
+            return true;
+        }
+
+        if (strstr(url,"m3u8")) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
 void NuPlayer::setDataSource(
         const char *url, const KeyedVector<String8, String8> *headers) {
     sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
 
-    if (!strncasecmp(url, "rtsp://", 7)) {
-        msg->setObject(
-                "source", new RTSPSource(url, headers, mUIDValid, mUID));
+    sp<Source> source;
+    if (IsHTTPLiveURL(url)) {
+        source = new HTTPLiveSource(url, headers, mUIDValid, mUID);
+    } else if (!strncasecmp(url, "rtsp://", 7)) {
+        source = new RTSPSource(url, headers, mUIDValid, mUID);
     } else {
-        msg->setObject(
-                "source", new HTTPLiveSource(url, headers, mUIDValid, mUID));
+        source = new GenericSource(url, headers, mUIDValid, mUID);
     }
 
+    msg->setObject("source", source);
+    msg->post();
+}
+
+void NuPlayer::setDataSource(int fd, int64_t offset, int64_t length) {
+    sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
+
+    sp<Source> source = new GenericSource(fd, offset, length);
+    msg->setObject("source", source);
     msg->post();
 }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 6be14be..25766e0 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -40,6 +40,8 @@
     void setDataSource(
             const char *url, const KeyedVector<String8, String8> *headers);
 
+    void setDataSource(int fd, int64_t offset, int64_t length);
+
     void setVideoSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture);
     void setAudioSink(const sp<MediaPlayerBase::AudioSink> &sink);
     void start();
@@ -60,12 +62,13 @@
 
 private:
     struct Decoder;
+    struct GenericSource;
     struct HTTPLiveSource;
     struct NuPlayerStreamListener;
     struct Renderer;
+    struct RTSPSource;
     struct Source;
     struct StreamingSource;
-    struct RTSPSource;
 
     enum {
         kWhatSetDataSource              = '=DaS',
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 460fc98..1600141 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -228,6 +228,20 @@
 
         buffer->meta()->setInt32("csd", true);
         mCSD.push(buffer);
+    } else if (meta->findData(kKeyVorbisInfo, &type, &data, &size)) {
+        sp<ABuffer> buffer = new ABuffer(size);
+        memcpy(buffer->data(), data, size);
+
+        buffer->meta()->setInt32("csd", true);
+        mCSD.push(buffer);
+
+        CHECK(meta->findData(kKeyVorbisBooks, &type, &data, &size));
+
+        buffer = new ABuffer(size);
+        memcpy(buffer->data(), data, size);
+
+        buffer->meta()->setInt32("csd", true);
+        mCSD.push(buffer);
     }
 
     return msg;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 5aa99bf..253bc2fa 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -76,7 +76,13 @@
 }
 
 status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) {
-    return INVALID_OPERATION;
+    CHECK_EQ((int)mState, (int)UNINITIALIZED);
+
+    mPlayer->setDataSource(fd, offset, length);
+
+    mState = STOPPED;
+
+    return OK;
 }
 
 status_t NuPlayerDriver::setDataSource(const sp<IStreamSource> &source) {
@@ -97,13 +103,16 @@
 }
 
 status_t NuPlayerDriver::prepare() {
+    sendEvent(MEDIA_SET_VIDEO_SIZE, 320, 240);
     return OK;
 }
 
 status_t NuPlayerDriver::prepareAsync() {
+    status_t err = prepare();
+
     notifyListener(MEDIA_PREPARED);
 
-    return OK;
+    return err;
 }
 
 status_t NuPlayerDriver::start() {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 5738ecb..ecbc428 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -376,7 +376,8 @@
     bool tooLate = (mVideoLateByUs > 40000);
 
     if (tooLate) {
-        ALOGV("video late by %lld us (%.2f secs)", mVideoLateByUs, mVideoLateByUs / 1E6);
+        ALOGV("video late by %lld us (%.2f secs)",
+             mVideoLateByUs, mVideoLateByUs / 1E6);
     } else {
         ALOGV("rendering video at media time %.2f secs", mediaTimeUs / 1E6);
     }
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 77714f3..7d7bd7d 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -42,6 +42,7 @@
         OggExtractor.cpp                  \
         SampleIterator.cpp                \
         SampleTable.cpp                   \
+        SkipCutBuffer.cpp                 \
         StagefrightMediaScanner.cpp       \
         StagefrightMetadataRetriever.cpp  \
         SurfaceMediaSource.cpp            \
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 6c95d4e..9385b8a 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -373,7 +373,8 @@
 
     if (mInitCheck == OK) {
         if (mHasVideo) {
-            mFileMetaData->setCString(kKeyMIMEType, "video/mp4");
+            mFileMetaData->setCString(
+                    kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MPEG4);
         } else {
             mFileMetaData->setCString(kKeyMIMEType, "audio/mp4");
         }
@@ -599,6 +600,7 @@
 }
 
 status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
+    ALOGV("entering parseChunk %lld/%d", *offset, depth);
     uint32_t hdr[2];
     if (mDataSource->readAt(*offset, hdr, 8) < 8) {
         return ERROR_IO;
@@ -625,6 +627,7 @@
 
     char chunk[5];
     MakeFourCCString(chunk_type, chunk);
+    ALOGV("chunk: %s @ %lld", chunk, *offset);
 
 #if 0
     static const char kWhitespace[] = "                                        ";
@@ -1302,6 +1305,8 @@
             break;
         }
 
+        case FOURCC('m', 'e', 'a', 'n'):
+        case FOURCC('n', 'a', 'm', 'e'):
         case FOURCC('d', 'a', 't', 'a'):
         {
             if (mPath.size() == 6 && underMetaDataPath(mPath)) {
@@ -1437,6 +1442,15 @@
             break;
         }
 
+        case FOURCC('-', '-', '-', '-'):
+        {
+            mLastCommentMean.clear();
+            mLastCommentName.clear();
+            mLastCommentData.clear();
+            *offset += chunk_size;
+            break;
+        }
+
         default:
         {
             *offset += chunk_size;
@@ -1553,6 +1567,9 @@
     uint32_t flags = U32_AT(buffer);
 
     uint32_t metadataKey = 0;
+    char chunk[5];
+    MakeFourCCString(mPath[4], chunk);
+    ALOGV("meta: %s @ %lld", chunk, offset);
     switch (mPath[4]) {
         case FOURCC(0xa9, 'a', 'l', 'b'):
         {
@@ -1632,6 +1649,35 @@
             }
             break;
         }
+        case FOURCC('-', '-', '-', '-'):
+        {
+            buffer[size] = '\0';
+            switch (mPath[5]) {
+                case FOURCC('m', 'e', 'a', 'n'):
+                    mLastCommentMean.setTo((const char *)buffer + 4);
+                    break;
+                case FOURCC('n', 'a', 'm', 'e'):
+                    mLastCommentName.setTo((const char *)buffer + 4);
+                    break;
+                case FOURCC('d', 'a', 't', 'a'):
+                    mLastCommentData.setTo((const char *)buffer + 8);
+                    break;
+            }
+            if (mLastCommentMean == "com.apple.iTunes"
+                    && mLastCommentName == "iTunSMPB"
+                    && mLastCommentData.length() != 0) {
+                int32_t delay, padding;
+                if (sscanf(mLastCommentData,
+                           " %*x %x %x %*x", &delay, &padding) == 2) {
+                    mLastTrack->meta->setInt32(kKeyEncoderDelay, delay);
+                    mLastTrack->meta->setInt32(kKeyEncoderPadding, padding);
+                }
+                mLastCommentMean.clear();
+                mLastCommentName.clear();
+                mLastCommentData.clear();
+            }
+            break;
+        }
 
         default:
             break;
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index 2549de6..2740d6b 100644
--- a/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/MediaDefs.cpp
@@ -41,7 +41,7 @@
 const char *MEDIA_MIMETYPE_AUDIO_FLAC = "audio/flac";
 const char *MEDIA_MIMETYPE_AUDIO_AAC_ADTS = "audio/aac-adts";
 
-const char *MEDIA_MIMETYPE_CONTAINER_MPEG4 = "video/mpeg4";
+const char *MEDIA_MIMETYPE_CONTAINER_MPEG4 = "video/mp4";
 const char *MEDIA_MIMETYPE_CONTAINER_WAV = "audio/wav";
 const char *MEDIA_MIMETYPE_CONTAINER_OGG = "application/ogg";
 const char *MEDIA_MIMETYPE_CONTAINER_MATROSKA = "video/x-matroska";
diff --git a/media/libstagefright/MetaData.cpp b/media/libstagefright/MetaData.cpp
index 66dec90..755594a 100644
--- a/media/libstagefright/MetaData.cpp
+++ b/media/libstagefright/MetaData.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MetaData"
+#include <utils/Log.h>
+
 #include <stdlib.h>
 #include <string.h>
 
@@ -282,5 +286,60 @@
     mSize = 0;
 }
 
+String8 MetaData::typed_data::asString() const {
+    String8 out;
+    const void *data = storage();
+    switch(mType) {
+        case TYPE_NONE:
+            out = String8::format("no type, size %d)", mSize);
+            break;
+        case TYPE_C_STRING:
+            out = String8::format("(char*) %s", (const char *)data);
+            break;
+        case TYPE_INT32:
+            out = String8::format("(int32_t) %d", *(int32_t *)data);
+            break;
+        case TYPE_INT64:
+            out = String8::format("(int64_t) %lld", *(int64_t *)data);
+            break;
+        case TYPE_FLOAT:
+            out = String8::format("(float) %f", *(float *)data);
+            break;
+        case TYPE_POINTER:
+            out = String8::format("(void*) %p", *(void **)data);
+            break;
+        case TYPE_RECT:
+        {
+            const Rect *r = (const Rect *)data;
+            out = String8::format("Rect(%d, %d, %d, %d)",
+                                  r->mLeft, r->mTop, r->mRight, r->mBottom);
+            break;
+        }
+
+        default:
+            out = String8::format("(unknown type %d, size %d)", mType, mSize);
+            break;
+    }
+    return out;
+}
+
+static void MakeFourCCString(uint32_t x, char *s) {
+    s[0] = x >> 24;
+    s[1] = (x >> 16) & 0xff;
+    s[2] = (x >> 8) & 0xff;
+    s[3] = x & 0xff;
+    s[4] = '\0';
+}
+
+void MetaData::dumpToLog() const {
+    for (int i = mItems.size(); --i >= 0;) {
+        int32_t key = mItems.keyAt(i);
+        char cc[5];
+        MakeFourCCString(key, cc);
+        const typed_data &item = mItems.valueAt(i);
+        ALOGI("%s: %s", cc, item.asString().string());
+    }
+}
+
 }  // namespace android
 
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index d5e6bec..8b6e9d5 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -38,6 +38,7 @@
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/OMXCodec.h>
 #include <media/stagefright/Utils.h>
+#include <media/stagefright/SkipCutBuffer.h>
 #include <utils/Vector.h>
 
 #include <OMX_Audio.h>
@@ -1303,6 +1304,7 @@
       mSeekMode(ReadOptions::SEEK_CLOSEST_SYNC),
       mTargetTimeUs(-1),
       mOutputPortSettingsChangedPending(false),
+      mSkipCutBuffer(NULL),
       mLeftOverBuffer(NULL),
       mPaused(false),
       mNativeWindow(
@@ -1413,6 +1415,9 @@
 
     free(mMIME);
     mMIME = NULL;
+
+    delete mSkipCutBuffer;
+    mSkipCutBuffer = NULL;
 }
 
 status_t OMXCodec::init() {
@@ -1573,6 +1578,34 @@
              portIndex == kPortIndexInput ? "input" : "output");
     }
 
+    if (portIndex == kPortIndexOutput) {
+
+        sp<MetaData> meta = mSource->getFormat();
+        int32_t delay = 0;
+        if (!meta->findInt32(kKeyEncoderDelay, &delay)) {
+            delay = 0;
+        }
+        int32_t padding = 0;
+        if (!meta->findInt32(kKeyEncoderPadding, &padding)) {
+            padding = 0;
+        }
+        int32_t numchannels = 0;
+        if (delay + padding) {
+            if (meta->findInt32(kKeyChannelCount, &numchannels)) {
+                size_t frameSize = numchannels * sizeof(int16_t);
+                if (mSkipCutBuffer) {
+                    size_t prevbuffersize = mSkipCutBuffer->size();
+                    if (prevbuffersize != 0) {
+                        ALOGW("Replacing SkipCutBuffer holding %d bytes", prevbuffersize);
+                    }
+                    delete mSkipCutBuffer;
+                }
+                mSkipCutBuffer = new SkipCutBuffer(delay * frameSize, padding * frameSize,
+                                                   def.nBufferSize);
+            }
+        }
+    }
+
     // dumpPortStatus(portIndex);
 
     if (portIndex == kPortIndexInput && (mFlags & kUseSecureInputBuffers)) {
@@ -2490,6 +2523,10 @@
             CHECK_EQ(countBuffersWeOwn(mPortBuffers[portIndex]),
                      mPortBuffers[portIndex].size());
 
+            if (mSkipCutBuffer && mPortStatus[kPortIndexOutput] == ENABLED) {
+                mSkipCutBuffer->clear();
+            }
+
             if (mState == RECONFIGURING) {
                 CHECK_EQ(portIndex, (OMX_U32)kPortIndexOutput);
 
@@ -3800,6 +3837,9 @@
     info->mStatus = OWNED_BY_CLIENT;
 
     info->mMediaBuffer->add_ref();
+    if (mSkipCutBuffer) {
+        mSkipCutBuffer->submit(info->mMediaBuffer);
+    }
     *buffer = info->mMediaBuffer;
 
     return OK;
diff --git a/media/libstagefright/SkipCutBuffer.cpp b/media/libstagefright/SkipCutBuffer.cpp
new file mode 100755
index 0000000..6d331b0
--- /dev/null
+++ b/media/libstagefright/SkipCutBuffer.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SkipCutBuffer"
+#include <utils/Log.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/SkipCutBuffer.h>
+
+namespace android {
+
+SkipCutBuffer::SkipCutBuffer(int32_t skip, int32_t cut, int32_t output_size) {
+    mFrontPadding = skip;
+    mBackPadding = cut;
+    mWriteHead = 0;
+    mReadHead = 0;
+    mCapacity = cut + output_size;
+    mCutBuffer = new char[mCapacity];
+    ALOGV("skipcutbuffer %d %d %d", skip, cut, mCapacity);
+}
+
+SkipCutBuffer::~SkipCutBuffer() {
+    delete[] mCutBuffer;
+}
+
+void SkipCutBuffer::submit(MediaBuffer *buffer) {
+    int32_t offset = buffer->range_offset();
+    int32_t buflen = buffer->range_length();
+
+    // drop the initial data from the buffer if needed
+    if (mFrontPadding > 0) {
+        // still data left to drop
+        int32_t to_drop = (buflen < mFrontPadding) ? buflen : mFrontPadding;
+        offset += to_drop;
+        buflen -= to_drop;
+        buffer->set_range(offset, buflen);
+        mFrontPadding -= to_drop;
+    }
+
+
+    // append data to cutbuffer
+    char *src = ((char*) buffer->data()) + offset;
+    write(src, buflen);
+
+
+    // the mediabuffer is now empty. Fill it from cutbuffer, always leaving
+    // at least mBackPadding bytes in the cutbuffer
+    char *dst = (char*) buffer->data();
+    size_t copied = read(dst, buffer->size());
+    buffer->set_range(0, copied);
+}
+
+void SkipCutBuffer::clear() {
+    mWriteHead = mReadHead = 0;
+}
+
+void SkipCutBuffer::write(const char *src, size_t num) {
+    int32_t sizeused = (mWriteHead - mReadHead);
+    if (sizeused < 0) sizeused += mCapacity;
+
+    // everything must fit
+    CHECK_GE((mCapacity - size_t(sizeused)), num);
+
+    size_t copyfirst = (mCapacity - mWriteHead);
+    if (copyfirst > num) copyfirst = num;
+    if (copyfirst) {
+        memcpy(mCutBuffer + mWriteHead, src, copyfirst);
+        num -= copyfirst;
+        src += copyfirst;
+        mWriteHead += copyfirst;
+        CHECK_LE(mWriteHead, mCapacity);
+        if (mWriteHead == mCapacity) mWriteHead = 0;
+        if (num) {
+            memcpy(mCutBuffer, src, num);
+            mWriteHead += num;
+        }
+    }
+}
+
+size_t SkipCutBuffer::read(char *dst, size_t num) {
+    int32_t available = (mWriteHead - mReadHead);
+    if (available < 0) available += mCapacity;
+
+    available -= mBackPadding;
+    if (available <=0) {
+        return 0;
+    }
+    if (available < num) {
+        num = available;
+    }
+
+    size_t copyfirst = (mCapacity - mReadHead);
+    if (copyfirst > num) copyfirst = num;
+    if (copyfirst) {
+        memcpy(dst, mCutBuffer + mReadHead, copyfirst);
+        num -= copyfirst;
+        dst += copyfirst;
+        mReadHead += copyfirst;
+        CHECK_LE(mReadHead, mCapacity);
+        if (mReadHead == mCapacity) mReadHead = 0;
+        if (num) {
+            memcpy(dst, mCutBuffer, num);
+            mReadHead += num;
+        }
+    }
+    return available;
+}
+
+size_t SkipCutBuffer::size() {
+    int32_t available = (mWriteHead - mReadHead);
+    if (available < 0) available += mCapacity;
+    return available;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
index ad55295..92009ee 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
@@ -115,6 +115,7 @@
     mDecoderBuf = malloc(memRequirements);
 
     pvmp3_InitDecoder(mConfig, mDecoderBuf);
+    mIsFirst = true;
 }
 
 OMX_ERRORTYPE SoftMP3::internalGetParameter(
@@ -190,7 +191,10 @@
             inInfo->mOwnedByUs = false;
             notifyEmptyBufferDone(inHeader);
 
-            outHeader->nFilledLen = 0;
+            // pad the end of the stream with 529 samples, since that many samples
+            // were trimmed off the beginning when decoding started
+            outHeader->nFilledLen = kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t);
+            memset(outHeader->pBuffer, 0, outHeader->nFilledLen);
             outHeader->nFlags = OMX_BUFFERFLAG_EOS;
 
             outQueue.erase(outQueue.begin());
@@ -251,8 +255,17 @@
             return;
         }
 
-        outHeader->nOffset = 0;
-        outHeader->nFilledLen = mConfig->outputFrameSize * sizeof(int16_t);
+        if (mIsFirst) {
+            mIsFirst = false;
+            // The decoder delay is 529 samples, so trim that many samples off
+            // the start of the first output buffer. This essentially makes this
+            // decoder have zero delay, which the rest of the pipeline assumes.
+            outHeader->nOffset = kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t);
+            outHeader->nFilledLen = mConfig->outputFrameSize * sizeof(int16_t) - outHeader->nOffset;
+        } else {
+            outHeader->nOffset = 0;
+            outHeader->nFilledLen = mConfig->outputFrameSize * sizeof(int16_t);
+        }
 
         outHeader->nTimeStamp =
             mAnchorTimeUs
@@ -288,6 +301,7 @@
         // Make sure that the next buffer output does not still
         // depend on fragments from the last one decoded.
         pvmp3_InitDecoder(mConfig, mDecoderBuf);
+        mIsFirst = true;
     }
 }
 
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.h b/media/libstagefright/codecs/mp3dec/SoftMP3.h
index 70d0682..3a05466 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.h
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.h
@@ -46,7 +46,8 @@
 private:
     enum {
         kNumBuffers = 4,
-        kOutputBufferSize = 4608 * 2
+        kOutputBufferSize = 4608 * 2,
+        kPVMP3DecoderDelay = 529 // frames
     };
 
     tPVMP3DecoderExternal *mConfig;
@@ -57,8 +58,7 @@
     int32_t mNumChannels;
     int32_t mSamplingRate;
 
-    bool mConfigured;
-
+    bool mIsFirst;
     bool mSignalledError;
 
     enum {
diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h
index eae62c6..5c549e0 100644
--- a/media/libstagefright/include/MPEG4Extractor.h
+++ b/media/libstagefright/include/MPEG4Extractor.h
@@ -20,6 +20,7 @@
 
 #include <media/stagefright/MediaExtractor.h>
 #include <utils/Vector.h>
+#include <utils/String8.h>
 
 namespace android {
 
@@ -64,6 +65,9 @@
     sp<MetaData> mFileMetaData;
 
     Vector<uint32_t> mPath;
+    String8 mLastCommentMean;
+    String8 mLastCommentName;
+    String8 mLastCommentData;
 
     status_t readMetaData();
     status_t parseChunk(off64_t *offset, int depth);
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 8e2294c..f69fc53 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -1145,11 +1145,15 @@
                 switch(error) {
                 case EGL11.EGL_CONTEXT_LOST:
                     return false;
+                case EGL10.EGL_BAD_CURRENT_SURFACE:
+                    // The current surface is bad, probably because the window manager has closed
+                    // the associated window. Ignore this error, on the assumption that the
+                    // application will be closed soon.
+                    break;
                 case EGL10.EGL_BAD_NATIVE_WINDOW:
-                    // The native window is bad, probably because the
-                    // window manager has closed it. Ignore this error,
-                    // on the expectation that the application will be closed soon.
-                    Log.e("EglHelper", "eglSwapBuffers returned EGL_BAD_NATIVE_WINDOW. tid=" + Thread.currentThread().getId());
+                    // The native window is bad, probably because the window manager has closed it.
+                    // Ignore this error, on the assumption that the application will be closed
+                    // soon.
                     break;
                 default:
                     throwEglException("eglSwapBuffers", error);
@@ -1841,7 +1845,7 @@
                         ! renderer.startsWith(kMSM7K_RENDERER_PREFIX);
                     notifyAll();
                 }
-                mLimitedGLESContexts = !mMultipleGLESContextsAllowed || renderer.startsWith(kADRENO);
+                mLimitedGLESContexts = !mMultipleGLESContextsAllowed;
                 if (LOG_SURFACE) {
                     Log.w(TAG, "checkGLDriver renderer = \"" + renderer + "\" multipleContextsAllowed = "
                         + mMultipleGLESContextsAllowed
@@ -1867,6 +1871,11 @@
             }
         }
 
+        /**
+         * This check was required for some pre-Android-3.0 hardware. Android 3.0 provides
+         * support for hardware-accelerated views, therefore multiple EGL contexts are
+         * supported on all Android 3.0+ EGL drivers.
+         */
         private boolean mGLESVersionCheckComplete;
         private int mGLESVersion;
         private boolean mGLESDriverCheckComplete;
@@ -1875,7 +1884,6 @@
         private static final int kGLES_20 = 0x20000;
         private static final String kMSM7K_RENDERER_PREFIX =
             "Q3Dimension MSM7500 ";
-        private static final String kADRENO = "Adreno";
         private GLThread mEglOwner;
     }
 
diff --git a/opengl/java/com/google/android/gles_jni/GLImpl.java b/opengl/java/com/google/android/gles_jni/GLImpl.java
index 090c0cb7..07f9e91 100644
--- a/opengl/java/com/google/android/gles_jni/GLImpl.java
+++ b/opengl/java/com/google/android/gles_jni/GLImpl.java
@@ -23,6 +23,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.os.Build;
+import android.os.UserId;
 import android.util.Log;
 
 import java.nio.Buffer;
@@ -67,7 +68,7 @@
         int version = 0;
         IPackageManager pm = AppGlobals.getPackageManager();
         try {
-            ApplicationInfo applicationInfo = pm.getApplicationInfo(appName, 0);
+            ApplicationInfo applicationInfo = pm.getApplicationInfo(appName, 0, UserId.myUserId());
             if (applicationInfo != null) {
                 version = applicationInfo.targetSdkVersion;
             }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 330a189..abf713b 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -84,6 +84,7 @@
     public DatabaseHelper(Context context) {
         super(context, DATABASE_NAME, null, DATABASE_VERSION);
         mContext = context;
+        setWriteAheadLoggingEnabled(true);
     }
 
     public static boolean isValidTable(String name) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 95fd62d..1fa3695 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -260,7 +260,6 @@
         // Watch for external modifications to the database file,
         // keeping our cache in sync.
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
-        db.enableWriteAheadLogging();
         sObserverInstance = new SettingsFileObserver(db.getPath());
         sObserverInstance.startWatching();
         startAsyncCachePopulation();
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index e2e65b9..13aaacb 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -53,7 +53,7 @@
     <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"መተግበሪያ <xliff:g id="APPLICATION">%1$s</xliff:g> የUSB ተቀጥላ ላይ እንዲደርስ ፍቀድ?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"የዚህ USB ተቀጥላ ሲያያዝ <xliff:g id="ACTIVITY">%1$s</xliff:g>ይከፈት?"</string>
     <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"የዚህ USB ተቀጥላ ሲያያዝ <xliff:g id="ACTIVITY">%1$s</xliff:g>  ይከፈት?"</string>
-    <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"ምንም የተጫኑ መተግበሪያዎች ከዚህ የUSB ተቀጥላ ጋር አይሰሩም። በ<xliff:g id="URL">%1$s</xliff:g> ስለዚህ ተቀጥላ የበለጠ እወቅ።"</string>
+    <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"ምንም የተጫኑ መተግበሪያዎች ከዚህ የUSB ተቀጥላ ጋር አይሰሩም። በ<xliff:g id="URL">%1$s</xliff:g> ስለዚህ ተቀጥላ የበለጠ ለመረዳት።"</string>
     <string name="title_usb_accessory" msgid="4966265263465181372">"የUSB  ተቀጥላ"</string>
     <string name="label_view" msgid="6304565553218192990">"ዕይታ"</string>
     <string name="always_use_device" msgid="1450287437017315906">"ለዚህ USB  መሣሪያ በነባሪነት ተጠቀም"</string>
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index a1f7316..b5dace0 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -463,6 +463,7 @@
     // Screenshot trigger states
     // Time to volume and power must be pressed within this interval of each other.
     private static final long SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS = 150;
+    private boolean mScreenshotChordEnabled;
     private boolean mVolumeDownKeyTriggered;
     private long mVolumeDownKeyTime;
     private boolean mVolumeDownKeyConsumedByScreenshotChord;
@@ -636,7 +637,8 @@
     }
 
     private void interceptScreenshotChord() {
-        if (mVolumeDownKeyTriggered && mPowerKeyTriggered && !mVolumeUpKeyTriggered) {
+        if (mScreenshotChordEnabled
+                && mVolumeDownKeyTriggered && mPowerKeyTriggered && !mVolumeUpKeyTriggered) {
             final long now = SystemClock.uptimeMillis();
             if (now <= mVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS
                     && now <= mPowerKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) {
@@ -882,6 +884,9 @@
         mSafeModeEnabledVibePattern = getLongIntArray(mContext.getResources(),
                 com.android.internal.R.array.config_safeModeEnabledVibePattern);
 
+        mScreenshotChordEnabled = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_enableScreenshotChord);
+
         // Controls rotation and the like.
         initializeHdmiState();
 
@@ -1574,7 +1579,7 @@
         // If we think we might have a volume down & power key chord on the way
         // but we're not sure, then tell the dispatcher to wait a little while and
         // try again later before dispatching.
-        if ((flags & KeyEvent.FLAG_FALLBACK) == 0) {
+        if (mScreenshotChordEnabled && (flags & KeyEvent.FLAG_FALLBACK) == 0) {
             if (mVolumeDownKeyTriggered && !mPowerKeyTriggered) {
                 final long now = SystemClock.uptimeMillis();
                 final long timeoutTime = mVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS;
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 3ab4e34..e92e69c 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -3481,23 +3481,27 @@
             const sp<IMemory>& sharedBuffer,
             int sessionId)
     :   TrackBase(thread, client, sampleRate, format, channelMask, frameCount, sharedBuffer, sessionId),
-    mMute(false), mSharedBuffer(sharedBuffer), mName(-1), mMainBuffer(NULL), mAuxBuffer(NULL),
+    mMute(false),
+    // mFillingUpStatus ?
+    // mRetryCount initialized later when needed
+    mSharedBuffer(sharedBuffer),
+    mStreamType(streamType),
+    mName(-1),  // see note below
+    mMainBuffer(thread->mixBuffer()),
+    mAuxBuffer(NULL),
     mAuxEffectId(0), mHasVolumeController(false)
 {
     if (mCblk != NULL) {
-        if (thread != NULL) {
-            mName = thread->getTrackName_l();
-            mMainBuffer = thread->mixBuffer();
-        }
-        ALOGV("Track constructor name %d, calling pid %d", mName, IPCThreadState::self()->getCallingPid());
-        if (mName < 0) {
-            ALOGE("no more track names available");
-        }
-        mStreamType = streamType;
         // NOTE: audio_track_cblk_t::frameSize for 8 bit PCM data is based on a sample size of
         // 16 bit because data is converted to 16 bit before being stored in buffer by AudioTrack
         mCblk->frameSize = audio_is_linear_pcm(format) ? mChannelCount * sizeof(int16_t) : sizeof(uint8_t);
+        // to avoid leaking a track name, do not allocate one unless there is an mCblk
+        mName = thread->getTrackName_l();
+        if (mName < 0) {
+            ALOGE("no more track names available");
+        }
     }
+    ALOGV("Track constructor name %d, calling pid %d", mName, IPCThreadState::self()->getCallingPid());
 }
 
 AudioFlinger::PlaybackThread::Track::~Track()
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 7a57613..d1950a3 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -681,9 +681,9 @@
             enum {FS_FILLING, FS_FILLED, FS_ACTIVE};
             mutable uint8_t     mFillingUpStatus;
             int8_t              mRetryCount;
-            sp<IMemory>         mSharedBuffer;
+            const sp<IMemory>   mSharedBuffer;
             bool                mResetDone;
-            audio_stream_type_t mStreamType;
+            const audio_stream_type_t mStreamType;
             int                 mName;
             int16_t             *mMainBuffer;
             int32_t             *mAuxBuffer;
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 081f1f4..a85b605 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -325,9 +325,10 @@
                     service.onConfigurationChanged();
                 }
             } else {
-                // TODO: Verify that this only needs to be delivered for the related user and not
-                // all the users
-                getImplForUser().onBroadcastReceived(intent);
+                for (int i = 0; i < mAppWidgetServices.size(); i++) {
+                    AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
+                    service.onBroadcastReceived(intent);
+                }
             }
         }
     };
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java
index 9c408c4..182a884 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -17,6 +17,7 @@
 package com.android.server;
 
 import android.app.AlarmManager;
+import android.app.AppGlobals;
 import android.app.PendingIntent;
 import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetProviderInfo;
@@ -27,6 +28,7 @@
 import android.content.Intent.FilterComparison;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
@@ -158,7 +160,7 @@
 
     Context mContext;
     Locale mLocale;
-    PackageManager mPackageManager;
+    IPackageManager mPm;
     AlarmManager mAlarmManager;
     ArrayList<Provider> mInstalledProviders = new ArrayList<Provider>();
     int mNextAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + 1;
@@ -174,7 +176,7 @@
 
     AppWidgetServiceImpl(Context context, int userId) {
         mContext = context;
-        mPackageManager = context.getPackageManager();
+        mPm = AppGlobals.getPackageManager();
         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
         mUserId = userId;
     }
@@ -1009,16 +1011,19 @@
     }
 
     void loadAppWidgetList() {
-        PackageManager pm = mPackageManager;
-
         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
-        List<ResolveInfo> broadcastReceivers = pm.queryBroadcastReceivers(intent,
-                PackageManager.GET_META_DATA);
+        try {
+            List<ResolveInfo> broadcastReceivers = mPm.queryIntentReceivers(intent,
+                    intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+                    PackageManager.GET_META_DATA, mUserId);
 
-        final int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
-        for (int i = 0; i < N; i++) {
-            ResolveInfo ri = broadcastReceivers.get(i);
-            addProviderLocked(ri);
+            final int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
+            for (int i = 0; i < N; i++) {
+                ResolveInfo ri = broadcastReceivers.get(i);
+                addProviderLocked(ri);
+            }
+        } catch (RemoteException re) {
+            // Shouldn't happen, local call
         }
     }
 
@@ -1131,7 +1136,7 @@
         ActivityInfo activityInfo = ri.activityInfo;
         XmlResourceParser parser = null;
         try {
-            parser = activityInfo.loadXmlMetaData(mPackageManager,
+            parser = activityInfo.loadXmlMetaData(mContext.getPackageManager(),
                     AppWidgetManager.META_DATA_APPWIDGET_PROVIDER);
             if (parser == null) {
                 Slog.w(TAG, "No " + AppWidgetManager.META_DATA_APPWIDGET_PROVIDER
@@ -1159,7 +1164,7 @@
             info.provider = component;
             p.uid = activityInfo.applicationInfo.uid;
 
-            Resources res = mPackageManager
+            Resources res = mContext.getPackageManager()
                     .getResourcesForApplication(activityInfo.applicationInfo);
 
             TypedArray sa = res.obtainAttributes(attrs,
@@ -1188,7 +1193,7 @@
             if (className != null) {
                 info.configure = new ComponentName(component.getPackageName(), className);
             }
-            info.label = activityInfo.loadLabel(mPackageManager).toString();
+            info.label = activityInfo.loadLabel(mContext.getPackageManager()).toString();
             info.icon = ri.getIconResource();
             info.previewImage = sa.getResourceId(
                     com.android.internal.R.styleable.AppWidgetProviderInfo_previewImage, 0);
@@ -1213,7 +1218,12 @@
     }
 
     int getUidForPackage(String packageName) throws PackageManager.NameNotFoundException {
-        PackageInfo pkgInfo = mPackageManager.getPackageInfo(packageName, 0);
+        PackageInfo pkgInfo = null;
+        try {
+            pkgInfo = mPm.getPackageInfo(packageName, 0, mUserId);
+        } catch (RemoteException re) {
+            // Shouldn't happen, local call
+        }
         if (pkgInfo == null || pkgInfo.applicationInfo == null) {
             throw new PackageManager.NameNotFoundException();
         }
@@ -1493,9 +1503,15 @@
     void addProvidersForPackageLocked(String pkgName) {
         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
         intent.setPackage(pkgName);
-        List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent,
-                PackageManager.GET_META_DATA);
-
+        List<ResolveInfo> broadcastReceivers;
+        try {
+            broadcastReceivers = mPm.queryIntentReceivers(intent,
+                    intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+                    PackageManager.GET_META_DATA, mUserId);
+        } catch (RemoteException re) {
+            // Shouldn't happen, local call
+            return;
+        }
         final int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
         for (int i = 0; i < N; i++) {
             ResolveInfo ri = broadcastReceivers.get(i);
@@ -1513,8 +1529,15 @@
         HashSet<String> keep = new HashSet<String>();
         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
         intent.setPackage(pkgName);
-        List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent,
-                PackageManager.GET_META_DATA);
+        List<ResolveInfo> broadcastReceivers;
+        try {
+            broadcastReceivers = mPm.queryIntentReceivers(intent,
+                intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+                PackageManager.GET_META_DATA, mUserId);
+        } catch (RemoteException re) {
+            // Shouldn't happen, local call
+            return;
+        }
 
         // add the missing ones and collect which ones to keep
         int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index a7b08f5..bd12270 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -1986,6 +1986,16 @@
             try {
                 mCurrentPackage = mPackageManager.getPackageInfo(request.packageName,
                         PackageManager.GET_SIGNATURES);
+                if (mCurrentPackage.applicationInfo.backupAgentName == null) {
+                    // The manifest has changed but we had a stale backup request pending.
+                    // This won't happen again because the app won't be requesting further
+                    // backups.
+                    Slog.i(TAG, "Package " + request.packageName
+                            + " no longer supports backup; skipping");
+                    addBackupTrace("skipping - no agent, completion is noop");
+                    executeNextState(BackupState.RUNNING_QUEUE);
+                    return;
+                }
 
                 IBackupAgent agent = null;
                 try {
@@ -2547,6 +2557,8 @@
                 finalizeBackup(out);
             } catch (RemoteException e) {
                 Slog.e(TAG, "App died during full backup");
+            } catch (Exception e) {
+                Slog.e(TAG, "Internal exception during full backup", e);
             } finally {
                 tearDown(pkg);
                 try {
diff --git a/services/java/com/android/server/IntentResolver.java b/services/java/com/android/server/IntentResolver.java
index b3d7220..f7e841e 100644
--- a/services/java/com/android/server/IntentResolver.java
+++ b/services/java/com/android/server/IntentResolver.java
@@ -201,7 +201,7 @@
     }
 
     public List<R> queryIntentFromList(Intent intent, String resolvedType, 
-            boolean defaultOnly, ArrayList<ArrayList<F>> listCut) {
+            boolean defaultOnly, ArrayList<ArrayList<F>> listCut, int userId) {
         ArrayList<R> resultList = new ArrayList<R>();
 
         final boolean debug = localLOGV ||
@@ -212,13 +212,14 @@
         int N = listCut.size();
         for (int i = 0; i < N; ++i) {
             buildResolveList(intent, categories, debug, defaultOnly,
-                             resolvedType, scheme, listCut.get(i), resultList);
+                    resolvedType, scheme, listCut.get(i), resultList, userId);
         }
         sortResults(resultList);
         return resultList;
     }
 
-    public List<R> queryIntent(Intent intent, String resolvedType, boolean defaultOnly) {
+    public List<R> queryIntent(Intent intent, String resolvedType, boolean defaultOnly,
+            int userId) {
         String scheme = intent.getScheme();
 
         ArrayList<R> finalList = new ArrayList<R>();
@@ -290,19 +291,19 @@
         FastImmutableArraySet<String> categories = getFastIntentCategories(intent);
         if (firstTypeCut != null) {
             buildResolveList(intent, categories, debug, defaultOnly,
-                    resolvedType, scheme, firstTypeCut, finalList);
+                    resolvedType, scheme, firstTypeCut, finalList, userId);
         }
         if (secondTypeCut != null) {
             buildResolveList(intent, categories, debug, defaultOnly,
-                    resolvedType, scheme, secondTypeCut, finalList);
+                    resolvedType, scheme, secondTypeCut, finalList, userId);
         }
         if (thirdTypeCut != null) {
             buildResolveList(intent, categories, debug, defaultOnly,
-                    resolvedType, scheme, thirdTypeCut, finalList);
+                    resolvedType, scheme, thirdTypeCut, finalList, userId);
         }
         if (schemeCut != null) {
             buildResolveList(intent, categories, debug, defaultOnly,
-                    resolvedType, scheme, schemeCut, finalList);
+                    resolvedType, scheme, schemeCut, finalList, userId);
         }
         sortResults(finalList);
 
@@ -329,7 +330,7 @@
      * "stopped," that is whether it should not be included in the result
      * if the intent requests to excluded stopped objects.
      */
-    protected boolean isFilterStopped(F filter) {
+    protected boolean isFilterStopped(F filter, int userId) {
         return false;
     }
 
@@ -341,7 +342,7 @@
     protected abstract String packageForFilter(F filter);
     
     @SuppressWarnings("unchecked")
-    protected R newResult(F filter, int match) {
+    protected R newResult(F filter, int match, int userId) {
         return (R)filter;
     }
 
@@ -504,7 +505,7 @@
 
     private void buildResolveList(Intent intent, FastImmutableArraySet<String> categories,
             boolean debug, boolean defaultOnly,
-            String resolvedType, String scheme, List<F> src, List<R> dest) {
+            String resolvedType, String scheme, List<F> src, List<R> dest, int userId) {
         final String action = intent.getAction();
         final Uri data = intent.getData();
         final String packageName = intent.getPackage();
@@ -519,7 +520,7 @@
             int match;
             if (debug) Slog.v(TAG, "Matching against filter " + filter);
 
-            if (excludingStopped && isFilterStopped(filter)) {
+            if (excludingStopped && isFilterStopped(filter, userId)) {
                 if (debug) {
                     Slog.v(TAG, "  Filter's target is stopped; skipping");
                 }
@@ -547,7 +548,7 @@
                 if (debug) Slog.v(TAG, "  Filter matched!  match=0x" +
                         Integer.toHexString(match));
                 if (!defaultOnly || filter.hasCategory(Intent.CATEGORY_DEFAULT)) {
-                    final R oneResult = newResult(filter, match);
+                    final R oneResult = newResult(filter, match, userId);
                     if (oneResult != null) {
                         dest.add(oneResult);
                     }
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 366160b..510bdb2 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -48,6 +48,7 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.UserId;
 import android.os.storage.IMountService;
 import android.os.storage.IMountServiceListener;
 import android.os.storage.IMountShutdownObserver;
@@ -1674,7 +1675,7 @@
             return false;
         }
 
-        final int packageUid = mPms.getPackageUid(packageName);
+        final int packageUid = mPms.getPackageUid(packageName, UserId.getUserId(callerUid));
 
         if (DEBUG_OBB) {
             Slog.d(TAG, "packageName = " + packageName + ", packageUid = " +
diff --git a/services/java/com/android/server/WiredAccessoryObserver.java b/services/java/com/android/server/WiredAccessoryObserver.java
index 326b940..a7a46dd 100644
--- a/services/java/com/android/server/WiredAccessoryObserver.java
+++ b/services/java/com/android/server/WiredAccessoryObserver.java
@@ -30,8 +30,11 @@
 import android.media.AudioManager;
 import android.util.Log;
 
+import java.io.File;
 import java.io.FileReader;
 import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * <p>WiredAccessoryObserver monitors for a wired headset on the main board or dock.
@@ -39,17 +42,6 @@
 class WiredAccessoryObserver extends UEventObserver {
     private static final String TAG = WiredAccessoryObserver.class.getSimpleName();
     private static final boolean LOG = true;
-    private static final int MAX_AUDIO_PORTS = 3; /* h2w, USB Audio & hdmi */
-    private static final String uEventInfo[][] = { {"DEVPATH=/devices/virtual/switch/h2w",
-                                                    "/sys/class/switch/h2w/state",
-                                                    "/sys/class/switch/h2w/name"},
-                                                   {"DEVPATH=/devices/virtual/switch/usb_audio",
-                                                    "/sys/class/switch/usb_audio/state",
-                                                    "/sys/class/switch/usb_audio/name"},
-                                                   {"DEVPATH=/devices/virtual/switch/hdmi",
-                                                    "/sys/class/switch/hdmi/state",
-                                                    "/sys/class/switch/hdmi/name"} };
-
     private static final int BIT_HEADSET = (1 << 0);
     private static final int BIT_HEADSET_NO_MIC = (1 << 1);
     private static final int BIT_USB_HEADSET_ANLG = (1 << 2);
@@ -60,10 +52,89 @@
                                                    BIT_HDMI_AUDIO);
     private static final int HEADSETS_WITH_MIC = BIT_HEADSET;
 
+    private static class UEventInfo {
+        private final String mDevName;
+        private final int mState1Bits;
+        private final int mState2Bits;
+
+        public UEventInfo(String devName, int state1Bits, int state2Bits) {
+            mDevName = devName;
+            mState1Bits = state1Bits;
+            mState2Bits = state2Bits;
+        }
+
+        public String getDevName() { return mDevName; }
+
+        public String getDevPath() {
+            return String.format("DEVPATH=/devices/virtual/switch/%s", mDevName);
+        }
+
+        public String getSwitchStatePath() {
+            return String.format("/sys/class/switch/%s/state", mDevName);
+        }
+
+        public boolean checkSwitchExists() {
+            File f = new File(getSwitchStatePath());
+            return ((null != f) && f.exists());
+        }
+
+        public int computeNewHeadsetState(int headsetState, int switchState) {
+            int preserveMask = ~(mState1Bits | mState2Bits);
+            int setBits = ((switchState == 1) ? mState1Bits :
+                          ((switchState == 2) ? mState2Bits : 0));
+
+            return ((headsetState & preserveMask) | setBits);
+        }
+    }
+
+    private static List<UEventInfo> makeObservedUEventList() {
+        List<UEventInfo> retVal = new ArrayList<UEventInfo>();
+        UEventInfo uei;
+
+        // Monitor h2w
+        uei = new UEventInfo("h2w", BIT_HEADSET, BIT_HEADSET_NO_MIC);
+        if (uei.checkSwitchExists()) {
+            retVal.add(uei);
+        } else {
+            Slog.w(TAG, "This kernel does not have wired headset support");
+        }
+
+        // Monitor USB
+        uei = new UEventInfo("usb_audio", BIT_USB_HEADSET_ANLG, BIT_USB_HEADSET_DGTL);
+        if (uei.checkSwitchExists()) {
+            retVal.add(uei);
+        } else {
+            Slog.w(TAG, "This kernel does not have usb audio support");
+        }
+
+        // Monitor HDMI
+        //
+        // If the kernel has support for the "hdmi_audio" switch, use that.  It will be signalled
+        // only when the HDMI driver has a video mode configured, and the downstream sink indicates
+        // support for audio in its EDID.
+        //
+        // If the kernel does not have an "hdmi_audio" switch, just fall back on the older "hdmi"
+        // switch instead.
+        uei = new UEventInfo("hdmi_audio", BIT_HDMI_AUDIO, 0);
+        if (uei.checkSwitchExists()) {
+            retVal.add(uei);
+        } else {
+            uei = new UEventInfo("hdmi", BIT_HDMI_AUDIO, 0);
+            if (uei.checkSwitchExists()) {
+                retVal.add(uei);
+            } else {
+                Slog.w(TAG, "This kernel does not have HDMI audio support");
+            }
+        }
+
+        return retVal;
+    }
+
+    private static List<UEventInfo> uEventInfo = makeObservedUEventList();
+
     private int mHeadsetState;
     private int mPrevHeadsetState;
     private String mHeadsetName;
-    private int switchState;
 
     private final Context mContext;
     private final WakeLock mWakeLock;  // held while there is a pending route change
@@ -85,11 +156,12 @@
         // one on the board, one on the dock and one on HDMI:
         // observe three UEVENTs
         init();  // set initial status
-        for (int i = 0; i < MAX_AUDIO_PORTS; i++) {
-            startObserving(uEventInfo[i][0]);
+        for (int i = 0; i < uEventInfo.size(); ++i) {
+            UEventInfo uei = uEventInfo.get(i);
+            startObserving(uei.getDevPath());
         }
       }
-  }
+    }
 
     @Override
     public void onUEvent(UEventObserver.UEvent event) {
@@ -106,50 +178,47 @@
 
     private synchronized final void updateState(String name, int state)
     {
-        if (name.equals("usb_audio")) {
-            switchState = ((mHeadsetState & (BIT_HEADSET|BIT_HEADSET_NO_MIC|BIT_HDMI_AUDIO)) |
-                           ((state == 1) ? BIT_USB_HEADSET_ANLG :
-                                         ((state == 2) ? BIT_USB_HEADSET_DGTL : 0)));
-        } else if (name.equals("hdmi")) {
-            switchState = ((mHeadsetState & (BIT_HEADSET|BIT_HEADSET_NO_MIC|
-                                             BIT_USB_HEADSET_DGTL|BIT_USB_HEADSET_ANLG)) |
-                           ((state == 1) ? BIT_HDMI_AUDIO : 0));
-        } else {
-            switchState = ((mHeadsetState & (BIT_HDMI_AUDIO|BIT_USB_HEADSET_ANLG|
-                                             BIT_USB_HEADSET_DGTL)) |
-                            ((state == 1) ? BIT_HEADSET :
-                                          ((state == 2) ? BIT_HEADSET_NO_MIC : 0)));
+        // FIXME:  When ueventd informs of a change in state for a switch, it does not have to be
+        // the case that the name reported by /sys/class/switch/<device>/name is the same as
+        // <device>.  For normal users of the linux switch class driver, it will be.  But it is
+        // technically possible to hook the print_name method in the class driver and return a
+        // different name each and every time the name sysfs entry is queried.
+        //
+        // Right now this is not the case for any of the switch implementations used here.  I'm not
+        // certain anyone would ever choose to implement such a dynamic name, or what it would mean
+        // for the implementation at this level, but if it ever happens, we will need to revisit
+        // this code.
+        for (int i = 0; i < uEventInfo.size(); ++i) {
+            UEventInfo uei = uEventInfo.get(i);
+            if (name.equals(uei.getDevName())) {
+                update(name, uei.computeNewHeadsetState(mHeadsetState, state));
+                return;
+            }
         }
-        update(name, switchState);
     }
 
     private synchronized final void init() {
         char[] buffer = new char[1024];
-
-        String newName = mHeadsetName;
-        int newState = mHeadsetState;
         mPrevHeadsetState = mHeadsetState;
 
         if (LOG) Slog.v(TAG, "init()");
 
-        for (int i = 0; i < MAX_AUDIO_PORTS; i++) {
+        for (int i = 0; i < uEventInfo.size(); ++i) {
+            UEventInfo uei = uEventInfo.get(i);
             try {
-                FileReader file = new FileReader(uEventInfo[i][1]);
+                int curState;
+                FileReader file = new FileReader(uei.getSwitchStatePath());
                 int len = file.read(buffer, 0, 1024);
                 file.close();
-                newState = Integer.valueOf((new String(buffer, 0, len)).trim());
+                curState = Integer.valueOf((new String(buffer, 0, len)).trim());
 
-                file = new FileReader(uEventInfo[i][2]);
-                len = file.read(buffer, 0, 1024);
-                file.close();
-                newName = new String(buffer, 0, len).trim();
-
-                if (newState > 0) {
-                    updateState(newName, newState);
+                if (curState > 0) {
+                    updateState(uei.getDevName(), curState);
                 }
 
             } catch (FileNotFoundException e) {
-                Slog.w(TAG, "This kernel does not have wired headset support");
+                Slog.w(TAG, uei.getSwitchStatePath() +
+                        " not found while attempting to determine initial switch state");
             } catch (Exception e) {
                 Slog.e(TAG, "" , e);
             }
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index d21212f..b422678 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1079,7 +1079,8 @@
                     int uid = msg.arg1;
                     boolean restart = (msg.arg2 == 1);
                     String pkg = (String) msg.obj;
-                    forceStopPackageLocked(pkg, uid, restart, false, true, false);
+                    forceStopPackageLocked(pkg, uid, restart, false, true, false,
+                            UserId.getUserId(uid));
                 }
             } break;
             case FINALIZE_PENDING_INTENT_MSG: {
@@ -1289,7 +1290,7 @@
 
             ApplicationInfo info =
                 mSelf.mContext.getPackageManager().getApplicationInfo(
-                        "android", STOCK_PM_FLAGS);
+                            "android", STOCK_PM_FLAGS);
             mSystemThread.installSystemApplicationInfo(info);
        
             synchronized (mSelf) {
@@ -2369,7 +2370,8 @@
                 List<ResolveInfo> resolves =
                     AppGlobals.getPackageManager().queryIntentActivities(
                             intent, r.resolvedType,
-                            PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
+                            PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS,
+                            UserId.getCallingUserId());
 
                 // Look for the original activity in the list...
                 final int N = resolves != null ? resolves.size() : 0;
@@ -3291,7 +3293,7 @@
             int pkgUid = -1;
             synchronized(this) {
                 try {
-                    pkgUid = pm.getPackageUid(packageName);
+                    pkgUid = pm.getPackageUid(packageName, userId);
                 } catch (RemoteException e) {
                 }
                 if (pkgUid == -1) {
@@ -3312,7 +3314,7 @@
             
             try {
                 //clear application user data
-                pm.clearApplicationUserData(packageName, observer);
+                pm.clearApplicationUserData(packageName, observer, userId);
                 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
                         Uri.fromParts("package", packageName, null));
                 intent.putExtra(Intent.EXTRA_UID, pkgUid);
@@ -3339,13 +3341,14 @@
             throw new SecurityException(msg);
         }
         
+        int userId = UserId.getCallingUserId();
         long callingId = Binder.clearCallingIdentity();
         try {
             IPackageManager pm = AppGlobals.getPackageManager();
             int pkgUid = -1;
             synchronized(this) {
                 try {
-                    pkgUid = pm.getPackageUid(packageName);
+                    pkgUid = pm.getPackageUid(packageName, userId);
                 } catch (RemoteException e) {
                 }
                 if (pkgUid == -1) {
@@ -3412,16 +3415,14 @@
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
-        final int userId = Binder.getOrigCallingUser();
+        final int userId = UserId.getCallingUserId();
         long callingId = Binder.clearCallingIdentity();
         try {
             IPackageManager pm = AppGlobals.getPackageManager();
             int pkgUid = -1;
             synchronized(this) {
                 try {
-                    pkgUid = pm.getPackageUid(packageName);
-                    // Convert the uid to the one for the calling user
-                    pkgUid = UserId.getUid(userId, pkgUid);
+                    pkgUid = pm.getPackageUid(packageName, userId);
                 } catch (RemoteException e) {
                 }
                 if (pkgUid == -1) {
@@ -3430,7 +3431,7 @@
                 }
                 forceStopPackageLocked(packageName, pkgUid);
                 try {
-                    pm.setPackageStoppedState(packageName, true);
+                    pm.setPackageStoppedState(packageName, true, userId);
                 } catch (RemoteException e) {
                 } catch (IllegalArgumentException e) {
                     Slog.w(TAG, "Failed trying to unstop package "
@@ -3545,7 +3546,7 @@
     }
 
     private void forceStopPackageLocked(final String packageName, int uid) {
-        forceStopPackageLocked(packageName, uid, false, false, true, false);
+        forceStopPackageLocked(packageName, uid, false, false, true, false, UserId.getUserId(uid));
         Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
                 Uri.fromParts("package", packageName, null));
         if (!mProcessesReady) {
@@ -3602,13 +3603,13 @@
 
     private final boolean forceStopPackageLocked(String name, int uid,
             boolean callerWillRestart, boolean purgeCache, boolean doit,
-            boolean evenPersistent) {
+            boolean evenPersistent, int userId) {
         int i;
         int N;
 
         if (uid < 0) {
             try {
-                uid = AppGlobals.getPackageManager().getPackageUid(name);
+                uid = AppGlobals.getPackageManager().getPackageUid(name, userId);
             } catch (RemoteException e) {
             }
         }
@@ -3659,7 +3660,6 @@
         }
 
         ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
-        int userId = UserId.getUserId(uid);
         for (ServiceRecord service : mServiceMap.getAllServices(userId)) {
             if (service.packageName.equals(name)
                     && (service.app == null || evenPersistent || !service.app.persistent)) {
@@ -4107,11 +4107,11 @@
                 if (pkgs != null) {
                     for (String pkg : pkgs) {
                         synchronized (ActivityManagerService.this) {
-                          if (forceStopPackageLocked(pkg, -1, false, false, false, false)) {
-                              setResultCode(Activity.RESULT_OK);
-                              return;
-                          }
-                       }
+                            if (forceStopPackageLocked(pkg, -1, false, false, false, false, 0)) {
+                                setResultCode(Activity.RESULT_OK);
+                                return;
+                            }
+                        }
                     }
                 }
             }
@@ -4290,8 +4290,8 @@
             try {
                 if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
                     int uid = AppGlobals.getPackageManager()
-                            .getPackageUid(packageName);
-                    if (UserId.getAppId(callingUid) != uid) {
+                            .getPackageUid(packageName, UserId.getUserId(callingUid));
+                    if (!UserId.isSameApp(callingUid, uid)) {
                         String msg = "Permission Denial: getIntentSender() from pid="
                             + Binder.getCallingPid()
                             + ", uid=" + Binder.getCallingUid()
@@ -4386,7 +4386,7 @@
             PendingIntentRecord rec = (PendingIntentRecord)sender;
             try {
                 int uid = AppGlobals.getPackageManager()
-                        .getPackageUid(rec.key.packageName);
+                        .getPackageUid(rec.key.packageName, UserId.getCallingUserId());
                 if (!UserId.isSameApp(uid, Binder.getCallingUid())) {
                     String msg = "Permission Denial: cancelIntentSender() from pid="
                         + Binder.getCallingPid()
@@ -4796,7 +4796,7 @@
         } else {
             try {
                 pi = pm.resolveContentProvider(name,
-                        PackageManager.GET_URI_PERMISSION_PATTERNS);
+                        PackageManager.GET_URI_PERMISSION_PATTERNS, UserId.getUserId(callingUid));
             } catch (RemoteException ex) {
             }
         }
@@ -4808,7 +4808,7 @@
         int targetUid = lastTargetUid;
         if (targetUid < 0 && targetPkg != null) {
             try {
-                targetUid = pm.getPackageUid(targetPkg);
+                targetUid = pm.getPackageUid(targetPkg, UserId.getUserId(callingUid));
                 if (targetUid < 0) {
                     if (DEBUG_URI_PERMISSION) Slog.v(TAG,
                             "Can't grant URI permission no uid for: " + targetPkg);
@@ -5100,14 +5100,14 @@
 
         final String authority = uri.getAuthority();
         ProviderInfo pi = null;
-        ContentProviderRecord cpr = mProviderMap.getProviderByName(authority,
-                UserId.getUserId(callingUid));
+        int userId = UserId.getUserId(callingUid);
+        ContentProviderRecord cpr = mProviderMap.getProviderByName(authority, userId);
         if (cpr != null) {
             pi = cpr.info;
         } else {
             try {
                 pi = pm.resolveContentProvider(authority,
-                        PackageManager.GET_URI_PERMISSION_PATTERNS);
+                        PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
             } catch (RemoteException ex) {
             }
         }
@@ -5202,7 +5202,7 @@
             } else {
                 try {
                     pi = pm.resolveContentProvider(authority,
-                            PackageManager.GET_URI_PERMISSION_PATTERNS);
+                            PackageManager.GET_URI_PERMISSION_PATTERNS, r.userId);
                 } catch (RemoteException ex) {
                 }
             }
@@ -5480,12 +5480,13 @@
                         // Check whether this activity is currently available.
                         try {
                             if (rti.origActivity != null) {
-                                if (pm.getActivityInfo(rti.origActivity, 0) == null) {
+                                if (pm.getActivityInfo(rti.origActivity, 0, callingUserId)
+                                        == null) {
                                     continue;
                                 }
                             } else if (rti.baseIntent != null) {
                                 if (pm.queryIntentActivities(rti.baseIntent,
-                                        null, 0) == null) {
+                                        null, 0, callingUserId) == null) {
                                     continue;
                                 }
                             }
@@ -6132,15 +6133,14 @@
                 try {
                     cpi = AppGlobals.getPackageManager().
                         resolveContentProvider(name,
-                                STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
+                            STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
                 } catch (RemoteException ex) {
                 }
                 if (cpi == null) {
                     return null;
                 }
 
-                cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo,
-                        Binder.getOrigCallingUser());
+                cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
 
                 String msg;
                 if ((msg=checkContentProviderPermissionLocked(cpi, r)) != null) {
@@ -6157,7 +6157,7 @@
                 }
 
                 ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
-                cpr = mProviderMap.getProviderByClass(comp, Binder.getOrigCallingUser());
+                cpr = mProviderMap.getProviderByClass(comp, userId);
                 final boolean firstClass = cpr == null;
                 if (firstClass) {
                     try {
@@ -6165,13 +6165,13 @@
                             AppGlobals.getPackageManager().
                                 getApplicationInfo(
                                         cpi.applicationInfo.packageName,
-                                        STOCK_PM_FLAGS);
+                                        STOCK_PM_FLAGS, userId);
                         if (ai == null) {
                             Slog.w(TAG, "No package info for content provider "
                                     + cpi.name);
                             return null;
                         }
-                        ai = getAppInfoForUser(ai, Binder.getOrigCallingUser());
+                        ai = getAppInfoForUser(ai, userId);
                         cpr = new ContentProviderRecord(this, cpi, ai, comp);
                     } catch (RemoteException ex) {
                         // pm is in same process, this will never happen.
@@ -6212,7 +6212,7 @@
                         // Content provider is now in use, its package can't be stopped.
                         try {
                             AppGlobals.getPackageManager().setPackageStoppedState(
-                                    cpr.appInfo.packageName, false);
+                                    cpr.appInfo.packageName, false, userId);
                         } catch (RemoteException e) {
                         } catch (IllegalArgumentException e) {
                             Slog.w(TAG, "Failed trying to unstop package "
@@ -6546,7 +6546,7 @@
         // This package really, really can not be stopped.
         try {
             AppGlobals.getPackageManager().setPackageStoppedState(
-                    info.packageName, false);
+                    info.packageName, false, UserId.getUserId(app.uid));
         } catch (RemoteException e) {
         } catch (IllegalArgumentException e) {
             Slog.w(TAG, "Failed trying to unstop package "
@@ -6778,7 +6778,7 @@
             mDebugTransient = !persistent;
             if (packageName != null) {
                 final long origId = Binder.clearCallingIdentity();
-                forceStopPackageLocked(packageName, -1, false, false, true, true);
+                forceStopPackageLocked(packageName, -1, false, false, true, true, 0);
                 Binder.restoreCallingIdentity(origId);
             }
         }
@@ -7137,7 +7137,7 @@
                 List<ResolveInfo> ris = null;
                 try {
                     ris = AppGlobals.getPackageManager().queryIntentReceivers(
-                                intent, null, 0);
+                            intent, null, 0, 0);
                 } catch (RemoteException e) {
                 }
                 if (ris != null) {
@@ -7394,6 +7394,10 @@
     }
 
     private boolean handleAppCrashLocked(ProcessRecord app) {
+        if (mHeadless) {
+            Log.e(TAG, "handleAppCrashLocked: " + app.processName);
+            return false;
+        }
         long now = SystemClock.uptimeMillis();
 
         Long crashTime;
@@ -7441,7 +7445,7 @@
             mMainStack.resumeTopActivityLocked(null);
         } else {
             ActivityRecord r = mMainStack.topRunningActivityLocked(null);
-            if (r.app == app) {
+            if (r != null && r.app == app) {
                 // If the top running activity is from this crashing
                 // process, then terminate it to avoid getting in a loop.
                 Slog.w(TAG, "  Force finishing activity "
@@ -7803,7 +7807,7 @@
             for (String pkg : process.pkgList) {
                 sb.append("Package: ").append(pkg);
                 try {
-                    PackageInfo pi = pm.getPackageInfo(pkg, 0);
+                    PackageInfo pi = pm.getPackageInfo(pkg, 0, 0);
                     if (pi != null) {
                         sb.append(" v").append(pi.versionCode);
                         if (pi.versionName != null) {
@@ -8201,7 +8205,7 @@
             IPackageManager pm = AppGlobals.getPackageManager();
             for (String pkg : extList) {
                 try {
-                    ApplicationInfo info = pm.getApplicationInfo(pkg, 0);
+                    ApplicationInfo info = pm.getApplicationInfo(pkg, 0, UserId.getCallingUserId());
                     if ((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
                         retList.add(info);
                     }
@@ -10682,21 +10686,21 @@
     };
 
     private ServiceLookupResult findServiceLocked(Intent service,
-            String resolvedType) {
+            String resolvedType, int userId) {
         ServiceRecord r = null;
         if (service.getComponent() != null) {
-            r = mServiceMap.getServiceByName(service.getComponent(), Binder.getOrigCallingUser());
+            r = mServiceMap.getServiceByName(service.getComponent(), userId);
         }
         if (r == null) {
             Intent.FilterComparison filter = new Intent.FilterComparison(service);
-            r = mServiceMap.getServiceByIntent(filter, Binder.getOrigCallingUser());
+            r = mServiceMap.getServiceByIntent(filter, userId);
         }
 
         if (r == null) {
             try {
                 ResolveInfo rInfo =
                     AppGlobals.getPackageManager().resolveService(
-                            service, resolvedType, 0);
+                                service, resolvedType, 0, userId);
                 ServiceInfo sInfo =
                     rInfo != null ? rInfo.serviceInfo : null;
                 if (sInfo == null) {
@@ -10767,7 +10771,7 @@
             try {
                 ResolveInfo rInfo =
                     AppGlobals.getPackageManager().resolveService(
-                            service, resolvedType, STOCK_PM_FLAGS);
+                                service, resolvedType, STOCK_PM_FLAGS, userId);
                 ServiceInfo sInfo =
                     rInfo != null ? rInfo.serviceInfo : null;
                 if (sInfo == null) {
@@ -11132,7 +11136,7 @@
         // Service is now being launched, its package can't be stopped.
         try {
             AppGlobals.getPackageManager().setPackageStoppedState(
-                    r.packageName, false);
+                    r.packageName, false, r.userId);
         } catch (RemoteException e) {
         } catch (IllegalArgumentException e) {
             Slog.w(TAG, "Failed trying to unstop package "
@@ -11437,7 +11441,8 @@
             }
 
             // If this service is active, make sure it is stopped.
-            ServiceLookupResult r = findServiceLocked(service, resolvedType);
+            ServiceLookupResult r = findServiceLocked(service, resolvedType,
+                    callerApp == null ? UserId.getCallingUserId() : callerApp.userId);
             if (r != null) {
                 if (r.record != null) {
                     final long origId = Binder.clearCallingIdentity();
@@ -11465,7 +11470,8 @@
         IBinder ret = null;
 
         synchronized(this) {
-            ServiceLookupResult r = findServiceLocked(service, resolvedType);
+            ServiceLookupResult r = findServiceLocked(service, resolvedType,
+                    UserId.getCallingUserId());
             
             if (r != null) {
                 // r.record is null if findServiceLocked() failed the caller permission check
@@ -12094,7 +12100,7 @@
             // Backup agent is now in use, its package can't be stopped.
             try {
                 AppGlobals.getPackageManager().setPackageStoppedState(
-                        app.packageName, false);
+                        app.packageName, false, UserId.getUserId(app.uid));
             } catch (RemoteException e) {
             } catch (IllegalArgumentException e) {
                 Slog.w(TAG, "Failed trying to unstop package "
@@ -12458,7 +12464,7 @@
                         String list[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
                         if (list != null && (list.length > 0)) {
                             for (String pkg : list) {
-                                forceStopPackageLocked(pkg, -1, false, true, true, false);
+                                forceStopPackageLocked(pkg, -1, false, true, true, false, userId);
                             }
                             sendPackageBroadcastLocked(
                                     IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE, list);
@@ -12469,7 +12475,8 @@
                         if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
                             if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
                                 forceStopPackageLocked(ssp,
-                                        intent.getIntExtra(Intent.EXTRA_UID, -1), false, true, true, false);
+                                        intent.getIntExtra(Intent.EXTRA_UID, -1), false, true, true,
+                                        false, userId);
                             }
                             if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
                                 sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REMOVED,
@@ -12586,7 +12593,7 @@
             if (intent.getComponent() != null) {
                 // Broadcast is going to one specific receiver class...
                 ActivityInfo ai = AppGlobals.getPackageManager().
-                    getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
+                        getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS, userId);
                 if (ai != null) {
                     receivers = new ArrayList();
                     ResolveInfo ri = new ResolveInfo();
@@ -12594,15 +12601,15 @@
                     receivers.add(ri);
                 }
             } else {
-                // TODO: Apply userId
                 // Need to resolve the intent to interested receivers...
                 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
                          == 0) {
                     receivers =
                         AppGlobals.getPackageManager().queryIntentReceivers(
-                                intent, resolvedType, STOCK_PM_FLAGS);
+                                    intent, resolvedType, STOCK_PM_FLAGS, userId);
                 }
-                registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
+                registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false,
+                        userId);
             }
         } catch (RemoteException ex) {
             // pm is in same process, this will never happen.
@@ -12893,7 +12900,7 @@
                 ii = mContext.getPackageManager().getInstrumentationInfo(
                     className, STOCK_PM_FLAGS);
                 ai = mContext.getPackageManager().getApplicationInfo(
-                    ii.targetPackage, STOCK_PM_FLAGS);
+                        ii.targetPackage, STOCK_PM_FLAGS);
             } catch (PackageManager.NameNotFoundException e) {
             }
             if (ii == null) {
@@ -12921,9 +12928,10 @@
                 throw new SecurityException(msg);
             }
 
+            int userId = UserId.getCallingUserId();
             final long origId = Binder.clearCallingIdentity();
             // Instrumentation can kill and relaunch even persistent processes
-            forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true);
+            forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true, userId);
             ProcessRecord app = addAppLocked(ai, false);
             app.instrumentationClass = className;
             app.instrumentationInfo = ai;
@@ -12978,11 +12986,12 @@
         app.instrumentationProfileFile = null;
         app.instrumentationArguments = null;
 
-        forceStopPackageLocked(app.processName, -1, false, false, true, true);
+        forceStopPackageLocked(app.processName, -1, false, false, true, true, app.userId);
     }
 
     public void finishInstrumentation(IApplicationThread target,
             int resultCode, Bundle results) {
+        int userId = UserId.getCallingUserId();
         // Refuse possible leaked file descriptors
         if (results != null && results.hasFileDescriptors()) {
             throw new IllegalArgumentException("File descriptors passed in Intent");
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 7e8df35..48b4f4ff 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1445,9 +1445,8 @@
         // Launching this app's activity, make sure the app is no longer
         // considered stopped.
         try {
-            // TODO: Apply to the correct userId
             AppGlobals.getPackageManager().setPackageStoppedState(
-                    next.packageName, false);
+                    next.packageName, false, next.userId); /* TODO: Verify if correct userid */
         } catch (RemoteException e1) {
         } catch (IllegalArgumentException e) {
             Slog.w(TAG, "Failed trying to unstop package "
@@ -2847,7 +2846,7 @@
     }
 
     ActivityInfo resolveActivity(Intent intent, String resolvedType, int startFlags,
-             String profileFile, ParcelFileDescriptor profileFd) {
+            String profileFile, ParcelFileDescriptor profileFd, int userId) {
         // Collect information about the target of the Intent.
         ActivityInfo aInfo;
         try {
@@ -2855,7 +2854,7 @@
                 AppGlobals.getPackageManager().resolveIntent(
                         intent, resolvedType,
                         PackageManager.MATCH_DEFAULT_ONLY
-                        | ActivityManagerService.STOCK_PM_FLAGS);
+                                    | ActivityManagerService.STOCK_PM_FLAGS, userId);
             aInfo = rInfo != null ? rInfo.activityInfo : null;
         } catch (RemoteException e) {
             aInfo = null;
@@ -2909,7 +2908,7 @@
 
         // Collect information about the target of the Intent.
         ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags,
-                profileFile, profileFd);
+                profileFile, profileFd, userId);
         aInfo = mService.getActivityInfoForUser(aInfo, userId);
 
         synchronized (mService) {
@@ -2989,7 +2988,7 @@
                                 AppGlobals.getPackageManager().resolveIntent(
                                         intent, null,
                                         PackageManager.MATCH_DEFAULT_ONLY
-                                        | ActivityManagerService.STOCK_PM_FLAGS);
+                                        | ActivityManagerService.STOCK_PM_FLAGS, userId);
                             aInfo = rInfo != null ? rInfo.activityInfo : null;
                             aInfo = mService.getActivityInfoForUser(aInfo, userId);
                         } catch (RemoteException e) {
@@ -3098,7 +3097,7 @@
 
                     // Collect information about the target of the Intent.
                     ActivityInfo aInfo = resolveActivity(intent, resolvedTypes[i],
-                            0, null, null);
+                            0, null, null, userId);
                     // TODO: New, check if this is correct
                     aInfo = mService.getActivityInfoForUser(aInfo, userId);
 
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
index 39b63db..1b83e0b 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -732,7 +732,7 @@
             // Broadcast is being executed, its package can't be stopped.
             try {
                 AppGlobals.getPackageManager().setPackageStoppedState(
-                        r.curComponent.getPackageName(), false);
+                        r.curComponent.getPackageName(), false, UserId.getUserId(r.callingUid));
             } catch (RemoteException e) {
             } catch (IllegalArgumentException e) {
                 Slog.w(TAG, "Failed trying to unstop package "
diff --git a/services/java/com/android/server/am/CompatModePackages.java b/services/java/com/android/server/am/CompatModePackages.java
index cd72202..3ba3fbb 100644
--- a/services/java/com/android/server/am/CompatModePackages.java
+++ b/services/java/com/android/server/am/CompatModePackages.java
@@ -121,7 +121,7 @@
     public void handlePackageAddedLocked(String packageName, boolean updated) {
         ApplicationInfo ai = null;
         try {
-            ai = AppGlobals.getPackageManager().getApplicationInfo(packageName, 0);
+            ai = AppGlobals.getPackageManager().getApplicationInfo(packageName, 0, 0);
         } catch (RemoteException e) {
         }
         if (ai == null) {
@@ -220,7 +220,7 @@
     public int getPackageScreenCompatModeLocked(String packageName) {
         ApplicationInfo ai = null;
         try {
-            ai = AppGlobals.getPackageManager().getApplicationInfo(packageName, 0);
+            ai = AppGlobals.getPackageManager().getApplicationInfo(packageName, 0, 0);
         } catch (RemoteException e) {
         }
         if (ai == null) {
@@ -232,7 +232,7 @@
     public void setPackageScreenCompatModeLocked(String packageName, int mode) {
         ApplicationInfo ai = null;
         try {
-            ai = AppGlobals.getPackageManager().getApplicationInfo(packageName, 0);
+            ai = AppGlobals.getPackageManager().getApplicationInfo(packageName, 0, 0);
         } catch (RemoteException e) {
         }
         if (ai == null) {
@@ -365,7 +365,7 @@
                 }
                 ApplicationInfo ai = null;
                 try {
-                    ai = pm.getApplicationInfo(pkg, 0);
+                    ai = pm.getApplicationInfo(pkg, 0, 0);
                 } catch (RemoteException e) {
                 }
                 if (ai == null) {
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 0e04d59..1f1e720 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -41,7 +41,6 @@
 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.NetworkTemplate.MATCH_ETHERNET;
 import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
 import static android.net.NetworkTemplate.MATCH_MOBILE_4G;
@@ -74,6 +73,7 @@
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.net.ConnectivityManager;
 import android.net.IConnectivityManager;
@@ -96,6 +96,7 @@
 import android.os.MessageQueue.IdleHandler;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
+import android.os.UserId;
 import android.provider.Settings;
 import android.telephony.TelephonyManager;
 import android.text.format.Formatter;
@@ -158,6 +159,7 @@
     private static final int VERSION_SPLIT_SNOOZE = 5;
     private static final int VERSION_ADDED_TIMEZONE = 6;
     private static final int VERSION_ADDED_INFERRED = 7;
+    private static final int VERSION_SWITCH_APP_ID = 8;
 
     // @VisibleForTesting
     public static final int TYPE_WARNING = 0x1;
@@ -167,6 +169,7 @@
     private static final String TAG_POLICY_LIST = "policy-list";
     private static final String TAG_NETWORK_POLICY = "network-policy";
     private static final String TAG_UID_POLICY = "uid-policy";
+    private static final String TAG_APP_POLICY = "app-policy";
 
     private static final String ATTR_VERSION = "version";
     private static final String ATTR_RESTRICT_BACKGROUND = "restrictBackground";
@@ -182,6 +185,7 @@
     private static final String ATTR_METERED = "metered";
     private static final String ATTR_INFERRED = "inferred";
     private static final String ATTR_UID = "uid";
+    private static final String ATTR_APP_ID = "appId";
     private static final String ATTR_POLICY = "policy";
 
     private static final String TAG_ALLOW_BACKGROUND = TAG + ":allowBackground";
@@ -223,8 +227,8 @@
     /** Currently active network rules for ifaces. */
     private HashMap<NetworkPolicy, String[]> mNetworkRules = Maps.newHashMap();
 
-    /** Defined UID policies. */
-    private SparseIntArray mUidPolicy = new SparseIntArray();
+    /** Defined app policies. */
+    private SparseIntArray mAppPolicy = new SparseIntArray();
     /** Currently derived rules for each UID. */
     private SparseIntArray mUidRules = new SparseIntArray();
 
@@ -379,18 +383,26 @@
 
             final String action = intent.getAction();
             final int uid = intent.getIntExtra(EXTRA_UID, 0);
+            final int appId = UserId.getAppId(uid);
             synchronized (mRulesLock) {
                 if (ACTION_PACKAGE_ADDED.equals(action)) {
+                    // NOTE: PACKAGE_ADDED is currently only sent once, and is
+                    // not broadcast when users are added.
+
                     // update rules for UID, since it might be subject to
                     // global background data policy.
                     if (LOGV) Slog.v(TAG, "ACTION_PACKAGE_ADDED for uid=" + uid);
-                    updateRulesForUidLocked(uid);
+                    updateRulesForAppLocked(appId);
 
                 } else if (ACTION_UID_REMOVED.equals(action)) {
+                    // NOTE: UID_REMOVED is currently only sent once, and is not
+                    // broadcast when users are removed.
+
                     // remove any policy and update rules to clean up.
                     if (LOGV) Slog.v(TAG, "ACTION_UID_REMOVED for uid=" + uid);
-                    mUidPolicy.delete(uid);
-                    updateRulesForUidLocked(uid);
+
+                    mAppPolicy.delete(appId);
+                    updateRulesForAppLocked(appId);
                     writePolicyLocked();
                 }
             }
@@ -949,7 +961,7 @@
 
         // clear any existing policy and read from disk
         mNetworkPolicy.clear();
-        mUidPolicy.clear();
+        mAppPolicy.clear();
 
         FileInputStream fis = null;
         try {
@@ -1028,11 +1040,21 @@
                         final int uid = readIntAttribute(in, ATTR_UID);
                         final int policy = readIntAttribute(in, ATTR_POLICY);
 
-                        if (isUidValidForPolicy(mContext, uid)) {
-                            setUidPolicyUnchecked(uid, policy, false);
+                        final int appId = UserId.getAppId(uid);
+                        if (UserId.isApp(appId)) {
+                            setAppPolicyUnchecked(appId, policy, false);
                         } else {
                             Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring");
                         }
+                    } else if (TAG_APP_POLICY.equals(tag)) {
+                        final int appId = readIntAttribute(in, ATTR_APP_ID);
+                        final int policy = readIntAttribute(in, ATTR_POLICY);
+
+                        if (UserId.isApp(appId)) {
+                            setAppPolicyUnchecked(appId, policy, false);
+                        } else {
+                            Slog.w(TAG, "unable to apply policy to appId " + appId + "; ignoring");
+                        }
                     }
                 }
             }
@@ -1077,7 +1099,7 @@
             out.startDocument(null, true);
 
             out.startTag(null, TAG_POLICY_LIST);
-            writeIntAttribute(out, ATTR_VERSION, VERSION_ADDED_INFERRED);
+            writeIntAttribute(out, ATTR_VERSION, VERSION_SWITCH_APP_ID);
             writeBooleanAttribute(out, ATTR_RESTRICT_BACKGROUND, mRestrictBackground);
 
             // write all known network policies
@@ -1102,17 +1124,17 @@
             }
 
             // write all known uid policies
-            for (int i = 0; i < mUidPolicy.size(); i++) {
-                final int uid = mUidPolicy.keyAt(i);
-                final int policy = mUidPolicy.valueAt(i);
+            for (int i = 0; i < mAppPolicy.size(); i++) {
+                final int appId = mAppPolicy.keyAt(i);
+                final int policy = mAppPolicy.valueAt(i);
 
                 // skip writing empty policies
                 if (policy == POLICY_NONE) continue;
 
-                out.startTag(null, TAG_UID_POLICY);
-                writeIntAttribute(out, ATTR_UID, uid);
+                out.startTag(null, TAG_APP_POLICY);
+                writeIntAttribute(out, ATTR_APP_ID, appId);
                 writeIntAttribute(out, ATTR_POLICY, policy);
-                out.endTag(null, TAG_UID_POLICY);
+                out.endTag(null, TAG_APP_POLICY);
             }
 
             out.endTag(null, TAG_POLICY_LIST);
@@ -1127,24 +1149,24 @@
     }
 
     @Override
-    public void setUidPolicy(int uid, int policy) {
+    public void setAppPolicy(int appId, int policy) {
         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
 
-        if (!isUidValidForPolicy(mContext, uid)) {
-            throw new IllegalArgumentException("cannot apply policy to UID " + uid);
+        if (!UserId.isApp(appId)) {
+            throw new IllegalArgumentException("cannot apply policy to appId " + appId);
         }
 
-        setUidPolicyUnchecked(uid, policy, true);
+        setAppPolicyUnchecked(appId, policy, true);
     }
 
-    private void setUidPolicyUnchecked(int uid, int policy, boolean persist) {
+    private void setAppPolicyUnchecked(int appId, int policy, boolean persist) {
         final int oldPolicy;
         synchronized (mRulesLock) {
-            oldPolicy = getUidPolicy(uid);
-            mUidPolicy.put(uid, policy);
+            oldPolicy = getAppPolicy(appId);
+            mAppPolicy.put(appId, policy);
 
             // uid policy changed, recompute rules and persist policy.
-            updateRulesForUidLocked(uid);
+            updateRulesForAppLocked(appId);
             if (persist) {
                 writePolicyLocked();
             }
@@ -1152,11 +1174,11 @@
     }
 
     @Override
-    public int getUidPolicy(int uid) {
+    public int getAppPolicy(int appId) {
         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
 
         synchronized (mRulesLock) {
-            return mUidPolicy.get(uid, POLICY_NONE);
+            return mAppPolicy.get(appId, POLICY_NONE);
         }
     }
 
@@ -1347,27 +1369,29 @@
                 fout.print("  "); fout.println(policy.toString());
             }
 
-            fout.println("Policy status for known UIDs:");
+            fout.println("Policy for apps:");
+            int size = mAppPolicy.size();
+            for (int i = 0; i < size; i++) {
+                final int appId = mAppPolicy.keyAt(i);
+                final int policy = mAppPolicy.valueAt(i);
+                fout.print("  appId=");
+                fout.print(appId);
+                fout.print(" policy=");
+                dumpPolicy(fout, policy);
+                fout.println();
+            }
 
             final SparseBooleanArray knownUids = new SparseBooleanArray();
-            collectKeys(mUidPolicy, knownUids);
             collectKeys(mUidForeground, knownUids);
             collectKeys(mUidRules, knownUids);
 
-            final int size = knownUids.size();
+            fout.println("Status for known UIDs:");
+            size = knownUids.size();
             for (int i = 0; i < size; i++) {
                 final int uid = knownUids.keyAt(i);
                 fout.print("  UID=");
                 fout.print(uid);
 
-                fout.print(" policy=");
-                final int policyIndex = mUidPolicy.indexOfKey(uid);
-                if (policyIndex < 0) {
-                    fout.print("UNKNOWN");
-                } else {
-                    dumpPolicy(fout, mUidPolicy.valueAt(policyIndex));
-                }
-
                 fout.print(" foreground=");
                 final int foregroundIndex = mUidPidForeground.indexOfKey(uid);
                 if (foregroundIndex < 0) {
@@ -1457,7 +1481,8 @@
         final PackageManager pm = mContext.getPackageManager();
         final List<ApplicationInfo> apps = pm.getInstalledApplications(0);
         for (ApplicationInfo app : apps) {
-            updateRulesForUidLocked(app.uid);
+            final int appId = UserId.getAppId(app.uid);
+            updateRulesForAppLocked(appId);
         }
 
         // and catch system UIDs
@@ -1476,13 +1501,21 @@
         }
     }
 
+    private void updateRulesForAppLocked(int appId) {
+        for (UserInfo user : mContext.getPackageManager().getUsers()) {
+            final int uid = UserId.getUid(user.id, appId);
+            updateRulesForUidLocked(uid);
+        }
+    }
+
     private void updateRulesForUidLocked(int uid) {
-        final int uidPolicy = getUidPolicy(uid);
+        final int appId = UserId.getAppId(uid);
+        final int appPolicy = getAppPolicy(appId);
         final boolean uidForeground = isUidForeground(uid);
 
         // derive active rules based on policy and active state
         int uidRules = RULE_ALLOW_ALL;
-        if (!uidForeground && (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
+        if (!uidForeground && (appPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
             // uid in background, and policy says to block metered data
             uidRules = RULE_REJECT_METERED;
         }
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index bc98f86..95666c0 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -395,7 +395,7 @@
     static final int MCS_GIVE_UP = 11;
     static final int UPDATED_MEDIA_STATUS = 12;
     static final int WRITE_SETTINGS = 13;
-    static final int WRITE_STOPPED_PACKAGES = 14;
+    static final int WRITE_PACKAGE_RESTRICTIONS = 14;
     static final int PACKAGE_VERIFIED = 15;
     static final int CHECK_PENDING_VERIFICATION = 16;
 
@@ -406,6 +406,9 @@
 
     final UserManager mUserManager;
 
+    // Stores a list of users whose package restrictions file needs to be updated
+    private HashSet<Integer> mDirtyUsers = new HashSet<Integer>();
+
     final private DefaultContainerConnection mDefContainerConn =
             new DefaultContainerConnection();
     class DefaultContainerConnection implements ServiceConnection {
@@ -629,7 +632,7 @@
                             packages[i] = ent.getKey();
                             components[i] = ent.getValue();
                             PackageSetting ps = mSettings.mPackages.get(ent.getKey());
-                            uids[i] = (ps != null) ? ps.userId : -1;
+                            uids[i] = (ps != null) ? ps.uid : -1;
                             i++;
                         }
                         size = i;
@@ -735,16 +738,20 @@
                     Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
                     synchronized (mPackages) {
                         removeMessages(WRITE_SETTINGS);
-                        removeMessages(WRITE_STOPPED_PACKAGES);
+                        removeMessages(WRITE_PACKAGE_RESTRICTIONS);
                         mSettings.writeLPr();
+                        mDirtyUsers.clear();
                     }
                     Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                 } break;
-                case WRITE_STOPPED_PACKAGES: {
+                case WRITE_PACKAGE_RESTRICTIONS: {
                     Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
                     synchronized (mPackages) {
-                        removeMessages(WRITE_STOPPED_PACKAGES);
-                        mSettings.writeStoppedLPr();
+                        removeMessages(WRITE_PACKAGE_RESTRICTIONS);
+                        for (int userId : mDirtyUsers) {
+                            mSettings.writePackageRestrictionsLPr(userId);
+                        }
+                        mDirtyUsers.clear();
                     }
                     Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                 } break;
@@ -811,10 +818,11 @@
             mHandler.sendEmptyMessageDelayed(WRITE_SETTINGS, WRITE_SETTINGS_DELAY);
         }
     }
-    
-    void scheduleWriteStoppedPackagesLocked() {
-        if (!mHandler.hasMessages(WRITE_STOPPED_PACKAGES)) {
-            mHandler.sendEmptyMessageDelayed(WRITE_STOPPED_PACKAGES, WRITE_SETTINGS_DELAY);
+
+    void scheduleWritePackageRestrictionsLocked(int userId) {
+        mDirtyUsers.add(userId);
+        if (!mHandler.hasMessages(WRITE_PACKAGE_RESTRICTIONS)) {
+            mHandler.sendEmptyMessageDelayed(WRITE_PACKAGE_RESTRICTIONS, WRITE_SETTINGS_DELAY);
         }
     }
 
@@ -916,7 +924,7 @@
 
             readPermissions();
 
-            mRestoredSettings = mSettings.readLPw();
+            mRestoredSettings = mSettings.readLPw(getUsers());
             long startTime = SystemClock.uptimeMillis();
 
             EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
@@ -1180,7 +1188,7 @@
     private String getRequiredVerifierLPr() {
         final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
         final List<ResolveInfo> receivers = queryIntentReceivers(verification, PACKAGE_MIME_TYPE,
-                PackageManager.GET_DISABLED_COMPONENTS);
+                PackageManager.GET_DISABLED_COMPONENTS, 0 /* TODO: Which userId? */);
 
         String requiredVerifier = null;
 
@@ -1512,7 +1520,8 @@
                 ps.firstInstallTime, ps.lastUpdateTime, gp.grantedPermissions);
     }
 
-    public PackageInfo getPackageInfo(String packageName, int flags) {
+    @Override
+    public PackageInfo getPackageInfo(String packageName, int flags, int userId) {
         // reader
         synchronized (mPackages) {
             PackageParser.Package p = mPackages.get(packageName);
@@ -1522,7 +1531,7 @@
                 return generatePackageInfo(p, flags);
             }
             if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
-                return generatePackageInfoFromSettingsLPw(packageName, flags);
+                return generatePackageInfoFromSettingsLPw(packageName, flags, userId);
             }
         }
         return null;
@@ -1551,20 +1560,21 @@
         }
         return out;
     }
-    
-    public int getPackageUid(String packageName) {
+
+    @Override
+    public int getPackageUid(String packageName, int userId) {
         // reader
         synchronized (mPackages) {
             PackageParser.Package p = mPackages.get(packageName);
             if(p != null) {
-                return p.applicationInfo.uid;
+                return UserId.getUid(userId, p.applicationInfo.uid);
             }
             PackageSetting ps = mSettings.mPackages.get(packageName);
             if((ps == null) || (ps.pkg == null) || (ps.pkg.applicationInfo == null)) {
                 return -1;
             }
             p = ps.pkg;
-            return p != null ? p.applicationInfo.uid : -1;
+            return p != null ? UserId.getUid(userId, p.applicationInfo.uid) : -1;
         }
     }
 
@@ -1652,11 +1662,12 @@
         }
     }
 
-    private ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags) {
+    private ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags,
+            int userId) {
         PackageSetting ps = mSettings.mPackages.get(packageName);
         if (ps != null) {
             if (ps.pkg == null) {
-                PackageInfo pInfo = generatePackageInfoFromSettingsLPw(packageName, flags);
+                PackageInfo pInfo = generatePackageInfoFromSettingsLPw(packageName, flags, userId);
                 if (pInfo != null) {
                     return pInfo.applicationInfo;
                 }
@@ -1667,7 +1678,8 @@
         return null;
     }
 
-    private PackageInfo generatePackageInfoFromSettingsLPw(String packageName, int flags) {
+    private PackageInfo generatePackageInfoFromSettingsLPw(String packageName, int flags,
+            int userId) {
         PackageSetting ps = mSettings.mPackages.get(packageName);
         if (ps != null) {
             if (ps.pkg == null) {
@@ -1679,15 +1691,16 @@
                 ps.pkg.applicationInfo.dataDir =
                         getDataPathForPackage(ps.pkg.packageName, 0).getPath();
                 ps.pkg.applicationInfo.nativeLibraryDir = ps.nativeLibraryPathString;
-                ps.pkg.mSetEnabled = ps.enabled;
-                ps.pkg.mSetStopped = ps.stopped;
             }
+            ps.pkg.mSetEnabled = ps.getEnabled(userId);
+            ps.pkg.mSetStopped = ps.getStopped(userId);
             return generatePackageInfo(ps.pkg, flags);
         }
         return null;
     }
 
-    public ApplicationInfo getApplicationInfo(String packageName, int flags) {
+    @Override
+    public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
         // writer
         synchronized (mPackages) {
             PackageParser.Package p = mPackages.get(packageName);
@@ -1702,7 +1715,7 @@
                 return mAndroidApplication;
             }
             if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
-                return generateApplicationInfoFromSettingsLPw(packageName, flags);
+                return generateApplicationInfoFromSettingsLPw(packageName, flags, userId);
             }
         }
         return null;
@@ -1758,16 +1771,13 @@
         });
     }
 
-    public ActivityInfo getActivityInfo(ComponentName component, int flags) {
-        return getActivityInfo(component, flags, Binder.getOrigCallingUser());
-    }
-
-    ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
+    @Override
+    public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
         synchronized (mPackages) {
             PackageParser.Activity a = mActivities.mActivities.get(component);
 
             if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a);
-            if (a != null && mSettings.isEnabledLPr(a.info, flags)) {
+            if (a != null && mSettings.isEnabledLPr(a.info, flags, userId)) {
                 return PackageParser.generateActivityInfo(a, flags, userId);
             }
             if (mResolveComponentName.equals(component)) {
@@ -1777,48 +1787,39 @@
         return null;
     }
 
-    public ActivityInfo getReceiverInfo(ComponentName component, int flags) {
-        return getReceiverInfo(component, flags, Binder.getOrigCallingUser());
-    }
-
-    ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) {
+    @Override
+    public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) {
         synchronized (mPackages) {
             PackageParser.Activity a = mReceivers.mActivities.get(component);
             if (DEBUG_PACKAGE_INFO) Log.v(
                 TAG, "getReceiverInfo " + component + ": " + a);
-            if (a != null && mSettings.isEnabledLPr(a.info, flags)) {
+            if (a != null && mSettings.isEnabledLPr(a.info, flags, userId)) {
                 return PackageParser.generateActivityInfo(a, flags, userId);
             }
         }
         return null;
     }
 
-    public ServiceInfo getServiceInfo(ComponentName component, int flags) {
-        return getServiceInfo(component, flags, Binder.getOrigCallingUser());
-    }
-
-    ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
+    @Override
+    public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
         synchronized (mPackages) {
             PackageParser.Service s = mServices.mServices.get(component);
             if (DEBUG_PACKAGE_INFO) Log.v(
                 TAG, "getServiceInfo " + component + ": " + s);
-            if (s != null && mSettings.isEnabledLPr(s.info, flags)) {
+            if (s != null && mSettings.isEnabledLPr(s.info, flags, userId)) {
                 return PackageParser.generateServiceInfo(s, flags, userId);
             }
         }
         return null;
     }
 
-    public ProviderInfo getProviderInfo(ComponentName component, int flags) {
-        return getProviderInfo(component, flags, UserId.getUserId(Binder.getCallingUid()));
-    }
-
-    ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) {
+    @Override
+    public ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) {
         synchronized (mPackages) {
             PackageParser.Provider p = mProvidersByComponent.get(component);
             if (DEBUG_PACKAGE_INFO) Log.v(
                 TAG, "getProviderInfo " + component + ": " + p);
-            if (p != null && mSettings.isEnabledLPr(p.info, flags)) {
+            if (p != null && mSettings.isEnabledLPr(p.info, flags, userId)) {
                 return PackageParser.generateProviderInfo(p, flags, userId);
             }
         }
@@ -1863,6 +1864,14 @@
         }
     }
 
+    private void checkValidCaller(int uid, int userId) {
+        if (UserId.getUserId(uid) == userId || uid == Process.SYSTEM_UID || uid == 0)
+            return;
+
+        throw new SecurityException("Caller uid=" + uid
+                + " is not privileged to communicate with user=" + userId);
+    }
+
     public int checkPermission(String permName, String pkgName) {
         synchronized (mPackages) {
             PackageParser.Package p = mPackages.get(pkgName);
@@ -1997,7 +2006,7 @@
             if (!async) {
                 mSettings.writeLPr();
             } else {
-                scheduleWriteSettingsLocked();            
+                scheduleWriteSettingsLocked();
             }
         }
         return added;
@@ -2232,14 +2241,15 @@
         }
     }
 
+    @Override
     public ResolveInfo resolveIntent(Intent intent, String resolvedType,
-            int flags) {
-        List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags);
-        return chooseBestActivity(intent, resolvedType, flags, query);
+            int flags, int userId) {
+        List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, userId);
+        return chooseBestActivity(intent, resolvedType, flags, query, userId);
     }
 
     private ResolveInfo chooseBestActivity(Intent intent, String resolvedType,
-                                           int flags, List<ResolveInfo> query) {
+            int flags, List<ResolveInfo> query, int userId) {
         if (query != null) {
             final int N = query.size();
             if (N == 1) {
@@ -2263,7 +2273,7 @@
                 // If we have saved a preference for a preferred activity for
                 // this Intent, use that.
                 ResolveInfo ri = findPreferredActivity(intent, resolvedType,
-                        flags, query, r0.priority);
+                        flags, query, r0.priority, userId);
                 if (ri != null) {
                     return ri;
                 }
@@ -2274,7 +2284,7 @@
     }
 
     ResolveInfo findPreferredActivity(Intent intent, String resolvedType,
-            int flags, List<ResolveInfo> query, int priority) {
+            int flags, List<ResolveInfo> query, int priority, int userId) {
         // writer
         synchronized (mPackages) {
             if (intent.getSelector() != null) {
@@ -2283,7 +2293,7 @@
             if (DEBUG_PREFERRED) intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
             List<PreferredActivity> prefs =
                     mSettings.mPreferredActivities.queryIntent(intent, resolvedType,
-                            (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0);
+                            (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId);
             if (prefs != null && prefs.size() > 0) {
                 // First figure out how good the original match set is.
                 // We will only allow preferred activities that came
@@ -2317,7 +2327,7 @@
                     if (pa.mPref.mMatch != match) {
                         continue;
                     }
-                    final ActivityInfo ai = getActivityInfo(pa.mPref.mComponent, flags);
+                    final ActivityInfo ai = getActivityInfo(pa.mPref.mComponent, flags, userId);
                     if (DEBUG_PREFERRED) {
                         Log.v(TAG, "Got preferred activity:");
                         if (ai != null) {
@@ -2367,8 +2377,9 @@
         return null;
     }
 
+    @Override
     public List<ResolveInfo> queryIntentActivities(Intent intent,
-            String resolvedType, int flags) {
+            String resolvedType, int flags, int userId) {
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -2379,7 +2390,7 @@
 
         if (comp != null) {
             final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
-            final ActivityInfo ai = getActivityInfo(comp, flags);
+            final ActivityInfo ai = getActivityInfo(comp, flags, userId);
             if (ai != null) {
                 final ResolveInfo ri = new ResolveInfo();
                 ri.activityInfo = ai;
@@ -2392,24 +2403,25 @@
         synchronized (mPackages) {
             final String pkgName = intent.getPackage();
             if (pkgName == null) {
-                return mActivities.queryIntent(intent, resolvedType, flags);
+                return mActivities.queryIntent(intent, resolvedType, flags, userId);
             }
             final PackageParser.Package pkg = mPackages.get(pkgName);
             if (pkg != null) {
                 return mActivities.queryIntentForPackage(intent, resolvedType, flags,
-                        pkg.activities);
+                        pkg.activities, userId);
             }
             return new ArrayList<ResolveInfo>();
         }
     }
 
+    @Override
     public List<ResolveInfo> queryIntentActivityOptions(ComponentName caller,
             Intent[] specifics, String[] specificTypes, Intent intent,
-            String resolvedType, int flags) {
+            String resolvedType, int flags, int userId) {
         final String resultsAction = intent.getAction();
 
         List<ResolveInfo> results = queryIntentActivities(intent, resolvedType, flags
-                | PackageManager.GET_RESOLVED_FILTER);
+                | PackageManager.GET_RESOLVED_FILTER, userId);
 
         if (DEBUG_INTENT_MATCHING) {
             Log.v(TAG, "Query " + intent + ": " + results);
@@ -2452,7 +2464,7 @@
                     ri = resolveIntent(
                         sintent,
                         specificTypes != null ? specificTypes[i] : null,
-                        flags);
+                            flags, userId);
                     if (ri == null) {
                         continue;
                     }
@@ -2463,7 +2475,7 @@
                     comp = new ComponentName(ai.applicationInfo.packageName,
                             ai.name);
                 } else {
-                    ai = getActivityInfo(comp, flags);
+                    ai = getActivityInfo(comp, flags, userId);
                     if (ai == null) {
                         continue;
                     }
@@ -2572,7 +2584,9 @@
         return results;
     }
 
-    public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags) {
+    @Override
+    public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags,
+            int userId) {
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -2582,7 +2596,7 @@
         }
         if (comp != null) {
             List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
-            ActivityInfo ai = getReceiverInfo(comp, flags);
+            ActivityInfo ai = getReceiverInfo(comp, flags, userId);
             if (ai != null) {
                 ResolveInfo ri = new ResolveInfo();
                 ri.activityInfo = ai;
@@ -2595,18 +2609,20 @@
         synchronized (mPackages) {
             String pkgName = intent.getPackage();
             if (pkgName == null) {
-                return mReceivers.queryIntent(intent, resolvedType, flags);
+                return mReceivers.queryIntent(intent, resolvedType, flags, userId);
             }
             final PackageParser.Package pkg = mPackages.get(pkgName);
             if (pkg != null) {
-                return mReceivers.queryIntentForPackage(intent, resolvedType, flags, pkg.receivers);
+                return mReceivers.queryIntentForPackage(intent, resolvedType, flags, pkg.receivers,
+                        userId);
             }
             return null;
         }
     }
 
-    public ResolveInfo resolveService(Intent intent, String resolvedType, int flags) {
-        List<ResolveInfo> query = queryIntentServices(intent, resolvedType, flags);
+    @Override
+    public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) {
+        List<ResolveInfo> query = queryIntentServices(intent, resolvedType, flags, userId);
         if (query != null) {
             if (query.size() >= 1) {
                 // If there is more than one service with the same priority,
@@ -2617,7 +2633,9 @@
         return null;
     }
 
-    public List<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags) {
+    @Override
+    public List<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags,
+            int userId) {
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -2627,7 +2645,7 @@
         }
         if (comp != null) {
             final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
-            final ServiceInfo si = getServiceInfo(comp, flags);
+            final ServiceInfo si = getServiceInfo(comp, flags, userId);
             if (si != null) {
                 final ResolveInfo ri = new ResolveInfo();
                 ri.serviceInfo = si;
@@ -2640,11 +2658,12 @@
         synchronized (mPackages) {
             String pkgName = intent.getPackage();
             if (pkgName == null) {
-                return mServices.queryIntent(intent, resolvedType, flags);
+                return mServices.queryIntent(intent, resolvedType, flags, userId);
             }
             final PackageParser.Package pkg = mPackages.get(pkgName);
             if (pkg != null) {
-                return mServices.queryIntentForPackage(intent, resolvedType, flags, pkg.services);
+                return mServices.queryIntentForPackage(intent, resolvedType, flags, pkg.services,
+                        userId);
             }
             return null;
         }
@@ -2669,6 +2688,7 @@
         final ParceledListSlice<PackageInfo> list = new ParceledListSlice<PackageInfo>();
         final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
         final String[] keys;
+        int userId = UserId.getCallingUserId();
 
         // writer
         synchronized (mPackages) {
@@ -2689,7 +2709,7 @@
                 if (listUninstalled) {
                     final PackageSetting ps = mSettings.mPackages.get(packageName);
                     if (ps != null) {
-                        pi = generatePackageInfoFromSettingsLPw(ps.name, flags);
+                        pi = generatePackageInfoFromSettingsLPw(ps.name, flags, userId);
                     }
                 } else {
                     final PackageParser.Package p = mPackages.get(packageName);
@@ -2711,8 +2731,9 @@
         return list;
     }
 
+    @Override
     public ParceledListSlice<ApplicationInfo> getInstalledApplications(int flags,
-            String lastRead) {
+            String lastRead, int userId) {
         final ParceledListSlice<ApplicationInfo> list = new ParceledListSlice<ApplicationInfo>();
         final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
         final String[] keys;
@@ -2728,7 +2749,6 @@
             Arrays.sort(keys);
             int i = getContinuationPoint(keys, lastRead);
             final int N = keys.length;
-            final int userId = UserId.getUserId(Binder.getCallingUid());
 
             while (i < N) {
                 final String packageName = keys[i++];
@@ -2737,7 +2757,7 @@
                 if (listUninstalled) {
                     final PackageSetting ps = mSettings.mPackages.get(packageName);
                     if (ps != null) {
-                        ai = generateApplicationInfoFromSettingsLPw(ps.name, flags);
+                        ai = generateApplicationInfoFromSettingsLPw(ps.name, flags, userId);
                     }
                 } else {
                     final PackageParser.Package p = mPackages.get(packageName);
@@ -2779,16 +2799,16 @@
         return finalList;
     }
 
-    public ProviderInfo resolveContentProvider(String name, int flags) {
+    @Override
+    public ProviderInfo resolveContentProvider(String name, int flags, int userId) {
         // reader
         synchronized (mPackages) {
             final PackageParser.Provider provider = mProviders.get(name);
             return provider != null
-                    && mSettings.isEnabledLPr(provider.info, flags)
+                    && mSettings.isEnabledLPr(provider.info, flags, userId)
                     && (!mSafeMode || (provider.info.applicationInfo.flags
                             &ApplicationInfo.FLAG_SYSTEM) != 0)
-                    ? PackageParser.generateProviderInfo(provider, flags,
-                            UserId.getUserId(Binder.getCallingUid()))
+                    ? PackageParser.generateProviderInfo(provider, flags, userId)
                     : null;
         }
     }
@@ -2824,15 +2844,15 @@
         // reader
         synchronized (mPackages) {
             final Iterator<PackageParser.Provider> i = mProvidersByComponent.values().iterator();
-            final int userId = UserId.getUserId(Binder.getCallingUid());
+            final int userId = processName != null ?
+                    UserId.getUserId(uid) : UserId.getCallingUserId();
             while (i.hasNext()) {
                 final PackageParser.Provider p = i.next();
                 if (p.info.authority != null
                         && (processName == null
                                 || (p.info.processName.equals(processName)
-                                        && UserId.getAppId(p.info.applicationInfo.uid)
-                                            == UserId.getAppId(uid)))
-                        && mSettings.isEnabledLPr(p.info, flags)
+                                        && UserId.isSameApp(p.info.applicationInfo.uid, uid)))
+                        && mSettings.isEnabledLPr(p.info, flags, userId)
                         && (!mSafeMode
                                 || (p.info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)) {
                     if (finalList == null) {
@@ -3482,7 +3502,7 @@
                 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
             }
 
-            pkg.applicationInfo.uid = pkgSetting.userId;
+            pkg.applicationInfo.uid = pkgSetting.uid;
             pkg.mExtras = pkgSetting;
 
             if (!verifySignaturesLP(pkgSetting, pkg)) {
@@ -4480,19 +4500,20 @@
     private final class ActivityIntentResolver
             extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> {
         public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
-                boolean defaultOnly) {
+                boolean defaultOnly, int userId) {
             mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;
-            return super.queryIntent(intent, resolvedType, defaultOnly);
+            return super.queryIntent(intent, resolvedType, defaultOnly, userId);
         }
 
-        public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags) {
+        public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags,
+                int userId) {
             mFlags = flags;
             return super.queryIntent(intent, resolvedType,
-                (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0);
+                    (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId);
         }
 
         public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
-                int flags, ArrayList<PackageParser.Activity> packageActivities) {
+                int flags, ArrayList<PackageParser.Activity> packageActivities, int userId) {
             if (packageActivities == null) {
                 return null;
             }
@@ -4509,7 +4530,7 @@
                     listCut.add(intentFilters);
                 }
             }
-            return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut);
+            return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);
         }
 
         public final void addActivity(PackageParser.Activity a, String type) {
@@ -4574,7 +4595,7 @@
         }
 
         @Override
-        protected boolean isFilterStopped(PackageParser.ActivityIntentInfo filter) {
+        protected boolean isFilterStopped(PackageParser.ActivityIntentInfo filter, int userId) {
             PackageParser.Package p = filter.activity.owner;
             if (p != null) {
                 PackageSetting ps = (PackageSetting)p.mExtras;
@@ -4582,7 +4603,7 @@
                     // System apps are never considered stopped for purposes of
                     // filtering, because there may be no way for the user to
                     // actually re-launch them.
-                    return ps.stopped && (ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0;
+                    return ps.getStopped(userId) && (ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0;
                 }
             }
             return false;
@@ -4595,8 +4616,8 @@
         
         @Override
         protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info,
-                int match) {
-            if (!mSettings.isEnabledLPr(info.activity.info, mFlags)) {
+                int match, int userId) {
+            if (!mSettings.isEnabledLPr(info.activity.info, mFlags, userId)) {
                 return null;
             }
             final PackageParser.Activity activity = info.activity;
@@ -4605,8 +4626,7 @@
                 return null;
             }
             final ResolveInfo res = new ResolveInfo();
-            res.activityInfo = PackageParser.generateActivityInfo(activity, mFlags,
-                    Binder.getOrigCallingUser());
+            res.activityInfo = PackageParser.generateActivityInfo(activity, mFlags, userId);
             if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) {
                 res.filter = info;
             }
@@ -4660,19 +4680,20 @@
     private final class ServiceIntentResolver
             extends IntentResolver<PackageParser.ServiceIntentInfo, ResolveInfo> {
         public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
-                boolean defaultOnly) {
+                boolean defaultOnly, int userId) {
             mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;
-            return super.queryIntent(intent, resolvedType, defaultOnly);
+            return super.queryIntent(intent, resolvedType, defaultOnly, userId);
         }
 
-        public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags) {
+        public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags,
+                int userId) {
             mFlags = flags;
             return super.queryIntent(intent, resolvedType,
-                (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0);
+                    (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId);
         }
 
         public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
-                int flags, ArrayList<PackageParser.Service> packageServices) {
+                int flags, ArrayList<PackageParser.Service> packageServices, int userId) {
             if (packageServices == null) {
                 return null;
             }
@@ -4689,7 +4710,7 @@
                     listCut.add(intentFilters);
                 }
             }
-            return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut);
+            return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);
         }
 
         public final void addService(PackageParser.Service s) {
@@ -4749,7 +4770,7 @@
         }
 
         @Override
-        protected boolean isFilterStopped(PackageParser.ServiceIntentInfo filter) {
+        protected boolean isFilterStopped(PackageParser.ServiceIntentInfo filter, int userId) {
             PackageParser.Package p = filter.service.owner;
             if (p != null) {
                 PackageSetting ps = (PackageSetting)p.mExtras;
@@ -4757,7 +4778,8 @@
                     // System apps are never considered stopped for purposes of
                     // filtering, because there may be no way for the user to
                     // actually re-launch them.
-                    return ps.stopped && (ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0;
+                    return ps.getStopped(userId)
+                            && (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0;
                 }
             }
             return false;
@@ -4770,9 +4792,9 @@
         
         @Override
         protected ResolveInfo newResult(PackageParser.ServiceIntentInfo filter,
-                int match) {
+                int match, int userId) {
             final PackageParser.ServiceIntentInfo info = (PackageParser.ServiceIntentInfo)filter;
-            if (!mSettings.isEnabledLPr(info.service.info, mFlags)) {
+            if (!mSettings.isEnabledLPr(info.service.info, mFlags, userId)) {
                 return null;
             }
             final PackageParser.Service service = info.service;
@@ -4781,8 +4803,7 @@
                 return null;
             }
             final ResolveInfo res = new ResolveInfo();
-            res.serviceInfo = PackageParser.generateServiceInfo(service, mFlags,
-                    Binder.getOrigCallingUser());
+            res.serviceInfo = PackageParser.generateServiceInfo(service, mFlags, userId);
             if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) {
                 res.filter = filter;
             }
@@ -5635,14 +5656,14 @@
                  * do, then we'll defer to them to verify the packages.
                  */
                 final int requiredUid = mRequiredVerifierPackage == null ? -1
-                        : getPackageUid(mRequiredVerifierPackage);
+                        : getPackageUid(mRequiredVerifierPackage, 0);
                 if (requiredUid != -1 && isVerificationEnabled()) {
                     final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
                     verification.setDataAndType(packageURI, PACKAGE_MIME_TYPE);
                     verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
 
                     final List<ResolveInfo> receivers = queryIntentReceivers(verification, null,
-                            PackageManager.GET_DISABLED_COMPONENTS);
+                            PackageManager.GET_DISABLED_COMPONENTS, 0 /* TODO: Which userId? */);
 
                     if (DEBUG_VERIFY) {
                         Slog.d(TAG, "Found " + receivers.size() + " verifiers for intent "
@@ -7316,17 +7337,19 @@
         return ret;
     }
 
+    @Override
     public void clearApplicationUserData(final String packageName,
-            final IPackageDataObserver observer) {
+            final IPackageDataObserver observer, final int userId) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.CLEAR_APP_USER_DATA, null);
+        checkValidCaller(Binder.getCallingUid(), userId);
         // Queue up an async operation since the package deletion may take a little while.
         mHandler.post(new Runnable() {
             public void run() {
                 mHandler.removeCallbacks(this);
                 final boolean succeeded;
                 synchronized (mInstallLock) {
-                    succeeded = clearApplicationUserDataLI(packageName);
+                    succeeded = clearApplicationUserDataLI(packageName, userId);
                 }
                 if (succeeded) {
                     // invoke DeviceStorageMonitor's update method to clear any notifications
@@ -7347,7 +7370,7 @@
         });
     }
 
-    private boolean clearApplicationUserDataLI(String packageName) {
+    private boolean clearApplicationUserDataLI(String packageName, int userId) {
         if (packageName == null) {
             Slog.w(TAG, "Attempt to delete null packageName.");
             return false;
@@ -7379,7 +7402,7 @@
                 return false;
             }
         }
-        int retCode = mInstaller.clearUserData(packageName, 0); // TODO - correct userId
+        int retCode = mInstaller.clearUserData(packageName, userId);
         if (retCode < 0) {
             Slog.w(TAG, "Couldn't remove cache files for package: "
                     + packageName);
@@ -7393,12 +7416,13 @@
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.DELETE_CACHE_FILES, null);
         // Queue up an async operation since the package deletion may take a little while.
+        final int userId = UserId.getCallingUserId();
         mHandler.post(new Runnable() {
             public void run() {
                 mHandler.removeCallbacks(this);
                 final boolean succeded;
                 synchronized (mInstallLock) {
-                    succeded = deleteApplicationCacheFilesLI(packageName);
+                    succeded = deleteApplicationCacheFilesLI(packageName, userId);
                 }
                 if(observer != null) {
                     try {
@@ -7411,7 +7435,7 @@
         });
     }
 
-    private boolean deleteApplicationCacheFilesLI(String packageName) {
+    private boolean deleteApplicationCacheFilesLI(String packageName, int userId) {
         if (packageName == null) {
             Slog.w(TAG, "Attempt to delete null packageName.");
             return false;
@@ -7429,6 +7453,7 @@
             Slog.w(TAG, "Package " + packageName + " has no applicationInfo.");
             return false;
         }
+        // TODO: Pass userId to deleteCacheFiles
         int retCode = mInstaller.deleteCacheFiles(packageName);
         if (retCode < 0) {
             Slog.w(TAG, "Couldn't remove cache files for package: "
@@ -7695,19 +7720,21 @@
         return num;
     }
 
+    @Override
     public void setApplicationEnabledSetting(String appPackageName,
-            int newState, int flags) {
-        setEnabledSetting(appPackageName, null, newState, flags);
+            int newState, int flags, int userId) {
+        setEnabledSetting(appPackageName, null, newState, flags, userId);
     }
 
+    @Override
     public void setComponentEnabledSetting(ComponentName componentName,
-            int newState, int flags) {
+            int newState, int flags, int userId) {
         setEnabledSetting(componentName.getPackageName(),
-                componentName.getClassName(), newState, flags);
+                componentName.getClassName(), newState, flags, userId);
     }
 
     private void setEnabledSetting(
-            final String packageName, String className, int newState, final int flags) {
+            final String packageName, String className, int newState, final int flags, int userId) {
         if (!(newState == COMPONENT_ENABLED_STATE_DEFAULT
               || newState == COMPONENT_ENABLED_STATE_ENABLED
               || newState == COMPONENT_ENABLED_STATE_DISABLED
@@ -7719,6 +7746,7 @@
         final int uid = Binder.getCallingUid();
         final int permission = mContext.checkCallingPermission(
                 android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
+        checkValidCaller(uid, userId);
         final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
         boolean sendNow = false;
         boolean isApp = (className == null);
@@ -7738,19 +7766,20 @@
                         "Unknown component: " + packageName
                         + "/" + className);
             }
-            if (!allowedByPermission && (!UserId.isSameApp(uid, pkgSetting.userId))) {
+            // Allow root and verify that userId is not being specified by a different user
+            if (!allowedByPermission && !UserId.isSameApp(uid, pkgSetting.uid)) {
                 throw new SecurityException(
                         "Permission Denial: attempt to change component state from pid="
                         + Binder.getCallingPid()
-                        + ", uid=" + uid + ", package uid=" + pkgSetting.userId);
+                        + ", uid=" + uid + ", package uid=" + pkgSetting.uid);
             }
             if (className == null) {
                 // We're dealing with an application/package level state change
-                if (pkgSetting.enabled == newState) {
+                if (pkgSetting.getEnabled(userId) == newState) {
                     // Nothing to do
                     return;
                 }
-                pkgSetting.enabled = newState;
+                pkgSetting.setEnabled(newState, userId);
                 pkgSetting.pkg.mSetEnabled = newState;
             } else {
                 // We're dealing with a component level state change
@@ -7767,17 +7796,17 @@
                 }
                 switch (newState) {
                 case COMPONENT_ENABLED_STATE_ENABLED:
-                    if (!pkgSetting.enableComponentLPw(className)) {
+                    if (!pkgSetting.enableComponentLPw(className, userId)) {
                         return;
                     }
                     break;
                 case COMPONENT_ENABLED_STATE_DISABLED:
-                    if (!pkgSetting.disableComponentLPw(className)) {
+                    if (!pkgSetting.disableComponentLPw(className, userId)) {
                         return;
                     }
                     break;
                 case COMPONENT_ENABLED_STATE_DEFAULT:
-                    if (!pkgSetting.restoreComponentLPw(className)) {
+                    if (!pkgSetting.restoreComponentLPw(className, userId)) {
                         return;
                     }
                     break;
@@ -7786,8 +7815,8 @@
                     return;
                 }
             }
-            mSettings.writeLPr();
-            packageUid = pkgSetting.userId;
+            mSettings.writePackageRestrictionsLPr(userId);
+            packageUid = pkgSetting.uid;
             components = mPendingBroadcasts.get(packageName);
             final boolean newPackage = components == null;
             if (newPackage) {
@@ -7838,16 +7867,17 @@
         sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED,  packageName, extras, null, null);
     }
 
-    public void setPackageStoppedState(String packageName, boolean stopped) {
+    public void setPackageStoppedState(String packageName, boolean stopped, int userId) {
         final int uid = Binder.getCallingUid();
         final int permission = mContext.checkCallingOrSelfPermission(
                 android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
         final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
+        checkValidCaller(uid, userId);
         // writer
         synchronized (mPackages) {
             if (mSettings.setPackageStoppedStateLPw(packageName, stopped, allowedByPermission,
-                    uid)) {
-                scheduleWriteStoppedPackagesLocked();
+                    uid, userId)) {
+                scheduleWritePackageRestrictionsLocked(userId);
             }
         }
     }
@@ -7859,17 +7889,23 @@
         }
     }
 
-    public int getApplicationEnabledSetting(String packageName) {
+    @Override
+    public int getApplicationEnabledSetting(String packageName, int userId) {
+        int uid = Binder.getCallingUid();
+        checkValidCaller(uid, userId);
         // reader
         synchronized (mPackages) {
-            return mSettings.getApplicationEnabledSettingLPr(packageName);
+            return mSettings.getApplicationEnabledSettingLPr(packageName, userId);
         }
     }
 
-    public int getComponentEnabledSetting(ComponentName componentName) {
+    @Override
+    public int getComponentEnabledSetting(ComponentName componentName, int userId) {
+        int uid = Binder.getCallingUid();
+        checkValidCaller(uid, userId);
         // reader
         synchronized (mPackages) {
-            return mSettings.getComponentEnabledSettingLPr(componentName);
+            return mSettings.getComponentEnabledSettingLPr(componentName, userId);
         }
     }
 
@@ -8073,7 +8109,7 @@
                 pw.print("  Required: ");
                 pw.print(mRequiredVerifierPackage);
                 pw.print(" (uid=");
-                pw.print(getPackageUid(mRequiredVerifierPackage));
+                pw.print(getPackageUid(mRequiredVerifierPackage, 0));
                 pw.println(")");
             }
 
@@ -8338,7 +8374,7 @@
                                     + " at code path: " + ps.codePathString);
                         // We do have a valid package installed on sdcard
                         processCids.put(args, ps.codePathString);
-                        int uid = ps.userId;
+                        int uid = ps.uid;
                         if (uid != -1) {
                             uidList[num++] = uid;
                         }
diff --git a/services/java/com/android/server/pm/PackageSetting.java b/services/java/com/android/server/pm/PackageSetting.java
index efdc2b3..48ed9bf 100644
--- a/services/java/com/android/server/pm/PackageSetting.java
+++ b/services/java/com/android/server/pm/PackageSetting.java
@@ -24,7 +24,7 @@
  * Settings data for a particular package we know about.
  */
 final class PackageSetting extends PackageSettingBase {
-    int userId;
+    int uid;
     PackageParser.Package pkg;
     SharedUserSetting sharedUser;
 
@@ -41,7 +41,7 @@
     PackageSetting(PackageSetting orig) {
         super(orig);
 
-        userId = orig.userId;
+        uid = orig.uid;
         pkg = orig.pkg;
         sharedUser = orig.sharedUser;
     }
@@ -50,6 +50,6 @@
     public String toString() {
         return "PackageSetting{"
             + Integer.toHexString(System.identityHashCode(this))
-            + " " + name + "/" + userId + "}";
+            + " " + name + "/" + uid + "}";
     }
 }
\ No newline at end of file
diff --git a/services/java/com/android/server/pm/PackageSettingBase.java b/services/java/com/android/server/pm/PackageSettingBase.java
index e2f83ad..b7cf8d6 100644
--- a/services/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/java/com/android/server/pm/PackageSettingBase.java
@@ -20,6 +20,8 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
 
+import android.util.SparseArray;
+import android.util.SparseIntArray;
 
 import java.io.File;
 import java.util.HashSet;
@@ -62,20 +64,22 @@
 
     // Whether this package is currently stopped, thus can not be
     // started until explicitly launched by the user.
-    public boolean stopped;
+    private SparseArray<Boolean> stopped = new SparseArray<Boolean>();
 
     // Set to true if we have never launched this app.
-    public boolean notLaunched;
+    private SparseArray<Boolean> notLaunched = new SparseArray<Boolean>();
 
     /* Explicitly disabled components */
-    HashSet<String> disabledComponents = new HashSet<String>(0);
+    private SparseArray<HashSet<String>> disabledComponents = new SparseArray<HashSet<String>>();
     /* Explicitly enabled components */
-    HashSet<String> enabledComponents = new HashSet<String>(0);
-    int enabled = COMPONENT_ENABLED_STATE_DEFAULT;
+    private SparseArray<HashSet<String>> enabledComponents = new SparseArray<HashSet<String>>();
+    /* Enabled state */
+    private SparseIntArray enabled = new SparseIntArray();
+
     int installStatus = PKG_INSTALL_COMPLETE;
 
     PackageSettingBase origPackage;
-    
+
     /* package name of the app that installed this package */
     String installerPackageName;
     PackageSettingBase(String name, String realName, File codePath, File resourcePath,
@@ -111,14 +115,12 @@
 
         permissionsFixed = base.permissionsFixed;
         haveGids = base.haveGids;
-        stopped = base.stopped;
         notLaunched = base.notLaunched;
 
-        disabledComponents = (HashSet<String>) base.disabledComponents.clone();
-
-        enabledComponents = (HashSet<String>) base.enabledComponents.clone();
-
-        enabled = base.enabled;
+        disabledComponents = (SparseArray<HashSet<String>>) base.disabledComponents.clone();
+        enabledComponents = (SparseArray<HashSet<String>>) base.enabledComponents.clone();
+        enabled = (SparseIntArray) base.enabled.clone();
+        stopped = (SparseArray<Boolean>) base.stopped.clone();
         installStatus = base.installStatus;
 
         origPackage = base.origPackage;
@@ -177,31 +179,98 @@
         installStatus = base.installStatus;
     }
 
-    boolean enableComponentLPw(String componentClassName) {
-        boolean changed = disabledComponents.remove(componentClassName);
-        changed |= enabledComponents.add(componentClassName);
+    void setEnabled(int state, int userId) {
+        enabled.put(userId, state);
+    }
+
+    int getEnabled(int userId) {
+        return enabled.get(userId, COMPONENT_ENABLED_STATE_DEFAULT);
+    }
+
+    boolean getStopped(int userId) {
+        return stopped.get(userId, false);
+    }
+
+    void setStopped(boolean stop, int userId) {
+        stopped.put(userId, stop);
+    }
+
+    boolean getNotLaunched(int userId) {
+        return notLaunched.get(userId, false);
+    }
+
+    void setNotLaunched(boolean stop, int userId) {
+        notLaunched.put(userId, stop);
+    }
+
+    HashSet<String> getEnabledComponents(int userId) {
+        return getComponentHashSet(enabledComponents, userId);
+    }
+
+    HashSet<String> getDisabledComponents(int userId) {
+        return getComponentHashSet(disabledComponents, userId);
+    }
+
+    void setEnabledComponents(HashSet<String> components, int userId) {
+        enabledComponents.put(userId, components);
+    }
+
+    void setDisabledComponents(HashSet<String> components, int userId) {
+        disabledComponents.put(userId, components);
+    }
+
+    private HashSet<String> getComponentHashSet(SparseArray<HashSet<String>> setArray, int userId) {
+        HashSet<String> set = setArray.get(userId);
+        if (set == null) {
+            set = new HashSet<String>(1);
+            setArray.put(userId, set);
+        }
+        return set;
+    }
+
+    void addDisabledComponent(String componentClassName, int userId) {
+        HashSet<String> disabled = getComponentHashSet(disabledComponents, userId);
+        disabled.add(componentClassName);
+    }
+
+    void addEnabledComponent(String componentClassName, int userId) {
+        HashSet<String> enabled = getComponentHashSet(enabledComponents, userId);
+        enabled.add(componentClassName);
+    }
+
+    boolean enableComponentLPw(String componentClassName, int userId) {
+        HashSet<String> disabled = getComponentHashSet(disabledComponents, userId);
+        HashSet<String> enabled = getComponentHashSet(enabledComponents, userId);
+        boolean changed = disabled.remove(componentClassName);
+        changed |= enabled.add(componentClassName);
         return changed;
     }
 
-    boolean disableComponentLPw(String componentClassName) {
-        boolean changed = enabledComponents.remove(componentClassName);
-        changed |= disabledComponents.add(componentClassName);
+    boolean disableComponentLPw(String componentClassName, int userId) {
+        HashSet<String> disabled = getComponentHashSet(disabledComponents, userId);
+        HashSet<String> enabled = getComponentHashSet(enabledComponents, userId);
+        boolean changed = enabled.remove(componentClassName);
+        changed |= disabled.add(componentClassName);
         return changed;
     }
 
-    boolean restoreComponentLPw(String componentClassName) {
-        boolean changed = enabledComponents.remove(componentClassName);
-        changed |= disabledComponents.remove(componentClassName);
+    boolean restoreComponentLPw(String componentClassName, int userId) {
+        HashSet<String> disabled = getComponentHashSet(disabledComponents, userId);
+        HashSet<String> enabled = getComponentHashSet(enabledComponents, userId);
+        boolean changed = enabled.remove(componentClassName);
+        changed |= disabled.remove(componentClassName);
         return changed;
     }
 
-    int getCurrentEnabledStateLPr(String componentName) {
-        if (enabledComponents.contains(componentName)) {
+    int getCurrentEnabledStateLPr(String componentName, int userId) {
+        HashSet<String> disabled = getComponentHashSet(disabledComponents, userId);
+        HashSet<String> enabled = getComponentHashSet(enabledComponents, userId);
+        if (enabled.contains(componentName)) {
             return COMPONENT_ENABLED_STATE_ENABLED;
-        } else if (disabledComponents.contains(componentName)) {
+        } else if (disabled.contains(componentName)) {
             return COMPONENT_ENABLED_STATE_DISABLED;
         } else {
             return COMPONENT_ENABLED_STATE_DEFAULT;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 363d020..b541c8c 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -32,6 +32,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
+import android.app.AppGlobals;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
@@ -40,11 +41,14 @@
 import android.content.pm.PackageParser;
 import android.content.pm.PermissionInfo;
 import android.content.pm.Signature;
+import android.content.pm.UserInfo;
 import android.content.pm.VerifierDeviceIdentity;
 import android.os.Binder;
 import android.os.Environment;
 import android.os.FileUtils;
 import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserId;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -63,6 +67,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 
 import libcore.io.IoUtils;
@@ -78,6 +83,17 @@
     private static final String TAG_READ_EXTERNAL_STORAGE = "read-external-storage";
     private static final String ATTR_ENFORCEMENT = "enforcement";
 
+    private static final String TAG_ITEM = "item";
+    private static final String TAG_DISABLED_COMPONENTS = "disabled-components";
+    private static final String TAG_ENABLED_COMPONENTS = "enabled-components";
+    private static final String TAG_PACKAGE_RESTRICTIONS = "package-restrictions";
+    private static final String TAG_PACKAGE = "pkg";
+
+    private static final String ATTR_NAME = "name";
+    private static final String ATTR_NOT_LAUNCHED = "nl";
+    private static final String ATTR_ENABLED = "enabled";
+    private static final String ATTR_STOPPED = "stopped";
+
     private final File mSettingsFilename;
     private final File mBackupSettingsFilename;
     private final File mPackageListFilename;
@@ -153,19 +169,24 @@
      */
     private final ArrayList<PendingPackage> mPendingPackages = new ArrayList<PendingPackage>();
 
+    private final File mSystemDir;
     Settings() {
-        File dataDir = Environment.getDataDirectory();
-        File systemDir = new File(dataDir, "system");
-        systemDir.mkdirs();
-        FileUtils.setPermissions(systemDir.toString(),
+        this(Environment.getDataDirectory());
+    }
+
+    Settings(File dataDir) {
+        mSystemDir = new File(dataDir, "system");
+        mSystemDir.mkdirs();
+        FileUtils.setPermissions(mSystemDir.toString(),
                 FileUtils.S_IRWXU|FileUtils.S_IRWXG
                 |FileUtils.S_IROTH|FileUtils.S_IXOTH,
                 -1, -1);
-        mSettingsFilename = new File(systemDir, "packages.xml");
-        mBackupSettingsFilename = new File(systemDir, "packages-backup.xml");
-        mPackageListFilename = new File(systemDir, "packages.list");
-        mStoppedPackagesFilename = new File(systemDir, "packages-stopped.xml");
-        mBackupStoppedPackagesFilename = new File(systemDir, "packages-stopped-backup.xml");
+        mSettingsFilename = new File(mSystemDir, "packages.xml");
+        mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
+        mPackageListFilename = new File(mSystemDir, "packages.list");
+        // Deprecated: Needed for migration
+        mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
+        mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
     }
 
     PackageSetting getPackageLPw(PackageParser.Package pkg, PackageSetting origPackage,
@@ -254,7 +275,7 @@
             p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
         }
         PackageSetting ret = addPackageLPw(name, p.realName, p.codePath, p.resourcePath,
-                p.nativeLibraryPathString, p.userId, p.versionCode, p.pkgFlags);
+                p.nativeLibraryPathString, p.uid, p.versionCode, p.pkgFlags);
         mDisabledSysPackages.remove(name);
         return ret;
     }
@@ -263,7 +284,7 @@
             String nativeLibraryPathString, int uid, int vc, int pkgFlags) {
         PackageSetting p = mPackages.get(name);
         if (p != null) {
-            if (p.userId == uid) {
+            if (p.uid == uid) {
                 return p;
             }
             PackageManagerService.reportSettingsProblem(Log.ERROR,
@@ -272,7 +293,7 @@
         }
         p = new PackageSetting(name, realName, codePath, resourcePath, nativeLibraryPathString,
                 vc, pkgFlags);
-        p.userId = uid;
+        p.uid = uid;
         if (addUserIdLPw(uid, p, name)) {
             mPackages.put(name, p);
             return p;
@@ -323,7 +344,7 @@
             }
         }
     }
-    
+
     private PackageSetting getPackageLPw(String name, PackageSetting origPackage,
             String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
             String nativeLibraryPathString, int vc, int pkgFlags, boolean create, boolean add) {
@@ -335,13 +356,13 @@
                     // This is an updated system app with versions in both system
                     // and data partition. Just let the most recent version
                     // take precedence.
-                    Slog.w(PackageManagerService.TAG, "Trying to update system app code path from " +
-                            p.codePathString + " to " + codePath.toString());
+                    Slog.w(PackageManagerService.TAG, "Trying to update system app code path from "
+                            + p.codePathString + " to " + codePath.toString());
                 } else {
                     // Just a change in the code path is not an issue, but
                     // let's log a message about it.
-                    Slog.i(PackageManagerService.TAG, "Package " + name + " codePath changed from " + p.codePath
-                            + " to " + codePath + "; Retaining data and using new");
+                    Slog.i(PackageManagerService.TAG, "Package " + name + " codePath changed from "
+                            + p.codePath + " to " + codePath + "; Retaining data and using new");
                     /*
                      * Since we've changed paths, we need to prefer the new
                      * native library path over the one stored in the
@@ -378,15 +399,15 @@
                 // We are consuming the data from an existing package.
                 p = new PackageSetting(origPackage.name, name, codePath, resourcePath,
                         nativeLibraryPathString, vc, pkgFlags);
-                if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package " + name
-                        + " is adopting original package " + origPackage.name);
+                if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package "
+                        + name + " is adopting original package " + origPackage.name);
                 // Note that we will retain the new package's signature so
                 // that we can keep its data.
                 PackageSignatures s = p.signatures;
                 p.copyFrom(origPackage);
                 p.signatures = s;
                 p.sharedUser = origPackage.sharedUser;
-                p.userId = origPackage.userId;
+                p.uid = origPackage.uid;
                 p.origPackage = origPackage;
                 mRenamedPackages.put(name, origPackage.name);
                 name = origPackage.name;
@@ -404,11 +425,17 @@
                         e.fillInStackTrace();
                         Slog.i(PackageManagerService.TAG, "Stopping package " + name, e);
                     }
-                    p.stopped = true;
-                    p.notLaunched = true;
+                    List<UserInfo> users = getAllUsers();
+                    if (users != null) {
+                        for (UserInfo user : users) {
+                            p.setStopped(true, user.id);
+                            p.setNotLaunched(true, user.id);
+                            writePackageRestrictionsLPr(user.id);
+                        }
+                    }
                 }
                 if (sharedUser != null) {
-                    p.userId = sharedUser.userId;
+                    p.uid = sharedUser.userId;
                 } else {
                     // Clone the setting here for disabled system packages
                     PackageSetting dis = mDisabledSysPackages.get(name);
@@ -420,21 +447,31 @@
                         if (dis.signatures.mSignatures != null) {
                             p.signatures.mSignatures = dis.signatures.mSignatures.clone();
                         }
-                        p.userId = dis.userId;
+                        p.uid = dis.uid;
                         // Clone permissions
                         p.grantedPermissions = new HashSet<String>(dis.grantedPermissions);
                         // Clone component info
-                        p.disabledComponents = new HashSet<String>(dis.disabledComponents);
-                        p.enabledComponents = new HashSet<String>(dis.enabledComponents);
+                        List<UserInfo> users = getAllUsers();
+                        if (users != null) {
+                            for (UserInfo user : users) {
+                                int userId = user.id;
+                                p.setDisabledComponents(
+                                        new HashSet<String>(dis.getDisabledComponents(userId)),
+                                        userId);
+                                p.setEnabledComponents(
+                                        new HashSet<String>(dis.getEnabledComponents(userId)),
+                                        userId);
+                            }
+                        }
                         // Add new setting to list of user ids
-                        addUserIdLPw(p.userId, p, name);
+                        addUserIdLPw(p.uid, p, name);
                     } else {
                         // Assign new user id
-                        p.userId = newUserIdLPw(p);
+                        p.uid = newUserIdLPw(p);
                     }
                 }
             }
-            if (p.userId < 0) {
+            if (p.uid < 0) {
                 PackageManagerService.reportSettingsProblem(Log.WARN,
                         "Package " + name + " could not be assigned a valid uid");
                 return null;
@@ -450,8 +487,8 @@
 
     void insertPackageSettingLPw(PackageSetting p, PackageParser.Package pkg) {
         p.pkg = pkg;
-        pkg.mSetEnabled = p.enabled;
-        pkg.mSetStopped = p.stopped;
+        // pkg.mSetEnabled = p.getEnabled(userId);
+        // pkg.mSetStopped = p.getStopped(userId);
         final String codePath = pkg.applicationInfo.sourceDir;
         final String resourcePath = pkg.applicationInfo.publicSourceDir;
         // Update code path if needed
@@ -475,18 +512,18 @@
             p.nativeLibraryPathString = nativeLibraryPath;
         }
         // Update version code if needed
-         if (pkg.mVersionCode != p.versionCode) {
+        if (pkg.mVersionCode != p.versionCode) {
             p.versionCode = pkg.mVersionCode;
         }
-         // Update signatures if needed.
-         if (p.signatures.mSignatures == null) {
-             p.signatures.assignSignatures(pkg.mSignatures);
-         }
-         // If this app defines a shared user id initialize
-         // the shared user signatures as well.
-         if (p.sharedUser != null && p.sharedUser.signatures.mSignatures == null) {
-             p.sharedUser.signatures.assignSignatures(pkg.mSignatures);
-         }
+        // Update signatures if needed.
+        if (p.signatures.mSignatures == null) {
+            p.signatures.assignSignatures(pkg.mSignatures);
+        }
+        // If this app defines a shared user id initialize
+        // the shared user signatures as well.
+        if (p.sharedUser != null && p.sharedUser.signatures.mSignatures == null) {
+            p.sharedUser.signatures.assignSignatures(pkg.mSignatures);
+        }
         addPackageSettingLPw(p, pkg.packageName, p.sharedUser);
     }
 
@@ -502,9 +539,9 @@
                         + p.sharedUser + " but is now " + sharedUser
                         + "; I am not changing its files so it will probably fail!");
                 p.sharedUser.packages.remove(p);
-            } else if (p.userId != sharedUser.userId) {
+            } else if (p.uid != sharedUser.userId) {
                 PackageManagerService.reportSettingsProblem(Log.ERROR,
-                    "Package " + p.name + " was user id " + p.userId
+                    "Package " + p.name + " was user id " + p.uid
                     + " but is now user " + sharedUser
                     + " with id " + sharedUser.userId
                     + "; I am not changing its files so it will probably fail!");
@@ -512,7 +549,7 @@
 
             sharedUser.packages.add(p);
             p.sharedUser = sharedUser;
-            p.userId = sharedUser.userId;
+            p.uid = sharedUser.userId;
         }
     }
 
@@ -577,8 +614,8 @@
                     return p.sharedUser.userId;
                 }
             } else {
-                removeUserIdLPw(p.userId);
-                return p.userId;
+                removeUserIdLPw(p.uid);
+                return p.uid;
             }
         }
         return -1;
@@ -591,7 +628,7 @@
                 p.sharedUser.packages.remove(p);
                 p.sharedUser.packages.add(newp);
             } else {
-                replaceUserIdLPw(p.userId, newp);
+                replaceUserIdLPw(p.uid, newp);
             }
         }
         mPackages.put(name, newp);
@@ -658,50 +695,269 @@
         }
     }
 
-    void writeStoppedLPr() {
+    private File getUserPackagesStateFile(int userId) {
+        return new File(mSystemDir,
+                "users/" + userId + "/package-restrictions.xml");
+    }
+
+    private File getUserPackagesStateBackupFile(int userId) {
+        return new File(mSystemDir,
+                "users/" + userId + "/package-restrictions-backup.xml");
+    }
+
+    void writeAllUsersPackageRestrictionsLPr() {
+        List<UserInfo> users = getAllUsers();
+        if (users == null) return;
+
+        for (UserInfo user : users) {
+            writePackageRestrictionsLPr(user.id);
+        }
+    }
+
+    void readAllUsersPackageRestrictionsLPr() {
+        List<UserInfo> users = getAllUsers();
+        if (users == null) {
+            readPackageRestrictionsLPr(0);
+            return;
+        }
+
+        for (UserInfo user : users) {
+            readPackageRestrictionsLPr(user.id);
+        }
+    }
+
+    void readPackageRestrictionsLPr(int userId) {
+        FileInputStream str = null;
+        File userPackagesStateFile = getUserPackagesStateFile(userId);
+        File backupFile = getUserPackagesStateBackupFile(userId);
+        if (backupFile.exists()) {
+            try {
+                str = new FileInputStream(backupFile);
+                mReadMessages.append("Reading from backup stopped packages file\n");
+                PackageManagerService.reportSettingsProblem(Log.INFO,
+                        "Need to read from backup stopped packages file");
+                if (userPackagesStateFile.exists()) {
+                    // If both the backup and normal file exist, we
+                    // ignore the normal one since it might have been
+                    // corrupted.
+                    Slog.w(PackageManagerService.TAG, "Cleaning up stopped packages file "
+                            + userPackagesStateFile);
+                    userPackagesStateFile.delete();
+                }
+            } catch (java.io.IOException e) {
+                // We'll try for the normal settings file.
+            }
+        }
+
+        try {
+            if (str == null) {
+                if (!userPackagesStateFile.exists()) {
+                    mReadMessages.append("No stopped packages file found\n");
+                    PackageManagerService.reportSettingsProblem(Log.INFO,
+                            "No stopped packages file; "
+                            + "assuming all started");
+                    // At first boot, make sure no packages are stopped.
+                    // We usually want to have third party apps initialize
+                    // in the stopped state, but not at first boot.
+                    for (PackageSetting pkg : mPackages.values()) {
+                        pkg.setStopped(false, userId);
+                        pkg.setNotLaunched(false, userId);
+                    }
+                    return;
+                }
+                str = new FileInputStream(userPackagesStateFile);
+            }
+            final XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(str, null);
+
+            int type;
+            while ((type=parser.next()) != XmlPullParser.START_TAG
+                       && type != XmlPullParser.END_DOCUMENT) {
+                ;
+            }
+
+            if (type != XmlPullParser.START_TAG) {
+                mReadMessages.append("No start tag found in package restrictions file\n");
+                PackageManagerService.reportSettingsProblem(Log.WARN,
+                        "No start tag found in package manager stopped packages");
+                return;
+            }
+
+            int outerDepth = parser.getDepth();
+            PackageSetting ps = null;
+            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+                   && (type != XmlPullParser.END_TAG
+                           || parser.getDepth() > outerDepth)) {
+                if (type == XmlPullParser.END_TAG
+                        || type == XmlPullParser.TEXT) {
+                    continue;
+                }
+
+                String tagName = parser.getName();
+                if (tagName.equals(TAG_PACKAGE)) {
+                    String name = parser.getAttributeValue(null, ATTR_NAME);
+                    ps = mPackages.get(name);
+                    if (ps == null) {
+                        Slog.w(PackageManagerService.TAG, "No package known for stopped package: "
+                                + name);
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    }
+                    String enabledStr = parser.getAttributeValue(null, ATTR_ENABLED);
+                    int enabled = enabledStr == null ? COMPONENT_ENABLED_STATE_DEFAULT
+                            : Integer.parseInt(enabledStr);
+                    ps.setEnabled(enabled, userId);
+                    String stoppedStr = parser.getAttributeValue(null, ATTR_STOPPED);
+                    boolean stopped = stoppedStr == null ? false : Boolean.parseBoolean(stoppedStr);
+                    ps.setStopped(stopped, userId);
+                    String notLaunchedStr = parser.getAttributeValue(null, ATTR_NOT_LAUNCHED);
+                    boolean notLaunched = stoppedStr == null ? false
+                            : Boolean.parseBoolean(notLaunchedStr);
+                    ps.setNotLaunched(notLaunched, userId);
+
+                    int packageDepth = parser.getDepth();
+                    while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+                            && (type != XmlPullParser.END_TAG
+                            || parser.getDepth() > packageDepth)) {
+                        if (type == XmlPullParser.END_TAG
+                                || type == XmlPullParser.TEXT) {
+                            continue;
+                        }
+                        tagName = parser.getName();
+                        if (tagName.equals(TAG_ENABLED_COMPONENTS)) {
+                            HashSet<String> components = readComponentsLPr(parser);
+                            ps.setEnabledComponents(components, userId);
+                        } else if (tagName.equals(TAG_DISABLED_COMPONENTS)) {
+                            HashSet<String> components = readComponentsLPr(parser);
+                            ps.setDisabledComponents(components, userId);
+                        }
+                    }
+                } else {
+                    Slog.w(PackageManagerService.TAG, "Unknown element under <stopped-packages>: "
+                          + parser.getName());
+                    XmlUtils.skipCurrentTag(parser);
+                }
+            }
+
+            str.close();
+
+        } catch (XmlPullParserException e) {
+            mReadMessages.append("Error reading: " + e.toString());
+            PackageManagerService.reportSettingsProblem(Log.ERROR,
+                    "Error reading stopped packages: " + e);
+            Log.wtf(PackageManagerService.TAG, "Error reading package manager stopped packages", e);
+
+        } catch (java.io.IOException e) {
+            mReadMessages.append("Error reading: " + e.toString());
+            PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
+            Log.wtf(PackageManagerService.TAG, "Error reading package manager stopped packages", e);
+        }
+    }
+
+    private HashSet<String> readComponentsLPr(XmlPullParser parser)
+            throws IOException, XmlPullParserException {
+        HashSet<String> components = new HashSet<String>();
+        int type;
+        int outerDepth = parser.getDepth();
+        String tagName;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG
+                || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG
+                    || type == XmlPullParser.TEXT) {
+                continue;
+            }
+            tagName = parser.getName();
+            if (tagName.equals(TAG_ITEM)) {
+                String componentName = parser.getAttributeValue(null, ATTR_NAME);
+                if (componentName != null) {
+                    components.add(componentName);
+                }
+            }
+        }
+        return components;
+    }
+
+    void writePackageRestrictionsLPr(int userId) {
         // Keep the old stopped packages around until we know the new ones have
         // been successfully written.
-        if (mStoppedPackagesFilename.exists()) {
+        File userPackagesStateFile = getUserPackagesStateFile(userId);
+        File backupFile = getUserPackagesStateBackupFile(userId);
+        new File(userPackagesStateFile.getParent()).mkdirs();
+        if (userPackagesStateFile.exists()) {
             // Presence of backup settings file indicates that we failed
             // to persist packages earlier. So preserve the older
             // backup for future reference since the current packages
             // might have been corrupted.
-            if (!mBackupStoppedPackagesFilename.exists()) {
-                if (!mStoppedPackagesFilename.renameTo(mBackupStoppedPackagesFilename)) {
-                    Log.wtf(PackageManagerService.TAG, "Unable to backup package manager stopped packages, "
+            if (!backupFile.exists()) {
+                if (!userPackagesStateFile.renameTo(backupFile)) {
+                    Log.wtf(PackageManagerService.TAG, "Unable to backup user packages state file, "
                             + "current changes will be lost at reboot");
                     return;
                 }
             } else {
-                mStoppedPackagesFilename.delete();
+                userPackagesStateFile.delete();
                 Slog.w(PackageManagerService.TAG, "Preserving older stopped packages backup");
             }
         }
 
         try {
-            final FileOutputStream fstr = new FileOutputStream(mStoppedPackagesFilename);
+            final FileOutputStream fstr = new FileOutputStream(userPackagesStateFile);
             final BufferedOutputStream str = new BufferedOutputStream(fstr);
 
-            //XmlSerializer serializer = XmlUtils.serializerInstance();
             final XmlSerializer serializer = new FastXmlSerializer();
             serializer.setOutput(str, "utf-8");
             serializer.startDocument(null, true);
             serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
 
-            serializer.startTag(null, "stopped-packages");
+            serializer.startTag(null, TAG_PACKAGE_RESTRICTIONS);
 
             for (final PackageSetting pkg : mPackages.values()) {
-                if (pkg.stopped) {
-                    serializer.startTag(null, "pkg");
-                    serializer.attribute(null, "name", pkg.name);
-                    if (pkg.notLaunched) {
-                        serializer.attribute(null, "nl", "1");
+                if (pkg.getStopped(userId)
+                        || pkg.getNotLaunched(userId)
+                        || pkg.getEnabled(userId) != COMPONENT_ENABLED_STATE_DEFAULT
+                        || pkg.getEnabledComponents(userId).size() > 0
+                        || pkg.getDisabledComponents(userId).size() > 0) {
+                    serializer.startTag(null, TAG_PACKAGE);
+                    serializer.attribute(null, ATTR_NAME, pkg.name);
+                    boolean stopped = pkg.getStopped(userId);
+                    boolean notLaunched = pkg.getNotLaunched(userId);
+                    int enabled = pkg.getEnabled(userId);
+                    HashSet<String> enabledComponents = pkg.getEnabledComponents(userId);
+                    HashSet<String> disabledComponents = pkg.getDisabledComponents(userId);
+
+                    if (stopped) {
+                        serializer.attribute(null, ATTR_STOPPED, "true");
                     }
-                    serializer.endTag(null, "pkg");
+                    if (notLaunched) {
+                        serializer.attribute(null, ATTR_NOT_LAUNCHED, "true");
+                    }
+                    if (enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
+                        serializer.attribute(null, ATTR_ENABLED, Integer.toString(enabled));
+                    }
+                    if (enabledComponents.size() > 0) {
+                        serializer.startTag(null, TAG_ENABLED_COMPONENTS);
+                        for (final String name : enabledComponents) {
+                            serializer.startTag(null, TAG_ITEM);
+                            serializer.attribute(null, ATTR_NAME, name);
+                            serializer.endTag(null, TAG_ITEM);
+                        }
+                        serializer.endTag(null, TAG_ENABLED_COMPONENTS);
+                    }
+                    if (disabledComponents.size() > 0) {
+                        serializer.startTag(null, TAG_DISABLED_COMPONENTS);
+                        for (final String name : disabledComponents) {
+                            serializer.startTag(null, TAG_ITEM);
+                            serializer.attribute(null, ATTR_NAME, name);
+                            serializer.endTag(null, TAG_ITEM);
+                        }
+                        serializer.endTag(null, TAG_DISABLED_COMPONENTS);
+                    }
+                    serializer.endTag(null, TAG_PACKAGE);
                 }
             }
 
-            serializer.endTag(null, "stopped-packages");
+            serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS);
 
             serializer.endDocument();
 
@@ -711,8 +967,8 @@
 
             // New settings successfully written, old ones are no longer
             // needed.
-            mBackupStoppedPackagesFilename.delete();
-            FileUtils.setPermissions(mStoppedPackagesFilename.toString(),
+            backupFile.delete();
+            FileUtils.setPermissions(userPackagesStateFile.toString(),
                     FileUtils.S_IRUSR|FileUtils.S_IWUSR
                     |FileUtils.S_IRGRP|FileUtils.S_IWGRP,
                     -1, -1);
@@ -720,26 +976,30 @@
             // Done, all is good!
             return;
         } catch(java.io.IOException e) {
-            Log.wtf(PackageManagerService.TAG, "Unable to write package manager stopped packages, "
+            Log.wtf(PackageManagerService.TAG,
+                    "Unable to write package manager user packages state, "
                     + " current changes will be lost at reboot", e);
         }
 
         // Clean up partially written files
-        if (mStoppedPackagesFilename.exists()) {
-            if (!mStoppedPackagesFilename.delete()) {
-                Log.i(PackageManagerService.TAG, "Failed to clean up mangled file: " + mStoppedPackagesFilename);
+        if (userPackagesStateFile.exists()) {
+            if (!userPackagesStateFile.delete()) {
+                Log.i(PackageManagerService.TAG, "Failed to clean up mangled file: "
+                        + mStoppedPackagesFilename);
             }
         }
     }
 
     // Note: assumed "stopped" field is already cleared in all packages.
+    // Legacy reader, used to read in the old file format after an upgrade. Not used after that.
     void readStoppedLPw() {
         FileInputStream str = null;
         if (mBackupStoppedPackagesFilename.exists()) {
             try {
                 str = new FileInputStream(mBackupStoppedPackagesFilename);
                 mReadMessages.append("Reading from backup stopped packages file\n");
-                PackageManagerService.reportSettingsProblem(Log.INFO, "Need to read from backup stopped packages file");
+                PackageManagerService.reportSettingsProblem(Log.INFO,
+                        "Need to read from backup stopped packages file");
                 if (mSettingsFilename.exists()) {
                     // If both the backup and normal file exist, we
                     // ignore the normal one since it might have been
@@ -757,14 +1017,14 @@
             if (str == null) {
                 if (!mStoppedPackagesFilename.exists()) {
                     mReadMessages.append("No stopped packages file found\n");
-                    PackageManagerService.reportSettingsProblem(Log.INFO, "No stopped packages file file; "
-                            + "assuming all started");
+                    PackageManagerService.reportSettingsProblem(Log.INFO,
+                            "No stopped packages file file; assuming all started");
                     // At first boot, make sure no packages are stopped.
                     // We usually want to have third party apps initialize
                     // in the stopped state, but not at first boot.
                     for (PackageSetting pkg : mPackages.values()) {
-                        pkg.stopped = false;
-                        pkg.notLaunched = false;
+                        pkg.setStopped(false, 0);
+                        pkg.setNotLaunched(false, 0);
                     }
                     return;
                 }
@@ -796,16 +1056,17 @@
                 }
 
                 String tagName = parser.getName();
-                if (tagName.equals("pkg")) {
-                    String name = parser.getAttributeValue(null, "name");
+                if (tagName.equals(TAG_PACKAGE)) {
+                    String name = parser.getAttributeValue(null, ATTR_NAME);
                     PackageSetting ps = mPackages.get(name);
                     if (ps != null) {
-                        ps.stopped = true;
-                        if ("1".equals(parser.getAttributeValue(null, "nl"))) {
-                            ps.notLaunched = true;
+                        ps.setStopped(true, 0);
+                        if ("1".equals(parser.getAttributeValue(null, ATTR_NOT_LAUNCHED))) {
+                            ps.setNotLaunched(true, 0);
                         }
                     } else {
-                        Slog.w(PackageManagerService.TAG, "No package known for stopped package: " + name);
+                        Slog.w(PackageManagerService.TAG,
+                                "No package known for stopped package: " + name);
                     }
                     XmlUtils.skipCurrentTag(parser);
                 } else {
@@ -817,12 +1078,13 @@
 
             str.close();
 
-        } catch(XmlPullParserException e) {
+        } catch (XmlPullParserException e) {
             mReadMessages.append("Error reading: " + e.toString());
-            PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading stopped packages: " + e);
+            PackageManagerService.reportSettingsProblem(Log.ERROR,
+                    "Error reading stopped packages: " + e);
             Log.wtf(PackageManagerService.TAG, "Error reading package manager stopped packages", e);
 
-        } catch(java.io.IOException e) {
+        } catch (java.io.IOException e) {
             mReadMessages.append("Error reading: " + e.toString());
             PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
             Log.wtf(PackageManagerService.TAG, "Error reading package manager stopped packages", e);
@@ -906,23 +1168,23 @@
 
             serializer.startTag(null, "preferred-activities");
             for (final PreferredActivity pa : mPreferredActivities.filterSet()) {
-                serializer.startTag(null, "item");
+                serializer.startTag(null, TAG_ITEM);
                 pa.writeToXml(serializer);
-                serializer.endTag(null, "item");
+                serializer.endTag(null, TAG_ITEM);
             }
             serializer.endTag(null, "preferred-activities");
 
             for (final SharedUserSetting usr : mSharedUsers.values()) {
                 serializer.startTag(null, "shared-user");
-                serializer.attribute(null, "name", usr.name);
+                serializer.attribute(null, ATTR_NAME, usr.name);
                 serializer.attribute(null, "userId",
                         Integer.toString(usr.userId));
                 usr.signatures.writeXml(serializer, "sigs", mPastSignatures);
                 serializer.startTag(null, "perms");
                 for (String name : usr.grantedPermissions) {
-                    serializer.startTag(null, "item");
-                    serializer.attribute(null, "name", name);
-                    serializer.endTag(null, "item");
+                    serializer.startTag(null, TAG_ITEM);
+                    serializer.attribute(null, ATTR_NAME, name);
+                    serializer.endTag(null, TAG_ITEM);
                 }
                 serializer.endTag(null, "perms");
                 serializer.endTag(null, "shared-user");
@@ -931,7 +1193,7 @@
             if (mPackagesToBeCleaned.size() > 0) {
                 for (int i=0; i<mPackagesToBeCleaned.size(); i++) {
                     serializer.startTag(null, "cleaning-package");
-                    serializer.attribute(null, "name", mPackagesToBeCleaned.get(i));
+                    serializer.attribute(null, ATTR_NAME, mPackagesToBeCleaned.get(i));
                     serializer.endTag(null, "cleaning-package");
                 }
             }
@@ -1016,8 +1278,7 @@
                     |FileUtils.S_IRGRP|FileUtils.S_IWGRP,
                     -1, -1);
 
-            writeStoppedLPr();
-
+            writeAllUsersPackageRestrictionsLPr();
             return;
 
         } catch(XmlPullParserException e) {
@@ -1030,7 +1291,8 @@
         // Clean up partially written files
         if (mSettingsFilename.exists()) {
             if (!mSettingsFilename.delete()) {
-                Log.wtf(PackageManagerService.TAG, "Failed to clean up mangled file: " + mSettingsFilename);
+                Log.wtf(PackageManagerService.TAG, "Failed to clean up mangled file: "
+                        + mSettingsFilename);
             }
         }
         //Debug.stopMethodTracing();
@@ -1039,7 +1301,7 @@
     void writeDisabledSysPackageLPr(XmlSerializer serializer, final PackageSetting pkg)
             throws java.io.IOException {
         serializer.startTag(null, "updated-package");
-        serializer.attribute(null, "name", pkg.name);
+        serializer.attribute(null, ATTR_NAME, pkg.name);
         if (pkg.realName != null) {
             serializer.attribute(null, "realName", pkg.realName);
         }
@@ -1055,9 +1317,9 @@
             serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString);
         }
         if (pkg.sharedUser == null) {
-            serializer.attribute(null, "userId", Integer.toString(pkg.userId));
+            serializer.attribute(null, "userId", Integer.toString(pkg.uid));
         } else {
-            serializer.attribute(null, "sharedUserId", Integer.toString(pkg.userId));
+            serializer.attribute(null, "sharedUserId", Integer.toString(pkg.uid));
         }
         serializer.startTag(null, "perms");
         if (pkg.sharedUser == null) {
@@ -1072,9 +1334,9 @@
                     // this wont
                     // match the semantics of grantedPermissions. So write all
                     // permissions.
-                    serializer.startTag(null, "item");
-                    serializer.attribute(null, "name", name);
-                    serializer.endTag(null, "item");
+                    serializer.startTag(null, TAG_ITEM);
+                    serializer.attribute(null, ATTR_NAME, name);
+                    serializer.endTag(null, TAG_ITEM);
                 }
             }
         }
@@ -1085,7 +1347,7 @@
     void writePackageLPr(XmlSerializer serializer, final PackageSetting pkg)
             throws java.io.IOException {
         serializer.startTag(null, "package");
-        serializer.attribute(null, "name", pkg.name);
+        serializer.attribute(null, ATTR_NAME, pkg.name);
         if (pkg.realName != null) {
             serializer.attribute(null, "realName", pkg.realName);
         }
@@ -1102,16 +1364,13 @@
         serializer.attribute(null, "ut", Long.toHexString(pkg.lastUpdateTime));
         serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
         if (pkg.sharedUser == null) {
-            serializer.attribute(null, "userId", Integer.toString(pkg.userId));
+            serializer.attribute(null, "userId", Integer.toString(pkg.uid));
         } else {
-            serializer.attribute(null, "sharedUserId", Integer.toString(pkg.userId));
+            serializer.attribute(null, "sharedUserId", Integer.toString(pkg.uid));
         }
         if (pkg.uidError) {
             serializer.attribute(null, "uidError", "true");
         }
-        if (pkg.enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
-            serializer.attribute(null, "enabled", Integer.toString(pkg.enabled));
-        }
         if (pkg.installStatus == PackageSettingBase.PKG_INSTALL_INCOMPLETE) {
             serializer.attribute(null, "installStatus", "false");
         }
@@ -1127,31 +1386,13 @@
                 // empty permissions list so permissionsFixed will
                 // be set.
                 for (final String name : pkg.grantedPermissions) {
-                    serializer.startTag(null, "item");
-                    serializer.attribute(null, "name", name);
-                    serializer.endTag(null, "item");
+                    serializer.startTag(null, TAG_ITEM);
+                    serializer.attribute(null, ATTR_NAME, name);
+                    serializer.endTag(null, TAG_ITEM);
                 }
             }
             serializer.endTag(null, "perms");
         }
-        if (pkg.disabledComponents.size() > 0) {
-            serializer.startTag(null, "disabled-components");
-            for (final String name : pkg.disabledComponents) {
-                serializer.startTag(null, "item");
-                serializer.attribute(null, "name", name);
-                serializer.endTag(null, "item");
-            }
-            serializer.endTag(null, "disabled-components");
-        }
-        if (pkg.enabledComponents.size() > 0) {
-            serializer.startTag(null, "enabled-components");
-            for (final String name : pkg.enabledComponents) {
-                serializer.startTag(null, "item");
-                serializer.attribute(null, "name", name);
-                serializer.endTag(null, "item");
-            }
-            serializer.endTag(null, "enabled-components");
-        }
 
         serializer.endTag(null, "package");
     }
@@ -1159,8 +1400,8 @@
     void writePermissionLPr(XmlSerializer serializer, BasePermission bp)
             throws XmlPullParserException, java.io.IOException {
         if (bp.type != BasePermission.TYPE_BUILTIN && bp.sourcePackage != null) {
-            serializer.startTag(null, "item");
-            serializer.attribute(null, "name", bp.name);
+            serializer.startTag(null, TAG_ITEM);
+            serializer.attribute(null, ATTR_NAME, bp.name);
             serializer.attribute(null, "package", bp.sourcePackage);
             if (bp.protectionLevel != PermissionInfo.PROTECTION_NORMAL) {
                 serializer.attribute(null, "protection", Integer.toString(bp.protectionLevel));
@@ -1180,7 +1421,7 @@
                     }
                 }
             }
-            serializer.endTag(null, "item");
+            serializer.endTag(null, TAG_ITEM);
         }
     }
 
@@ -1198,7 +1439,7 @@
         return ret;
     }
 
-    boolean readLPw() {
+    boolean readLPw(List<UserInfo> users) {
         FileInputStream str = null;
         if (mBackupSettingsFilename.exists()) {
             try {
@@ -1273,7 +1514,7 @@
                 } else if (tagName.equals("updated-package")) {
                     readDisabledSysPackageLPw(parser);
                 } else if (tagName.equals("cleaning-package")) {
-                    String name = parser.getAttributeValue(null, "name");
+                    String name = parser.getAttributeValue(null, ATTR_NAME);
                     if (name != null) {
                         mPackagesToBeCleaned.add(name);
                     }
@@ -1366,14 +1607,29 @@
         final Iterator<PackageSetting> disabledIt = mDisabledSysPackages.values().iterator();
         while (disabledIt.hasNext()) {
             final PackageSetting disabledPs = disabledIt.next();
-            final Object id = getUserIdLPr(disabledPs.userId);
+            final Object id = getUserIdLPr(disabledPs.uid);
             if (id != null && id instanceof SharedUserSetting) {
                 disabledPs.sharedUser = (SharedUserSetting) id;
             }
         }
 
-        readStoppedLPw();
-
+        if (mBackupStoppedPackagesFilename.exists()
+                || mStoppedPackagesFilename.exists()) {
+            // Read old file
+            readStoppedLPw();
+            mBackupStoppedPackagesFilename.delete();
+            mStoppedPackagesFilename.delete();
+            // Migrate to new file format
+            writePackageRestrictionsLPr(0);
+        } else {
+            if (users == null) {
+                readPackageRestrictionsLPr(0);
+            } else {
+                for (UserInfo user : users) {
+                    readPackageRestrictionsLPr(user.id);
+                }
+            }
+        }
         mReadMessages.append("Read completed successfully: " + mPackages.size() + " packages, "
                 + mSharedUsers.size() + " shared uids\n");
 
@@ -1407,8 +1663,8 @@
             }
 
             final String tagName = parser.getName();
-            if (tagName.equals("item")) {
-                final String name = parser.getAttributeValue(null, "name");
+            if (tagName.equals(TAG_ITEM)) {
+                final String name = parser.getAttributeValue(null, ATTR_NAME);
                 final String sourcePackage = parser.getAttributeValue(null, "package");
                 final String ptype = parser.getAttributeValue(null, "type");
                 if (name != null && sourcePackage != null) {
@@ -1444,7 +1700,7 @@
 
     private void readDisabledSysPackageLPw(XmlPullParser parser) throws XmlPullParserException,
             IOException {
-        String name = parser.getAttributeValue(null, "name");
+        String name = parser.getAttributeValue(null, ATTR_NAME);
         String realName = parser.getAttributeValue(null, "realName");
         String codePathStr = parser.getAttributeValue(null, "codePath");
         String resourcePathStr = parser.getAttributeValue(null, "resourcePath");
@@ -1497,10 +1753,10 @@
             }
         }
         String idStr = parser.getAttributeValue(null, "userId");
-        ps.userId = idStr != null ? Integer.parseInt(idStr) : 0;
-        if (ps.userId <= 0) {
+        ps.uid = idStr != null ? Integer.parseInt(idStr) : 0;
+        if (ps.uid <= 0) {
             String sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
-            ps.userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
+            ps.uid = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
         }
         int outerDepth = parser.getDepth();
         int type;
@@ -1541,7 +1797,7 @@
         String version = null;
         int versionCode = 0;
         try {
-            name = parser.getAttributeValue(null, "name");
+            name = parser.getAttributeValue(null, ATTR_NAME);
             realName = parser.getAttributeValue(null, "realName");
             idStr = parser.getAttributeValue(null, "userId");
             uidError = parser.getAttributeValue(null, "uidError");
@@ -1672,17 +1928,18 @@
             packageSetting.uidError = "true".equals(uidError);
             packageSetting.installerPackageName = installerPackageName;
             packageSetting.nativeLibraryPathString = nativeLibraryPathStr;
-            final String enabledStr = parser.getAttributeValue(null, "enabled");
+            // Handle legacy string here for single-user mode
+            final String enabledStr = parser.getAttributeValue(null, ATTR_ENABLED);
             if (enabledStr != null) {
                 try {
-                    packageSetting.enabled = Integer.parseInt(enabledStr);
+                    packageSetting.setEnabled(Integer.parseInt(enabledStr), 0 /* userId */);
                 } catch (NumberFormatException e) {
                     if (enabledStr.equalsIgnoreCase("true")) {
-                        packageSetting.enabled = COMPONENT_ENABLED_STATE_ENABLED;
+                        packageSetting.setEnabled(COMPONENT_ENABLED_STATE_ENABLED, 0);
                     } else if (enabledStr.equalsIgnoreCase("false")) {
-                        packageSetting.enabled = COMPONENT_ENABLED_STATE_DISABLED;
+                        packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, 0);
                     } else if (enabledStr.equalsIgnoreCase("default")) {
-                        packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT;
+                        packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, 0);
                     } else {
                         PackageManagerService.reportSettingsProblem(Log.WARN,
                                 "Error in package manager settings: package " + name
@@ -1691,8 +1948,9 @@
                     }
                 }
             } else {
-                packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT;
+                packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, 0);
             }
+
             final String installStatusStr = parser.getAttributeValue(null, "installStatus");
             if (installStatusStr != null) {
                 if (installStatusStr.equalsIgnoreCase("false")) {
@@ -1711,10 +1969,11 @@
                 }
 
                 String tagName = parser.getName();
-                if (tagName.equals("disabled-components")) {
-                    readDisabledComponentsLPw(packageSetting, parser);
-                } else if (tagName.equals("enabled-components")) {
-                    readEnabledComponentsLPw(packageSetting, parser);
+                // Legacy 
+                if (tagName.equals(TAG_DISABLED_COMPONENTS)) {
+                    readDisabledComponentsLPw(packageSetting, parser, 0);
+                } else if (tagName.equals(TAG_ENABLED_COMPONENTS)) {
+                    readEnabledComponentsLPw(packageSetting, parser, 0);
                 } else if (tagName.equals("sigs")) {
                     packageSetting.signatures.readXml(parser, mPastSignatures);
                 } else if (tagName.equals("perms")) {
@@ -1731,8 +1990,8 @@
         }
     }
 
-    private void readDisabledComponentsLPw(PackageSettingBase packageSetting, XmlPullParser parser)
-            throws IOException, XmlPullParserException {
+    private void readDisabledComponentsLPw(PackageSettingBase packageSetting, XmlPullParser parser,
+            int userId) throws IOException, XmlPullParserException {
         int outerDepth = parser.getDepth();
         int type;
         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -1742,10 +2001,10 @@
             }
 
             String tagName = parser.getName();
-            if (tagName.equals("item")) {
-                String name = parser.getAttributeValue(null, "name");
+            if (tagName.equals(TAG_ITEM)) {
+                String name = parser.getAttributeValue(null, ATTR_NAME);
                 if (name != null) {
-                    packageSetting.disabledComponents.add(name.intern());
+                    packageSetting.addDisabledComponent(name.intern(), userId);
                 } else {
                     PackageManagerService.reportSettingsProblem(Log.WARN,
                             "Error in package manager settings: <disabled-components> has"
@@ -1759,8 +2018,8 @@
         }
     }
 
-    private void readEnabledComponentsLPw(PackageSettingBase packageSetting, XmlPullParser parser)
-            throws IOException, XmlPullParserException {
+    private void readEnabledComponentsLPw(PackageSettingBase packageSetting, XmlPullParser parser,
+            int userId) throws IOException, XmlPullParserException {
         int outerDepth = parser.getDepth();
         int type;
         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -1770,10 +2029,10 @@
             }
 
             String tagName = parser.getName();
-            if (tagName.equals("item")) {
-                String name = parser.getAttributeValue(null, "name");
+            if (tagName.equals(TAG_ITEM)) {
+                String name = parser.getAttributeValue(null, ATTR_NAME);
                 if (name != null) {
-                    packageSetting.enabledComponents.add(name.intern());
+                    packageSetting.addEnabledComponent(name.intern(), userId);
                 } else {
                     PackageManagerService.reportSettingsProblem(Log.WARN,
                             "Error in package manager settings: <enabled-components> has"
@@ -1787,13 +2046,13 @@
         }
     }
 
-    private void readSharedUserLPw(XmlPullParser parser) throws XmlPullParserException, IOException {
+    private void readSharedUserLPw(XmlPullParser parser) throws XmlPullParserException,IOException {
         String name = null;
         String idStr = null;
         int pkgFlags = 0;
         SharedUserSetting su = null;
         try {
-            name = parser.getAttributeValue(null, "name");
+            name = parser.getAttributeValue(null, ATTR_NAME);
             idStr = parser.getAttributeValue(null, "userId");
             int userId = idStr != null ? Integer.parseInt(idStr) : 0;
             if ("true".equals(parser.getAttributeValue(null, "system"))) {
@@ -1859,8 +2118,8 @@
             }
 
             String tagName = parser.getName();
-            if (tagName.equals("item")) {
-                String name = parser.getAttributeValue(null, "name");
+            if (tagName.equals(TAG_ITEM)) {
+                String name = parser.getAttributeValue(null, ATTR_NAME);
                 if (name != null) {
                     outPerms.add(name.intern());
                 } else {
@@ -1887,7 +2146,7 @@
             }
 
             String tagName = parser.getName();
-            if (tagName.equals("item")) {
+            if (tagName.equals(TAG_ITEM)) {
                 PreferredActivity pa = new PreferredActivity(parser);
                 if (pa.mPref.getParseError() == null) {
                     mPreferredActivities.addFilter(pa);
@@ -1940,32 +2199,34 @@
         return ps;
     }
 
-    boolean isEnabledLPr(ComponentInfo componentInfo, int flags) {
+    boolean isEnabledLPr(ComponentInfo componentInfo, int flags, int userId) {
         if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
             return true;
         }
-        final PackageSetting packageSettings = mPackages.get(componentInfo.packageName);
+        final String pkgName = componentInfo.packageName;
+        final PackageSetting packageSettings = mPackages.get(pkgName);
         if (PackageManagerService.DEBUG_SETTINGS) {
-            Log.v(PackageManagerService.TAG, "isEnabledLock - packageName = " + componentInfo.packageName
-                       + " componentName = " + componentInfo.name);
+            Log.v(PackageManagerService.TAG, "isEnabledLock - packageName = "
+                    + componentInfo.packageName + " componentName = " + componentInfo.name);
             Log.v(PackageManagerService.TAG, "enabledComponents: "
-                       + Arrays.toString(packageSettings.enabledComponents.toArray()));
+                    + Arrays.toString(packageSettings.getEnabledComponents(userId).toArray()));
             Log.v(PackageManagerService.TAG, "disabledComponents: "
-                       + Arrays.toString(packageSettings.disabledComponents.toArray()));
+                    + Arrays.toString(packageSettings.getDisabledComponents(userId).toArray()));
         }
         if (packageSettings == null) {
             return false;
         }
-        if (packageSettings.enabled == COMPONENT_ENABLED_STATE_DISABLED
-                || packageSettings.enabled == COMPONENT_ENABLED_STATE_DISABLED_USER
+        final int enabled = packageSettings.getEnabled(userId);
+        if (enabled == COMPONENT_ENABLED_STATE_DISABLED
+                || enabled == COMPONENT_ENABLED_STATE_DISABLED_USER
                 || (packageSettings.pkg != null && !packageSettings.pkg.applicationInfo.enabled
-                        && packageSettings.enabled == COMPONENT_ENABLED_STATE_DEFAULT)) {
+                    && enabled == COMPONENT_ENABLED_STATE_DEFAULT)) {
             return false;
         }
-        if (packageSettings.enabledComponents.contains(componentInfo.name)) {
+        if (packageSettings.getEnabledComponents(userId).contains(componentInfo.name)) {
             return true;
         }
-        if (packageSettings.disabledComponents.contains(componentInfo.name)) {
+        if (packageSettings.getDisabledComponents(userId).contains(componentInfo.name)) {
             return false;
         }
         return componentInfo.enabled;
@@ -1979,35 +2240,36 @@
         return pkg.installerPackageName;
     }
 
-    int getApplicationEnabledSettingLPr(String packageName) {
+    int getApplicationEnabledSettingLPr(String packageName, int userId) {
         final PackageSetting pkg = mPackages.get(packageName);
         if (pkg == null) {
             throw new IllegalArgumentException("Unknown package: " + packageName);
         }
-        return pkg.enabled;
+        return pkg.getEnabled(userId);
     }
 
-    int getComponentEnabledSettingLPr(ComponentName componentName) {
+    int getComponentEnabledSettingLPr(ComponentName componentName, int userId) {
         final String packageName = componentName.getPackageName();
         final PackageSetting pkg = mPackages.get(packageName);
         if (pkg == null) {
             throw new IllegalArgumentException("Unknown component: " + componentName);
         }
         final String classNameStr = componentName.getClassName();
-        return pkg.getCurrentEnabledStateLPr(classNameStr);
+        return pkg.getCurrentEnabledStateLPr(classNameStr, userId);
     }
-    
+
     boolean setPackageStoppedStateLPw(String packageName, boolean stopped,
-            boolean allowedByPermission, int uid) {
+            boolean allowedByPermission, int uid, int userId) {
+        int appId = UserId.getAppId(uid);
         final PackageSetting pkgSetting = mPackages.get(packageName);
         if (pkgSetting == null) {
             throw new IllegalArgumentException("Unknown package: " + packageName);
         }
-        if (!allowedByPermission && (uid != pkgSetting.userId)) {
+        if (!allowedByPermission && (appId != pkgSetting.uid)) {
             throw new SecurityException(
                     "Permission Denial: attempt to change stopped state from pid="
                     + Binder.getCallingPid()
-                    + ", uid=" + uid + ", package uid=" + pkgSetting.userId);
+                    + ", uid=" + uid + ", package uid=" + pkgSetting.uid);
         }
         if (DEBUG_STOPPED) {
             if (stopped) {
@@ -2016,22 +2278,33 @@
                 Slog.i(TAG, "Stopping package " + packageName, e);
             }
         }
-        if (pkgSetting.stopped != stopped) {
-            pkgSetting.stopped = stopped;
-            pkgSetting.pkg.mSetStopped = stopped;
-            if (pkgSetting.notLaunched) {
+        if (pkgSetting.getStopped(userId) != stopped) {
+            pkgSetting.setStopped(stopped, userId);
+            // pkgSetting.pkg.mSetStopped = stopped;
+            if (pkgSetting.getNotLaunched(userId)) {
                 if (pkgSetting.installerPackageName != null) {
                     PackageManagerService.sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH,
                             pkgSetting.name, null,
                             pkgSetting.installerPackageName, null);
                 }
-                pkgSetting.notLaunched = false;
+                pkgSetting.setNotLaunched(false, userId);
             }
             return true;
         }
         return false;
     }
 
+    private List<UserInfo> getAllUsers() {
+        try {
+            return AppGlobals.getPackageManager().getUsers();
+        } catch (RemoteException re) {
+            // Local to system process, shouldn't happen
+        } catch (NullPointerException npe) {
+            // packagemanager not yet initialized
+        }
+        return null;
+    }
+
     static final void printFlags(PrintWriter pw, int val, Object[] spec) {
         pw.print("[ ");
         for (int i=0; i<spec.length; i+=2) {
@@ -2096,7 +2369,7 @@
                 pw.println(ps.name);
             }
 
-            pw.print("    userId="); pw.print(ps.userId);
+            pw.print("    userId="); pw.print(ps.uid);
             pw.print(" gids="); pw.println(PackageManagerService.arrayToString(ps.gids));
             pw.print("    sharedUser="); pw.println(ps.sharedUser);
             pw.print("    pkg="); pw.println(ps.pkg);
@@ -2169,18 +2442,24 @@
             pw.print(" haveGids="); pw.println(ps.haveGids);
             pw.print("    pkgFlags=0x"); pw.print(Integer.toHexString(ps.pkgFlags));
             pw.print(" installStatus="); pw.print(ps.installStatus);
-            pw.print(" stopped="); pw.print(ps.stopped);
-            pw.print(" enabled="); pw.println(ps.enabled);
-            if (ps.disabledComponents.size() > 0) {
-                pw.println("    disabledComponents:");
-                for (String s : ps.disabledComponents) {
-                    pw.print("      "); pw.println(s);
+            List<UserInfo> users = getAllUsers();
+            for (UserInfo user : users) {
+                pw.print(" User "); pw.print(user.id); pw.print(": ");
+                pw.print(" stopped=");
+                pw.print(ps.getStopped(user.id));
+                pw.print(" enabled=");
+                pw.println(ps.getEnabled(user.id));
+                if (ps.getDisabledComponents(user.id).size() > 0) {
+                    pw.println("    disabledComponents:");
+                    for (String s : ps.getDisabledComponents(user.id)) {
+                        pw.print("      "); pw.println(s);
+                    }
                 }
-            }
-            if (ps.enabledComponents.size() > 0) {
-                pw.println("    enabledComponents:");
-                for (String s : ps.enabledComponents) {
-                    pw.print("      "); pw.println(s);
+                if (ps.getEnabledComponents(user.id).size() > 0) {
+                    pw.println("    enabledComponents:");
+                    for (String s : ps.getEnabledComponents(user.id)) {
+                        pw.print("      "); pw.println(s);
+                    }
                 }
             }
             if (ps.grantedPermissions.size() > 0) {
@@ -2234,7 +2513,7 @@
                     pw.println(ps.name);
                 }
                 pw.print("    userId=");
-                pw.println(ps.userId);
+                pw.println(ps.uid);
                 pw.print("    sharedUser=");
                 pw.println(ps.sharedUser);
                 pw.print("    codePath=");
@@ -2244,7 +2523,7 @@
             }
         }
     }
-    
+
     void dumpPermissionsLPr(PrintWriter pw, String packageName, DumpState dumpState) {
         boolean printedSomething = false;
         for (BasePermission p : mPermissions.values()) {
diff --git a/services/java/com/android/server/pm/UserManager.java b/services/java/com/android/server/pm/UserManager.java
index 5eacf4a..959e570 100644
--- a/services/java/com/android/server/pm/UserManager.java
+++ b/services/java/com/android/server/pm/UserManager.java
@@ -73,6 +73,9 @@
     UserManager(File dataDir, File baseUserPath) {
         mUsersDir = new File(dataDir, USER_INFO_DIR);
         mUsersDir.mkdirs();
+        // Make zeroth user directory, for services to migrate their files to that location
+        File userZeroDir = new File(mUsersDir, "0");
+        userZeroDir.mkdirs();
         mBaseUserPath = baseUserPath;
         FileUtils.setPermissions(mUsersDir.toString(),
                 FileUtils.S_IRWXU|FileUtils.S_IRWXG
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index ed83fbe..c2ded8a 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -43,6 +43,7 @@
 import android.os.Process;
 import android.os.storage.StorageManager;
 import android.os.storage.StorageVolume;
+import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UEventObserver;
 import android.provider.Settings;
@@ -206,6 +207,9 @@
     }
 
      private static String addFunction(String functions, String function) {
+         if ("none".equals(functions)) {
+             return function;
+         }
         if (!containsFunction(functions, function)) {
             if (functions.length() > 0) {
                 functions += ",";
@@ -222,6 +226,9 @@
                 split[i] = null;
             }
         }
+        if (split.length == 1 && split[0] == null) {
+            return "none";
+        }
         StringBuilder builder = new StringBuilder();
          for (int i = 0; i < split.length; i++) {
             String s = split[i];
@@ -365,11 +372,7 @@
             for (int i = 0; i < 20; i++) {
                 // State transition is done when sys.usb.state is set to the new configuration
                 if (state.equals(SystemProperties.get("sys.usb.state"))) return true;
-                try {
-                    // try again in 50ms
-                    Thread.sleep(50);
-                } catch (InterruptedException e) {
-                }
+                SystemClock.sleep(50);
             }
             Slog.e(TAG, "waitForState(" + state + ") FAILED");
             return false;
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java
index 3ae9f24..0e110be 100644
--- a/services/java/com/android/server/wm/AppWindowToken.java
+++ b/services/java/com/android/server/wm/AppWindowToken.java
@@ -56,7 +56,8 @@
     // These are used for determining when all windows associated with
     // an activity have been drawn, so they can be made visible together
     // at the same time.
-    int lastTransactionSequence;
+    // initialize so that it doesn't match mTransactionSequence which is an int.
+    long lastTransactionSequence = Long.MIN_VALUE;
     int numInterestingWindows;
     int numDrawnWindows;
     boolean inPendingTransaction;
@@ -113,7 +114,6 @@
         appWindowToken = this;
         appToken = _token;
         mInputApplicationHandle = new InputApplicationHandle(this);
-        lastTransactionSequence = service.mTransactionSequence-1;
     }
 
     public void setAnimation(Animation anim) {
@@ -190,14 +190,17 @@
         }
     }
 
-    void showAllWindowsLocked() {
+    boolean showAllWindowsLocked() {
+        boolean isAnimating = false;
         final int NW = allAppWindows.size();
         for (int i=0; i<NW; i++) {
             WindowState w = allAppWindows.get(i);
             if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG,
                     "performing show on: " + w);
             w.performShowLocked();
+            isAnimating |= w.isAnimating();
         }
+        return isAnimating;
     }
 
 
@@ -222,7 +225,7 @@
 
     // This must be called while inside a transaction.
     boolean stepAnimationLocked(long currentTime, int dw, int dh) {
-        if (!service.mDisplayFrozen && service.mPolicy.isScreenOnFully()) {
+        if (service.okToDisplay()) {
             // We will run animations as long as the display isn't frozen.
 
             if (animation == WindowManagerService.sDummyAnimation) {
diff --git a/services/java/com/android/server/wm/BlackFrame.java b/services/java/com/android/server/wm/BlackFrame.java
index 40e452a..c915932 100644
--- a/services/java/com/android/server/wm/BlackFrame.java
+++ b/services/java/com/android/server/wm/BlackFrame.java
@@ -32,12 +32,14 @@
     class BlackSurface {
         final int left;
         final int top;
+        final int layer;
         final Surface surface;
 
         BlackSurface(SurfaceSession session, int layer, int l, int t, int r, int b)
                 throws Surface.OutOfResourcesException {
             left = l;
             top = t;
+            this.layer = layer;
             int w = r-l;
             int h = b-t;
             surface = new Surface(session, 0, "BlackSurface",
@@ -45,8 +47,6 @@
             if (WindowManagerService.SHOW_TRANSACTIONS ||
                     WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
                             "  BLACK " + surface + ": CREATE layer=" + layer);
-            surface.setAlpha(1.0f);
-            surface.setLayer(layer);
         }
 
         void setMatrix(Matrix matrix) {
@@ -58,6 +58,8 @@
             surface.setMatrix(
                     mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
                     mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
+            surface.setAlpha(1.0f);
+            surface.setLayer(layer);
             if (false) {
                 Slog.i(WindowManagerService.TAG, "Black Surface @ (" + left + "," + top + "): ("
                         + mTmpFloats[Matrix.MTRANS_X] + ","
diff --git a/services/java/com/android/server/wm/DimAnimator.java b/services/java/com/android/server/wm/DimAnimator.java
index a9d4e01..85495ea 100644
--- a/services/java/com/android/server/wm/DimAnimator.java
+++ b/services/java/com/android/server/wm/DimAnimator.java
@@ -130,33 +130,31 @@
             }
         }
 
-        boolean animating = false;
-        if (mLastDimAnimTime != 0) {
+        boolean animating = mLastDimAnimTime != 0;
+        if (animating) {
             mDimCurrentAlpha += mDimDeltaPerMs
                     * (currentTime-mLastDimAnimTime);
-            boolean more = true;
             if (displayFrozen) {
                 // If the display is frozen, there is no reason to animate.
-                more = false;
+                animating = false;
             } else if (mDimDeltaPerMs > 0) {
                 if (mDimCurrentAlpha > mDimTargetAlpha) {
-                    more = false;
+                    animating = false;
                 }
             } else if (mDimDeltaPerMs < 0) {
                 if (mDimCurrentAlpha < mDimTargetAlpha) {
-                    more = false;
+                    animating = false;
                 }
             } else {
-                more = false;
+                animating = false;
             }
 
             // Do we need to continue animating?
-            if (more) {
+            if (animating) {
                 if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "  DIM "
                         + mDimSurface + ": alpha=" + mDimCurrentAlpha);
                 mLastDimAnimTime = currentTime;
                 mDimSurface.setAlpha(mDimCurrentAlpha);
-                animating = true;
             } else {
                 mDimCurrentAlpha = mDimTargetAlpha;
                 mLastDimAnimTime = 0;
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
new file mode 100644
index 0000000..b3dbee1
--- /dev/null
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -0,0 +1,575 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+
+package com.android.server.wm;
+
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+
+import android.content.Context;
+import android.os.SystemClock;
+import android.util.Log;
+import android.util.Slog;
+import android.view.Surface;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
+import android.view.WindowManagerPolicy;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+
+import com.android.internal.policy.impl.PhoneWindowManager;
+
+/**
+ * @author cmautner@google.com (Craig Mautner)
+ * Singleton class that carries out the animations and Surface operations in a separate task
+ * on behalf of WindowManagerService.
+ */
+public class WindowAnimator {
+    private static final String TAG = "WindowAnimations";
+
+    final WindowManagerService mService;
+    final Context mContext;
+    final WindowManagerPolicy mPolicy;
+
+    boolean mAnimating;
+    boolean mUpdateRotation;
+    boolean mTokenMayBeDrawn;
+    boolean mForceHiding;
+    WindowState mWindowAnimationBackground;
+    int mWindowAnimationBackgroundColor;
+    int mAdjResult;
+
+    int mPendingLayoutChanges;
+
+    /** Overall window dimensions */
+    int mDw, mDh;
+
+    /** Interior window dimensions */
+    int mInnerDw, mInnerDh;
+
+    /** Time of current animation step. Reset on each iteration */
+    long mCurrentTime;
+
+    /** Skip repeated AppWindowTokens initialization. Note that AppWindowsToken's version of this
+     * is a long initialized to Long.MIN_VALUE so that it doesn't match this value on startup. */
+    private int mTransactionSequence;
+
+    /** The one and only screen rotation if one is happening */
+    ScreenRotationAnimation mScreenRotationAnimation = null;
+
+    WindowAnimator(final WindowManagerService service, final Context context,
+            final WindowManagerPolicy policy) {
+        mService = service;
+        mContext = context;
+        mPolicy = policy;
+    }
+
+    private void updateWindowsAppsAndRotationAnimationsLocked() {
+        int i;
+        final int NAT = mService.mAppTokens.size();
+        for (i=0; i<NAT; i++) {
+            final AppWindowToken appToken = mService.mAppTokens.get(i);
+            if (appToken.stepAnimationLocked(mCurrentTime, mInnerDw, mInnerDh)) {
+                mAnimating = true;
+            }
+        }
+
+        if (mScreenRotationAnimation != null &&
+                (mScreenRotationAnimation.isAnimating() ||
+                        mScreenRotationAnimation.mFinishAnimReady)) {
+            if (mScreenRotationAnimation.stepAnimationLocked(mCurrentTime)) {
+                mUpdateRotation = false;
+                mAnimating = true;
+            } else {
+                mUpdateRotation = true;
+                mScreenRotationAnimation.kill();
+                mScreenRotationAnimation = null;
+            }
+        }
+    }
+
+    private void updateWindowsAndWallpaperLocked() {
+        ++mTransactionSequence;
+
+        for (int i = mService.mWindows.size() - 1; i >= 0; i--) {
+            WindowState w = mService.mWindows.get(i);
+
+            final WindowManager.LayoutParams attrs = w.mAttrs;
+
+            if (w.mSurface != null) {
+                // Take care of the window being ready to display.
+                if (w.commitFinishDrawingLocked(mCurrentTime)) {
+                    if ((w.mAttrs.flags
+                            & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
+                        if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG,
+                                "First draw done in potential wallpaper target " + w);
+                        mService.mInnerFields.mWallpaperMayChange = true;
+                        mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+                    }
+                }
+
+                // If the window has moved due to its containing
+                // content frame changing, then we'd like to animate
+                // it.  The checks here are ordered by what is least
+                // likely to be true first.
+                if (w.shouldAnimateMove()) {
+                    // Frame has moved, containing content frame
+                    // has also moved, and we're not currently animating...
+                    // let's do something.
+                    Animation a = AnimationUtils.loadAnimation(mContext,
+                            com.android.internal.R.anim.window_move_from_decor);
+                    w.setAnimation(a);
+                    w.mAnimDw = w.mLastFrame.left - w.mFrame.left;
+                    w.mAnimDh = w.mLastFrame.top - w.mFrame.top;
+                } else {
+                    w.mAnimDw = mInnerDw;
+                    w.mAnimDh = mInnerDh;
+                }
+
+                final boolean wasAnimating = w.mWasAnimating;
+                final boolean nowAnimating = w.stepAnimationLocked(mCurrentTime);
+
+                if (WindowManagerService.DEBUG_WALLPAPER) {
+                    Slog.v(TAG, w + ": wasAnimating=" + wasAnimating +
+                            ", nowAnimating=" + nowAnimating);
+                }
+
+                // If this window is animating, make a note that we have
+                // an animating window and take care of a request to run
+                // a detached wallpaper animation.
+                if (nowAnimating) {
+                    if (w.mAnimation != null) {
+                        if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0
+                                && w.mAnimation.getDetachWallpaper()) {
+                            mService.mInnerFields.mDetachedWallpaper = w;
+                        }
+                        if (w.mAnimation.getBackgroundColor() != 0) {
+                            if (mWindowAnimationBackground == null
+                                    || (w.mAnimLayer < mWindowAnimationBackground.mAnimLayer)) {
+                                mWindowAnimationBackground = w;
+                                mWindowAnimationBackgroundColor =
+                                        w.mAnimation.getBackgroundColor();
+                            }
+                        }
+                    }
+                    mAnimating = true;
+                }
+
+                // If this window's app token is running a detached wallpaper
+                // animation, make a note so we can ensure the wallpaper is
+                // displayed behind it.
+                if (w.mAppToken != null && w.mAppToken.animation != null
+                        && w.mAppToken.animating) {
+                    if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0
+                            && w.mAppToken.animation.getDetachWallpaper()) {
+                        mService.mInnerFields.mDetachedWallpaper = w;
+                    }
+                    if (w.mAppToken.animation.getBackgroundColor() != 0) {
+                        if (mWindowAnimationBackground == null
+                                || (w.mAnimLayer <
+                                        mWindowAnimationBackground.mAnimLayer)) {
+                            mWindowAnimationBackground = w;
+                            mWindowAnimationBackgroundColor =
+                                    w.mAppToken.animation.getBackgroundColor();
+                        }
+                    }
+                }
+
+                if (wasAnimating && !w.mAnimating && mService.mWallpaperTarget == w) {
+                    mService.mInnerFields.mWallpaperMayChange = true;
+                    mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+                }
+
+                if (mPolicy.doesForceHide(w, attrs)) {
+                    if (!wasAnimating && nowAnimating) {
+                        if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
+                                "Animation started that could impact force hide: "
+                                + w);
+                        mService.mInnerFields.mWallpaperForceHidingChanged = true;
+                        mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+                        mService.mFocusMayChange = true;
+                    } else if (w.isReadyForDisplay() && w.mAnimation == null) {
+                        mForceHiding = true;
+                    }
+                } else if (mPolicy.canBeForceHidden(w, attrs)) {
+                    boolean changed;
+                    if (mForceHiding) {
+                        changed = w.hideLw(false, false);
+                        if (WindowManagerService.DEBUG_VISIBILITY && changed) Slog.v(TAG,
+                                "Now policy hidden: " + w);
+                    } else {
+                        changed = w.showLw(false, false);
+                        if (WindowManagerService.DEBUG_VISIBILITY && changed) Slog.v(TAG,
+                                "Now policy shown: " + w);
+                        if (changed) {
+                            if (mService.mInnerFields.mWallpaperForceHidingChanged
+                                    && w.isVisibleNow() /*w.isReadyForDisplay()*/) {
+                                // Assume we will need to animate.  If
+                                // we don't (because the wallpaper will
+                                // stay with the lock screen), then we will
+                                // clean up later.
+                                Animation a = mPolicy.createForceHideEnterAnimation();
+                                if (a != null) {
+                                    w.setAnimation(a);
+                                }
+                            }
+                            if (mCurrentFocus == null || mCurrentFocus.mLayer < w.mLayer) {
+                                // We are showing on to of the current
+                                // focus, so re-evaluate focus to make
+                                // sure it is correct.
+                                mService.mFocusMayChange = true;
+                            }
+                        }
+                    }
+                    if (changed && (attrs.flags
+                            & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
+                        mService.mInnerFields.mWallpaperMayChange = true;
+                        mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+                    }
+                }
+            }
+
+            final AppWindowToken atoken = w.mAppToken;
+            if (atoken != null && (!atoken.allDrawn || atoken.freezingScreen)) {
+                if (atoken.lastTransactionSequence != mTransactionSequence) {
+                    atoken.lastTransactionSequence = mTransactionSequence;
+                    atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
+                    atoken.startingDisplayed = false;
+                }
+                if ((w.isOnScreen() || w.mAttrs.type
+                        == WindowManager.LayoutParams.TYPE_BASE_APPLICATION)
+                        && !w.mExiting && !w.mDestroying) {
+                    if (WindowManagerService.DEBUG_VISIBILITY ||
+                            WindowManagerService.DEBUG_ORIENTATION) {
+                        Slog.v(TAG, "Eval win " + w + ": isDrawn="
+                                + w.isDrawnLw()
+                                + ", isAnimating=" + w.isAnimating());
+                        if (!w.isDrawnLw()) {
+                            Slog.v(TAG, "Not displayed: s=" + w.mSurface
+                                    + " pv=" + w.mPolicyVisibility
+                                    + " dp=" + w.mDrawPending
+                                    + " cdp=" + w.mCommitDrawPending
+                                    + " ah=" + w.mAttachedHidden
+                                    + " th=" + atoken.hiddenRequested
+                                    + " a=" + w.mAnimating);
+                        }
+                    }
+                    if (w != atoken.startingWindow) {
+                        if (!atoken.freezingScreen || !w.mAppFreezing) {
+                            atoken.numInterestingWindows++;
+                            if (w.isDrawnLw()) {
+                                atoken.numDrawnWindows++;
+                                if (WindowManagerService.DEBUG_VISIBILITY ||
+                                        WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
+                                        "tokenMayBeDrawn: " + atoken
+                                        + " freezingScreen=" + atoken.freezingScreen
+                                        + " mAppFreezing=" + w.mAppFreezing);
+                                mTokenMayBeDrawn = true;
+                            }
+                        }
+                    } else if (w.isDrawnLw()) {
+                        atoken.startingDisplayed = true;
+                    }
+                }
+            } else if (w.mReadyToShow) {
+                w.performShowLocked();
+                mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
+            }
+        } // end forall windows
+    }
+
+    private void testTokenMayBeDrawnLocked() {
+        // See if any windows have been drawn, so they (and others
+        // associated with them) can now be shown.
+        final int NT = mService.mAppTokens.size();
+        for (int i=0; i<NT; i++) {
+            AppWindowToken wtoken = mService.mAppTokens.get(i);
+            if (wtoken.freezingScreen) {
+                int numInteresting = wtoken.numInterestingWindows;
+                if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
+                    if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
+                            "allDrawn: " + wtoken
+                            + " interesting=" + numInteresting
+                            + " drawn=" + wtoken.numDrawnWindows);
+                    wtoken.showAllWindowsLocked();
+                    mService.unsetAppFreezingScreenLocked(wtoken, false, true);
+                    if (WindowManagerService.DEBUG_ORIENTATION) Slog.i(TAG,
+                            "Setting mOrientationChangeComplete=true because wtoken "
+                            + wtoken + " numInteresting=" + numInteresting
+                            + " numDrawn=" + wtoken.numDrawnWindows);
+                    mService.mInnerFields.mOrientationChangeComplete = true;
+                }
+            } else if (!wtoken.allDrawn) {
+                int numInteresting = wtoken.numInterestingWindows;
+                if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
+                    if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
+                            "allDrawn: " + wtoken
+                            + " interesting=" + numInteresting
+                            + " drawn=" + wtoken.numDrawnWindows);
+                    wtoken.allDrawn = true;
+                    mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
+
+                    // We can now show all of the drawn windows!
+                    if (!mService.mOpeningApps.contains(wtoken)) {
+                        mAnimating |= wtoken.showAllWindowsLocked();
+                    }
+                }
+            }
+        }
+    }
+
+    private void performAnimationsLocked() {
+        if (WindowManagerService.DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: seq="
+                + mTransactionSequence + " mAnimating="
+                + mAnimating);
+
+        mTokenMayBeDrawn = false;
+        mService.mInnerFields.mWallpaperMayChange = false;
+        mForceHiding = false;
+        mService.mInnerFields.mDetachedWallpaper = null;
+        mWindowAnimationBackground = null;
+        mWindowAnimationBackgroundColor = 0;
+
+        updateWindowsAndWallpaperLocked();
+
+        if (mTokenMayBeDrawn) {
+            testTokenMayBeDrawnLocked();
+        }
+
+        if (WindowManagerService.DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: changes=0x"
+                + Integer.toHexString(mPendingLayoutChanges));
+    }
+
+    public void prepareSurfaceLocked(final WindowState w, final boolean recoveringMemory) {
+        if (w.mSurface == null) {
+            if (w.mOrientationChanging) {
+                if (WindowManagerService.DEBUG_ORIENTATION) {
+                    Slog.v(TAG, "Orientation change skips hidden " + w);
+                }
+                w.mOrientationChanging = false;
+            }
+            return;
+        }
+
+        boolean displayed = false;
+
+        w.computeShownFrameLocked();
+
+        int width, height;
+        if ((w.mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) {
+            // for a scaled surface, we just want to use
+            // the requested size.
+            width  = w.mRequestedWidth;
+            height = w.mRequestedHeight;
+        } else {
+            width = w.mCompatFrame.width();
+            height = w.mCompatFrame.height();
+        }
+
+        if (width < 1) {
+            width = 1;
+        }
+        if (height < 1) {
+            height = 1;
+        }
+        final boolean surfaceResized = w.mSurfaceW != width || w.mSurfaceH != height;
+        if (surfaceResized) {
+            w.mSurfaceW = width;
+            w.mSurfaceH = height;
+        }
+
+        if (w.mSurfaceX != w.mShownFrame.left
+                || w.mSurfaceY != w.mShownFrame.top) {
+            try {
+                if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
+                        "POS " + w.mShownFrame.left
+                        + ", " + w.mShownFrame.top, null);
+                w.mSurfaceX = w.mShownFrame.left;
+                w.mSurfaceY = w.mShownFrame.top;
+                w.mSurface.setPosition(w.mShownFrame.left, w.mShownFrame.top);
+            } catch (RuntimeException e) {
+                Slog.w(TAG, "Error positioning surface of " + w
+                        + " pos=(" + w.mShownFrame.left
+                        + "," + w.mShownFrame.top + ")", e);
+                if (!recoveringMemory) {
+                    mService.reclaimSomeSurfaceMemoryLocked(w, "position", true);
+                }
+            }
+        }
+
+        if (surfaceResized) {
+            try {
+                if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
+                        "SIZE " + width + "x" + height, null);
+                w.mSurfaceResized = true;
+                w.mSurface.setSize(width, height);
+            } catch (RuntimeException e) {
+                // If something goes wrong with the surface (such
+                // as running out of memory), don't take down the
+                // entire system.
+                Slog.e(TAG, "Error resizing surface of " + w
+                        + " size=(" + width + "x" + height + ")", e);
+                if (!recoveringMemory) {
+                    mService.reclaimSomeSurfaceMemoryLocked(w, "size", true);
+                }
+            }
+        }
+
+        if (w.mAttachedHidden || !w.isReadyForDisplay()) {
+            if (!w.mLastHidden) {
+                //dump();
+                w.mLastHidden = true;
+                if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
+                        "HIDE (performLayout)", null);
+                if (w.mSurface != null) {
+                    w.mSurfaceShown = false;
+                    try {
+                        w.mSurface.hide();
+                    } catch (RuntimeException e) {
+                        Slog.w(TAG, "Exception hiding surface in " + w);
+                    }
+                }
+            }
+            // If we are waiting for this window to handle an
+            // orientation change, well, it is hidden, so
+            // doesn't really matter.  Note that this does
+            // introduce a potential glitch if the window
+            // becomes unhidden before it has drawn for the
+            // new orientation.
+            if (w.mOrientationChanging) {
+                w.mOrientationChanging = false;
+                if (WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
+                        "Orientation change skips hidden " + w);
+            }
+        } else if (w.mLastLayer != w.mAnimLayer
+                || w.mLastAlpha != w.mShownAlpha
+                || w.mLastDsDx != w.mDsDx
+                || w.mLastDtDx != w.mDtDx
+                || w.mLastDsDy != w.mDsDy
+                || w.mLastDtDy != w.mDtDy
+                || w.mLastHScale != w.mHScale
+                || w.mLastVScale != w.mVScale
+                || w.mLastHidden) {
+            displayed = true;
+            w.mLastAlpha = w.mShownAlpha;
+            w.mLastLayer = w.mAnimLayer;
+            w.mLastDsDx = w.mDsDx;
+            w.mLastDtDx = w.mDtDx;
+            w.mLastDsDy = w.mDsDy;
+            w.mLastDtDy = w.mDtDy;
+            w.mLastHScale = w.mHScale;
+            w.mLastVScale = w.mVScale;
+            if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
+                    "alpha=" + w.mShownAlpha + " layer=" + w.mAnimLayer
+                    + " matrix=[" + (w.mDsDx*w.mHScale)
+                    + "," + (w.mDtDx*w.mVScale)
+                    + "][" + (w.mDsDy*w.mHScale)
+                    + "," + (w.mDtDy*w.mVScale) + "]", null);
+            if (w.mSurface != null) {
+                try {
+                    w.mSurfaceAlpha = w.mShownAlpha;
+                    w.mSurface.setAlpha(w.mShownAlpha);
+                    w.mSurfaceLayer = w.mAnimLayer;
+                    w.mSurface.setLayer(w.mAnimLayer);
+                    w.mSurface.setMatrix(
+                            w.mDsDx*w.mHScale, w.mDtDx*w.mVScale,
+                            w.mDsDy*w.mHScale, w.mDtDy*w.mVScale);
+                } catch (RuntimeException e) {
+                    Slog.w(TAG, "Error updating surface in " + w, e);
+                    if (!recoveringMemory) {
+                        mService.reclaimSomeSurfaceMemoryLocked(w, "update", true);
+                    }
+                }
+            }
+
+            if (w.mLastHidden && w.isDrawnLw()
+                    && !w.mReadyToShow) {
+                if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
+                        "SHOW (performLayout)", null);
+                if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + w
+                        + " during relayout");
+                if (mService.showSurfaceRobustlyLocked(w)) {
+                    w.mHasDrawn = true;
+                    w.mLastHidden = false;
+                } else {
+                    w.mOrientationChanging = false;
+                }
+            }
+            if (w.mSurface != null) {
+                w.mToken.hasVisible = true;
+            }
+        } else {
+            displayed = true;
+        }
+
+        if (displayed) {
+            if (w.mOrientationChanging) {
+                if (!w.isDrawnLw()) {
+                    mService.mInnerFields.mOrientationChangeComplete = false;
+                    if (WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
+                            "Orientation continue waiting for draw in " + w);
+                } else {
+                    w.mOrientationChanging = false;
+                    if (WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
+                            "Orientation change complete in " + w);
+                }
+            }
+            w.mToken.hasVisible = true;
+        }
+    }
+
+    void animate() {
+        mCurrentTime = SystemClock.uptimeMillis();
+
+        // Update animations of all applications, including those
+        // associated with exiting/removed apps
+        Surface.openTransaction();
+
+        try {
+            updateWindowsAppsAndRotationAnimationsLocked();
+            performAnimationsLocked();
+
+            // THIRD LOOP: Update the surfaces of all windows.
+
+            if (mScreenRotationAnimation != null) {
+                mScreenRotationAnimation.updateSurfaces();
+            }
+
+            final int N = mService.mWindows.size();
+            for (int i=N-1; i>=0; i--) {
+                WindowState w = mService.mWindows.get(i);
+                prepareSurfaceLocked(w, true);
+            }
+
+            if (mService.mDimAnimator != null && mService.mDimAnimator.mDimShown) {
+                mAnimating |= mService.mDimAnimator.updateSurface(mService.mInnerFields.mDimming,
+                            mCurrentTime, !mService.okToDisplay());
+            }
+
+            if (mService.mBlackFrame != null) {
+                if (mScreenRotationAnimation != null) {
+                    mService.mBlackFrame.setMatrix(
+                            mScreenRotationAnimation.getEnterTransformation().getMatrix());
+                } else {
+                    mService.mBlackFrame.clearMatrix();
+                }
+            }
+        } catch (RuntimeException e) {
+            Log.wtf(TAG, "Unhandled exception in Window Manager", e);
+        } finally {
+            Surface.closeTransaction();
+        }
+    }
+
+    WindowState mCurrentFocus;
+    void setCurrentFocus(WindowState currentFocus) {
+        mCurrentFocus = currentFocus;
+    }
+
+    void setDisplayDimensions(final int curWidth, final int curHeight,
+                        final int appWidth, final int appHeight) {
+        mDw = curWidth;
+        mDh = curHeight;
+        mInnerDw = appWidth;
+        mInnerDh = appHeight;
+    }
+
+}
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 407b732..26367d2 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -18,7 +18,6 @@
 
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.FLAG_BLUR_BEHIND;
 import static android.view.WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
 import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
@@ -173,7 +172,6 @@
     static final boolean HIDE_STACK_CRAWLS = true;
 
     static final boolean PROFILE_ORIENTATION = false;
-    static final boolean BLUR = true;
     static final boolean localLOGV = DEBUG;
 
     /** How much to multiply the policy's type layer, to reserve room
@@ -196,11 +194,6 @@
     static final int LAYER_OFFSET_DIM = 1;
 
     /**
-     * Blur surface layer is immediately below dim layer.
-     */
-    static final int LAYER_OFFSET_BLUR = 2;
-
-    /**
      * Layer at which to put the rotation freeze snapshot.
      */
     static final int FREEZE_LAYER = (TYPE_LAYER_MULTIPLIER * 200) + 1;
@@ -415,17 +408,12 @@
     IInputMethodManager mInputMethodManager;
 
     SurfaceSession mFxSession;
-    private DimAnimator mDimAnimator = null;
-    Surface mBlurSurface;
-    boolean mBlurShown;
+    DimAnimator mDimAnimator = null;
     Watermark mWatermark;
     StrictModeFlash mStrictModeFlash;
-    ScreenRotationAnimation mScreenRotationAnimation;
 
     BlackFrame mBlackFrame;
 
-    int mTransactionSequence = 0;
-
     final float[] mTmpFloats = new float[9];
 
     boolean mSafeMode;
@@ -584,27 +572,21 @@
 
     /** Pulled out of performLayoutAndPlaceSurfacesLockedInner in order to refactor into multiple
      * methods. */
-    private class LayoutAndSurfaceFields {
-        private boolean mAnimating = false;
-        private boolean mWallpaperForceHidingChanged = false;
-        private boolean mTokenMayBeDrawn = false;
-        private boolean mWallpaperMayChange = false;
-        private boolean mForceHiding = false;
-        private WindowState mDetachedWallpaper = null;
-        private WindowState mWindowAnimationBackground = null;
-        private int mWindowAnimationBackgroundColor = 0;
-        private boolean mOrientationChangeComplete = true;
+    class LayoutAndSurfaceFields {
+        boolean mWallpaperForceHidingChanged = false;
+        boolean mWallpaperMayChange = false;
+        WindowState mDetachedWallpaper = null;
+        boolean mOrientationChangeComplete = true;
         private int mAdjResult = 0;
         private Session mHoldScreen = null;
         private boolean mObscured = false;
-        private boolean mBlurring = false;
-        private boolean mDimming = false;
+        boolean mDimming = false;
         private boolean mSyswin = false;
         private float mScreenBrightness = -1;
         private float mButtonBrightness = -1;
         private boolean mUpdateRotation = false;
     }
-    private LayoutAndSurfaceFields mInnerFields = new LayoutAndSurfaceFields();
+    LayoutAndSurfaceFields mInnerFields = new LayoutAndSurfaceFields();
 
     private final class AnimationRunnable implements Runnable {
         @Override
@@ -617,6 +599,8 @@
     }
     final AnimationRunnable mAnimationRunnable = new AnimationRunnable();
     boolean mAnimationScheduled;
+    
+    final WindowAnimator mAnimator;
 
     final class DragInputEventReceiver extends InputEventReceiver {
         public DragInputEventReceiver(InputChannel inputChannel, Looper looper) {
@@ -735,6 +719,7 @@
             mAllowBootMessages = allowBootMsgs;
         }
 
+        @Override
         public void run() {
             Looper.prepare();
             WindowManagerService s = new WindowManagerService(mContext, mPM,
@@ -774,6 +759,7 @@
             mPM = pm;
         }
 
+        @Override
         public void run() {
             Looper.prepare();
             WindowManagerPolicyThread.set(this, Looper.myLooper());
@@ -836,6 +822,7 @@
         mHoldingScreenWakeLock.setReferenceCounted(false);
 
         mInputManager = new InputManager(context, this);
+        mAnimator = new WindowAnimator(this, context, mPolicy);
 
         PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);
         thr.start();
@@ -2217,7 +2204,7 @@
             if (mInTouchMode) {
                 res |= WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE;
             }
-            if (win == null || win.mAppToken == null || !win.mAppToken.clientHidden) {
+            if (win.mAppToken == null || !win.mAppToken.clientHidden) {
                 res |= WindowManagerImpl.ADD_FLAG_APP_VISIBLE;
             }
 
@@ -2284,7 +2271,7 @@
             + ", surface=" + win.mSurface);
 
         final long origId = Binder.clearCallingIdentity();
-        
+
         win.disposeInputChannel();
 
         if (DEBUG_APP_TRANSITIONS) Slog.v(
@@ -2302,11 +2289,11 @@
         // to hold off on removing the window until the animation is done.
         // If the display is frozen, just remove immediately, since the
         // animation wouldn't be seen.
-        if (win.mSurface != null && !mDisplayFrozen && mDisplayEnabled
-                && mPolicy.isScreenOnFully()) {
+        if (win.mSurface != null && okToDisplay()) {
             // If we are not currently running the exit animation, we
             // need to see about starting one.
-            if (wasVisible=win.isWinVisibleLw()) {
+            wasVisible = win.isWinVisibleLw();
+            if (wasVisible) {
 
                 int transit = WindowManagerPolicy.TRANSIT_EXIT;
                 if (win.getAttrs().type == TYPE_APPLICATION_STARTING) {
@@ -2687,8 +2674,7 @@
                     win.mEnterAnimationPending = true;
                 }
                 if (displayed) {
-                    if (win.isDrawnLw() && !mDisplayFrozen
-                            && mDisplayEnabled && mPolicy.isScreenOnFully()) {
+                    if (win.isDrawnLw() && okToDisplay()) {
                         applyEnterAnimationLocked(win);
                     }
                     if ((win.mAttrs.flags
@@ -3015,7 +3001,7 @@
         // frozen, there is no reason to animate and it can cause strange
         // artifacts when we unfreeze the display if some different animation
         // is running.
-        if (!mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOnFully()) {
+        if (okToDisplay()) {
             int anim = mPolicy.selectAnimationLw(win, transit);
             int attr = -1;
             Animation a = null;
@@ -3101,7 +3087,7 @@
         // frozen, there is no reason to animate and it can cause strange
         // artifacts when we unfreeze the display if some different animation
         // is running.
-        if (!mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOnFully()) {
+        if (okToDisplay()) {
             Animation a;
             if (mNextAppTransitionPackage != null) {
                 a = loadAnimation(mNextAppTransitionPackage, enter ?
@@ -3234,6 +3220,10 @@
         Slog.w(TAG, msg);
         return false;
     }
+    
+    boolean okToDisplay() {
+        return !mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOnFully();
+    }
 
     AppWindowToken findAppWindowToken(IBinder token) {
         WindowToken wtoken = mTokenMap.get(token);
@@ -3665,7 +3655,7 @@
             if (DEBUG_APP_TRANSITIONS) Slog.v(
                     TAG, "Prepare app transition: transit=" + transit
                     + " mNextAppTransition=" + mNextAppTransition);
-            if (!mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOnFully()) {
+            if (okToDisplay()) {
                 if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET
                         || mNextAppTransition == WindowManagerPolicy.TRANSIT_NONE) {
                     mNextAppTransition = transit;
@@ -3749,7 +3739,7 @@
             // If the display is frozen, we won't do anything until the
             // actual window is displayed so there is no reason to put in
             // the starting window.
-            if (mDisplayFrozen || !mDisplayEnabled || !mPolicy.isScreenOnFully()) {
+            if (!okToDisplay()) {
                 return;
             }
 
@@ -4039,8 +4029,7 @@
 
             // If we are preparing an app transition, then delay changing
             // the visibility of this token until we execute that transition.
-            if (!mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOnFully()
-                    && mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
+            if (okToDisplay() && mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
                 // Already in requested state, don't do anything more.
                 if (wtoken.hiddenRequested != visible) {
                     return;
@@ -4168,7 +4157,7 @@
         }
 
         synchronized(mWindowMap) {
-            if (configChanges == 0 && !mDisplayFrozen && mPolicy.isScreenOnFully()) {
+            if (configChanges == 0 && okToDisplay()) {
                 if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping set freeze of " + token);
                 return;
             }
@@ -5389,7 +5378,8 @@
             return false;
         }
 
-        if (mScreenRotationAnimation != null && mScreenRotationAnimation.isAnimating()) {
+        if (mAnimator.mScreenRotationAnimation != null &&
+                mAnimator.mScreenRotationAnimation.isAnimating()) {
             // Rotation updates cannot be performed while the previous rotation change
             // animation is still in progress.  Skip this update.  We will try updating
             // again after the animation is finished and the display is unfrozen.
@@ -5459,9 +5449,9 @@
         try {
             // NOTE: We disable the rotation in the emulator because
             //       it doesn't support hardware OpenGL emulation yet.
-            if (CUSTOM_SCREEN_ROTATION && mScreenRotationAnimation != null
-                    && mScreenRotationAnimation.hasScreenshot()) {
-                if (mScreenRotationAnimation.setRotation(rotation, mFxSession,
+            if (CUSTOM_SCREEN_ROTATION && mAnimator.mScreenRotationAnimation != null
+                    && mAnimator.mScreenRotationAnimation.hasScreenshot()) {
+                if (mAnimator.mScreenRotationAnimation.setRotation(rotation, mFxSession,
                         MAX_ANIMATION_DURATION, mTransitionAnimationScale,
                         mCurDisplayWidth, mCurDisplayHeight)) {
                     scheduleAnimationLocked();
@@ -5476,7 +5466,7 @@
             }
         }
 
-        rebuildBlackFrame(inTransaction);
+        rebuildBlackFrame();
 
         for (int i=mWindows.size()-1; i>=0; i--) {
             WindowState w = mWindows.get(i);
@@ -6163,6 +6153,8 @@
         synchronized(mDisplaySizeLock) {
             mAppDisplayWidth = appWidth;
             mAppDisplayHeight = appHeight;
+            mAnimator.setDisplayDimensions(mCurDisplayWidth, mCurDisplayHeight,
+                    mAppDisplayWidth, mAppDisplayHeight);
         }
         if (false) {
             Slog.i(TAG, "Set app display size: " + mAppDisplayWidth
@@ -6549,6 +6541,8 @@
                 }
                 mBaseDisplayWidth = mCurDisplayWidth = mAppDisplayWidth = mInitialDisplayWidth;
                 mBaseDisplayHeight = mCurDisplayHeight = mAppDisplayHeight = mInitialDisplayHeight;
+                mAnimator.setDisplayDimensions(mCurDisplayWidth, mCurDisplayHeight,
+                        mAppDisplayWidth, mAppDisplayHeight);
             }
             mInputManager.setDisplaySize(Display.DEFAULT_DISPLAY,
                     mDisplay.getRawWidth(), mDisplay.getRawHeight(),
@@ -7151,45 +7145,32 @@
         }
     }
 
-    private void rebuildBlackFrame(boolean inTransaction) {
-        if (!inTransaction) {
-            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
-                    ">>> OPEN TRANSACTION rebuildBlackFrame");
-            Surface.openTransaction();
+    private void rebuildBlackFrame() {
+        if (mBlackFrame != null) {
+            mBlackFrame.kill();
+            mBlackFrame = null;
         }
-        try {
-            if (mBlackFrame != null) {
-                mBlackFrame.kill();
-                mBlackFrame = null;
+        if (mBaseDisplayWidth < mInitialDisplayWidth
+                || mBaseDisplayHeight < mInitialDisplayHeight) {
+            int initW, initH, baseW, baseH;
+            final boolean rotated = (mRotation == Surface.ROTATION_90
+                    || mRotation == Surface.ROTATION_270);
+            if (rotated) {
+                initW = mInitialDisplayHeight;
+                initH = mInitialDisplayWidth;
+                baseW = mBaseDisplayHeight;
+                baseH = mBaseDisplayWidth;
+            } else {
+                initW = mInitialDisplayWidth;
+                initH = mInitialDisplayHeight;
+                baseW = mBaseDisplayWidth;
+                baseH = mBaseDisplayHeight;
             }
-            if (mBaseDisplayWidth < mInitialDisplayWidth
-                    || mBaseDisplayHeight < mInitialDisplayHeight) {
-                int initW, initH, baseW, baseH;
-                final boolean rotated = (mRotation == Surface.ROTATION_90
-                        || mRotation == Surface.ROTATION_270);
-                if (rotated) {
-                    initW = mInitialDisplayHeight;
-                    initH = mInitialDisplayWidth;
-                    baseW = mBaseDisplayHeight;
-                    baseH = mBaseDisplayWidth;
-                } else {
-                    initW = mInitialDisplayWidth;
-                    initH = mInitialDisplayHeight;
-                    baseW = mBaseDisplayWidth;
-                    baseH = mBaseDisplayHeight;
-                }
-                Rect outer = new Rect(0, 0, initW, initH);
-                Rect inner = new Rect(0, 0, baseW, baseH);
-                try {
-                    mBlackFrame = new BlackFrame(mFxSession, outer, inner, MASK_LAYER);
-                } catch (Surface.OutOfResourcesException e) {
-                }
-            }
-        } finally {
-            if (!inTransaction) {
-                Surface.closeTransaction();
-                if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
-                        "<<< CLOSE TRANSACTION rebuildBlackFrame");
+            Rect outer = new Rect(0, 0, initW, initH);
+            Rect inner = new Rect(0, 0, baseW, baseH);
+            try {
+                mBlackFrame = new BlackFrame(mFxSession, outer, inner, MASK_LAYER);
+            } catch (Surface.OutOfResourcesException e) {
             }
         }
     }
@@ -7240,7 +7221,7 @@
             mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
         }
 
-        rebuildBlackFrame(false);
+        rebuildBlackFrame();
 
         performLayoutAndPlaceSurfacesLocked();
     }
@@ -7625,7 +7606,7 @@
         // If the screen is currently frozen or off, then keep
         // it frozen/off until this window draws at its new
         // orientation.
-        if (mDisplayFrozen || !mPolicy.isScreenOnFully()) {
+        if (!okToDisplay()) {
             if (DEBUG_ORIENTATION) Slog.v(TAG,
                     "Changing surface while display frozen: " + w);
             w.mOrientationChanging = true;
@@ -7642,351 +7623,6 @@
 
     /**
      * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
-     * Update animations of all applications, including those associated with exiting/removed apps.
-     *
-     * @param currentTime The time which animations use for calculating transitions.
-     * @param innerDw Width of app window.
-     * @param innerDh Height of app window.
-     */
-    private void updateWindowsAppsAndRotationAnimationsLocked(long currentTime,
-                                                          int innerDw, int innerDh) {
-        int i;
-        final int NAT = mAppTokens.size();
-        for (i=0; i<NAT; i++) {
-            final AppWindowToken appToken = mAppTokens.get(i);
-            if (appToken.stepAnimationLocked(currentTime, innerDw, innerDh)) {
-                mInnerFields.mAnimating = true;
-            }
-        }
-        final int NEAT = mExitingAppTokens.size();
-        for (i=0; i<NEAT; i++) {
-            final AppWindowToken appToken = mExitingAppTokens.get(i);
-            if (appToken.stepAnimationLocked(currentTime, innerDw, innerDh)) {
-                mInnerFields.mAnimating = true;
-            }
-        }
-
-        if (mScreenRotationAnimation != null &&
-                (mScreenRotationAnimation.isAnimating() ||
-                        mScreenRotationAnimation.mFinishAnimReady)) {
-            if (mScreenRotationAnimation.stepAnimationLocked(currentTime)) {
-                mInnerFields.mUpdateRotation = false;
-                mInnerFields.mAnimating = true;
-            } else {
-                mInnerFields.mUpdateRotation = true;
-                mScreenRotationAnimation.kill();
-                mScreenRotationAnimation = null;
-            }
-        }
-    }
-
-    private void animateAndUpdateSurfaces(final long currentTime, final int dw, final int dh,
-                                          final int innerDw, final int innerDh, 
-                                          final boolean recoveringMemory) {
-        // Update animations of all applications, including those
-        // associated with exiting/removed apps
-        Surface.openTransaction();
-
-        try {
-            updateWindowsAppsAndRotationAnimationsLocked(currentTime, innerDw, innerDh);
-            mPendingLayoutChanges = performAnimationsLocked(currentTime, dw, dh,
-                    innerDw, innerDh);
-        
-            // THIRD LOOP: Update the surfaces of all windows.
-            
-            if (mScreenRotationAnimation != null) {
-                mScreenRotationAnimation.updateSurfaces();
-            }
-        
-            final int N = mWindows.size();
-            for (int i=N-1; i>=0; i--) {
-                WindowState w = mWindows.get(i);
-                prepareSurfaceLocked(w, recoveringMemory);
-            }
-        
-            if (mDimAnimator != null && mDimAnimator.mDimShown) {
-                mInnerFields.mAnimating |=
-                        mDimAnimator.updateSurface(mInnerFields.mDimming, currentTime,
-                            mDisplayFrozen || !mDisplayEnabled || !mPolicy.isScreenOnFully());
-            }
-        
-            if (!mInnerFields.mBlurring && mBlurShown) {
-                if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BLUR " + mBlurSurface
-                        + ": HIDE");
-                try {
-                    mBlurSurface.hide();
-                } catch (IllegalArgumentException e) {
-                    Slog.w(TAG, "Illegal argument exception hiding blur surface");
-                }
-                mBlurShown = false;
-            }
-        
-            if (mBlackFrame != null) {
-                if (mScreenRotationAnimation != null) {
-                    mBlackFrame.setMatrix(
-                            mScreenRotationAnimation.getEnterTransformation().getMatrix());
-                } else {
-                    mBlackFrame.clearMatrix();
-                }
-            }
-        } catch (RuntimeException e) {
-            Log.wtf(TAG, "Unhandled exception in Window Manager", e);
-        } finally {
-            Surface.closeTransaction();
-        }
-    }
-    
-    /**
-     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
-     *
-     * @param currentTime The time which animations use for calculating transitions.
-     * @param dw Width of app window.
-     * @param dh Height of app window.
-     * @param innerDw Width of app window.
-     * @param innerDh Height of app window.
-     */
-    private int updateWindowsAndWallpaperLocked(final long currentTime, final int dw, final int dh,
-                                                final int innerDw, final int innerDh) {
-        int changes = 0;
-        for (int i = mWindows.size() - 1; i >= 0; i--) {
-            WindowState w = mWindows.get(i);
-
-            final WindowManager.LayoutParams attrs = w.mAttrs;
-
-            if (w.mSurface != null) {
-                // Take care of the window being ready to display.
-                if (w.commitFinishDrawingLocked(currentTime)) {
-                    if ((w.mAttrs.flags
-                            & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
-                        if (DEBUG_WALLPAPER) Slog.v(TAG,
-                                "First draw done in potential wallpaper target " + w);
-                        mInnerFields.mWallpaperMayChange = true;
-                        changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-                    }
-                }
-
-                // If the window has moved due to its containing
-                // content frame changing, then we'd like to animate
-                // it.  The checks here are ordered by what is least
-                // likely to be true first.
-                if (w.shouldAnimateMove()) {
-                    // Frame has moved, containing content frame
-                    // has also moved, and we're not currently animating...
-                    // let's do something.
-                    Animation a = AnimationUtils.loadAnimation(mContext,
-                            com.android.internal.R.anim.window_move_from_decor);
-                    w.setAnimation(a);
-                    w.mAnimDw = w.mLastFrame.left - w.mFrame.left;
-                    w.mAnimDh = w.mLastFrame.top - w.mFrame.top;
-                } else {
-                    w.mAnimDw = innerDw;
-                    w.mAnimDh = innerDh;
-                }
-
-                final boolean wasAnimating = w.mWasAnimating;
-                final boolean nowAnimating = w.stepAnimationLocked(currentTime);
-
-                if (DEBUG_WALLPAPER) {
-                    Slog.v(TAG, w + ": wasAnimating=" + wasAnimating +
-                            ", nowAnimating=" + nowAnimating);
-                }
-
-                // If this window is animating, make a note that we have
-                // an animating window and take care of a request to run
-                // a detached wallpaper animation.
-                if (nowAnimating) {
-                    if (w.mAnimation != null) {
-                        if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0
-                                && w.mAnimation.getDetachWallpaper()) {
-                            mInnerFields.mDetachedWallpaper = w;
-                        }
-                        if (w.mAnimation.getBackgroundColor() != 0) {
-                            if (mInnerFields.mWindowAnimationBackground == null
-                                    || (w.mAnimLayer <
-                                            mInnerFields.mWindowAnimationBackground.mAnimLayer)) {
-                                mInnerFields.mWindowAnimationBackground = w;
-                                mInnerFields.mWindowAnimationBackgroundColor =
-                                        w.mAnimation.getBackgroundColor();
-                            }
-                        }
-                    }
-                    mInnerFields.mAnimating = true;
-                }
-
-                // If this window's app token is running a detached wallpaper
-                // animation, make a note so we can ensure the wallpaper is
-                // displayed behind it.
-                if (w.mAppToken != null && w.mAppToken.animation != null
-                        && w.mAppToken.animating) {
-                    if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0
-                            && w.mAppToken.animation.getDetachWallpaper()) {
-                        mInnerFields.mDetachedWallpaper = w;
-                    }
-                    if (w.mAppToken.animation.getBackgroundColor() != 0) {
-                        if (mInnerFields.mWindowAnimationBackground == null
-                                || (w.mAnimLayer <
-                                        mInnerFields.mWindowAnimationBackground.mAnimLayer)) {
-                            mInnerFields.mWindowAnimationBackground = w;
-                            mInnerFields.mWindowAnimationBackgroundColor =
-                                    w.mAppToken.animation.getBackgroundColor();
-                        }
-                    }
-                }
-
-                if (wasAnimating && !w.mAnimating && mWallpaperTarget == w) {
-                    mInnerFields.mWallpaperMayChange = true;
-                    changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-                }
-
-                if (mPolicy.doesForceHide(w, attrs)) {
-                    if (!wasAnimating && nowAnimating) {
-                        if (DEBUG_VISIBILITY) Slog.v(TAG,
-                                "Animation started that could impact force hide: "
-                                + w);
-                        mInnerFields.mWallpaperForceHidingChanged = true;
-                        changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-                        mFocusMayChange = true;
-                    } else if (w.isReadyForDisplay() && w.mAnimation == null) {
-                        mInnerFields.mForceHiding = true;
-                    }
-                } else if (mPolicy.canBeForceHidden(w, attrs)) {
-                    boolean changed;
-                    if (mInnerFields.mForceHiding) {
-                        changed = w.hideLw(false, false);
-                        if (DEBUG_VISIBILITY && changed) Slog.v(TAG,
-                                "Now policy hidden: " + w);
-                    } else {
-                        changed = w.showLw(false, false);
-                        if (DEBUG_VISIBILITY && changed) Slog.v(TAG,
-                                "Now policy shown: " + w);
-                        if (changed) {
-                            if (mInnerFields.mWallpaperForceHidingChanged
-                                    && w.isVisibleNow() /*w.isReadyForDisplay()*/) {
-                                // Assume we will need to animate.  If
-                                // we don't (because the wallpaper will
-                                // stay with the lock screen), then we will
-                                // clean up later.
-                                Animation a = mPolicy.createForceHideEnterAnimation();
-                                if (a != null) {
-                                    w.setAnimation(a);
-                                }
-                            }
-                            if (mCurrentFocus == null ||
-                                    mCurrentFocus.mLayer < w.mLayer) {
-                                // We are showing on to of the current
-                                // focus, so re-evaluate focus to make
-                                // sure it is correct.
-                                mFocusMayChange = true;
-                            }
-                        }
-                    }
-                    if (changed && (attrs.flags
-                            & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
-                        mInnerFields.mWallpaperMayChange = true;
-                        changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-                    }
-                }
-            }
-
-            final AppWindowToken atoken = w.mAppToken;
-            if (atoken != null && (!atoken.allDrawn || atoken.freezingScreen)) {
-                if (atoken.lastTransactionSequence != mTransactionSequence) {
-                    atoken.lastTransactionSequence = mTransactionSequence;
-                    atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
-                    atoken.startingDisplayed = false;
-                }
-                if ((w.isOnScreen() || w.mAttrs.type
-                        == WindowManager.LayoutParams.TYPE_BASE_APPLICATION)
-                        && !w.mExiting && !w.mDestroying) {
-                    if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
-                        Slog.v(TAG, "Eval win " + w + ": isDrawn="
-                                + w.isDrawnLw()
-                                + ", isAnimating=" + w.isAnimating());
-                        if (!w.isDrawnLw()) {
-                            Slog.v(TAG, "Not displayed: s=" + w.mSurface
-                                    + " pv=" + w.mPolicyVisibility
-                                    + " dp=" + w.mDrawPending
-                                    + " cdp=" + w.mCommitDrawPending
-                                    + " ah=" + w.mAttachedHidden
-                                    + " th=" + atoken.hiddenRequested
-                                    + " a=" + w.mAnimating);
-                        }
-                    }
-                    if (w != atoken.startingWindow) {
-                        if (!atoken.freezingScreen || !w.mAppFreezing) {
-                            atoken.numInterestingWindows++;
-                            if (w.isDrawnLw()) {
-                                atoken.numDrawnWindows++;
-                                if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG,
-                                        "tokenMayBeDrawn: " + atoken
-                                        + " freezingScreen=" + atoken.freezingScreen
-                                        + " mAppFreezing=" + w.mAppFreezing);
-                                mInnerFields.mTokenMayBeDrawn = true;
-                            }
-                        }
-                    } else if (w.isDrawnLw()) {
-                        atoken.startingDisplayed = true;
-                    }
-                }
-            } else if (w.mReadyToShow) {
-                w.performShowLocked();
-                changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
-            }
-        } // end forall windows
-
-        return changes;
-    }
-
-    /**
-     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
-     *
-     * @return bitmap indicating if another pass through layout must be made.
-     */
-    private int testTokenMayBeDrawnLocked() {
-        int changes = 0;
-        // See if any windows have been drawn, so they (and others
-        // associated with them) can now be shown.
-        final int NT = mAppTokens.size();
-        for (int i=0; i<NT; i++) {
-            AppWindowToken wtoken = mAppTokens.get(i);
-            if (wtoken.freezingScreen) {
-                int numInteresting = wtoken.numInterestingWindows;
-                if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
-                    if (DEBUG_VISIBILITY) Slog.v(TAG,
-                            "allDrawn: " + wtoken
-                            + " interesting=" + numInteresting
-                            + " drawn=" + wtoken.numDrawnWindows);
-                    wtoken.showAllWindowsLocked();
-                    unsetAppFreezingScreenLocked(wtoken, false, true);
-                    if (DEBUG_ORIENTATION) Slog.i(TAG,
-                            "Setting mOrientationChangeComplete=true because wtoken "
-                            + wtoken + " numInteresting=" + numInteresting
-                            + " numDrawn=" + wtoken.numDrawnWindows);
-                    mInnerFields.mOrientationChangeComplete = true;
-                }
-            } else if (!wtoken.allDrawn) {
-                int numInteresting = wtoken.numInterestingWindows;
-                if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
-                    if (DEBUG_VISIBILITY) Slog.v(TAG,
-                            "allDrawn: " + wtoken
-                            + " interesting=" + numInteresting
-                            + " drawn=" + wtoken.numDrawnWindows);
-                    wtoken.allDrawn = true;
-                    changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
-
-                    // We can now show all of the drawn windows!
-                    if (!mOpeningApps.contains(wtoken)) {
-                        wtoken.showAllWindowsLocked();
-                    }
-                }
-            }
-        }
-
-        return changes;
-    }
-
-    /**
-     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
      *
      * @return bitmap indicating if another pass through layout must be made.
      */
@@ -8160,7 +7796,7 @@
                         transit, false);
                 wtoken.updateReportedVisibilityLocked();
                 wtoken.waitingToShow = false;
-                wtoken.showAllWindowsLocked();
+                mAnimator.mAnimating |= wtoken.showAllWindowsLocked();
             }
             NN = mClosingApps.size();
             for (i=0; i<NN; i++) {
@@ -8258,14 +7894,14 @@
         if (mLowerWallpaperTarget == null) {
             // Whoops, we don't need a special wallpaper animation.
             // Clear them out.
-            mInnerFields.mForceHiding = false;
+            mAnimator.mForceHiding = false;
             for (int i=mWindows.size()-1; i>=0; i--) {
                 WindowState w = mWindows.get(i);
                 if (w.mSurface != null) {
                     final WindowManager.LayoutParams attrs = w.mAttrs;
                     if (mPolicy.doesForceHide(w, attrs) && w.isVisibleLw()) {
                         if (DEBUG_FOCUS) Slog.i(TAG, "win=" + w + " force hides other windows");
-                        mInnerFields.mForceHiding = true;
+                        mAnimator.mForceHiding = true;
                     } else if (mPolicy.canBeForceHidden(w, attrs)) {
                         if (!w.mAnimating) {
                             // We set the animation above so it
@@ -8296,14 +7932,14 @@
             mInnerFields.mWallpaperMayChange = true;
         }
 
-        if (mInnerFields.mWindowAnimationBackgroundColor != 0) {
+        if (mAnimator.mWindowAnimationBackgroundColor != 0) {
             // If the window that wants black is the current wallpaper
             // target, then the black goes *below* the wallpaper so we
             // don't cause the wallpaper to suddenly disappear.
-            WindowState target = mInnerFields.mWindowAnimationBackground;
-            if (mWallpaperTarget == mInnerFields.mWindowAnimationBackground
-                    || mLowerWallpaperTarget == mInnerFields.mWindowAnimationBackground
-                    || mUpperWallpaperTarget == mInnerFields.mWindowAnimationBackground) {
+            WindowState target = mAnimator.mWindowAnimationBackground;
+            if (mWallpaperTarget == target
+                    || mLowerWallpaperTarget == target
+                    || mUpperWallpaperTarget == target) {
                 for (int i=0; i<mWindows.size(); i++) {
                     WindowState w = mWindows.get(i);
                     if (w.mIsWallpaper) {
@@ -8319,7 +7955,7 @@
             final int dh = mCurDisplayHeight;
             mWindowAnimationBackgroundSurface.show(dw, dh,
                     target.mAnimLayer - LAYER_OFFSET_DIM,
-                    mInnerFields.mWindowAnimationBackgroundColor);
+                    mAnimator.mWindowAnimationBackgroundColor);
         } else if (mWindowAnimationBackgroundSurface != null) {
             mWindowAnimationBackgroundSurface.hide();
         }
@@ -8422,206 +8058,6 @@
     /**
      * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
      *
-     * @param w WindowState whos Surface is being prepared.
-     * @param recoveringMemory true if the caller will reclaim surface memory on error.
-     */
-    public void prepareSurfaceLocked(final WindowState w, final boolean recoveringMemory) {
-        // XXX NOTE: The logic here could be improved.  We have
-        // the decision about whether to resize a window separated
-        // from whether to hide the surface.  This can cause us to
-        // resize a surface even if we are going to hide it.  You
-        // can see this by (1) holding device in landscape mode on
-        // home screen; (2) tapping browser icon (device will rotate
-        // to landscape; (3) tap home.  The wallpaper will be resized
-        // in step 2 but then immediately hidden, causing us to
-        // have to resize and then redraw it again in step 3.  It
-        // would be nice to figure out how to avoid this, but it is
-        // difficult because we do need to resize surfaces in some
-        // cases while they are hidden such as when first showing a
-        // window.
-        
-        if (w.mSurface == null) {
-            if (w.mOrientationChanging) {
-                if (DEBUG_ORIENTATION) {
-                    Slog.v(TAG, "Orientation change skips hidden " + w);
-                }
-                w.mOrientationChanging = false;
-            }
-            return;
-        }
-        
-        boolean displayed = false;
-
-        w.computeShownFrameLocked();
-
-        int width, height;
-        if ((w.mAttrs.flags & w.mAttrs.FLAG_SCALED) != 0) {
-            // for a scaled surface, we just want to use
-            // the requested size.
-            width  = w.mRequestedWidth;
-            height = w.mRequestedHeight;
-        } else {
-            width = w.mCompatFrame.width();
-            height = w.mCompatFrame.height();
-        }
-
-        if (width < 1) {
-            width = 1;
-        }
-        if (height < 1) {
-            height = 1;
-        }
-        final boolean surfaceResized = w.mSurfaceW != width || w.mSurfaceH != height;
-        if (surfaceResized) {
-            w.mSurfaceW = width;
-            w.mSurfaceH = height;
-        }
-
-        if (w.mSurfaceX != w.mShownFrame.left
-                || w.mSurfaceY != w.mShownFrame.top) {
-            try {
-                if (SHOW_TRANSACTIONS) logSurface(w,
-                        "POS " + w.mShownFrame.left
-                        + ", " + w.mShownFrame.top, null);
-                w.mSurfaceX = w.mShownFrame.left;
-                w.mSurfaceY = w.mShownFrame.top;
-                w.mSurface.setPosition(w.mShownFrame.left, w.mShownFrame.top);
-            } catch (RuntimeException e) {
-                Slog.w(TAG, "Error positioning surface of " + w
-                        + " pos=(" + w.mShownFrame.left
-                        + "," + w.mShownFrame.top + ")", e);
-                if (!recoveringMemory) {
-                    reclaimSomeSurfaceMemoryLocked(w, "position", true);
-                }
-            }
-        }
-
-        if (surfaceResized) {
-            try {
-                if (SHOW_TRANSACTIONS) logSurface(w,
-                        "SIZE " + width + "x" + height, null);
-                w.mSurfaceResized = true;
-                w.mSurface.setSize(width, height);
-            } catch (RuntimeException e) {
-                // If something goes wrong with the surface (such
-                // as running out of memory), don't take down the
-                // entire system.
-                Slog.e(TAG, "Error resizing surface of " + w
-                        + " size=(" + width + "x" + height + ")", e);
-                if (!recoveringMemory) {
-                    reclaimSomeSurfaceMemoryLocked(w, "size", true);
-                }
-            }
-        }
-
-        updateResizingWindows(w);
-
-        if (w.mAttachedHidden || !w.isReadyForDisplay()) {
-            if (!w.mLastHidden) {
-                //dump();
-                w.mLastHidden = true;
-                if (SHOW_TRANSACTIONS) logSurface(w,
-                        "HIDE (performLayout)", null);
-                if (w.mSurface != null) {
-                    w.mSurfaceShown = false;
-                    try {
-                        w.mSurface.hide();
-                    } catch (RuntimeException e) {
-                        Slog.w(TAG, "Exception hiding surface in " + w);
-                    }
-                }
-            }
-            // If we are waiting for this window to handle an
-            // orientation change, well, it is hidden, so
-            // doesn't really matter.  Note that this does
-            // introduce a potential glitch if the window
-            // becomes unhidden before it has drawn for the
-            // new orientation.
-            if (w.mOrientationChanging) {
-                w.mOrientationChanging = false;
-                if (DEBUG_ORIENTATION) Slog.v(TAG,
-                        "Orientation change skips hidden " + w);
-            }
-        } else if (w.mLastLayer != w.mAnimLayer
-                || w.mLastAlpha != w.mShownAlpha
-                || w.mLastDsDx != w.mDsDx
-                || w.mLastDtDx != w.mDtDx
-                || w.mLastDsDy != w.mDsDy
-                || w.mLastDtDy != w.mDtDy
-                || w.mLastHScale != w.mHScale
-                || w.mLastVScale != w.mVScale
-                || w.mLastHidden) {
-            displayed = true;
-            w.mLastAlpha = w.mShownAlpha;
-            w.mLastLayer = w.mAnimLayer;
-            w.mLastDsDx = w.mDsDx;
-            w.mLastDtDx = w.mDtDx;
-            w.mLastDsDy = w.mDsDy;
-            w.mLastDtDy = w.mDtDy;
-            w.mLastHScale = w.mHScale;
-            w.mLastVScale = w.mVScale;
-            if (SHOW_TRANSACTIONS) logSurface(w,
-                    "alpha=" + w.mShownAlpha + " layer=" + w.mAnimLayer
-                    + " matrix=[" + (w.mDsDx*w.mHScale)
-                    + "," + (w.mDtDx*w.mVScale)
-                    + "][" + (w.mDsDy*w.mHScale)
-                    + "," + (w.mDtDy*w.mVScale) + "]", null);
-            if (w.mSurface != null) {
-                try {
-                    w.mSurfaceAlpha = w.mShownAlpha;
-                    w.mSurface.setAlpha(w.mShownAlpha);
-                    w.mSurfaceLayer = w.mAnimLayer;
-                    w.mSurface.setLayer(w.mAnimLayer);
-                    w.mSurface.setMatrix(
-                            w.mDsDx*w.mHScale, w.mDtDx*w.mVScale,
-                            w.mDsDy*w.mHScale, w.mDtDy*w.mVScale);
-                } catch (RuntimeException e) {
-                    Slog.w(TAG, "Error updating surface in " + w, e);
-                    if (!recoveringMemory) {
-                        reclaimSomeSurfaceMemoryLocked(w, "update", true);
-                    }
-                }
-            }
-
-            if (w.mLastHidden && w.isDrawnLw()
-                    && !w.mReadyToShow) {
-                if (SHOW_TRANSACTIONS) logSurface(w,
-                        "SHOW (performLayout)", null);
-                if (DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + w
-                        + " during relayout");
-                if (showSurfaceRobustlyLocked(w)) {
-                    w.mHasDrawn = true;
-                    w.mLastHidden = false;
-                } else {
-                    w.mOrientationChanging = false;
-                }
-            }
-            if (w.mSurface != null) {
-                w.mToken.hasVisible = true;
-            }
-        } else {
-            displayed = true;
-        }
-
-        if (displayed) {
-            if (w.mOrientationChanging) {
-                if (!w.isDrawnLw()) {
-                    mInnerFields.mOrientationChangeComplete = false;
-                    if (DEBUG_ORIENTATION) Slog.v(TAG,
-                            "Orientation continue waiting for draw in " + w);
-                } else {
-                    w.mOrientationChanging = false;
-                    if (DEBUG_ORIENTATION) Slog.v(TAG,
-                            "Orientation change complete in " + w);
-                }
-            }
-            w.mToken.hasVisible = true;
-        }
-    }
-
-    /**
-     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
-     *
      * @param w WindowState this method is applied to.
      * @param currentTime The time which animations use for calculating transitions.
      * @param innerDw Width of app window.
@@ -8656,132 +8092,28 @@
         boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
         if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
             // This window completely covers everything behind it,
-            // so we want to leave all of them as unblurred (for
+            // so we want to leave all of them as undimmed (for
             // performance reasons).
             mInnerFields.mObscured = true;
-        } else if (canBeSeen && (attrFlags & (FLAG_BLUR_BEHIND | FLAG_DIM_BEHIND)) != 0) {
-            if (localLOGV) Slog.v(TAG, "Win " + w
-                    + ": blurring=" + mInnerFields.mBlurring
-                    + " obscured=" + mInnerFields.mObscured);
-            if ((attrFlags&FLAG_DIM_BEHIND) != 0) {
-                if (!mInnerFields.mDimming) {
-                    //Slog.i(TAG, "DIM BEHIND: " + w);
-                    mInnerFields.mDimming = true;
-                    if (mDimAnimator == null) {
-                        mDimAnimator = new DimAnimator(mFxSession);
-                    }
-                    if (attrs.type == WindowManager.LayoutParams.TYPE_BOOT_PROGRESS) {
-                        mDimAnimator.show(mCurDisplayWidth, mCurDisplayHeight);
-                    } else {
-                        mDimAnimator.show(innerDw, innerDh);
-                    }
-                    mDimAnimator.updateParameters(mContext.getResources(),
-                            w, currentTime);
+        } else if (canBeSeen && (attrFlags & FLAG_DIM_BEHIND) != 0) {
+            if (localLOGV) Slog.v(TAG, "Win " + w + " obscured=" + mInnerFields.mObscured);
+            if (!mInnerFields.mDimming) {
+                //Slog.i(TAG, "DIM BEHIND: " + w);
+                mInnerFields.mDimming = true;
+                if (mDimAnimator == null) {
+                    mDimAnimator = new DimAnimator(mFxSession);
                 }
-            }
-            if ((attrFlags & FLAG_BLUR_BEHIND) != 0) {
-                if (!mInnerFields.mBlurring) {
-                    //Slog.i(TAG, "BLUR BEHIND: " + w);
-                    mInnerFields.mBlurring = true;
-                    if (mBlurSurface == null) {
-                        try {
-                            mBlurSurface = new Surface(mFxSession, 0,
-                                    "BlurSurface",
-                                    -1, 16, 16,
-                                    PixelFormat.OPAQUE,
-                                    Surface.FX_SURFACE_BLUR);
-                        } catch (Exception e) {
-                            Slog.e(TAG, "Exception creating Blur surface", e);
-                        }
-                        if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BLUR "
-                                + mBlurSurface + ": CREATE");
-                    }
-                    final int dw = mCurDisplayWidth;
-                    final int dh = mCurDisplayHeight;
-                    if (mBlurSurface != null) {
-                        if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BLUR "
-                                + mBlurSurface + ": pos=(0,0) (" +
-                                dw + "x" + dh + "), layer=" + (w.mAnimLayer-1));
-                        mBlurSurface.setPosition(0, 0);
-                        mBlurSurface.setSize(dw, dh);
-                        mBlurSurface.setLayer(w.mAnimLayer-LAYER_OFFSET_BLUR);
-                        if (!mBlurShown) {
-                            try {
-                                if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BLUR "
-                                        + mBlurSurface + ": SHOW");
-                                mBlurSurface.show();
-                            } catch (RuntimeException e) {
-                                Slog.w(TAG, "Failure showing blur surface", e);
-                            }
-                            mBlurShown = true;
-                        }
-                    }
+                if (attrs.type == WindowManager.LayoutParams.TYPE_BOOT_PROGRESS) {
+                    mDimAnimator.show(mCurDisplayWidth, mCurDisplayHeight);
+                } else {
+                    mDimAnimator.show(innerDw, innerDh);
                 }
+                mDimAnimator.updateParameters(mContext.getResources(),
+                        w, currentTime);
             }
         }
     }
 
-    private final int performAnimationsLocked(long currentTime, int dw, int dh,
-            int innerDw, int innerDh) {
-        ++mTransactionSequence;
-
-        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: seq="
-                + mTransactionSequence + " mAnimating="
-                + mInnerFields.mAnimating);
-
-        mInnerFields.mTokenMayBeDrawn = false;
-        mInnerFields.mWallpaperMayChange = false;
-        mInnerFields.mForceHiding = false;
-        mInnerFields.mDetachedWallpaper = null;
-        mInnerFields.mWindowAnimationBackground = null;
-        mInnerFields.mWindowAnimationBackgroundColor = 0;
-
-        int changes = updateWindowsAndWallpaperLocked(currentTime, dw, dh, innerDw, innerDh);
-
-        if (mInnerFields.mTokenMayBeDrawn) {
-            changes |= testTokenMayBeDrawnLocked();
-        }
-
-        // If we are ready to perform an app transition, check through
-        // all of the app tokens to be shown and see if they are ready
-        // to go.
-        if (mAppTransitionReady) {
-            changes |= handleAppTransitionReadyLocked();
-        }
-
-        mInnerFields.mAdjResult = 0;
-
-        if (!mInnerFields.mAnimating && mAppTransitionRunning) {
-            // We have finished the animation of an app transition.  To do
-            // this, we have delayed a lot of operations like showing and
-            // hiding apps, moving apps in Z-order, etc.  The app token list
-            // reflects the correct Z-order, but the window list may now
-            // be out of sync with it.  So here we will just rebuild the
-            // entire app window list.  Fun!
-            changes |= handleAnimatingStoppedAndTransitionLocked();
-        }
-
-        if (mInnerFields.mWallpaperForceHidingChanged && changes == 0 && !mAppTransitionReady) {
-            // At this point, there was a window with a wallpaper that
-            // was force hiding other windows behind it, but now it
-            // is going away.  This may be simple -- just animate
-            // away the wallpaper and its window -- or it may be
-            // hard -- the wallpaper now needs to be shown behind
-            // something that was hidden.
-            changes |= animateAwayWallpaperLocked();
-        }
-
-        changes |= testWallpaperAndBackgroundLocked();
-
-        if (mLayoutNeeded) {
-            changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
-        }
-
-        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: changes=0x"
-                + Integer.toHexString(changes));
-        return changes;
-    }
-
     // "Something has changed!  Let's make it correct now."
     private final void performLayoutAndPlaceSurfacesLockedInner(
             boolean recoveringMemory) {
@@ -8819,7 +8151,7 @@
         mInnerFields.mScreenBrightness = -1;
         mInnerFields.mButtonBrightness = -1;
         boolean focusDisplayed = false;
-        mInnerFields.mAnimating = false;
+        mAnimator.mAnimating = false;
         boolean createWatermark = false;
 
         if (mFxSession == null) {
@@ -8895,7 +8227,6 @@
             final boolean someoneLosingFocus = !mLosingFocus.isEmpty();
 
             mInnerFields.mObscured = false;
-            mInnerFields.mBlurring = false;
             mInnerFields.mDimming = false;
             mInnerFields.mSyswin = false;
             
@@ -8930,9 +8261,53 @@
             Surface.closeTransaction();
         }
 
+        // If we are ready to perform an app transition, check through
+        // all of the app tokens to be shown and see if they are ready
+        // to go.
+        if (mAppTransitionReady) {
+            mPendingLayoutChanges |= handleAppTransitionReadyLocked();
+        }
+
+        mInnerFields.mAdjResult = 0;
+
+        if (!mAnimator.mAnimating && mAppTransitionRunning) {
+            // We have finished the animation of an app transition.  To do
+            // this, we have delayed a lot of operations like showing and
+            // hiding apps, moving apps in Z-order, etc.  The app token list
+            // reflects the correct Z-order, but the window list may now
+            // be out of sync with it.  So here we will just rebuild the
+            // entire app window list.  Fun!
+            mPendingLayoutChanges |= handleAnimatingStoppedAndTransitionLocked();
+        }
+
+        if (mInnerFields.mWallpaperForceHidingChanged && mPendingLayoutChanges == 0 &&
+                !mAppTransitionReady) {
+            // At this point, there was a window with a wallpaper that
+            // was force hiding other windows behind it, but now it
+            // is going away.  This may be simple -- just animate
+            // away the wallpaper and its window -- or it may be
+            // hard -- the wallpaper now needs to be shown behind
+            // something that was hidden.
+            mPendingLayoutChanges |= animateAwayWallpaperLocked();
+        }
+
+        mPendingLayoutChanges |= testWallpaperAndBackgroundLocked();
+
+        if (mLayoutNeeded) {
+            mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
+        }
+
+        final int N = mWindows.size();
+        for (i=N-1; i>=0; i--) {
+            WindowState w = mWindows.get(i);
+            // TODO(cmautner): Can this move up to the loop at the end of try/catch above?
+            updateResizingWindows(w);
+        }
+
         // Update animations of all applications, including those
         // associated with exiting/removed apps
-        animateAndUpdateSurfaces(currentTime, dw, dh, innerDw, innerDh, recoveringMemory);
+        mAnimator.animate();
+        mPendingLayoutChanges |= mAnimator.mPendingLayoutChanges;
 
         if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                 "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
@@ -9036,7 +8411,7 @@
 
         boolean needRelayout = false;
 
-        if (!mInnerFields.mAnimating && mAppTransitionRunning) {
+        if (!mAnimator.mAnimating && mAppTransitionRunning) {
             // We have finished the animation of an app transition.  To do
             // this, we have delayed a lot of operations like showing and
             // hiding apps, moving apps in Z-order, etc.  The app token list
@@ -9066,7 +8441,7 @@
         }
         if (needRelayout) {
             requestTraversalLocked();
-        } else if (mInnerFields.mAnimating) {
+        } else if (mAnimator.mAnimating) {
             scheduleAnimationLocked();
         }
 
@@ -9332,6 +8707,7 @@
                 TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus);
             final WindowState oldFocus = mCurrentFocus;
             mCurrentFocus = newFocus;
+            mAnimator.setCurrentFocus(mCurrentFocus);
             mLosingFocus.remove(newFocus);
             int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);
 
@@ -9472,16 +8848,16 @@
         }
 
         if (CUSTOM_SCREEN_ROTATION) {
-            if (mScreenRotationAnimation != null) {
-                mScreenRotationAnimation.kill();
-                mScreenRotationAnimation = null;
+            if (mAnimator.mScreenRotationAnimation != null) {
+                mAnimator.mScreenRotationAnimation.kill();
+                mAnimator.mScreenRotationAnimation = null;
             }
-            if (mScreenRotationAnimation == null) {
-                mScreenRotationAnimation = new ScreenRotationAnimation(mContext,
+            if (mAnimator.mScreenRotationAnimation == null) {
+                mAnimator.mScreenRotationAnimation = new ScreenRotationAnimation(mContext,
                         mFxSession, inTransaction, mCurDisplayWidth, mCurDisplayHeight,
                         mDisplay.getRotation());
             }
-            if (!mScreenRotationAnimation.hasScreenshot()) {
+            if (!mAnimator.mScreenRotationAnimation.hasScreenshot()) {
                 Surface.freezeDisplay(0);
             }
         } else {
@@ -9506,20 +8882,20 @@
 
         boolean updateRotation = false;
         
-        if (CUSTOM_SCREEN_ROTATION && mScreenRotationAnimation != null
-                && mScreenRotationAnimation.hasScreenshot()) {
+        if (CUSTOM_SCREEN_ROTATION && mAnimator.mScreenRotationAnimation != null
+                && mAnimator.mScreenRotationAnimation.hasScreenshot()) {
             if (DEBUG_ORIENTATION) Slog.i(TAG, "**** Dismissing screen rotation animation");
-            if (mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
+            if (mAnimator.mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
                     mTransitionAnimationScale, mCurDisplayWidth, mCurDisplayHeight)) {
                 scheduleAnimationLocked();
             } else {
-                mScreenRotationAnimation = null;
+                mAnimator.mScreenRotationAnimation = null;
                 updateRotation = true;
             }
         } else {
-            if (mScreenRotationAnimation != null) {
-                mScreenRotationAnimation.kill();
-                mScreenRotationAnimation = null;
+            if (mAnimator.mScreenRotationAnimation != null) {
+                mAnimator.mScreenRotationAnimation.kill();
+                mAnimator.mScreenRotationAnimation = null;
             }
             updateRotation = true;
         }
@@ -9986,8 +9362,7 @@
             }
             pw.print("  mSystemBooted="); pw.print(mSystemBooted);
                     pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
-            pw.print("  mLayoutNeeded="); pw.print(mLayoutNeeded);
-                    pw.print(" mBlurShown="); pw.println(mBlurShown);
+            pw.print("  mLayoutNeeded="); pw.println(mLayoutNeeded);
             if (mDimAnimator != null) {
                 pw.println("  mDimAnimator:");
                 mDimAnimator.printTo("    ", pw);
@@ -10003,9 +9378,9 @@
             pw.print("  mLastWindowForcedOrientation"); pw.print(mLastWindowForcedOrientation);
                     pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation);
             pw.print("  mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount);
-            if (mScreenRotationAnimation != null) {
+            if (mAnimator.mScreenRotationAnimation != null) {
                 pw.println("  mScreenRotationAnimation:");
-                mScreenRotationAnimation.printTo("    ", pw);
+                mAnimator.mScreenRotationAnimation.printTo("    ", pw);
             }
             pw.print("  mWindowAnimationScale="); pw.print(mWindowAnimationScale);
                     pw.print(" mTransitionWindowAnimationScale="); pw.print(mTransitionAnimationScale);
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 9fc7049..cf61f7f 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -1011,7 +1011,7 @@
         // Save the animation state as it was before this step so WindowManagerService can tell if
         // we just started or just stopped animating by comparing mWasAnimating with isAnimating().
         mWasAnimating = mAnimating;
-        if (!mService.mDisplayFrozen && mService.mPolicy.isScreenOnFully()) {
+        if (mService.okToDisplay()) {
             // We will run animations as long as the display isn't frozen.
 
             if (isDrawnLw() && mAnimation != null) {
@@ -1227,8 +1227,8 @@
             }
         }
 
-        final boolean screenAnimation = mService.mScreenRotationAnimation != null
-                && mService.mScreenRotationAnimation.isAnimating();
+        final boolean screenAnimation = mService.mAnimator.mScreenRotationAnimation != null
+                && mService.mAnimator.mScreenRotationAnimation.isAnimating();
         if (selfTransformation || attachedTransformation != null
                 || appTransformation != null || screenAnimation) {
             // cache often used attributes locally
@@ -1268,7 +1268,7 @@
             }
             if (screenAnimation) {
                 tmpMatrix.postConcat(
-                        mService.mScreenRotationAnimation.getEnterTransformation().getMatrix());
+                        mService.mAnimator.mScreenRotationAnimation.getEnterTransformation().getMatrix());
             }
 
             // "convert" it into SurfaceFlinger's format
@@ -1311,7 +1311,7 @@
                 }
                 if (screenAnimation) {
                     mShownAlpha *=
-                        mService.mScreenRotationAnimation.getEnterTransformation().getAlpha();
+                        mService.mAnimator.mScreenRotationAnimation.getEnterTransformation().getAlpha();
                 }
             } else {
                 //Slog.i(TAG, "Not applying alpha transform");
@@ -1515,11 +1515,10 @@
      * sense to call from performLayoutAndPlaceSurfacesLockedInner().)
      */
     boolean shouldAnimateMove() {
-        return mContentChanged && !mExiting && !mLastHidden && !mService.mDisplayFrozen
+        return mContentChanged && !mExiting && !mLastHidden && mService.okToDisplay()
                 && (mFrame.top != mLastFrame.top
                         || mFrame.left != mLastFrame.left)
-                && (mAttachedWindow == null || !mAttachedWindow.shouldAnimateMove())
-                && mService.mPolicy.isScreenOnFully();
+                && (mAttachedWindow == null || !mAttachedWindow.shouldAnimateMove());
     }
 
     boolean isFullscreen(int screenWidth, int screenHeight) {
@@ -1606,7 +1605,7 @@
         if (doAnimation) {
             if (DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "doAnimation: mPolicyVisibility="
                     + mPolicyVisibility + " mAnimation=" + mAnimation);
-            if (mService.mDisplayFrozen || !mService.mPolicy.isScreenOnFully()) {
+            if (!mService.okToDisplay()) {
                 doAnimation = false;
             } else if (mPolicyVisibility && mAnimation == null) {
                 // Check for the case where we are currently visible and
@@ -1632,7 +1631,7 @@
 
     boolean hideLw(boolean doAnimation, boolean requestAnim) {
         if (doAnimation) {
-            if (mService.mDisplayFrozen || !mService.mPolicy.isScreenOnFully()) {
+            if (!mService.okToDisplay()) {
                 doAnimation = false;
             }
         }
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index b4fd55e..88ee867 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -53,6 +53,7 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.Signature;
+import android.content.pm.UserInfo;
 import android.net.ConnectivityManager;
 import android.net.IConnectivityManager;
 import android.net.INetworkManagementEventObserver;
@@ -69,6 +70,7 @@
 import android.os.INetworkManagementService;
 import android.os.IPowerManager;
 import android.os.MessageQueue.IdleHandler;
+import android.os.UserId;
 import android.test.AndroidTestCase;
 import android.test.mock.MockPackageManager;
 import android.test.suitebuilder.annotation.LargeTest;
@@ -84,7 +86,9 @@
 import org.easymock.IAnswer;
 
 import java.io.File;
+import java.util.ArrayList;
 import java.util.LinkedHashSet;
+import java.util.List;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
@@ -126,8 +130,16 @@
     private long mStartTime;
     private long mElapsedRealtime;
 
-    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 USER_ID = 0;
+    private static final int USER_ID_GUEST = 1;
+
+    private static final int APP_ID_A = android.os.Process.FIRST_APPLICATION_UID + 800;
+    private static final int APP_ID_B = android.os.Process.FIRST_APPLICATION_UID + 801;
+
+    private static final int UID_A = UserId.getUid(USER_ID, APP_ID_A);
+    private static final int UID_B = UserId.getUid(USER_ID, APP_ID_B);
+    private static final int UID_A_GUEST = UserId.getUid(USER_ID_GUEST, APP_ID_A);
+    private static final int UID_B_GUEST = UserId.getUid(USER_ID_GUEST, APP_ID_B);
 
     private static final int PID_1 = 400;
     private static final int PID_2 = 401;
@@ -161,6 +173,14 @@
                         info.signatures = new Signature[] { signature };
                         return info;
                     }
+
+                    @Override
+                    public List<UserInfo> getUsers() {
+                        final ArrayList<UserInfo> users = new ArrayList<UserInfo>();
+                        users.add(new UserInfo(USER_ID, "Primary", UserInfo.FLAG_PRIMARY));
+                        users.add(new UserInfo(USER_ID_GUEST, "Guest", 0));
+                        return users;
+                    }
                 };
             }
 
@@ -242,13 +262,13 @@
 
     @Suppress
     public void testPolicyChangeTriggersBroadcast() throws Exception {
-        mService.setUidPolicy(UID_A, POLICY_NONE);
+        mService.setAppPolicy(APP_ID_A, POLICY_NONE);
 
         // change background policy and expect broadcast
         final Future<Intent> backgroundChanged = mServiceContext.nextBroadcastIntent(
                 ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
 
-        mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
+        mService.setAppPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND);
 
         backgroundChanged.get();
     }
@@ -302,6 +322,7 @@
 
     public void testScreenChangesRules() throws Exception {
         Future<Void> future;
+        Future<Void> futureGuest;
 
         expectSetUidNetworkRules(UID_A, false);
         expectSetUidForeground(UID_A, true);
@@ -314,10 +335,14 @@
         // push strict policy for foreground uid, verify ALLOW rule
         expectSetUidNetworkRules(UID_A, false);
         expectSetUidForeground(UID_A, true);
+        expectSetUidNetworkRules(UID_A_GUEST, true);
+        expectSetUidForeground(UID_A_GUEST, false);
         future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
+        futureGuest = expectRulesChanged(UID_A_GUEST, RULE_REJECT_METERED);
         replay();
-        mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
+        mService.setAppPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND);
         future.get();
+        futureGuest.get();
         verifyAndReset();
 
         // now turn screen off and verify REJECT rule
@@ -343,6 +368,7 @@
 
     public void testPolicyNone() throws Exception {
         Future<Void> future;
+        Future<Void> futureGuest;
 
         expectSetUidNetworkRules(UID_A, false);
         expectSetUidForeground(UID_A, true);
@@ -355,10 +381,14 @@
         // POLICY_NONE should RULE_ALLOW in foreground
         expectSetUidNetworkRules(UID_A, false);
         expectSetUidForeground(UID_A, true);
+        expectSetUidNetworkRules(UID_A_GUEST, false);
+        expectSetUidForeground(UID_A_GUEST, false);
         future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
+        futureGuest = expectRulesChanged(UID_A_GUEST, RULE_ALLOW_ALL);
         replay();
-        mService.setUidPolicy(UID_A, POLICY_NONE);
+        mService.setAppPolicy(APP_ID_A, POLICY_NONE);
         future.get();
+        futureGuest.get();
         verifyAndReset();
 
         // POLICY_NONE should RULE_ALLOW in background
@@ -373,14 +403,19 @@
 
     public void testPolicyReject() throws Exception {
         Future<Void> future;
+        Future<Void> futureGuest;
 
         // POLICY_REJECT should RULE_ALLOW in background
         expectSetUidNetworkRules(UID_A, true);
         expectSetUidForeground(UID_A, false);
+        expectSetUidNetworkRules(UID_A_GUEST, true);
+        expectSetUidForeground(UID_A_GUEST, false);
         future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
+        futureGuest = expectRulesChanged(UID_A_GUEST, RULE_REJECT_METERED);
         replay();
-        mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
+        mService.setAppPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND);
         future.get();
+        futureGuest.get();
         verifyAndReset();
 
         // POLICY_REJECT should RULE_ALLOW in foreground
@@ -404,33 +439,46 @@
 
     public void testPolicyRejectAddRemove() throws Exception {
         Future<Void> future;
+        Future<Void> futureGuest;
 
         // POLICY_NONE should have RULE_ALLOW in background
         expectSetUidNetworkRules(UID_A, false);
         expectSetUidForeground(UID_A, false);
+        expectSetUidNetworkRules(UID_A_GUEST, false);
+        expectSetUidForeground(UID_A_GUEST, false);
         future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
+        futureGuest = expectRulesChanged(UID_A_GUEST, RULE_ALLOW_ALL);
         replay();
         mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
-        mService.setUidPolicy(UID_A, POLICY_NONE);
+        mService.setAppPolicy(APP_ID_A, POLICY_NONE);
         future.get();
+        futureGuest.get();
         verifyAndReset();
 
         // adding POLICY_REJECT should cause RULE_REJECT
         expectSetUidNetworkRules(UID_A, true);
         expectSetUidForeground(UID_A, false);
+        expectSetUidNetworkRules(UID_A_GUEST, true);
+        expectSetUidForeground(UID_A_GUEST, false);
         future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
+        futureGuest = expectRulesChanged(UID_A_GUEST, RULE_REJECT_METERED);
         replay();
-        mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
+        mService.setAppPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND);
         future.get();
+        futureGuest.get();
         verifyAndReset();
 
         // removing POLICY_REJECT should return us to RULE_ALLOW
         expectSetUidNetworkRules(UID_A, false);
         expectSetUidForeground(UID_A, false);
+        expectSetUidNetworkRules(UID_A_GUEST, false);
+        expectSetUidForeground(UID_A_GUEST, false);
         future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
+        futureGuest = expectRulesChanged(UID_A_GUEST, RULE_ALLOW_ALL);
         replay();
-        mService.setUidPolicy(UID_A, POLICY_NONE);
+        mService.setAppPolicy(APP_ID_A, POLICY_NONE);
         future.get();
+        futureGuest.get();
         verifyAndReset();
     }
 
@@ -599,25 +647,34 @@
 
     public void testUidRemovedPolicyCleared() throws Exception {
         Future<Void> future;
+        Future<Void> futureGuest;
 
         // POLICY_REJECT should RULE_REJECT in background
         expectSetUidNetworkRules(UID_A, true);
         expectSetUidForeground(UID_A, false);
+        expectSetUidNetworkRules(UID_A_GUEST, true);
+        expectSetUidForeground(UID_A_GUEST, false);
         future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
+        futureGuest = expectRulesChanged(UID_A_GUEST, RULE_REJECT_METERED);
         replay();
-        mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
+        mService.setAppPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND);
         future.get();
+        futureGuest.get();
         verifyAndReset();
 
         // uninstall should clear RULE_REJECT
         expectSetUidNetworkRules(UID_A, false);
         expectSetUidForeground(UID_A, false);
+        expectSetUidNetworkRules(UID_A_GUEST, false);
+        expectSetUidForeground(UID_A_GUEST, false);
         future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
+        futureGuest = expectRulesChanged(UID_A_GUEST, RULE_ALLOW_ALL);
         replay();
         final Intent intent = new Intent(ACTION_UID_REMOVED);
         intent.putExtra(EXTRA_UID, UID_A);
         mServiceContext.sendBroadcast(intent);
         future.get();
+        futureGuest.get();
         verifyAndReset();
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
new file mode 100644
index 0000000..796372d
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2012 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.pm;
+
+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.content.PackageHelper;
+import com.android.internal.os.AtomicFile;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.HashSet;
+
+import android.os.Debug;
+import android.os.Environment;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.storage.IMountService;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+public class PackageManagerSettingsTests extends AndroidTestCase {
+
+    private static final String PACKAGE_NAME_2 = "com.google.app2";
+    private static final String PACKAGE_NAME_3 = "com.android.app3";
+    private static final String PACKAGE_NAME_1 = "com.google.app1";
+    private static final boolean localLOGV = true;
+    public static final String TAG = "PackageManagerSettingsTests";
+    protected final String PREFIX = "android.content.pm";
+
+    private void writeFile(File file, byte[] data) {
+        file.mkdirs();
+        try {
+            AtomicFile aFile = new AtomicFile(file);
+            FileOutputStream fos = aFile.startWrite();
+            fos.write(data);
+            aFile.finishWrite(fos);
+        } catch (IOException ioe) {
+            Log.e(TAG, "Cannot write file " + file.getPath());
+        }
+    }
+
+    private void writePackagesXml() {
+        writeFile(new File(getContext().getFilesDir(), "system/packages.xml"),
+                ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+                + "<packages>"
+                + "<last-platform-version internal=\"15\" external=\"0\" />"
+                + "<permission-trees>"
+                + "<item name=\"com.google.android.permtree\" package=\"com.google.android.permpackage\" />"
+                + "</permission-trees>"
+                + "<permissions>"
+                + "<item name=\"android.permission.WRITE_CALL_LOG\" package=\"android\" protection=\"1\" />"
+                + "<item name=\"android.permission.ASEC_ACCESS\" package=\"android\" protection=\"2\" />"
+                + "<item name=\"android.permission.ACCESS_WIMAX_STATE\" package=\"android\" />"
+                + "<item name=\"android.permission.REBOOT\" package=\"android\" protection=\"18\" />"
+                + "</permissions>"
+                + "<package name=\"com.google.app1\" codePath=\"/system/app/app1.apk\" nativeLibraryPath=\"/data/data/com.google.app1/lib\" flags=\"1\" ft=\"1360e2caa70\" it=\"135f2f80d08\" ut=\"1360e2caa70\" version=\"1109\" sharedUserId=\"11000\">"
+                + "<sigs count=\"1\">"
+                + "<cert index=\"0\" key=\"308886\" />"
+                + "</sigs>"
+                + "</package>"
+                + "<package name=\"com.google.app2\" codePath=\"/system/app/app2.apk\" nativeLibraryPath=\"/data/data/com.google.app2/lib\" flags=\"1\" ft=\"1360e578718\" it=\"135f2f80d08\" ut=\"1360e578718\" version=\"15\" enabled=\"3\" userId=\"11001\">"
+                + "<sigs count=\"1\">"
+                + "<cert index=\"0\" />"
+                + "</sigs>"
+                + "</package>"
+                + "<package name=\"com.android.app3\" codePath=\"/system/app/app3.apk\" nativeLibraryPath=\"/data/data/com.android.app3/lib\" flags=\"1\" ft=\"1360e577b60\" it=\"135f2f80d08\" ut=\"1360e577b60\" version=\"15\" userId=\"11030\">"
+                + "<sigs count=\"1\">"
+                + "<cert index=\"1\" key=\"308366\" />"
+                + "</sigs>"
+                + "</package>"
+                + "<shared-user name=\"com.android.shared1\" userId=\"11000\">"
+                + "<sigs count=\"1\">"
+                + "<cert index=\"1\" />"
+                + "</sigs>"
+                + "<perms>"
+                + "<item name=\"android.permission.REBOOT\" />"
+                + "</perms>"
+                + "</shared-user>"
+                + "</packages>").getBytes());
+    }
+
+    private void writeStoppedPackagesXml() {
+        writeFile(new File(getContext().getFilesDir(), "system/packages-stopped.xml"),
+                ( "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+                + "<stopped-packages>"
+                + "<pkg name=\"com.google.app1\" nl=\"1\" />"
+                + "<pkg name=\"com.android.app3\" nl=\"1\" />"
+                + "</stopped-packages>")
+                .getBytes());
+    }
+
+    private void writePackagesList() {
+        writeFile(new File(getContext().getFilesDir(), "system/packages.list"),
+                ( "com.google.app1 11000 0 /data/data/com.google.app1"
+                + "com.google.app2 11001 0 /data/data/com.google.app2"
+                + "com.android.app3 11030 0 /data/data/com.android.app3")
+                .getBytes());
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    private void writeOldFiles() {
+        writePackagesXml();
+        writeStoppedPackagesXml();
+        writePackagesList();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    public void testSettingsReadOld() {
+        // Debug.waitForDebugger();
+
+        // Write the package files and make sure they're parsed properly the first time
+        writeOldFiles();
+        Settings settings = new Settings(getContext().getFilesDir());
+        assertEquals(true, settings.readLPw(null));
+        assertNotNull(settings.peekPackageLPr(PACKAGE_NAME_3));
+        assertNotNull(settings.peekPackageLPr(PACKAGE_NAME_1));
+
+        PackageSetting ps = settings.peekPackageLPr(PACKAGE_NAME_1);
+        assertEquals(COMPONENT_ENABLED_STATE_DEFAULT, ps.getEnabled(0));
+        assertEquals(true, ps.getNotLaunched(0));
+
+        ps = settings.peekPackageLPr(PACKAGE_NAME_2);
+        assertEquals(false, ps.getStopped(0));
+        assertEquals(COMPONENT_ENABLED_STATE_DISABLED_USER, ps.getEnabled(0));
+        assertEquals(COMPONENT_ENABLED_STATE_DEFAULT, ps.getEnabled(1));
+    }
+
+    public void testNewPackageRestrictionsFile() {
+        // Write the package files and make sure they're parsed properly the first time
+        writeOldFiles();
+        Settings settings = new Settings(getContext().getFilesDir());
+        assertEquals(true, settings.readLPw(null));
+
+        // Create Settings again to make it read from the new files
+        settings = new Settings(getContext().getFilesDir());
+        assertEquals(true, settings.readLPw(null));
+
+        PackageSetting ps = settings.peekPackageLPr(PACKAGE_NAME_2);
+        assertEquals(COMPONENT_ENABLED_STATE_DISABLED_USER, ps.getEnabled(0));
+        assertEquals(COMPONENT_ENABLED_STATE_DEFAULT, ps.getEnabled(1));
+    }
+
+    public void testEnableDisable() {
+        // Write the package files and make sure they're parsed properly the first time
+        writeOldFiles();
+        Settings settings = new Settings(getContext().getFilesDir());
+        assertEquals(true, settings.readLPw(null));
+
+        // Enable/Disable a package
+        PackageSetting ps = settings.peekPackageLPr(PACKAGE_NAME_1);
+        ps.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, 0);
+        ps.setEnabled(COMPONENT_ENABLED_STATE_ENABLED, 1);
+        assertEquals(COMPONENT_ENABLED_STATE_DISABLED, ps.getEnabled(0));
+        assertEquals(COMPONENT_ENABLED_STATE_ENABLED, ps.getEnabled(1));
+
+        // Enable/Disable a component
+        HashSet<String> components = new HashSet<String>();
+        String component1 = PACKAGE_NAME_1 + "/.Component1";
+        components.add(component1);
+        ps.setDisabledComponents(components, 0);
+        HashSet<String> componentsDisabled = ps.getDisabledComponents(0);
+        assertEquals(1, componentsDisabled.size());
+        assertEquals(component1, componentsDisabled.toArray()[0]);
+        boolean hasEnabled =
+                ps.getEnabledComponents(0) != null && ps.getEnabledComponents(1).size() > 0;
+        assertEquals(false, hasEnabled);
+
+        // User 1 should not have any disabled components
+        boolean hasDisabled =
+                ps.getDisabledComponents(1) != null && ps.getDisabledComponents(1).size() > 0;
+        assertEquals(false, hasDisabled);
+        ps.setEnabledComponents(components, 1);
+        assertEquals(1, ps.getEnabledComponents(1).size());
+        hasEnabled = ps.getEnabledComponents(0) != null && ps.getEnabledComponents(0).size() > 0;
+        assertEquals(false, hasEnabled);
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/AdnRecordCache.java b/telephony/java/com/android/internal/telephony/AdnRecordCache.java
index a175d49..db5f4da 100644
--- a/telephony/java/com/android/internal/telephony/AdnRecordCache.java
+++ b/telephony/java/com/android/internal/telephony/AdnRecordCache.java
@@ -33,7 +33,7 @@
 public final class AdnRecordCache extends Handler implements IccConstants {
     //***** Instance Variables
 
-    PhoneBase phone;
+    private IccFileHandler mFh;
     private UsimPhoneBookManager mUsimPhoneBookManager;
 
     // Indexed by EF ID
@@ -56,9 +56,9 @@
 
 
 
-    public AdnRecordCache(PhoneBase phone) {
-        this.phone = phone;
-        mUsimPhoneBookManager = new UsimPhoneBookManager(phone, this);
+    public AdnRecordCache(IccFileHandler fh) {
+        mFh = fh;
+        mUsimPhoneBookManager = new UsimPhoneBookManager(mFh, this);
     }
 
     //***** Called from SIMRecords
@@ -155,7 +155,7 @@
 
         userWriteResponse.put(efid, response);
 
-        new AdnRecordLoader(phone).updateEF(adn, efid, extensionEF,
+        new AdnRecordLoader(mFh).updateEF(adn, efid, extensionEF,
                 recordIndex, pin2,
                 obtainMessage(EVENT_UPDATE_ADN_DONE, efid, recordIndex, adn));
     }
@@ -233,7 +233,7 @@
 
         userWriteResponse.put(efid, response);
 
-        new AdnRecordLoader(phone).updateEF(newAdn, efid, extensionEF,
+        new AdnRecordLoader(mFh).updateEF(newAdn, efid, extensionEF,
                 index, pin2,
                 obtainMessage(EVENT_UPDATE_ADN_DONE, efid, index, newAdn));
     }
@@ -296,7 +296,7 @@
             return;
         }
 
-        new AdnRecordLoader(phone).loadAllFromEF(efid, extensionEf,
+        new AdnRecordLoader(mFh).loadAllFromEF(efid, extensionEf,
             obtainMessage(EVENT_LOAD_ALL_ADN_LIKE_DONE, efid, 0));
     }
 
diff --git a/telephony/java/com/android/internal/telephony/AdnRecordLoader.java b/telephony/java/com/android/internal/telephony/AdnRecordLoader.java
index 55bdc06..084fae6 100644
--- a/telephony/java/com/android/internal/telephony/AdnRecordLoader.java
+++ b/telephony/java/com/android/internal/telephony/AdnRecordLoader.java
@@ -20,16 +20,17 @@
 
 import android.os.AsyncResult;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
 import android.util.Log;
 
 
 public class AdnRecordLoader extends Handler {
-    static String LOG_TAG;
+    final static String LOG_TAG = "RIL_AdnRecordLoader";
 
     //***** Instance Variables
 
-    PhoneBase phone;
+    private IccFileHandler mFh;
     int ef;
     int extensionEF;
     int pendingExtLoads;
@@ -56,13 +57,11 @@
 
     //***** Constructor
 
-    public AdnRecordLoader(PhoneBase phone) {
+    public AdnRecordLoader(IccFileHandler fh) {
         // The telephony unit-test cases may create AdnRecords
         // in secondary threads
-        super(phone.getHandler().getLooper());
-
-        this.phone = phone;
-        LOG_TAG = phone.getPhoneName();
+        super(Looper.getMainLooper());
+        mFh = fh;
     }
 
     /**
@@ -77,7 +76,7 @@
         this.recordNumber = recordNumber;
         this.userResponse = response;
 
-        phone.mIccFileHandler.loadEFLinearFixed(
+        mFh.loadEFLinearFixed(
                     ef, recordNumber,
                     obtainMessage(EVENT_ADN_LOAD_DONE));
 
@@ -95,7 +94,7 @@
         this.extensionEF = extensionEF;
         this.userResponse = response;
 
-        phone.mIccFileHandler.loadEFLinearFixedAll(
+        mFh.loadEFLinearFixedAll(
                     ef,
                     obtainMessage(EVENT_ADN_LOAD_ALL_DONE));
 
@@ -122,7 +121,7 @@
         this.userResponse = response;
         this.pin2 = pin2;
 
-        phone.mIccFileHandler.getEFLinearRecordSize( ef,
+        mFh.getEFLinearRecordSize( ef,
             obtainMessage(EVENT_EF_LINEAR_RECORD_SIZE_DONE, adn));
     }
 
@@ -163,7 +162,7 @@
                                 ar.exception);
                     }
 
-                    phone.mIccFileHandler.updateEFLinearFixed(ef, recordNumber,
+                    mFh.updateEFLinearFixed(ef, recordNumber,
                             data, pin2, obtainMessage(EVENT_UPDATE_RECORD_DONE));
 
                     pendingExtLoads = 1;
@@ -203,7 +202,7 @@
 
                         pendingExtLoads = 1;
 
-                        phone.mIccFileHandler.loadEFLinearFixed(
+                        mFh.loadEFLinearFixed(
                             extensionEF, adn.extRecord,
                             obtainMessage(EVENT_EXT_RECORD_LOAD_DONE, adn));
                     }
@@ -253,7 +252,7 @@
 
                             pendingExtLoads++;
 
-                            phone.mIccFileHandler.loadEFLinearFixed(
+                            mFh.loadEFLinearFixed(
                                 extensionEF, adn.extRecord,
                                 obtainMessage(EVENT_EXT_RECORD_LOAD_DONE, adn));
                         }
diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java
index 965bafa..2139917 100644
--- a/telephony/java/com/android/internal/telephony/IccCard.java
+++ b/telephony/java/com/android/internal/telephony/IccCard.java
@@ -37,6 +37,7 @@
 import com.android.internal.telephony.CommandsInterface.RadioState;
 import com.android.internal.telephony.gsm.SIMFileHandler;
 import com.android.internal.telephony.gsm.SIMRecords;
+import com.android.internal.telephony.cat.CatService;
 import com.android.internal.telephony.cdma.CDMALTEPhone;
 import com.android.internal.telephony.cdma.CdmaLteUiccFileHandler;
 import com.android.internal.telephony.cdma.CdmaLteUiccRecords;
@@ -65,6 +66,8 @@
     protected PhoneBase mPhone;
     private IccRecords mIccRecords;
     private IccFileHandler mIccFileHandler;
+    private CatService mCatService;
+
     private RegistrantList mAbsentRegistrants = new RegistrantList();
     private RegistrantList mPinLockedRegistrants = new RegistrantList();
     private RegistrantList mNetworkLockedRegistrants = new RegistrantList();
@@ -185,14 +188,17 @@
                 mPhone.mCM, mHandler, EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null);
         if (phone.mCM.getLteOnCdmaMode() == Phone.LTE_ON_CDMA_TRUE
                 && phone instanceof CDMALTEPhone) {
-            mIccRecords = new CdmaLteUiccRecords(phone);
             mIccFileHandler = new CdmaLteUiccFileHandler(this, "", mPhone.mCM);
+            mIccRecords = new CdmaLteUiccRecords(this, mPhone.mContext, mPhone.mCM);
         } else {
-            mIccRecords = is3gpp ? new SIMRecords(phone) : new RuimRecords(phone);
             // Correct aid will be set later (when GET_SIM_STATUS returns)
             mIccFileHandler = is3gpp ? new SIMFileHandler(this, "", mPhone.mCM) :
                                        new RuimFileHandler(this, "", mPhone.mCM);
+            mIccRecords = is3gpp ? new SIMRecords(this, mPhone.mContext, mPhone.mCM) :
+                                   new RuimRecords(this, mPhone.mContext, mPhone.mCM);
         }
+        mCatService = CatService.getInstance(mPhone.mCM, mIccRecords,
+                mPhone.mContext, mIccFileHandler, this);
         mPhone.mCM.registerForOffOrNotAvailable(mHandler, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
         mPhone.mCM.registerForOn(mHandler, EVENT_RADIO_ON, null);
         mPhone.mCM.registerForIccStatusChanged(mHandler, EVENT_ICC_STATUS_CHANGED, null);
@@ -203,6 +209,7 @@
         mPhone.mCM.unregisterForIccStatusChanged(mHandler);
         mPhone.mCM.unregisterForOffOrNotAvailable(mHandler);
         mPhone.mCM.unregisterForOn(mHandler);
+        mCatService.dispose();
         mCdmaSSM.dispose(mHandler);
         mIccRecords.dispose();
         mIccFileHandler.dispose();
diff --git a/telephony/java/com/android/internal/telephony/IccRecords.java b/telephony/java/com/android/internal/telephony/IccRecords.java
index 6e82903..41c9d5a 100644
--- a/telephony/java/com/android/internal/telephony/IccRecords.java
+++ b/telephony/java/com/android/internal/telephony/IccRecords.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.telephony;
 
+import android.content.Context;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Message;
@@ -32,9 +33,16 @@
 
     protected static final boolean DBG = true;
     // ***** Instance Variables
+    protected boolean mDestroyed = false; // set to true once this object needs to be disposed of
+    protected Context mContext;
+    protected CommandsInterface mCi;
+    protected IccFileHandler mFh;
+    protected IccCard mParentCard;
 
-    protected PhoneBase phone;
     protected RegistrantList recordsLoadedRegistrants = new RegistrantList();
+    protected RegistrantList mRecordsEventsRegistrants = new RegistrantList();
+    protected RegistrantList mNewSmsRegistrants = new RegistrantList();
+    protected RegistrantList mNetworkSelectionModeAutomaticRegistrants = new RegistrantList();
 
     protected int recordsToLoad;  // number of pending load requests
 
@@ -71,6 +79,9 @@
 
     // ***** Event Constants
     protected static final int EVENT_SET_MSISDN_DONE = 30;
+    public static final int EVENT_MWI = 0;
+    public static final int EVENT_CFI = 1;
+    public static final int EVENT_SPN = 2;
 
     public static final int EVENT_GET_ICC_RECORD_DONE = 100;
 
@@ -91,15 +102,23 @@
     }
 
     // ***** Constructor
-
-    public IccRecords(PhoneBase p) {
-        this.phone = p;
+    public IccRecords(IccCard card, Context c, CommandsInterface ci) {
+        mContext = c;
+        mCi = ci;
+        mFh = card.getIccFileHandler();
+        mParentCard = card;
     }
 
     /**
      * Call when the IccRecords object is no longer going to be used.
      */
-    public abstract void dispose();
+    public void dispose() {
+        mDestroyed = true;
+        mParentCard = null;
+        mFh = null;
+        mCi = null;
+        mContext = null;
+    }
 
     protected abstract void onRadioOffOrNotAvailable();
     public abstract void onReady();
@@ -109,7 +128,15 @@
         return adnCache;
     }
 
+    public IccCard getIccCard() {
+        return mParentCard;
+    }
+
     public void registerForRecordsLoaded(Handler h, int what, Object obj) {
+        if (mDestroyed) {
+            return;
+        }
+
         Registrant r = new Registrant(h, what, obj);
         recordsLoadedRegistrants.add(r);
 
@@ -117,11 +144,35 @@
             r.notifyRegistrant(new AsyncResult(null, null, null));
         }
     }
-
     public void unregisterForRecordsLoaded(Handler h) {
         recordsLoadedRegistrants.remove(h);
     }
 
+    public void registerForRecordsEvents(Handler h, int what, Object obj) {
+        Registrant r = new Registrant (h, what, obj);
+        mRecordsEventsRegistrants.add(r);
+    }
+    public void unregisterForRecordsEvents(Handler h) {
+        mRecordsEventsRegistrants.remove(h);
+    }
+
+    public void registerForNewSms(Handler h, int what, Object obj) {
+        Registrant r = new Registrant (h, what, obj);
+        mNewSmsRegistrants.add(r);
+    }
+    public void unregisterForNewSms(Handler h) {
+        mNewSmsRegistrants.remove(h);
+    }
+
+    public void registerForNetworkSelectionModeAutomatic(
+            Handler h, int what, Object obj) {
+        Registrant r = new Registrant (h, what, obj);
+        mNetworkSelectionModeAutomaticRegistrants.add(r);
+    }
+    public void unregisterForNetworkSelectionModeAutomatic(Handler h) {
+        mNetworkSelectionModeAutomaticRegistrants.remove(h);
+    }
+
     /**
      * Get the International Mobile Subscriber ID (IMSI) on a SIM
      * for GSM, UMTS and like networks. Default is null if IMSI is
@@ -163,7 +214,7 @@
 
         AdnRecord adn = new AdnRecord(msisdnTag, msisdn);
 
-        new AdnRecordLoader(phone).updateEF(adn, EF_MSISDN, EF_EXT1, 1, null,
+        new AdnRecordLoader(mFh).updateEF(adn, EF_MSISDN, EF_EXT1, 1, null,
                 obtainMessage(EVENT_SET_MSISDN_DONE, onComplete));
     }
 
diff --git a/telephony/java/com/android/internal/telephony/MccTable.java b/telephony/java/com/android/internal/telephony/MccTable.java
index cdce841..e206783 100644
--- a/telephony/java/com/android/internal/telephony/MccTable.java
+++ b/telephony/java/com/android/internal/telephony/MccTable.java
@@ -18,6 +18,7 @@
 
 import android.app.ActivityManagerNative;
 import android.app.AlarmManager;
+import android.app.IActivityManager;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.net.wifi.WifiManager;
@@ -167,10 +168,10 @@
     /**
      * Updates MCC and MNC device configuration information for application retrieving
      * correct version of resources.  If either MCC or MNC is 0, they will be ignored (not set).
-     * @param phone PhoneBae to act on.
+     * @param context Context to act on.
      * @param mccmnc truncated imsi with just the MCC and MNC - MNC assumed to be from 4th to end
      */
-    public static void updateMccMncConfiguration(PhoneBase phone, String mccmnc) {
+    public static void updateMccMncConfiguration(Context context, String mccmnc) {
         if (!TextUtils.isEmpty(mccmnc)) {
             int mcc, mnc;
 
@@ -185,9 +186,9 @@
             Log.d(LOG_TAG, "updateMccMncConfiguration: mcc=" + mcc + ", mnc=" + mnc);
 
             if (mcc != 0) {
-                setTimezoneFromMccIfNeeded(phone, mcc);
-                setLocaleFromMccIfNeeded(phone, mcc);
-                setWifiCountryCodeFromMcc(phone, mcc);
+                setTimezoneFromMccIfNeeded(context, mcc);
+                setLocaleFromMccIfNeeded(context, mcc);
+                setWifiCountryCodeFromMcc(context, mcc);
             }
             try {
                 Configuration config = ActivityManagerNative.getDefault().getConfiguration();
@@ -205,16 +206,68 @@
     }
 
     /**
+     * Utility code to set the system locale if it's not set already
+     * @param context Context to act on.
+     * @param language Two character language code desired
+     * @param country Two character country code desired
+     *
+     *  {@hide}
+     */
+    public static void setSystemLocale(Context context, String language, String country) {
+        String l = SystemProperties.get("persist.sys.language");
+        String c = SystemProperties.get("persist.sys.country");
+
+        if (null == language) {
+            return; // no match possible
+        }
+        language = language.toLowerCase();
+        if (null == country) {
+            country = "";
+        }
+        country = country.toUpperCase();
+
+        if((null == l || 0 == l.length()) && (null == c || 0 == c.length())) {
+            try {
+                // try to find a good match
+                String[] locales = context.getAssets().getLocales();
+                final int N = locales.length;
+                String bestMatch = null;
+                for(int i = 0; i < N; i++) {
+                    // only match full (lang + country) locales
+                    if (locales[i]!=null && locales[i].length() >= 5 &&
+                            locales[i].substring(0,2).equals(language)) {
+                        if (locales[i].substring(3,5).equals(country)) {
+                            bestMatch = locales[i];
+                            break;
+                        } else if (null == bestMatch) {
+                            bestMatch = locales[i];
+                        }
+                    }
+                }
+                if (null != bestMatch) {
+                    IActivityManager am = ActivityManagerNative.getDefault();
+                    Configuration config = am.getConfiguration();
+                    config.locale = new Locale(bestMatch.substring(0,2),
+                                               bestMatch.substring(3,5));
+                    config.userSetLocale = true;
+                    am.updateConfiguration(config);
+                }
+            } catch (Exception e) {
+                // Intentionally left blank
+            }
+        }
+    }
+
+    /**
      * If the timezone is not already set, set it based on the MCC of the SIM.
-     * @param phone PhoneBase to act on (get context from).
+     * @param context Context to act on.
      * @param mcc Mobile Country Code of the SIM or SIM-like entity (build prop on CDMA)
      */
-    private static void setTimezoneFromMccIfNeeded(PhoneBase phone, int mcc) {
+    private static void setTimezoneFromMccIfNeeded(Context context, int mcc) {
         String timezone = SystemProperties.get(ServiceStateTracker.TIMEZONE_PROPERTY);
         if (timezone == null || timezone.length() == 0) {
             String zoneId = defaultTimeZoneForMcc(mcc);
             if (zoneId != null && zoneId.length() > 0) {
-                Context context = phone.getContext();
                 // Set time zone based on MCC
                 AlarmManager alarm =
                         (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
@@ -226,27 +279,31 @@
 
     /**
      * If the locale is not already set, set it based on the MCC of the SIM.
-     * @param phone PhoneBase to act on.
+     * @param context Context to act on.
      * @param mcc Mobile Country Code of the SIM or SIM-like entity (build prop on CDMA)
      */
-    private static void setLocaleFromMccIfNeeded(PhoneBase phone, int mcc) {
+    private static void setLocaleFromMccIfNeeded(Context context, int mcc) {
+        if (BaseCommands.getLteOnCdmaModeStatic() == Phone.LTE_ON_CDMA_TRUE) {
+            // Avoid system locale is set from MCC table if CDMALTEPhone is used.
+            // The locale will be picked up based on EFpl/EFli once CSIM records are loaded.
+            return;
+        }
         String language = MccTable.defaultLanguageForMcc(mcc);
         String country = MccTable.countryCodeForMcc(mcc);
 
         Log.d(LOG_TAG, "locale set to "+language+"_"+country);
-        phone.setSystemLocale(language, country, true);
+        setSystemLocale(context, language, country);
     }
 
     /**
      * If the number of allowed wifi channels has not been set, set it based on
      * the MCC of the SIM.
-     * @param phone PhoneBase to act on (get context from).
+     * @param context Context to act on.
      * @param mcc Mobile Country Code of the SIM or SIM-like entity (build prop on CDMA)
      */
-    private static void setWifiCountryCodeFromMcc(PhoneBase phone, int mcc) {
+    private static void setWifiCountryCodeFromMcc(Context context, int mcc) {
         String country = MccTable.countryCodeForMcc(mcc);
         if (!country.isEmpty()) {
-            Context context = phone.getContext();
             Log.d(LOG_TAG, "WIFI_COUNTRY_CODE set to " + country);
             WifiManager wM = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
             //persist
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index 0b5a82c..6fc0134 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -103,6 +103,10 @@
     protected static final int EVENT_EMERGENCY_CALLBACK_MODE_ENTER  = 25;
     protected static final int EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE = 26;
     protected static final int EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED = 27;
+    // other
+    protected static final int EVENT_SET_NETWORK_AUTOMATIC          = 28;
+    protected static final int EVENT_NEW_ICC_SMS                    = 29;
+    protected static final int EVENT_ICC_RECORD_EVENTS              = 30;
 
     // Key used to read/write current CLIR setting
     public static final String CLIR_KEY = "clir_key";
@@ -600,7 +604,7 @@
                 if (l.length() >=5) {
                     country = l.substring(3, 5);
                 }
-                setSystemLocale(language, country, false);
+                MccTable.setSystemLocale(mContext, language, country);
 
                 if (!country.isEmpty()) {
                     try {
@@ -619,62 +623,6 @@
     }
 
     /**
-     * Utility code to set the system locale if it's not set already
-     * @param language Two character language code desired
-     * @param country Two character country code desired
-     * @param fromMcc Indicating whether the locale is set according to MCC table.
-     *                This flag wil be ignored by default implementation.
-     *                TODO: Use a source enumeration so that source of the locale
-     *                      can be prioritized.
-     *
-     *  {@hide}
-     */
-    public void setSystemLocale(String language, String country, boolean fromMcc) {
-        String l = SystemProperties.get("persist.sys.language");
-        String c = SystemProperties.get("persist.sys.country");
-
-        if (null == language) {
-            return; // no match possible
-        }
-        language = language.toLowerCase();
-        if (null == country) {
-            country = "";
-        }
-        country = country.toUpperCase();
-
-        if((null == l || 0 == l.length()) && (null == c || 0 == c.length())) {
-            try {
-                // try to find a good match
-                String[] locales = mContext.getAssets().getLocales();
-                final int N = locales.length;
-                String bestMatch = null;
-                for(int i = 0; i < N; i++) {
-                    // only match full (lang + country) locales
-                    if (locales[i]!=null && locales[i].length() >= 5 &&
-                            locales[i].substring(0,2).equals(language)) {
-                        if (locales[i].substring(3,5).equals(country)) {
-                            bestMatch = locales[i];
-                            break;
-                        } else if (null == bestMatch) {
-                            bestMatch = locales[i];
-                        }
-                    }
-                }
-                if (null != bestMatch) {
-                    IActivityManager am = ActivityManagerNative.getDefault();
-                    Configuration config = am.getConfiguration();
-                    config.locale = new Locale(bestMatch.substring(0,2),
-                                               bestMatch.substring(3,5));
-                    config.userSetLocale = true;
-                    am.updateConfiguration(config);
-                }
-            } catch (Exception e) {
-                // Intentionally left blank
-            }
-        }
-    }
-
-    /**
      * Get state
      */
     public abstract Phone.State getState();
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
index 14a4b46..f914030 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
@@ -35,6 +35,7 @@
 import com.android.internal.telephony.PhoneProxy;
 import com.android.internal.telephony.SMSDispatcher;
 import com.android.internal.telephony.gsm.GsmSMSDispatcher;
+import com.android.internal.telephony.gsm.SmsMessage;
 import com.android.internal.telephony.ims.IsimRecords;
 import com.android.internal.telephony.uicc.UiccController;
 
@@ -62,17 +63,21 @@
     public CDMALTEPhone(Context context, CommandsInterface ci, PhoneNotifier notifier) {
         super(context, ci, notifier, false);
         m3gppSMS = new GsmSMSDispatcher(this, mSmsStorageMonitor, mSmsUsageMonitor);
+        mIccRecords.registerForNewSms(this, EVENT_NEW_ICC_SMS, null);
     }
 
     @Override
     public void handleMessage (Message msg) {
         AsyncResult ar;
-        Message onComplete;
         switch (msg.what) {
             // handle the select network completion callbacks.
             case EVENT_SET_NETWORK_MANUAL_COMPLETE:
                 handleSetSelectNetwork((AsyncResult) msg.obj);
                 break;
+            case EVENT_NEW_ICC_SMS:
+                ar = (AsyncResult)msg.obj;
+                m3gppSMS.dispatchMessage((SmsMessage)ar.result);
+                break;
             default:
                 super.handleMessage(msg);
         }
@@ -93,6 +98,7 @@
         synchronized(PhoneProxy.lockForRadioTechnologyChange) {
             super.dispose();
             m3gppSMS.dispose();
+            mIccRecords.unregisterForNewSms(this);
         }
     }
 
@@ -214,15 +220,6 @@
         return false;
     }
 
-    @Override
-    public void setSystemLocale(String language, String country, boolean fromMcc) {
-        // Avoid system locale is set from MCC table if CDMALTEPhone is used.
-        // The locale will be picked up based on EFpl/EFli once CSIM records are loaded.
-        if (fromMcc) return;
-
-        super.setSystemLocale(language, country, false);
-    }
-
     // return IMSI from USIM as subscriber ID.
     @Override
     public String getSubscriberId() {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index e86e441..ce581de 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -103,7 +103,6 @@
     PhoneSubInfo mSubInfo;
     EriManager mEriManager;
     WakeLock mWakeLock;
-    CatService mCcatService;
 
     // mEriFileLoadedRegistrants are informed after the ERI text has been loaded
     private final RegistrantList mEriFileLoadedRegistrants = new RegistrantList();
@@ -169,11 +168,9 @@
         mRuimSmsInterfaceManager = new RuimSmsInterfaceManager(this, mSMS);
         mSubInfo = new PhoneSubInfo(this);
         mEriManager = new EriManager(this, context, EriManager.ERI_FROM_XML);
-        mCcatService = CatService.getInstance(mCM, mIccRecords, mContext,
-                mIccFileHandler, mIccCard);
 
         mCM.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
-        mIccRecords.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null);
+        registerForRuimRecordEvents();
         mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
         mCM.registerForOn(this, EVENT_RADIO_ON, null);
         mCM.setOnSuppServiceNotification(this, EVENT_SSN, null);
@@ -225,7 +222,7 @@
             log("dispose");
 
             //Unregister from all former registered events
-            mIccRecords.unregisterForRecordsLoaded(this); //EVENT_RUIM_RECORDS_LOADED
+            unregisterForRuimRecordEvents();
             mCM.unregisterForAvailable(this); //EVENT_RADIO_AVAILABLE
             mCM.unregisterForOffOrNotAvailable(this); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE
             mCM.unregisterForOn(this); //EVENT_RADIO_ON
@@ -241,20 +238,16 @@
             mSST.dispose();
             mCdmaSSM.dispose(this);
             mSMS.dispose();
-            mIccFileHandler.dispose(); // instance of RuimFileHandler
-            mIccRecords.dispose();
             mRuimPhoneBookInterfaceManager.dispose();
             mRuimSmsInterfaceManager.dispose();
             mSubInfo.dispose();
             mEriManager.dispose();
-            mCcatService.dispose();
         }
     }
 
     @Override
     public void removeReferences() {
         log("removeReferences");
-        super.removeReferences();
         mRuimPhoneBookInterfaceManager = null;
         mRuimSmsInterfaceManager = null;
         mSubInfo = null;
@@ -262,8 +255,8 @@
         mCT = null;
         mSST = null;
         mEriManager = null;
-        mCcatService = null;
         mExitEcmRunnable = null;
+        super.removeReferences();
     }
 
     @Override
@@ -999,6 +992,11 @@
             }
             break;
 
+            case EVENT_ICC_RECORD_EVENTS:
+                ar = (AsyncResult)msg.obj;
+                processIccRecordEvents((Integer)ar.result);
+                break;
+
             case  EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE:{
                 handleExitEmergencyCallbackMode(msg);
             }
@@ -1063,10 +1061,22 @@
         }
     }
 
+    private void processIccRecordEvents(int eventCode) {
+        switch (eventCode) {
+            case RuimRecords.EVENT_MWI:
+                notifyMessageWaitingIndicator();
+                break;
+
+            default:
+                Log.e(LOG_TAG,"Unknown icc records event code " + eventCode);
+                break;
+        }
+    }
+
     /**
      * Handles the call to get the subscription source
      *
-     * @param holds the new CDMA subscription source value
+     * @param newSubscriptionSource holds the new CDMA subscription source value
      */
     private void handleCdmaSubscriptionSource(int newSubscriptionSource) {
         if (newSubscriptionSource != mCdmaSubscriptionSource) {
@@ -1423,7 +1433,7 @@
                 getContext().getContentResolver().insert(uri, map);
 
                 // Updates MCC MNC device configuration information
-                MccTable.updateMccMncConfiguration(this, operatorNumeric);
+                MccTable.updateMccMncConfiguration(mContext, operatorNumeric);
 
                 return true;
             } catch (SQLException e) {
@@ -1456,6 +1466,16 @@
         return mEriManager.isEriFileLoaded();
     }
 
+    private void registerForRuimRecordEvents() {
+        mIccRecords.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
+        mIccRecords.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null);
+    }
+
+    private void unregisterForRuimRecordEvents() {
+        mIccRecords.unregisterForRecordsEvents(this);
+        mIccRecords.unregisterForRecordsLoaded(this);
+    }
+
     protected void log(String s) {
         if (DBG)
             Log.d(LOG_TAG, "[CDMAPhone] " + s);
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java
index ca1e96d..eaa2ede 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java
@@ -15,6 +15,7 @@
  */
 package com.android.internal.telephony.cdma;
 
+import android.content.Context;
 import android.os.AsyncResult;
 import android.os.SystemProperties;
 import android.util.Log;
@@ -22,6 +23,8 @@
 import com.android.internal.telephony.AdnRecordLoader;
 import com.android.internal.telephony.GsmAlphabet;
 import com.android.internal.telephony.IccCardApplication.AppType;
+import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.IccCard;
 import com.android.internal.telephony.IccFileHandler;
 import com.android.internal.telephony.IccUtils;
 import com.android.internal.telephony.MccTable;
@@ -54,8 +57,8 @@
 
     private final IsimUiccRecords mIsimUiccRecords = new IsimUiccRecords();
 
-    public CdmaLteUiccRecords(PhoneBase p) {
-        super(p);
+    public CdmaLteUiccRecords(IccCard card, Context c, CommandsInterface ci) {
+        super(card, c, ci);
     }
 
     // Refer to ETSI TS 102.221
@@ -146,7 +149,7 @@
             }
             if (DBG) log("spn=" + spn);
             if (DBG) log("spnCondition=" + mCsimSpnDisplayCondition);
-            phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, spn);
+            SystemProperties.set(PROPERTY_ICC_OPERATOR_ALPHA, spn);
         }
     }
 
@@ -262,55 +265,54 @@
 
     @Override
     protected void fetchSimRecords() {
-        IccFileHandler iccFh = phone.getIccFileHandler();
         recordsRequested = true;
 
-        phone.mCM.getIMSI(obtainMessage(EVENT_GET_IMSI_DONE));
+        mCi.getIMSIForApp(mParentCard.getAid(), obtainMessage(EVENT_GET_IMSI_DONE));
         recordsToLoad++;
 
-        iccFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));
+        mFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));
         recordsToLoad++;
 
-        iccFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE));
+        mFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE));
         recordsToLoad++;
 
-        iccFh.loadEFTransparent(EF_PL,
+        mFh.loadEFTransparent(EF_PL,
                 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfPlLoaded()));
         recordsToLoad++;
 
-        new AdnRecordLoader(phone).loadFromEF(EF_MSISDN, EF_EXT1, 1,
+        new AdnRecordLoader(mFh).loadFromEF(EF_MSISDN, EF_EXT1, 1,
                 obtainMessage(EVENT_GET_MSISDN_DONE));
         recordsToLoad++;
 
-        iccFh.loadEFTransparent(EF_SST, obtainMessage(EVENT_GET_SST_DONE));
+        mFh.loadEFTransparent(EF_SST, obtainMessage(EVENT_GET_SST_DONE));
         recordsToLoad++;
 
-        iccFh.loadEFTransparent(EF_CSIM_LI,
+        mFh.loadEFTransparent(EF_CSIM_LI,
                 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimLiLoaded()));
         recordsToLoad++;
 
-        iccFh.loadEFTransparent(EF_CSIM_SPN,
+        mFh.loadEFTransparent(EF_CSIM_SPN,
                 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimSpnLoaded()));
         recordsToLoad++;
 
-        iccFh.loadEFLinearFixed(EF_CSIM_MDN, 1,
+        mFh.loadEFLinearFixed(EF_CSIM_MDN, 1,
                 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimMdnLoaded()));
         recordsToLoad++;
 
-        iccFh.loadEFTransparent(EF_CSIM_IMSIM,
+        mFh.loadEFTransparent(EF_CSIM_IMSIM,
                 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimImsimLoaded()));
         recordsToLoad++;
 
-        iccFh.loadEFLinearFixedAll(EF_CSIM_CDMAHOME,
+        mFh.loadEFLinearFixedAll(EF_CSIM_CDMAHOME,
                 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimCdmaHomeLoaded()));
         recordsToLoad++;
 
-        iccFh.loadEFTransparent(EF_CSIM_EPRL,
+        mFh.loadEFTransparent(EF_CSIM_EPRL,
                 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimEprlLoaded()));
         recordsToLoad++;
 
         // load ISIM records
-        recordsToLoad += mIsimUiccRecords.fetchIsimRecords(iccFh, this);
+        recordsToLoad += mIsimUiccRecords.fetchIsimRecords(mFh, this);
     }
 
     private int adjstMinDigits (int digits) {
@@ -354,7 +356,7 @@
                                     Integer.parseInt(imsi.substring(0,3)));
             }
             log("Setting locale to " + prefLang + "_" + country);
-            phone.setSystemLocale(prefLang, country, false);
+            MccTable.setSystemLocale(mContext, prefLang, country);
         } else {
             log ("No suitable CSIM selected locale");
         }
@@ -362,7 +364,7 @@
 
     private String findBestLanguage(byte[] languages) {
         String bestMatch = null;
-        String[] locales = phone.getContext().getAssets().getLocales();
+        String[] locales = mContext.getAssets().getLocales();
 
         if ((languages == null) || (locales == null)) return null;
 
@@ -436,23 +438,14 @@
             return true;
         }
 
-        if (phone == null || phone.mIccCard == null) {
+        if (mParentCard == null) {
             return false;
         }
 
-        if (phone.mIccCard.isApplicationOnIcc(AppType.APPTYPE_CSIM) &&
+        if (mParentCard.isApplicationOnIcc(AppType.APPTYPE_CSIM) &&
             ((mMdn == null) || (mMin == null))) {
             return false;
         }
         return true;
     }
-
-    /**
-     * Dispatch 3GPP format message. For CDMA/LTE phones,
-     * send the message to the secondary 3GPP format SMS dispatcher.
-     */
-    @Override
-    protected int dispatchGsmMessage(SmsMessageBase message) {
-        return ((CDMALTEPhone) phone).m3gppSMS.dispatchMessage(message);
-    }
 }
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java b/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java
index 9f30d36..f440935 100644
--- a/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java
@@ -45,9 +45,6 @@
         super(card, aid, ci);
     }
 
-    public void dispose() {
-    }
-
     protected void finalize() {
         Log.d(LOG_TAG, "RuimFileHandler finalized");
     }
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
index 265dff7..3855515 100755
--- a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
@@ -18,6 +18,7 @@
 
 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC;
+import android.content.Context;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Message;
@@ -78,19 +79,19 @@
     private static final int EVENT_RUIM_REFRESH = 31;
 
 
-    public RuimRecords(PhoneBase p) {
-        super(p);
+    public RuimRecords(IccCard card, Context c, CommandsInterface ci) {
+        super(card, c, ci);
 
-        adnCache = new AdnRecordCache(phone);
+        adnCache = new AdnRecordCache(mFh);
 
         recordsRequested = false;  // No load request is made till SIM ready
 
         // recordsToLoad is set to 0 because no requests are made yet
         recordsToLoad = 0;
 
-        p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
+        mCi.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
         // NOTE the EVENT_SMS_ON_RUIM is not registered
-        p.mCM.registerForIccRefresh(this, EVENT_RUIM_REFRESH, null);
+        mCi.registerForIccRefresh(this, EVENT_RUIM_REFRESH, null);
 
         // Start off by setting empty state
         onRadioOffOrNotAvailable();
@@ -99,9 +100,11 @@
 
     @Override
     public void dispose() {
+        if (DBG) log("Disposing RuimRecords " + this);
         //Unregister for all events
-        phone.mCM.unregisterForOffOrNotAvailable( this);
-        phone.mCM.unregisterForIccRefresh(this);
+        mCi.unregisterForOffOrNotAvailable( this);
+        mCi.unregisterForIccRefresh(this);
+        super.dispose();
     }
 
     @Override
@@ -196,7 +199,7 @@
 
         boolean isRecordLoadResponse = false;
 
-        if (!phone.mIsTheCurrentActivePhone) {
+        if (mDestroyed) {
             loge("Received message " + msg +
                     "[" + msg.what + "] while being destroyed. Ignoring.");
             return;
@@ -235,7 +238,7 @@
                 String operatorNumeric = getRUIMOperatorNumeric();
                 if (operatorNumeric != null) {
                     if(operatorNumeric.length() <= 6){
-                        MccTable.updateMccMncConfiguration(phone, operatorNumeric);
+                        MccTable.updateMccMncConfiguration(mContext, operatorNumeric);
                     }
                 }
             break;
@@ -314,6 +317,7 @@
         // One record loaded successfully or failed, In either case
         // we need to update the recordsToLoad count
         recordsToLoad -= 1;
+        if (DBG) log("RuimRecords:onRecordLoaded " + recordsToLoad + " requested: " + recordsRequested);
 
         if (recordsToLoad == 0 && recordsRequested == true) {
             onAllRecordsLoaded();
@@ -338,7 +342,7 @@
         }
         recordsLoadedRegistrants.notifyRegistrants(
             new AsyncResult(null, null, null));
-        phone.mIccCard.broadcastIccStateChangedIntent(
+        mParentCard.broadcastIccStateChangedIntent(
                 IccCard.INTENT_VALUE_ICC_LOADED, null);
     }
 
@@ -348,13 +352,12 @@
           READY is sent before IMSI ready
         */
 
-        phone.mIccCard.broadcastIccStateChangedIntent(
+        mParentCard.broadcastIccStateChangedIntent(
                 IccCard.INTENT_VALUE_ICC_READY, null);
 
         fetchRuimRecords();
 
-        phone.mCM.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE));
-
+        mCi.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE));
     }
 
 
@@ -363,13 +366,14 @@
 
         Log.v(LOG_TAG, "RuimRecords:fetchRuimRecords " + recordsToLoad);
 
-        phone.mCM.getIMSI(obtainMessage(EVENT_GET_IMSI_DONE));
+        mCi.getIMSI(obtainMessage(EVENT_GET_IMSI_DONE));
         recordsToLoad++;
 
-        phone.getIccFileHandler().loadEFTransparent(EF_ICCID,
+        mFh.loadEFTransparent(EF_ICCID,
                 obtainMessage(EVENT_GET_ICCID_DONE));
         recordsToLoad++;
 
+        log("RuimRecords:fetchRuimRecords " + recordsToLoad + " requested: " + recordsRequested);
         // Further records that can be inserted are Operator/OEM dependent
     }
 
@@ -401,7 +405,7 @@
         }
         countVoiceMessages = countWaiting;
 
-        ((CDMAPhone) phone).notifyMessageWaitingIndicator();
+        mRecordsEventsRegistrants.notifyResult(EVENT_MWI);
     }
 
     private void handleRuimRefresh(IccRefreshResponse refreshResponse) {
@@ -411,7 +415,7 @@
         }
 
         if (refreshResponse.aid != null &&
-                !refreshResponse.aid.equals(phone.getIccCard().getAid())) {
+                !refreshResponse.aid.equals(mParentCard.getAid())) {
             // This is for different app. Ignore.
             return;
         }
@@ -429,7 +433,7 @@
                 break;
             case IccRefreshResponse.REFRESH_RESULT_RESET:
                 if (DBG) log("handleRuimRefresh with SIM_REFRESH_RESET");
-                phone.mCM.setRadioPower(false, null);
+                mCi.setRadioPower(false, null);
                 /* Note: no need to call setRadioPower(true).  Assuming the desired
                 * radio power state is still ON (as tracked by ServiceStateTracker),
                 * ServiceStateTracker will call setRadioPower when it receives the
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index 5e9a4f2..6e10542 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -101,7 +101,6 @@
     // Instance Variables
     GsmCallTracker mCT;
     GsmServiceStateTracker mSST;
-    CatService mStkService;
     ArrayList <GsmMmiCode> mPendingMMIs = new ArrayList<GsmMmiCode>();
     SimPhoneBookInterfaceManager mSimPhoneBookIntManager;
     SimSmsInterfaceManager mSimSmsIntManager;
@@ -149,10 +148,9 @@
             mSimSmsIntManager = new SimSmsInterfaceManager(this, mSMS);
             mSubInfo = new PhoneSubInfo(this);
         }
-        mStkService = CatService.getInstance(mCM, mIccRecords, mContext, mIccFileHandler, mIccCard);
 
         mCM.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
-        mIccRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
+        registerForSimRecordEvents();
         mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
         mCM.registerForOn(this, EVENT_RADIO_ON, null);
         mCM.setOnUSSD(this, EVENT_USSD, null);
@@ -205,7 +203,7 @@
 
             //Unregister from all former registered events
             mCM.unregisterForAvailable(this); //EVENT_RADIO_AVAILABLE
-            mIccRecords.unregisterForRecordsLoaded(this); //EVENT_SIM_RECORDS_LOADED
+            unregisterForSimRecordEvents();
             mCM.unregisterForOffOrNotAvailable(this); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE
             mCM.unregisterForOn(this); //EVENT_RADIO_ON
             mSST.unregisterForNetworkAttached(this); //EVENT_REGISTERED_TO_NETWORK
@@ -215,12 +213,9 @@
             mPendingMMIs.clear();
 
             //Force all referenced classes to unregister their former registered events
-            mStkService.dispose();
             mCT.dispose();
             mDataConnectionTracker.dispose();
             mSST.dispose();
-            mIccFileHandler.dispose(); // instance of SimFileHandler
-            mIccRecords.dispose();
             mSimPhoneBookIntManager.dispose();
             mSimSmsIntManager.dispose();
             mSubInfo.dispose();
@@ -230,15 +225,14 @@
     @Override
     public void removeReferences() {
         Log.d(LOG_TAG, "removeReferences");
-        super.removeReferences();
         mSimulatedRadioControl = null;
-        mStkService = null;
         mSimPhoneBookIntManager = null;
         mSimSmsIntManager = null;
         mSubInfo = null;
         mIccFileHandler = null;
         mCT = null;
         mSST = null;
+        super.removeReferences();
     }
 
     protected void finalize() {
@@ -1288,6 +1282,21 @@
                 }
                 break;
 
+            case EVENT_NEW_ICC_SMS:
+                ar = (AsyncResult)msg.obj;
+                mSMS.dispatchMessage((SmsMessage)ar.result);
+                break;
+
+            case EVENT_SET_NETWORK_AUTOMATIC:
+                ar = (AsyncResult)msg.obj;
+                setNetworkSelectionModeAutomatic((Message)ar.result);
+                break;
+
+            case EVENT_ICC_RECORD_EVENTS:
+                ar = (AsyncResult)msg.obj;
+                processIccRecordEvents((Integer)ar.result);
+                break;
+
             // handle the select network completion callbacks.
             case EVENT_SET_NETWORK_MANUAL_COMPLETE:
             case EVENT_SET_NETWORK_AUTOMATIC_COMPLETE:
@@ -1311,7 +1320,18 @@
         }
     }
 
-    /**
+    private void processIccRecordEvents(int eventCode) {
+        switch (eventCode) {
+            case SIMRecords.EVENT_CFI:
+                notifyCallForwardingIndicator();
+                break;
+            case SIMRecords.EVENT_MWI:
+                notifyMessageWaitingIndicator();
+                break;
+        }
+    }
+
+   /**
      * Sets the "current" field in the telephony provider according to the SIM's operator
      *
      * @return true for success; false otherwise.
@@ -1460,4 +1480,20 @@
     public boolean isCspPlmnEnabled() {
         return mIccRecords.isCspPlmnEnabled();
     }
+
+    private void registerForSimRecordEvents() {
+        mIccRecords.registerForNetworkSelectionModeAutomatic(
+                this, EVENT_SET_NETWORK_AUTOMATIC, null);
+        mIccRecords.registerForNewSms(this, EVENT_NEW_ICC_SMS, null);
+        mIccRecords.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
+        mIccRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
+    }
+
+    private void unregisterForSimRecordEvents() {
+        mIccRecords.unregisterForNetworkSelectionModeAutomatic(this);
+        mIccRecords.unregisterForNewSms(this);
+        mIccRecords.unregisterForRecordsEvents(this);
+        mIccRecords.unregisterForRecordsLoaded(this);
+    }
+
 }
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMFileHandler.java b/telephony/java/com/android/internal/telephony/gsm/SIMFileHandler.java
index 455ee74..dcc9cfd 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SIMFileHandler.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMFileHandler.java
@@ -40,10 +40,6 @@
         super(card, aid, ci);
     }
 
-    public void dispose() {
-        super.dispose();
-    }
-
     protected void finalize() {
         Log.d(LOG_TAG, "SIMFileHandler finalized");
     }
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
index 68d3b2a..b88af2c 100755
--- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
@@ -21,6 +21,7 @@
 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC;
 import android.content.Context;
 import android.os.AsyncResult;
+import android.os.Handler;
 import android.os.Message;
 import android.os.SystemProperties;
 import android.util.Log;
@@ -174,10 +175,10 @@
 
     // ***** Constructor
 
-    public SIMRecords(PhoneBase p) {
-        super(p);
+    public SIMRecords(IccCard card, Context c, CommandsInterface ci) {
+        super(card, c, ci);
 
-        adnCache = new AdnRecordCache(phone);
+        adnCache = new AdnRecordCache(mFh);
 
         mVmConfig = new VoiceMailConstants();
         mSpnOverride = new SpnOverride();
@@ -187,10 +188,10 @@
         // recordsToLoad is set to 0 because no requests are made yet
         recordsToLoad = 0;
 
-        p.mCM.registerForOffOrNotAvailable(
+        mCi.registerForOffOrNotAvailable(
                         this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
-        p.mCM.setOnSmsOnSim(this, EVENT_SMS_ON_SIM, null);
-        p.mCM.registerForIccRefresh(this, EVENT_SIM_REFRESH, null);
+        mCi.setOnSmsOnSim(this, EVENT_SMS_ON_SIM, null);
+        mCi.registerForIccRefresh(this, EVENT_SIM_REFRESH, null);
 
         // Start off by setting empty state
         onRadioOffOrNotAvailable();
@@ -199,9 +200,12 @@
 
     @Override
     public void dispose() {
+        if (DBG) log("Disposing SIMRecords " + this);
         //Unregister for all events
-        phone.mCM.unregisterForOffOrNotAvailable( this);
-        phone.mCM.unregisterForIccRefresh(this);
+        mCi.unregisterForOffOrNotAvailable( this);
+        mCi.unregisterForIccRefresh(this);
+        mCi.unSetOnSmsOnSim(this);
+        super.dispose();
     }
 
     protected void finalize() {
@@ -224,9 +228,9 @@
 
         adnCache.reset();
 
-        phone.setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, null);
-        phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, null);
-        phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, null);
+        SystemProperties.set(PROPERTY_ICC_OPERATOR_NUMERIC, null);
+        SystemProperties.set(PROPERTY_ICC_OPERATOR_ALPHA, null);
+        SystemProperties.set(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, null);
 
         // recordsRequested is set to false indicating that the SIM
         // read requests made so far are not valid. This is set to
@@ -280,7 +284,7 @@
 
         AdnRecord adn = new AdnRecord(msisdnTag, msisdn);
 
-        new AdnRecordLoader(phone).updateEF(adn, EF_MSISDN, EF_EXT1, 1, null,
+        new AdnRecordLoader(mFh).updateEF(adn, EF_MSISDN, EF_EXT1, 1, null,
                 obtainMessage(EVENT_SET_MSISDN_DONE, onComplete));
     }
 
@@ -332,13 +336,13 @@
 
         if (mailboxIndex != 0 && mailboxIndex != 0xff) {
 
-            new AdnRecordLoader(phone).updateEF(adn, EF_MBDN, EF_EXT6,
+            new AdnRecordLoader(mFh).updateEF(adn, EF_MBDN, EF_EXT6,
                     mailboxIndex, null,
                     obtainMessage(EVENT_SET_MBDN_DONE, onComplete));
 
         } else if (isCphsMailboxEnabled()) {
 
-            new AdnRecordLoader(phone).updateEF(adn, EF_MAILBOX_CPHS,
+            new AdnRecordLoader(mFh).updateEF(adn, EF_MAILBOX_CPHS,
                     EF_EXT1, 1, null,
                     obtainMessage(EVENT_SET_CPHS_MAILBOX_DONE, onComplete));
 
@@ -379,7 +383,7 @@
 
         countVoiceMessages = countWaiting;
 
-        phone.notifyMessageWaitingIndicator();
+        mRecordsEventsRegistrants.notifyResult(EVENT_MWI);
 
         try {
             if (efMWIS != null) {
@@ -398,7 +402,7 @@
                     efMWIS[1] = (byte) countWaiting;
                 }
 
-                phone.getIccFileHandler().updateEFLinearFixed(
+                mFh.updateEFLinearFixed(
                     EF_MWIS, 1, efMWIS, null,
                     obtainMessage (EVENT_UPDATE_DONE, EF_MWIS));
             }
@@ -408,7 +412,7 @@
                 efCPHS_MWI[0] = (byte)((efCPHS_MWI[0] & 0xf0)
                             | (countVoiceMessages == 0 ? 0x5 : 0xa));
 
-                phone.getIccFileHandler().updateEFTransparent(
+                mFh.updateEFTransparent(
                     EF_VOICE_MAIL_INDICATOR_CPHS, efCPHS_MWI,
                     obtainMessage (EVENT_UPDATE_DONE, EF_VOICE_MAIL_INDICATOR_CPHS));
             }
@@ -435,7 +439,7 @@
 
         callForwardingEnabled = enable;
 
-        phone.notifyCallForwardingIndicator();
+        mRecordsEventsRegistrants.notifyResult(EVENT_CFI);
 
         try {
             if (mEfCfis != null) {
@@ -449,7 +453,7 @@
                 // TODO: Should really update other fields in EF_CFIS, eg,
                 // dialing number.  We don't read or use it right now.
 
-                phone.getIccFileHandler().updateEFLinearFixed(
+                mFh.updateEFLinearFixed(
                         EF_CFIS, 1, mEfCfis, null,
                         obtainMessage (EVENT_UPDATE_DONE, EF_CFIS));
             }
@@ -463,7 +467,7 @@
                             | CFF_UNCONDITIONAL_DEACTIVE);
                 }
 
-                phone.getIccFileHandler().updateEFTransparent(
+                mFh.updateEFTransparent(
                         EF_CFF_CPHS, mEfCff,
                         obtainMessage (EVENT_UPDATE_DONE, EF_CFF_CPHS));
             }
@@ -516,7 +520,7 @@
 
         boolean isRecordLoadResponse = false;
 
-        if (!phone.mIsTheCurrentActivePhone) {
+        if (mDestroyed) {
             loge("Received message " + msg + "[" + msg.what + "] " +
                     " while being destroyed. Ignoring.");
             return;
@@ -574,9 +578,9 @@
 
                 if (mncLength != UNKNOWN && mncLength != UNINITIALIZED) {
                     // finally have both the imsi and the mncLength and can parse the imsi properly
-                    MccTable.updateMccMncConfiguration(phone, imsi.substring(0, 3 + mncLength));
+                    MccTable.updateMccMncConfiguration(mContext, imsi.substring(0, 3 + mncLength));
                 }
-                phone.mIccCard.broadcastIccStateChangedIntent(
+                mParentCard.broadcastIccStateChangedIntent(
                         IccCard.INTENT_VALUE_ICC_IMSI, null);
             break;
 
@@ -607,12 +611,12 @@
 
                 if (isValidMbdn) {
                     // Note: MBDN was not included in NUM_OF_SIM_RECORDS_LOADED
-                    new AdnRecordLoader(phone).loadFromEF(EF_MBDN, EF_EXT6,
+                    new AdnRecordLoader(mFh).loadFromEF(EF_MBDN, EF_EXT6,
                             mailboxIndex, obtainMessage(EVENT_GET_MBDN_DONE));
                 } else {
                     // If this EF not present, try mailbox as in CPHS standard
                     // CPHS (CPHS4_2.WW6) is a european standard.
-                    new AdnRecordLoader(phone).loadFromEF(EF_MAILBOX_CPHS,
+                    new AdnRecordLoader(mFh).loadFromEF(EF_MAILBOX_CPHS,
                             EF_EXT1, 1,
                             obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
                 }
@@ -644,7 +648,7 @@
                         // FIXME right now, only load line1's CPHS voice mail entry
 
                         recordsToLoad += 1;
-                        new AdnRecordLoader(phone).loadFromEF(
+                        new AdnRecordLoader(mFh).loadFromEF(
                                 EF_MAILBOX_CPHS, EF_EXT1, 1,
                                 obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
                     }
@@ -661,7 +665,7 @@
                     // FIXME should use SST to decide
                     // FIXME right now, only load line1's CPHS voice mail entry
                     recordsToLoad += 1;
-                    new AdnRecordLoader(phone).loadFromEF(
+                    new AdnRecordLoader(mFh).loadFromEF(
                             EF_MAILBOX_CPHS, EF_EXT1, 1,
                             obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
 
@@ -729,7 +733,7 @@
                     countVoiceMessages = -1;
                 }
 
-                phone.notifyMessageWaitingIndicator();
+                mRecordsEventsRegistrants.notifyResult(EVENT_MWI);
             break;
 
             case EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE:
@@ -758,7 +762,7 @@
                         countVoiceMessages = 0;
                     }
 
-                    phone.notifyMessageWaitingIndicator();
+                    mRecordsEventsRegistrants.notifyResult(EVENT_MWI);
                 }
             break;
 
@@ -839,7 +843,8 @@
                     if (imsi != null && mncLength != UNKNOWN) {
                         // finally have both imsi and the length of the mnc and can parse
                         // the imsi properly
-                        MccTable.updateMccMncConfiguration(phone, imsi.substring(0, 3 + mncLength));
+                        MccTable.updateMccMncConfiguration(mContext,
+                                imsi.substring(0, 3 + mncLength));
                     }
                 }
             break;
@@ -867,7 +872,7 @@
                     callForwardingEnabled =
                         ((data[0] & CFF_LINE1_MASK) == CFF_UNCONDITIONAL_ACTIVE);
 
-                    phone.notifyCallForwardingIndicator();
+                    mRecordsEventsRegistrants.notifyResult(EVENT_CFI);
                 }
                 break;
 
@@ -940,7 +945,7 @@
                             + ar.exception + " length " + index.length);
                 } else {
                     log("READ EF_SMS RECORD index=" + index[0]);
-                    phone.getIccFileHandler().loadEFLinearFixed(EF_SMS,index[0],
+                    mFh.loadEFLinearFixed(EF_SMS,index[0],
                             obtainMessage(EVENT_GET_SMS_DONE));
                 }
                 break;
@@ -1012,7 +1017,7 @@
                         onCphsCompleted = null;
                     }
 
-                    new AdnRecordLoader(phone).
+                    new AdnRecordLoader(mFh).
                             updateEF(adn, EF_MAILBOX_CPHS, EF_EXT1, 1, null,
                             obtainMessage(EVENT_SET_CPHS_MAILBOX_DONE,
                                     onCphsCompleted));
@@ -1066,7 +1071,7 @@
                 // Refer TS 51.011 Section 10.3.46 for the content description
                 callForwardingEnabled = ((data[1] & 0x01) != 0);
 
-                phone.notifyCallForwardingIndicator();
+                mRecordsEventsRegistrants.notifyResult(EVENT_CFI);
                 break;
 
             case EVENT_GET_CSP_CPHS_DONE:
@@ -1103,18 +1108,18 @@
         switch(efid) {
             case EF_MBDN:
                 recordsToLoad++;
-                new AdnRecordLoader(phone).loadFromEF(EF_MBDN, EF_EXT6,
+                new AdnRecordLoader(mFh).loadFromEF(EF_MBDN, EF_EXT6,
                         mailboxIndex, obtainMessage(EVENT_GET_MBDN_DONE));
                 break;
             case EF_MAILBOX_CPHS:
                 recordsToLoad++;
-                new AdnRecordLoader(phone).loadFromEF(EF_MAILBOX_CPHS, EF_EXT1,
+                new AdnRecordLoader(mFh).loadFromEF(EF_MAILBOX_CPHS, EF_EXT1,
                         1, obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
                 break;
             case EF_CSP_CPHS:
                 recordsToLoad++;
                 log("[CSP] SIM Refresh for EF_CSP_CPHS");
-                phone.getIccFileHandler().loadEFTransparent(EF_CSP_CPHS,
+                mFh.loadEFTransparent(EF_CSP_CPHS,
                         obtainMessage(EVENT_GET_CSP_CPHS_DONE));
                 break;
             default:
@@ -1134,7 +1139,7 @@
         }
 
         if (refreshResponse.aid != null &&
-                !refreshResponse.aid.equals(phone.getIccCard().getAid())) {
+                !refreshResponse.aid.equals(mParentCard.getAid())) {
             // This is for different app. Ignore.
             return;
         }
@@ -1152,7 +1157,7 @@
                 break;
             case IccRefreshResponse.REFRESH_RESULT_RESET:
                 if (DBG) log("handleSimRefresh with SIM_REFRESH_RESET");
-                phone.mCM.setRadioPower(false, null);
+                mCi.setRadioPower(false, null);
                 /* Note: no need to call setRadioPower(true).  Assuming the desired
                 * radio power state is still ON (as tracked by ServiceStateTracker),
                 * ServiceStateTracker will call setRadioPower when it receives the
@@ -1174,7 +1179,8 @@
      * to send messages to the secondary 3GPP format SMS dispatcher.
      */
     protected int dispatchGsmMessage(SmsMessageBase message) {
-        return phone.mSMS.dispatchMessage(message);
+        mNewSmsRegistrants.notifyResult(message);
+        return 0;
     }
 
     private void handleSms(byte[] ba) {
@@ -1226,7 +1232,7 @@
                 ba[0] = 1;
 
                 if (false) { // XXX writing seems to crash RdoServD
-                    phone.getIccFileHandler().updateEFLinearFixed(EF_SMS,
+                    mFh.updateEFLinearFixed(EF_SMS,
                             i, ba, null, obtainMessage(EVENT_MARK_SMS_READ_DONE, i));
                 }
             }
@@ -1237,6 +1243,7 @@
         // One record loaded successfully or failed, In either case
         // we need to update the recordsToLoad count
         recordsToLoad -= 1;
+        if (DBG) log("onRecordLoaded " + recordsToLoad + " requested: " + recordsRequested);
 
         if (recordsToLoad == 0 && recordsRequested == true) {
             onAllRecordsLoaded();
@@ -1253,10 +1260,10 @@
 
         // Some fields require more than one SIM record to set
 
-        phone.setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, operator);
+        SystemProperties.set(PROPERTY_ICC_OPERATOR_NUMERIC, operator);
 
         if (imsi != null) {
-            phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY,
+            SystemProperties.set(PROPERTY_ICC_OPERATOR_ISO_COUNTRY,
                     MccTable.countryCodeForMcc(Integer.parseInt(imsi.substring(0,3))));
         }
         else {
@@ -1268,7 +1275,7 @@
 
         recordsLoadedRegistrants.notifyRegistrants(
             new AsyncResult(null, null, null));
-        phone.mIccCard.broadcastIccStateChangedIntent(
+        mParentCard.broadcastIccStateChangedIntent(
                 IccCard.INTENT_VALUE_ICC_LOADED, null);
     }
 
@@ -1294,7 +1301,7 @@
         /* broadcast intent SIM_READY here so that we can make sure
           READY is sent before IMSI ready
         */
-        phone.mIccCard.broadcastIccStateChangedIntent(
+        mParentCard.broadcastIccStateChangedIntent(
                 IccCard.INTENT_VALUE_ICC_READY, null);
 
         fetchSimRecords();
@@ -1302,31 +1309,30 @@
 
     protected void fetchSimRecords() {
         recordsRequested = true;
-        IccFileHandler iccFh = phone.getIccFileHandler();
 
-        logv("fetchSimRecords " + recordsToLoad);
+        if (DBG) log("fetchSimRecords " + recordsToLoad);
 
-        phone.mCM.getIMSIForApp(phone.getIccCard().getAid(), obtainMessage(EVENT_GET_IMSI_DONE));
+        mCi.getIMSIForApp(mParentCard.getAid(), obtainMessage(EVENT_GET_IMSI_DONE));
         recordsToLoad++;
 
-        iccFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));
+        mFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));
         recordsToLoad++;
 
         // FIXME should examine EF[MSISDN]'s capability configuration
         // to determine which is the voice/data/fax line
-        new AdnRecordLoader(phone).loadFromEF(EF_MSISDN, EF_EXT1, 1,
+        new AdnRecordLoader(mFh).loadFromEF(EF_MSISDN, EF_EXT1, 1,
                     obtainMessage(EVENT_GET_MSISDN_DONE));
         recordsToLoad++;
 
         // Record number is subscriber profile
-        iccFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE));
+        mFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE));
         recordsToLoad++;
 
-        iccFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE));
+        mFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE));
         recordsToLoad++;
 
         // Record number is subscriber profile
-        iccFh.loadEFLinearFixed(EF_MWIS, 1, obtainMessage(EVENT_GET_MWIS_DONE));
+        mFh.loadEFLinearFixed(EF_MWIS, 1, obtainMessage(EVENT_GET_MWIS_DONE));
         recordsToLoad++;
 
 
@@ -1334,39 +1340,39 @@
         // the same info as EF[MWIS]. If both exist, both are updated
         // but the EF[MWIS] data is preferred
         // Please note this must be loaded after EF[MWIS]
-        iccFh.loadEFTransparent(
+        mFh.loadEFTransparent(
                 EF_VOICE_MAIL_INDICATOR_CPHS,
                 obtainMessage(EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE));
         recordsToLoad++;
 
         // Same goes for Call Forward Status indicator: fetch both
         // EF[CFIS] and CPHS-EF, with EF[CFIS] preferred.
-        iccFh.loadEFLinearFixed(EF_CFIS, 1, obtainMessage(EVENT_GET_CFIS_DONE));
+        mFh.loadEFLinearFixed(EF_CFIS, 1, obtainMessage(EVENT_GET_CFIS_DONE));
         recordsToLoad++;
-        iccFh.loadEFTransparent(EF_CFF_CPHS, obtainMessage(EVENT_GET_CFF_DONE));
+        mFh.loadEFTransparent(EF_CFF_CPHS, obtainMessage(EVENT_GET_CFF_DONE));
         recordsToLoad++;
 
 
         getSpnFsm(true, null);
 
-        iccFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE));
+        mFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE));
         recordsToLoad++;
 
-        iccFh.loadEFLinearFixed(EF_PNN, 1, obtainMessage(EVENT_GET_PNN_DONE));
+        mFh.loadEFLinearFixed(EF_PNN, 1, obtainMessage(EVENT_GET_PNN_DONE));
         recordsToLoad++;
 
-        iccFh.loadEFTransparent(EF_SST, obtainMessage(EVENT_GET_SST_DONE));
+        mFh.loadEFTransparent(EF_SST, obtainMessage(EVENT_GET_SST_DONE));
         recordsToLoad++;
 
-        iccFh.loadEFTransparent(EF_INFO_CPHS, obtainMessage(EVENT_GET_INFO_CPHS_DONE));
+        mFh.loadEFTransparent(EF_INFO_CPHS, obtainMessage(EVENT_GET_INFO_CPHS_DONE));
         recordsToLoad++;
 
-        iccFh.loadEFTransparent(EF_CSP_CPHS,obtainMessage(EVENT_GET_CSP_CPHS_DONE));
+        mFh.loadEFTransparent(EF_CSP_CPHS,obtainMessage(EVENT_GET_CSP_CPHS_DONE));
         recordsToLoad++;
 
         // XXX should seek instead of examining them all
         if (false) { // XXX
-            iccFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE));
+            mFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE));
             recordsToLoad++;
         }
 
@@ -1379,9 +1385,10 @@
                          + "ffffffffffffffffffffffffffffff";
             byte[] ba = IccUtils.hexStringToBytes(sms);
 
-            iccFh.updateEFLinearFixed(EF_SMS, 1, ba, null,
+            mFh.updateEFLinearFixed(EF_SMS, 1, ba, null,
                             obtainMessage(EVENT_MARK_SMS_READ_DONE, 1));
         }
+        if (DBG) log("fetchSimRecords " + recordsToLoad + " requested: " + recordsRequested);
     }
 
     /**
@@ -1467,7 +1474,7 @@
             case INIT:
                 spn = null;
 
-                phone.getIccFileHandler().loadEFTransparent( EF_SPN,
+                mFh.loadEFTransparent(EF_SPN,
                         obtainMessage(EVENT_GET_SPN_DONE));
                 recordsToLoad++;
 
@@ -1481,11 +1488,11 @@
 
                     if (DBG) log("Load EF_SPN: " + spn
                             + " spnDisplayCondition: " + spnDisplayCondition);
-                    phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, spn);
+                    SystemProperties.set(PROPERTY_ICC_OPERATOR_ALPHA, spn);
 
                     spnState = Get_Spn_Fsm_State.IDLE;
                 } else {
-                    phone.getIccFileHandler().loadEFTransparent( EF_SPN_CPHS,
+                    mFh.loadEFTransparent( EF_SPN_CPHS,
                             obtainMessage(EVENT_GET_SPN_DONE));
                     recordsToLoad++;
 
@@ -1503,11 +1510,11 @@
                             data, 0, data.length - 1 );
 
                     if (DBG) log("Load EF_SPN_CPHS: " + spn);
-                    phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, spn);
+                    SystemProperties.set(PROPERTY_ICC_OPERATOR_ALPHA, spn);
 
                     spnState = Get_Spn_Fsm_State.IDLE;
                 } else {
-                    phone.getIccFileHandler().loadEFTransparent(
+                    mFh.loadEFTransparent(
                             EF_SPN_SHORT_CPHS, obtainMessage(EVENT_GET_SPN_DONE));
                     recordsToLoad++;
 
@@ -1521,7 +1528,7 @@
                             data, 0, data.length - 1);
 
                     if (DBG) log("Load EF_SPN_SHORT_CPHS: " + spn);
-                    phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, spn);
+                    SystemProperties.set(PROPERTY_ICC_OPERATOR_ALPHA, spn);
                 }else {
                     if (DBG) log("No SPN loaded in either CHPS or 3GPP");
                 }
@@ -1638,7 +1645,7 @@
                      // Operator Selection menu should be disabled.
                      // Operator Selection Mode should be set to Automatic.
                      log("[CSP] Set Automatic Network Selection");
-                     phone.setNetworkSelectionModeAutomatic(null);
+                     mNetworkSelectionModeAutomaticRegistrants.notifyRegistrants();
                  }
                  return;
              }
diff --git a/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java b/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java
index a9efc98..8f5a420 100755
--- a/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java
+++ b/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java
@@ -24,6 +24,7 @@
 import com.android.internal.telephony.AdnRecord;
 import com.android.internal.telephony.AdnRecordCache;
 import com.android.internal.telephony.IccConstants;
+import com.android.internal.telephony.IccFileHandler;
 import com.android.internal.telephony.IccUtils;
 import com.android.internal.telephony.PhoneBase;
 
@@ -42,7 +43,7 @@
     private static final boolean DBG = true;
     private PbrFile mPbrFile;
     private Boolean mIsPbrPresent;
-    private PhoneBase mPhone;
+    private IccFileHandler mFh;
     private AdnRecordCache mAdnCache;
     private Object mLock = new Object();
     private ArrayList<AdnRecord> mPhoneBookRecords;
@@ -74,8 +75,8 @@
     private static final int USIM_EFEMAIL_TAG = 0xCA;
     private static final int USIM_EFCCP1_TAG  = 0xCB;
 
-    public UsimPhoneBookManager(PhoneBase phone, AdnRecordCache cache) {
-        mPhone = phone;
+    public UsimPhoneBookManager(IccFileHandler fh, AdnRecordCache cache) {
+        mFh = fh;
         mPhoneBookRecords = new ArrayList<AdnRecord>();
         mPbrFile = null;
         // We assume its present, after the first read this is updated.
@@ -138,7 +139,7 @@
     }
 
     private void readPbrFileAndWait() {
-        mPhone.getIccFileHandler().loadEFLinearFixedAll(EF_PBR, obtainMessage(EVENT_PBR_LOAD_DONE));
+        mFh.loadEFLinearFixedAll(EF_PBR, obtainMessage(EVENT_PBR_LOAD_DONE));
         try {
             mLock.wait();
         } catch (InterruptedException e) {
@@ -165,7 +166,7 @@
                 }
             }
             // Read the EFEmail file.
-            mPhone.getIccFileHandler().loadEFLinearFixedAll(fileIds.get(USIM_EFEMAIL_TAG),
+            mFh.loadEFLinearFixedAll(fileIds.get(USIM_EFEMAIL_TAG),
                     obtainMessage(EVENT_EMAIL_LOAD_DONE));
             try {
                 mLock.wait();
@@ -183,7 +184,7 @@
     }
 
     private void readIapFileAndWait(int efid) {
-        mPhone.getIccFileHandler().loadEFLinearFixedAll(efid, obtainMessage(EVENT_IAP_LOAD_DONE));
+        mFh.loadEFLinearFixedAll(efid, obtainMessage(EVENT_IAP_LOAD_DONE));
         try {
             mLock.wait();
         } catch (InterruptedException e) {
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/mesh.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/mesh.rs
index 627ab99..1354897 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/mesh.rs
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/mesh.rs
@@ -11,29 +11,29 @@
 static bool test_mesh_getters() {
     bool failed = false;
 
-    _RS_ASSERT(rsMeshGetVertexAllocationCount(mesh) == 2);
-    _RS_ASSERT(rsMeshGetPrimitiveCount(mesh) == 3);
+    _RS_ASSERT(rsgMeshGetVertexAllocationCount(mesh) == 2);
+    _RS_ASSERT(rsgMeshGetPrimitiveCount(mesh) == 3);
 
-    rs_allocation meshV0 = rsMeshGetVertexAllocation(mesh, 0);
-    rs_allocation meshV1 = rsMeshGetVertexAllocation(mesh, 1);
-    rs_allocation meshV2 = rsMeshGetVertexAllocation(mesh, 2);
+    rs_allocation meshV0 = rsgMeshGetVertexAllocation(mesh, 0);
+    rs_allocation meshV1 = rsgMeshGetVertexAllocation(mesh, 1);
+    rs_allocation meshV2 = rsgMeshGetVertexAllocation(mesh, 2);
     _RS_ASSERT(meshV0.p == vertexAlloc0.p);
     _RS_ASSERT(meshV1.p == vertexAlloc1.p);
     _RS_ASSERT(!rsIsObject(meshV2));
 
-    rs_allocation meshI0 = rsMeshGetIndexAllocation(mesh, 0);
-    rs_allocation meshI1 = rsMeshGetIndexAllocation(mesh, 1);
-    rs_allocation meshI2 = rsMeshGetIndexAllocation(mesh, 2);
-    rs_allocation meshI3 = rsMeshGetIndexAllocation(mesh, 3);
+    rs_allocation meshI0 = rsgMeshGetIndexAllocation(mesh, 0);
+    rs_allocation meshI1 = rsgMeshGetIndexAllocation(mesh, 1);
+    rs_allocation meshI2 = rsgMeshGetIndexAllocation(mesh, 2);
+    rs_allocation meshI3 = rsgMeshGetIndexAllocation(mesh, 3);
     _RS_ASSERT(meshI0.p == indexAlloc0.p);
     _RS_ASSERT(!rsIsObject(meshI1));
     _RS_ASSERT(meshI2.p == indexAlloc2.p);
     _RS_ASSERT(!rsIsObject(meshI3));
 
-    rs_primitive p0 = rsMeshGetPrimitive(mesh, 0);
-    rs_primitive p1 = rsMeshGetPrimitive(mesh, 1);
-    rs_primitive p2 = rsMeshGetPrimitive(mesh, 2);
-    rs_primitive p3 = rsMeshGetPrimitive(mesh, 3);
+    rs_primitive p0 = rsgMeshGetPrimitive(mesh, 0);
+    rs_primitive p1 = rsgMeshGetPrimitive(mesh, 1);
+    rs_primitive p2 = rsgMeshGetPrimitive(mesh, 2);
+    rs_primitive p3 = rsgMeshGetPrimitive(mesh, 3);
 
     _RS_ASSERT(p0 == RS_PRIMITIVE_POINT);
     _RS_ASSERT(p1 == RS_PRIMITIVE_LINE);
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/sampler.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/sampler.rs
index ac9a549..ff1c0a7 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/sampler.rs
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/sampler.rs
@@ -9,35 +9,35 @@
 static bool test_sampler_getters() {
     bool failed = false;
 
-    _RS_ASSERT(rsgSamplerGetMagnification(minification) == RS_SAMPLER_NEAREST);
-    _RS_ASSERT(rsgSamplerGetMinification(minification) == RS_SAMPLER_LINEAR_MIP_LINEAR);
-    _RS_ASSERT(rsgSamplerGetWrapS(minification) == RS_SAMPLER_CLAMP);
-    _RS_ASSERT(rsgSamplerGetWrapT(minification) == RS_SAMPLER_CLAMP);
-    _RS_ASSERT(rsgSamplerGetAnisotropy(minification) == 1.0f);
+    _RS_ASSERT(rsSamplerGetMagnification(minification) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsSamplerGetMinification(minification) == RS_SAMPLER_LINEAR_MIP_LINEAR);
+    _RS_ASSERT(rsSamplerGetWrapS(minification) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsSamplerGetWrapT(minification) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsSamplerGetAnisotropy(minification) == 1.0f);
 
-    _RS_ASSERT(rsgSamplerGetMagnification(magnification) == RS_SAMPLER_LINEAR);
-    _RS_ASSERT(rsgSamplerGetMinification(magnification) == RS_SAMPLER_NEAREST);
-    _RS_ASSERT(rsgSamplerGetWrapS(magnification) == RS_SAMPLER_CLAMP);
-    _RS_ASSERT(rsgSamplerGetWrapT(magnification) == RS_SAMPLER_CLAMP);
-    _RS_ASSERT(rsgSamplerGetAnisotropy(magnification) == 1.0f);
+    _RS_ASSERT(rsSamplerGetMagnification(magnification) == RS_SAMPLER_LINEAR);
+    _RS_ASSERT(rsSamplerGetMinification(magnification) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsSamplerGetWrapS(magnification) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsSamplerGetWrapT(magnification) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsSamplerGetAnisotropy(magnification) == 1.0f);
 
-    _RS_ASSERT(rsgSamplerGetMagnification(wrapS) == RS_SAMPLER_NEAREST);
-    _RS_ASSERT(rsgSamplerGetMinification(wrapS) == RS_SAMPLER_NEAREST);
-    _RS_ASSERT(rsgSamplerGetWrapS(wrapS) == RS_SAMPLER_WRAP);
-    _RS_ASSERT(rsgSamplerGetWrapT(wrapS) == RS_SAMPLER_CLAMP);
-    _RS_ASSERT(rsgSamplerGetAnisotropy(wrapS) == 1.0f);
+    _RS_ASSERT(rsSamplerGetMagnification(wrapS) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsSamplerGetMinification(wrapS) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsSamplerGetWrapS(wrapS) == RS_SAMPLER_WRAP);
+    _RS_ASSERT(rsSamplerGetWrapT(wrapS) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsSamplerGetAnisotropy(wrapS) == 1.0f);
 
-    _RS_ASSERT(rsgSamplerGetMagnification(wrapT) == RS_SAMPLER_NEAREST);
-    _RS_ASSERT(rsgSamplerGetMinification(wrapT) == RS_SAMPLER_NEAREST);
-    _RS_ASSERT(rsgSamplerGetWrapS(wrapT) == RS_SAMPLER_CLAMP);
-    _RS_ASSERT(rsgSamplerGetWrapT(wrapT) == RS_SAMPLER_WRAP);
-    _RS_ASSERT(rsgSamplerGetAnisotropy(wrapT) == 1.0f);
+    _RS_ASSERT(rsSamplerGetMagnification(wrapT) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsSamplerGetMinification(wrapT) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsSamplerGetWrapS(wrapT) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsSamplerGetWrapT(wrapT) == RS_SAMPLER_WRAP);
+    _RS_ASSERT(rsSamplerGetAnisotropy(wrapT) == 1.0f);
 
-    _RS_ASSERT(rsgSamplerGetMagnification(anisotropy) == RS_SAMPLER_NEAREST);
-    _RS_ASSERT(rsgSamplerGetMinification(anisotropy) == RS_SAMPLER_NEAREST);
-    _RS_ASSERT(rsgSamplerGetWrapS(anisotropy) == RS_SAMPLER_CLAMP);
-    _RS_ASSERT(rsgSamplerGetWrapT(anisotropy) == RS_SAMPLER_CLAMP);
-    _RS_ASSERT(rsgSamplerGetAnisotropy(anisotropy) == 8.0f);
+    _RS_ASSERT(rsSamplerGetMagnification(anisotropy) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsSamplerGetMinification(anisotropy) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsSamplerGetWrapS(anisotropy) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsSamplerGetWrapT(anisotropy) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsSamplerGetAnisotropy(anisotropy) == 8.0f);
 
     if (failed) {
         rsDebug("test_sampler_getters FAILED", 0);
diff --git a/tools/aapt/ZipFile.cpp b/tools/aapt/ZipFile.cpp
index 8057068..3994c31 100644
--- a/tools/aapt/ZipFile.cpp
+++ b/tools/aapt/ZipFile.cpp
@@ -20,8 +20,8 @@
 
 #define LOG_TAG "zip"
 
-#include <androidfw/ZipUtils.h>
 #include <utils/Log.h>
+#include <utils/ZipUtils.h>
 
 #include "ZipFile.h"
 
diff --git a/wifi/java/android/net/wifi/NetworkUpdateResult.java b/wifi/java/android/net/wifi/NetworkUpdateResult.java
index 6b7b68b..234bbe1 100644
--- a/wifi/java/android/net/wifi/NetworkUpdateResult.java
+++ b/wifi/java/android/net/wifi/NetworkUpdateResult.java
@@ -22,6 +22,7 @@
     int netId;
     boolean ipChanged;
     boolean proxyChanged;
+    boolean isNewNetwork = false;
 
     public NetworkUpdateResult(int id) {
         netId = id;
@@ -58,4 +59,12 @@
     public boolean hasProxyChanged() {
         return proxyChanged;
     }
+
+    public boolean isNewNetwork() {
+        return isNewNetwork;
+    }
+
+    public void setIsNewNetwork(boolean isNew) {
+        isNewNetwork = isNew;
+    }
 }
diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java
index 46ad036..5dec269 100644
--- a/wifi/java/android/net/wifi/WifiConfigStore.java
+++ b/wifi/java/android/net/wifi/WifiConfigStore.java
@@ -273,7 +273,8 @@
             mConfiguredNetworks.get(netId).status = Status.ENABLED;
         }
         mWifiNative.saveConfig();
-        sendConfiguredNetworksChangedBroadcast();
+        sendConfiguredNetworksChangedBroadcast(config, result.isNewNetwork() ?
+                WifiManager.CHANGE_REASON_ADDED : WifiManager.CHANGE_REASON_CONFIG_CHANGE);
         return result;
     }
 
@@ -307,13 +308,16 @@
     boolean forgetNetwork(int netId) {
         if (mWifiNative.removeNetwork(netId)) {
             mWifiNative.saveConfig();
+            WifiConfiguration target = null;
             WifiConfiguration config = mConfiguredNetworks.get(netId);
             if (config != null) {
-                mConfiguredNetworks.remove(netId);
+                target = mConfiguredNetworks.remove(netId);
                 mNetworkIds.remove(configKey(config));
             }
-            writeIpAndProxyConfigurations();
-            sendConfiguredNetworksChangedBroadcast();
+            if (target != null) {
+                writeIpAndProxyConfigurations();
+                sendConfiguredNetworksChangedBroadcast(target, WifiManager.CHANGE_REASON_REMOVED);
+            }
             return true;
         } else {
             loge("Failed to remove network " + netId);
@@ -332,7 +336,11 @@
      */
     int addOrUpdateNetwork(WifiConfiguration config) {
         NetworkUpdateResult result = addOrUpdateNetworkNative(config);
-        sendConfiguredNetworksChangedBroadcast();
+        if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) {
+            sendConfiguredNetworksChangedBroadcast(mConfiguredNetworks.get(result.getNetworkId()),
+                    result.isNewNetwork ? WifiManager.CHANGE_REASON_ADDED :
+                        WifiManager.CHANGE_REASON_CONFIG_CHANGE);
+        }
         return result.getNetworkId();
     }
 
@@ -347,14 +355,17 @@
      */
     boolean removeNetwork(int netId) {
         boolean ret = mWifiNative.removeNetwork(netId);
+        WifiConfiguration config = null;
         if (ret) {
-            WifiConfiguration config = mConfiguredNetworks.get(netId);
+            config = mConfiguredNetworks.get(netId);
             if (config != null) {
-                mConfiguredNetworks.remove(netId);
+                config = mConfiguredNetworks.remove(netId);
                 mNetworkIds.remove(configKey(config));
             }
         }
-        sendConfiguredNetworksChangedBroadcast();
+        if (config != null) {
+            sendConfiguredNetworksChangedBroadcast(config, WifiManager.CHANGE_REASON_REMOVED);
+        }
         return ret;
     }
 
@@ -364,12 +375,24 @@
      * API. The more powerful selectNetwork()/saveNetwork() is used by the
      * state machine for connecting to a network
      *
-     * @param netId network to be removed
+     * @param netId network to be enabled
      * @return {@code true} if it succeeds, {@code false} otherwise
      */
     boolean enableNetwork(int netId, boolean disableOthers) {
         boolean ret = enableNetworkWithoutBroadcast(netId, disableOthers);
-        sendConfiguredNetworksChangedBroadcast();
+        if (disableOthers) {
+            sendConfiguredNetworksChangedBroadcast();
+        } else {
+            WifiConfiguration enabledNetwork = null;
+            synchronized(mConfiguredNetworks) {
+                enabledNetwork = mConfiguredNetworks.get(netId);
+            }
+            // check just in case the network was removed by someone else.
+            if (enabledNetwork != null) {
+                sendConfiguredNetworksChangedBroadcast(enabledNetwork,
+                        WifiManager.CHANGE_REASON_CONFIG_CHANGE);
+            }
+        }
         return ret;
     }
 
@@ -402,13 +425,18 @@
      */
     boolean disableNetwork(int netId, int reason) {
         boolean ret = mWifiNative.disableNetwork(netId);
+        WifiConfiguration network = null;
         WifiConfiguration config = mConfiguredNetworks.get(netId);
         /* Only change the reason if the network was not previously disabled */
         if (config != null && config.status != Status.DISABLED) {
             config.status = Status.DISABLED;
             config.disableReason = reason;
+            network = config;
         }
-        sendConfiguredNetworksChangedBroadcast();
+        if (network != null) {
+            sendConfiguredNetworksChangedBroadcast(network,
+                    WifiManager.CHANGE_REASON_CONFIG_CHANGE);
+        }
         return ret;
     }
 
@@ -574,9 +602,29 @@
         return false;
     }
 
+    /**
+     * Should be called when a single network configuration is made.
+     * @param network The network configuration that changed.
+     * @param reason The reason for the change, should be one of WifiManager.CHANGE_REASON_ADDED,
+     * WifiManager.CHANGE_REASON_REMOVED, or WifiManager.CHANGE_REASON_CHANGE.
+     */
+    private void sendConfiguredNetworksChangedBroadcast(WifiConfiguration network,
+            int reason) {
+        Intent intent = new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION);
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+        intent.putExtra(WifiManager.EXTRA_MULTIPLE_NETWORKS_CHANGED, false);
+        intent.putExtra(WifiManager.EXTRA_WIFI_CONFIGURATION, network);
+        intent.putExtra(WifiManager.EXTRA_CHANGE_REASON, reason);
+        mContext.sendBroadcast(intent);
+    }
+
+    /**
+     * Should be called when multiple network configuration changes are made.
+     */
     private void sendConfiguredNetworksChangedBroadcast() {
         Intent intent = new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION);
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+        intent.putExtra(WifiManager.EXTRA_MULTIPLE_NETWORKS_CHANGED, true);
         mContext.sendBroadcast(intent);
     }
 
@@ -1135,6 +1183,7 @@
         mNetworkIds.put(configKey(currentConfig), netId);
 
         NetworkUpdateResult result = writeIpAndProxyConfigurationsOnChange(currentConfig, config);
+        result.setIsNewNetwork(newNetwork);
         result.setNetworkId(netId);
         return result;
     }
@@ -1234,7 +1283,8 @@
         if (ipChanged || proxyChanged) {
             currentConfig.linkProperties = linkProperties;
             writeIpAndProxyConfigurations();
-            sendConfiguredNetworksChangedBroadcast();
+            sendConfiguredNetworksChangedBroadcast(currentConfig,
+                    WifiManager.CHANGE_REASON_CONFIG_CHANGE);
         }
         return new NetworkUpdateResult(ipChanged, proxyChanged);
     }
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index d746810..8aa613b 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -294,12 +294,53 @@
 
     /**
      * Broadcast intent action indicating that the configured networks changed.
-     * This can be as a result of adding/updating/deleting a network
+     * This can be as a result of adding/updating/deleting a network. If
+     * {@link #EXTRA_MULTIPLE_NETWORKS_CHANGED} is set to true the new configuration
+     * can be retreived with the {@link #EXTRA_WIFI_CONFIGURATION} extra. If multiple
+     * Wi-Fi configurations changed, {@link #EXTRA_WIFI_CONFIGURATION} will not be present.
      * @hide
      */
     public static final String CONFIGURED_NETWORKS_CHANGED_ACTION =
         "android.net.wifi.CONFIGURED_NETWORKS_CHANGE";
     /**
+     * The lookup key for a (@link android.net.wifi.WifiConfiguration} object representing
+     * the changed Wi-Fi configuration when the {@link #CONFIGURED_NETWORKS_CHANGED_ACTION}
+     * broadcast is sent.
+     * @hide
+     */
+    public static final String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration";
+    /**
+     * Multiple network configurations have changed.
+     * @see #CONFIGURED_NETWORKS_CHANGED_ACTION
+     *
+     * @hide
+     */
+    public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
+    /**
+     * The lookup key for an integer indicating the reason a Wi-Fi network configuration
+     * has changed. Only present if {@link #EXTRA_MULTIPLE_NETWORKS_CHANGED} is {@code false}
+     * @see #CONFIGURED_NETWORKS_CHANGED_ACTION
+     * @hide
+     */
+    public static final String EXTRA_CHANGE_REASON = "changeReason";
+    /**
+     * The configuration is new and was added.
+     * @hide
+     */
+    public static final int CHANGE_REASON_ADDED = 0;
+    /**
+     * The configuration was removed and is no longer present in the system's list of
+     * configured networks.
+     * @hide
+     */
+    public static final int CHANGE_REASON_REMOVED = 1;
+    /**
+     * The configuration has changed as a result of explicit action or because the system
+     * took an automated action such as disabling a malfunctioning configuration.
+     * @hide
+     */
+    public static final int CHANGE_REASON_CONFIG_CHANGE = 2;
+    /**
      * An access point scan has completed, and results are available from the supplicant.
      * Call {@link #getScanResults()} to obtain the results.
      */
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 05a8ca7..cbf7bf8 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -394,7 +394,7 @@
      * Starting and shutting down driver too quick causes problems leading to driver
      * being in a bad state. Delay driver stop.
      */
-    private static final int DELAYED_DRIVER_STOP_MS = 2 * 60 * 1000; /* 2 minutes */
+    private final int mDriverStopDelayMs;
     private int mDelayedStopCounter;
     private boolean mInDelayedStop = false;
 
@@ -563,6 +563,9 @@
         mDefaultSupplicantScanIntervalMs = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_wifi_supplicant_scan_interval);
 
+        mDriverStopDelayMs = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_wifi_driver_stop_delay);
+
         mContext.registerReceiver(
             new BroadcastReceiver() {
                 @Override
@@ -2589,7 +2592,7 @@
                     } else {
                         /* send regular delayed shut down */
                         sendMessageDelayed(obtainMessage(CMD_DELAYED_STOP_DRIVER,
-                                mDelayedStopCounter, 0), DELAYED_DRIVER_STOP_MS);
+                                mDelayedStopCounter, 0), mDriverStopDelayMs);
                     }
                     break;
                 case CMD_START_DRIVER: