Merge "Separate animation into separate class."
diff --git a/api/current.txt b/api/current.txt
index 665b054..20b0be6 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);
@@ -7312,6 +7313,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;
@@ -25899,6 +25901,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 +26624,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/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/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..bf10bcb 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.walEnabled) {
+                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,7 @@
         }
 
         // Remember what changed.
-        boolean syncModeChanged = !configuration.syncMode.equalsIgnoreCase(
-                mConfiguration.syncMode);
-        boolean journalModeChanged = !configuration.journalMode.equalsIgnoreCase(
-                mConfiguration.journalMode);
+        boolean walModeChanged = configuration.walEnabled != mConfiguration.walEnabled;
         boolean localeChanged = !configuration.locale.equals(mConfiguration.locale);
 
         // Update configuration parameters.
@@ -361,14 +398,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..27c9ee5 100644
--- a/core/java/android/database/sqlite/SQLiteConnectionPool.java
+++ b/core/java/android/database/sqlite/SQLiteConnectionPool.java
@@ -257,7 +257,33 @@
         synchronized (mLock) {
             throwIfClosedLocked();
 
+            boolean restrictToOneConnection = false;
+            if (mConfiguration.walEnabled != configuration.walEnabled) {
+                // 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();
+
+                restrictToOneConnection = true;
+            }
+
             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 (restrictToOneConnection) {
+                    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
@@ -453,11 +479,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,6 +488,15 @@
     }
 
     // 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) {
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index bf32ea7..0ecce4d 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
@@ -834,8 +830,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 +1735,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,8 +1768,15 @@
 
         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;
+            }
         }
     }
 
@@ -1805,12 +1821,16 @@
      * </p>
      *
      * @return true if write-ahead-logging is set. false otherwise
+     *
+     * @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.
      */
     public boolean enableWriteAheadLogging() {
         synchronized (mLock) {
             throwIfNotOpenLocked();
 
-            if (mIsWALEnabledLocked) {
+            if (mConfigurationLocked.walEnabled) {
                 return true;
             }
 
@@ -1835,32 +1855,45 @@
                 return false;
             }
 
-            mIsWALEnabledLocked = true;
+            final int oldMaxConnectionPoolSize = mConfigurationLocked.maxConnectionPoolSize;
             mConfigurationLocked.maxConnectionPoolSize = SQLiteGlobal.getWALConnectionPoolSize();
-            mConfigurationLocked.syncMode = SQLiteGlobal.getWALSyncMode();
-            mConfigurationLocked.journalMode = "WAL";
-            mConnectionPoolLocked.reconfigure(mConfigurationLocked);
+            mConfigurationLocked.walEnabled = true;
+            try {
+                mConnectionPoolLocked.reconfigure(mConfigurationLocked);
+            } catch (RuntimeException ex) {
+                mConfigurationLocked.maxConnectionPoolSize = oldMaxConnectionPoolSize;
+                mConfigurationLocked.walEnabled = false;
+                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.
      */
     public void disableWriteAheadLogging() {
         synchronized (mLock) {
             throwIfNotOpenLocked();
 
-            if (!mIsWALEnabledLocked) {
+            if (!mConfigurationLocked.walEnabled) {
                 return;
             }
 
-            mIsWALEnabledLocked = false;
+            final int oldMaxConnectionPoolSize = mConfigurationLocked.maxConnectionPoolSize;
             mConfigurationLocked.maxConnectionPoolSize = 1;
-            mConfigurationLocked.syncMode = SQLiteGlobal.getDefaultSyncMode();
-            mConfigurationLocked.journalMode = SQLiteGlobal.getDefaultJournalMode();
-            mConnectionPoolLocked.reconfigure(mConfigurationLocked);
+            mConfigurationLocked.walEnabled = false;
+            try {
+                mConnectionPoolLocked.reconfigure(mConfigurationLocked);
+            } catch (RuntimeException ex) {
+                mConfigurationLocked.maxConnectionPoolSize = oldMaxConnectionPoolSize;
+                mConfigurationLocked.walEnabled = true;
+                throw ex;
+            }
         }
     }
 
diff --git a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
index efbcaca..e06a5ee 100644
--- a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
+++ b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
@@ -85,18 +85,11 @@
     public Locale locale;
 
     /**
-     * The database synchronization mode.
+     * True if WAL mode is enabled.
      *
-     * Default is {@link SQLiteGlobal#getDefaultSyncMode()}.
+     * Default is false.
      */
-    public String syncMode;
-
-    /**
-     * The database journal mode.
-     *
-     * Default is {@link SQLiteGlobal#getDefaultJournalMode()}.
-     */
-    public String journalMode;
+    public boolean walEnabled;
 
     /**
      * The custom functions to register.
@@ -124,8 +117,6 @@
         maxConnectionPoolSize = 1;
         maxSqlCacheSize = 25;
         locale = Locale.getDefault();
-        syncMode = SQLiteGlobal.getDefaultSyncMode();
-        journalMode = SQLiteGlobal.getDefaultJournalMode();
     }
 
     /**
@@ -162,8 +153,7 @@
         maxConnectionPoolSize = other.maxConnectionPoolSize;
         maxSqlCacheSize = other.maxSqlCacheSize;
         locale = other.locale;
-        syncMode = other.syncMode;
-        journalMode = other.journalMode;
+        walEnabled = other.walEnabled;
         customFunctions.clear();
         customFunctions.addAll(other.customFunctions);
     }
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/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 d403cb9e..ffffc73 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.
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 e553a2e..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
@@ -1464,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
@@ -1497,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
@@ -1587,8 +1582,6 @@
         mWebViewPrivate.setScrollYRaw(mScrollY);
     }
 
-    // === END: WebView Proxy binding ===
-
     private static class TrustStorageListener extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -1969,7 +1962,6 @@
      */
     @Override
     public void setHorizontalScrollbarOverlay(boolean overlay) {
-        checkThread();
         mOverlayHorizontalScrollbar = overlay;
     }
 
@@ -1978,7 +1970,6 @@
      */
     @Override
     public void setVerticalScrollbarOverlay(boolean overlay) {
-        checkThread();
         mOverlayVerticalScrollbar = overlay;
     }
 
@@ -1987,7 +1978,6 @@
      */
     @Override
     public boolean overlayHorizontalScrollbar() {
-        checkThread();
         return mOverlayHorizontalScrollbar;
     }
 
@@ -1996,7 +1986,6 @@
      */
     @Override
     public boolean overlayVerticalScrollbar() {
-        checkThread();
         return mOverlayVerticalScrollbar;
     }
 
@@ -2022,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) {
@@ -2039,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();
     }
 
@@ -2085,7 +2072,6 @@
      */
     @Override
     public SslCertificate getCertificate() {
-        checkThread();
         return mCertificate;
     }
 
@@ -2094,7 +2080,6 @@
      */
     @Override
     public void setCertificate(SslCertificate certificate) {
-        checkThread();
         if (DebugFlags.WEB_VIEW) {
             Log.v(LOGTAG, "setCertificate=" + certificate);
         }
@@ -2111,7 +2096,6 @@
      */
     @Override
     public void savePassword(String host, String username, String password) {
-        checkThread();
         mDatabase.setUsernamePassword(host, username, password);
     }
 
@@ -2121,7 +2105,6 @@
     @Override
     public void setHttpAuthUsernamePassword(String host, String realm,
             String username, String password) {
-        checkThread();
         mDatabase.setHttpAuthUsernamePassword(host, realm, username, password);
     }
 
@@ -2130,7 +2113,6 @@
      */
     @Override
     public String[] getHttpAuthUsernamePassword(String host, String realm) {
-        checkThread();
         return mDatabase.getHttpAuthUsernamePassword(host, realm);
     }
 
@@ -2170,7 +2152,6 @@
      */
     @Override
     public void destroy() {
-        checkThread();
         destroyImpl();
     }
 
@@ -2203,7 +2184,6 @@
      */
     @Deprecated
     public static void enablePlatformNotifications() {
-        checkThread();
         synchronized (WebViewClassic.class) {
             sNotificationsEnabled = true;
             Context context = JniUtil.getContext();
@@ -2217,7 +2197,6 @@
      */
     @Deprecated
     public static void disablePlatformNotifications() {
-        checkThread();
         synchronized (WebViewClassic.class) {
             sNotificationsEnabled = false;
             Context context = JniUtil.getContext();
@@ -2231,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);
     }
 
@@ -2243,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);
@@ -2265,7 +2240,6 @@
      */
     @Override
     public WebBackForwardList saveState(Bundle outState) {
-        checkThread();
         if (outState == null) {
             return null;
         }
@@ -2317,7 +2291,6 @@
     @Override
     @Deprecated
     public boolean savePicture(Bundle b, final File dest) {
-        checkThread();
         if (dest == null || b == null) {
             return false;
         }
@@ -2379,7 +2352,6 @@
     @Override
     @Deprecated
     public boolean restorePicture(Bundle b, File src) {
-        checkThread();
         if (src == null || b == null) {
             return false;
         }
@@ -2425,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 {
@@ -2441,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 {
@@ -2471,7 +2441,6 @@
      */
     @Override
     public WebBackForwardList restoreState(Bundle inState) {
-        checkThread();
         WebBackForwardList returnList = null;
         if (inState == null) {
             return returnList;
@@ -2528,7 +2497,6 @@
      */
     @Override
     public void loadUrl(String url, Map<String, String> additionalHttpHeaders) {
-        checkThread();
         loadUrlImpl(url, additionalHttpHeaders);
     }
 
@@ -2546,7 +2514,6 @@
      */
     @Override
     public void loadUrl(String url) {
-        checkThread();
         loadUrlImpl(url);
     }
 
@@ -2562,7 +2529,6 @@
      */
     @Override
     public void postUrl(String url, byte[] postData) {
-        checkThread();
         if (URLUtil.isNetworkUrl(url)) {
             switchOutDrawHistory();
             WebViewCore.PostUrlData arg = new WebViewCore.PostUrlData();
@@ -2580,7 +2546,6 @@
      */
     @Override
     public void loadData(String data, String mimeType, String encoding) {
-        checkThread();
         loadDataImpl(data, mimeType, encoding);
     }
 
@@ -2601,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);
@@ -2623,7 +2587,6 @@
      */
     @Override
     public void saveWebArchive(String filename) {
-        checkThread();
         saveWebArchiveImpl(filename, false, null);
     }
 
@@ -2645,7 +2608,6 @@
      */
     @Override
     public void saveWebArchive(String basename, boolean autoname, ValueCallback<String> callback) {
-        checkThread();
         saveWebArchiveImpl(basename, autoname, callback);
     }
 
@@ -2660,7 +2622,6 @@
      */
     @Override
     public void stopLoading() {
-        checkThread();
         // TODO: should we clear all the messages in the queue before sending
         // STOP_LOADING?
         switchOutDrawHistory();
@@ -2672,7 +2633,6 @@
      */
     @Override
     public void reload() {
-        checkThread();
         clearHelpers();
         switchOutDrawHistory();
         mWebViewCore.sendMessage(EventHub.RELOAD);
@@ -2683,7 +2643,6 @@
      */
     @Override
     public boolean canGoBack() {
-        checkThread();
         WebBackForwardList l = mCallbackProxy.getBackForwardList();
         synchronized (l) {
             if (l.getClearPending()) {
@@ -2699,7 +2658,6 @@
      */
     @Override
     public void goBack() {
-        checkThread();
         goBackOrForwardImpl(-1);
     }
 
@@ -2708,7 +2666,6 @@
      */
     @Override
     public boolean canGoForward() {
-        checkThread();
         WebBackForwardList l = mCallbackProxy.getBackForwardList();
         synchronized (l) {
             if (l.getClearPending()) {
@@ -2724,7 +2681,6 @@
      */
     @Override
     public void goForward() {
-        checkThread();
         goBackOrForwardImpl(1);
     }
 
@@ -2733,7 +2689,6 @@
      */
     @Override
     public boolean canGoBackOrForward(int steps) {
-        checkThread();
         WebBackForwardList l = mCallbackProxy.getBackForwardList();
         synchronized (l) {
             if (l.getClearPending()) {
@@ -2750,7 +2705,6 @@
      */
     @Override
     public void goBackOrForward(int steps) {
-        checkThread();
         goBackOrForwardImpl(steps);
     }
 
@@ -2771,7 +2725,6 @@
      */
     @Override
     public boolean isPrivateBrowsingEnabled() {
-        checkThread();
         return getSettings().isPrivateBrowsingEnabled();
     }
 
@@ -2793,7 +2746,6 @@
      */
     @Override
     public boolean pageUp(boolean top) {
-        checkThread();
         if (mNativeClass == 0) {
             return false;
         }
@@ -2818,7 +2770,6 @@
      */
     @Override
     public boolean pageDown(boolean bottom) {
-        checkThread();
         if (mNativeClass == 0) {
             return false;
         }
@@ -2842,7 +2793,6 @@
      */
     @Override
     public void clearView() {
-        checkThread();
         mContentWidth = 0;
         mContentHeight = 0;
         setBaseLayer(0, null, false, false);
@@ -2854,7 +2804,6 @@
      */
     @Override
     public Picture capturePicture() {
-        checkThread();
         if (mNativeClass == 0) return null;
         Picture result = new Picture();
         nativeCopyBaseContentToPicture(result);
@@ -2866,7 +2815,6 @@
      */
     @Override
     public float getScale() {
-        checkThread();
         return mZoomManager.getScale();
     }
 
@@ -2884,7 +2832,6 @@
      */
     @Override
     public void setInitialScale(int scaleInPercent) {
-        checkThread();
         mZoomManager.setInitialScaleInPercent(scaleInPercent);
     }
 
@@ -2893,7 +2840,6 @@
      */
     @Override
     public void invokeZoomPicker() {
-        checkThread();
         if (!getSettings().supportZoom()) {
             Log.w(LOGTAG, "This WebView doesn't support zoom.");
             return;
@@ -2907,7 +2853,6 @@
      */
     @Override
     public HitTestResult getHitTestResult() {
-        checkThread();
         return mInitialHitTestResult;
     }
 
@@ -2943,7 +2888,6 @@
      */
     @Override
     public void requestFocusNodeHref(Message hrefMsg) {
-        checkThread();
         if (hrefMsg == null) {
             return;
         }
@@ -2966,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();
@@ -3020,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) {
@@ -3042,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;
@@ -3422,7 +3363,6 @@
         return getViewHeight();
     }
 
-    /** @hide */
     @Override
     public void onDrawVerticalScrollBar(Canvas canvas,
                                            Drawable scrollBar,
@@ -3471,7 +3411,6 @@
      */
     @Override
     public String getUrl() {
-        checkThread();
         WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
         return h != null ? h.getUrl() : null;
     }
@@ -3481,7 +3420,6 @@
      */
     @Override
     public String getOriginalUrl() {
-        checkThread();
         WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
         return h != null ? h.getOriginalUrl() : null;
     }
@@ -3491,7 +3429,6 @@
      */
     @Override
     public String getTitle() {
-        checkThread();
         WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
         return h != null ? h.getTitle() : null;
     }
@@ -3501,7 +3438,6 @@
      */
     @Override
     public Bitmap getFavicon() {
-        checkThread();
         WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
         return h != null ? h.getFavicon() : null;
     }
@@ -3520,7 +3456,6 @@
      */
     @Override
     public int getProgress() {
-        checkThread();
         return mCallbackProxy.getProgress();
     }
 
@@ -3529,7 +3464,6 @@
      */
     @Override
     public int getContentHeight() {
-        checkThread();
         return mContentHeight;
     }
 
@@ -3541,9 +3475,6 @@
         return mContentWidth;
     }
 
-    /**
-     * @hide
-     */
     public int getPageBackgroundColor() {
         return nativeGetBackgroundColor();
     }
@@ -3553,7 +3484,6 @@
      */
     @Override
     public void pauseTimers() {
-        checkThread();
         mWebViewCore.sendMessage(EventHub.PAUSE_TIMERS);
     }
 
@@ -3562,7 +3492,6 @@
      */
     @Override
     public void resumeTimers() {
-        checkThread();
         mWebViewCore.sendMessage(EventHub.RESUME_TIMERS);
     }
 
@@ -3571,7 +3500,6 @@
      */
     @Override
     public void onPause() {
-        checkThread();
         if (!mIsPaused) {
             mIsPaused = true;
             mWebViewCore.sendMessage(EventHub.ON_PAUSE);
@@ -3610,7 +3538,6 @@
      */
     @Override
     public void onResume() {
-        checkThread();
         if (mIsPaused) {
             mIsPaused = false;
             mWebViewCore.sendMessage(EventHub.ON_RESUME);
@@ -3642,7 +3569,6 @@
      */
     @Override
     public void freeMemory() {
-        checkThread();
         mWebViewCore.sendMessage(EventHub.FREE_MEMORY);
     }
 
@@ -3651,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.
@@ -3664,7 +3589,6 @@
      */
     @Override
     public void clearFormData() {
-        checkThread();
         if (mAutoCompletePopup != null) {
             mAutoCompletePopup.clearAdapter();
         }
@@ -3675,7 +3599,6 @@
      */
     @Override
     public void clearHistory() {
-        checkThread();
         mCallbackProxy.getBackForwardList().setClearPending();
         mWebViewCore.sendMessage(EventHub.CLEAR_HISTORY);
     }
@@ -3685,7 +3608,6 @@
      */
     @Override
     public void clearSslPreferences() {
-        checkThread();
         mWebViewCore.sendMessage(EventHub.CLEAR_SSL_PREF_TABLE);
     }
 
@@ -3694,7 +3616,6 @@
      */
     @Override
     public WebBackForwardList copyBackForwardList() {
-        checkThread();
         return mCallbackProxy.getBackForwardList().clone();
     }
 
@@ -3705,7 +3626,6 @@
      * @param listener An implementation of FindListener
      */
      public void setFindListener(FindListener listener) {
-         checkThread();
          mFindListener = listener;
      }
 
@@ -3714,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);
     }
@@ -3727,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;
@@ -3772,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
@@ -3841,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:
@@ -3876,7 +3788,6 @@
      */
     @Override
     public void clearMatches() {
-        checkThread();
         if (mNativeClass == 0)
             return;
         mWebViewCore.removeMessages(EventHub.FIND_ALL);
@@ -3906,7 +3817,6 @@
      */
     @Override
     public void documentHasImages(Message response) {
-        checkThread();
         if (response == null) {
             return;
         }
@@ -3915,8 +3825,6 @@
 
     /**
      * Request the scroller to abort any ongoing animation
-     *
-     * @hide
      */
     public void stopScroll() {
         mScroller.forceFinished(true);
@@ -4340,7 +4248,6 @@
      */
     @Override
     public void setWebViewClient(WebViewClient client) {
-        checkThread();
         mCallbackProxy.setWebViewClient(client);
     }
 
@@ -4348,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();
@@ -4359,7 +4266,6 @@
      */
     @Override
     public void setDownloadListener(DownloadListener listener) {
-        checkThread();
         mCallbackProxy.setDownloadListener(listener);
     }
 
@@ -4368,7 +4274,6 @@
      */
     @Override
     public void setWebChromeClient(WebChromeClient client) {
-        checkThread();
         mCallbackProxy.setWebChromeClient(client);
     }
 
@@ -4376,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();
@@ -4387,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);
@@ -4395,7 +4299,6 @@
 
     /**
      * Gets the WebBackForwardListClient.
-     * {@hide}
      */
     public WebBackForwardListClient getWebBackForwardListClient() {
         return mCallbackProxy.getWebBackForwardListClient();
@@ -4407,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);
@@ -4432,7 +4328,6 @@
      */
     @Override
     public void addJavascriptInterface(Object object, String name) {
-        checkThread();
         if (object == null) {
             return;
         }
@@ -4447,7 +4342,6 @@
      */
     @Override
     public void removeJavascriptInterface(String interfaceName) {
-        checkThread();
         if (mWebViewCore != null) {
             WebViewCore.JSInterfaceData arg = new WebViewCore.JSInterfaceData();
             arg.mInterfaceName = interfaceName;
@@ -4462,7 +4356,6 @@
      */
     @Override
     public WebSettingsClassic getSettings() {
-        checkThread();
         return (mWebViewCore != null) ? mWebViewCore.getSettings() : null;
     }
 
@@ -4471,7 +4364,6 @@
      */
     @Deprecated
     public static synchronized PluginList getPluginList() {
-        checkThread();
         return new PluginList();
     }
 
@@ -4480,7 +4372,6 @@
      */
     @Deprecated
     public void refreshPlugins(boolean reloadOpenPages) {
-        checkThread();
     }
 
     //-------------------------------------------------------------------------
@@ -4784,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());
@@ -5135,7 +5026,7 @@
     /**
      * Dump the display tree to "/sdcard/displayTree.txt"
      *
-     * @hide debug only
+     * debug only
      */
     public void dumpDisplayTree() {
         nativeDumpDisplayTree(getUrl());
@@ -5145,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);
@@ -5155,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);
@@ -5164,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);
@@ -5173,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) {
@@ -5510,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);
@@ -5548,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;
@@ -5575,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();
@@ -5587,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
@@ -5603,7 +5493,7 @@
     }
 
     /**
-     * @hide This is an implementation detail.
+     * This is an implementation detail.
      */
     public SearchBox getSearchBox() {
         if ((mWebViewCore == null) || (mWebViewCore.getBrowserFrame() == null)) {
@@ -5779,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);
@@ -6861,7 +6748,6 @@
     private DrawData mLoadedPicture;
 
     public void setMapTrackballToArrowKeys(boolean setMap) {
-        checkThread();
         mMapTrackballToArrowKeys = setMap;
     }
 
@@ -7088,7 +6974,6 @@
     }
 
     public void flingScroll(int vx, int vy) {
-        checkThread();
         mScroller.fling(getScrollX(), getScrollY(), vx, vy, 0, computeMaxScrollX(), 0,
                 computeMaxScrollY(), mOverflingDistance, mOverflingDistance);
         invalidate();
@@ -7210,7 +7095,6 @@
     @Override
     @Deprecated
     public View getZoomControls() {
-        checkThread();
         if (!getSettings().supportZoom()) {
             Log.w(LOGTAG, "This WebView doesn't support zoom.");
             return null;
@@ -7239,7 +7123,6 @@
      */
     @Override
     public boolean canZoomIn() {
-        checkThread();
         return mZoomManager.canZoomIn();
     }
 
@@ -7248,7 +7131,6 @@
      */
     @Override
     public boolean canZoomOut() {
-        checkThread();
         return mZoomManager.canZoomOut();
     }
 
@@ -7257,7 +7139,6 @@
      */
     @Override
     public boolean zoomIn() {
-        checkThread();
         return mZoomManager.zoomIn();
     }
 
@@ -7266,7 +7147,6 @@
      */
     @Override
     public boolean zoomOut() {
-        checkThread();
         return mZoomManager.zoomOut();
     }
 
@@ -7556,9 +7436,6 @@
         mWebViewCore.sendMessageDelayed(EventHub.SAVE_DOCUMENT_STATE, null, 1000);
     }
 
-    /**
-     * @hide
-     */
     public synchronized WebViewCore getWebViewCore() {
         return mWebViewCore;
     }
@@ -8740,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();
@@ -9130,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) {
@@ -9306,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);
@@ -9316,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;
@@ -9326,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;
@@ -9353,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();
     }
@@ -9404,7 +9271,7 @@
     /**
      * Begin collecting per-tile profiling data
      *
-     * @hide only used by profiling tests
+     * only used by profiling tests
      */
     public void tileProfilingStart() {
         nativeTileProfilingStart();
@@ -9412,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/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/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-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/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/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/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/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/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/rs/scriptc/rs_graphics.rsh b/libs/rs/scriptc/rs_graphics.rsh
index e3fde828..80491ee 100644
--- a/libs/rs/scriptc/rs_graphics.rsh
+++ b/libs/rs/scriptc/rs_graphics.rsh
@@ -83,88 +83,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 +100,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 +109,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/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/libmedia/Android.mk b/media/libmedia/Android.mk
index 21e8f29..43008d4 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -3,47 +3,26 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-    AudioParameter.cpp
-LOCAL_MODULE:= libmedia_helper
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-    AudioTrack.cpp \
-    IAudioFlinger.cpp \
-    IAudioFlingerClient.cpp \
-    IAudioTrack.cpp \
-    IAudioRecord.cpp \
-    AudioRecord.cpp \
-    AudioSystem.cpp \
-    mediaplayer.cpp \
-    IMediaPlayerService.cpp \
-    IMediaPlayerClient.cpp \
-    IMediaRecorderClient.cpp \
-    IMediaPlayer.cpp \
-    IMediaRecorder.cpp \
-    IStreamSource.cpp \
-    Metadata.cpp \
-    mediarecorder.cpp \
-    IMediaMetadataRetriever.cpp \
-    mediametadataretriever.cpp \
-    ToneGenerator.cpp \
-    JetPlayer.cpp \
-    IOMX.cpp \
-    IAudioPolicyService.cpp \
-    MediaScanner.cpp \
-    MediaScannerClient.cpp \
     autodetect.cpp \
     IMediaDeathNotifier.cpp \
+    IMediaMetadataRetriever.cpp \
+    IMediaPlayerClient.cpp \
+    IMediaPlayer.cpp \
+    IMediaPlayerService.cpp \
+    IMediaRecorderClient.cpp \
+    IMediaRecorder.cpp \
+    IOMX.cpp \
+    IStreamSource.cpp \
+    JetPlayer.cpp \
+    mediametadataretriever.cpp \
+    mediaplayer.cpp \
     MediaProfiles.cpp \
-    IEffect.cpp \
-    IEffectClient.cpp \
-    AudioEffect.cpp \
-    Visualizer.cpp \
-    MemoryLeakTrackUtil.cpp
+    mediarecorder.cpp \
+    MediaScannerClient.cpp \
+    MediaScanner.cpp \
+    MemoryLeakTrackUtil.cpp \
+    Metadata.cpp \
+    Visualizer.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	libui libcutils libutils libbinder libsonivox libicuuc libexpat \
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/libmedia_native/Android.mk b/media/libmedia_native/Android.mk
index 065a90f..07f0978 100644
--- a/media/libmedia_native/Android.mk
+++ b/media/libmedia_native/Android.mk
@@ -1,11 +1,39 @@
-LOCAL_PATH := $(call my-dir)
+# FIXME remove "/../libmedia" at same time as rename
+LOCAL_PATH := $(call my-dir)/../libmedia
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES :=
+LOCAL_SRC_FILES:= \
+    AudioParameter.cpp
+LOCAL_MODULE:= libmedia_helper
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    AudioEffect.cpp \
+    AudioRecord.cpp \
+    AudioSystem.cpp \
+    AudioTrack.cpp \
+    IAudioFlingerClient.cpp \
+    IAudioFlinger.cpp \
+    IAudioPolicyService.cpp \
+    IAudioRecord.cpp \
+    IAudioTrack.cpp \
+    IEffectClient.cpp \
+    IEffect.cpp \
+    ToneGenerator.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+    libaudioutils libbinder libcutils libutils
 
 LOCAL_MODULE:= libmedia_native
 
+LOCAL_C_INCLUDES := \
+    $(call include-path-for, audio-utils)
+
 LOCAL_MODULE_TAGS := optional
 
 include $(BUILD_SHARED_LIBRARY)
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/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/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/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/Android.mk b/services/audioflinger/Android.mk
index 257f62c..69204d3 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -22,7 +22,6 @@
     libcutils \
     libutils \
     libbinder \
-    libmedia \
     libmedia_native \
     libhardware \
     libhardware_legacy \
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/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/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/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java
index 7ae6692..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();
@@ -194,6 +197,8 @@
             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);
@@ -204,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/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 9e4a735..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,8 +168,6 @@
         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);
         registerForRuimRecordEvents();
@@ -245,14 +242,12 @@
             mRuimSmsInterfaceManager.dispose();
             mSubInfo.dispose();
             mEriManager.dispose();
-            mCcatService.dispose();
         }
     }
 
     @Override
     public void removeReferences() {
         log("removeReferences");
-        super.removeReferences();
         mRuimPhoneBookInterfaceManager = null;
         mRuimSmsInterfaceManager = null;
         mSubInfo = null;
@@ -260,8 +255,8 @@
         mCT = null;
         mSST = null;
         mEriManager = null;
-        mCcatService = null;
         mExitEcmRunnable = null;
+        super.removeReferences();
     }
 
     @Override
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index 27f362c..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,7 +148,6 @@
             mSimSmsIntManager = new SimSmsInterfaceManager(this, mSMS);
             mSubInfo = new PhoneSubInfo(this);
         }
-        mStkService = CatService.getInstance(mCM, mIccRecords, mContext, mIccFileHandler, mIccCard);
 
         mCM.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
         registerForSimRecordEvents();
@@ -215,7 +213,6 @@
             mPendingMMIs.clear();
 
             //Force all referenced classes to unregister their former registered events
-            mStkService.dispose();
             mCT.dispose();
             mDataConnectionTracker.dispose();
             mSST.dispose();
@@ -228,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() {
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs
index 11b8c30..0eaca4a 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs
@@ -7,11 +7,11 @@
 static bool test_program_raster_getters() {
     bool failed = false;
 
-    _RS_ASSERT(rsgProgramRasterGetPointSpriteEnabled(pointSpriteEnabled) == true);
-    _RS_ASSERT(rsgProgramRasterGetCullMode(pointSpriteEnabled) == RS_CULL_BACK);
+    _RS_ASSERT(rsProgramRasterGetPointSpriteEnabled(pointSpriteEnabled) == true);
+    _RS_ASSERT(rsProgramRasterGetCullMode(pointSpriteEnabled) == RS_CULL_BACK);
 
-    _RS_ASSERT(rsgProgramRasterGetPointSpriteEnabled(cullMode) == false);
-    _RS_ASSERT(rsgProgramRasterGetCullMode(cullMode) == RS_CULL_FRONT);
+    _RS_ASSERT(rsProgramRasterGetPointSpriteEnabled(cullMode) == false);
+    _RS_ASSERT(rsProgramRasterGetCullMode(cullMode) == RS_CULL_FRONT);
 
     if (failed) {
         rsDebug("test_program_raster_getters FAILED", 0);
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs
index 3cd8a20..7b47408 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs
@@ -14,95 +14,95 @@
 static bool test_program_store_getters() {
     bool failed = false;
 
-    _RS_ASSERT(rsgProgramStoreGetDepthFunc(depthFunc) == RS_DEPTH_FUNC_GREATER);
-    _RS_ASSERT(rsgProgramStoreGetDepthMask(depthFunc) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskR(depthFunc) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskG(depthFunc) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskB(depthFunc) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskA(depthFunc) == false);
-    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(depthFunc) == false);
-    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(depthFunc) == RS_BLEND_SRC_ZERO);
-    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(depthFunc) == RS_BLEND_DST_ZERO);
+    _RS_ASSERT(rsProgramStoreGetDepthFunc(depthFunc) == RS_DEPTH_FUNC_GREATER);
+    _RS_ASSERT(rsProgramStoreGetDepthMask(depthFunc) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskR(depthFunc) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskG(depthFunc) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskB(depthFunc) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskA(depthFunc) == false);
+    _RS_ASSERT(rsProgramStoreGetDitherEnabled(depthFunc) == false);
+    _RS_ASSERT(rsProgramStoreGetBlendSrcFunc(depthFunc) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsProgramStoreGetBlendDstFunc(depthFunc) == RS_BLEND_DST_ZERO);
 
-    _RS_ASSERT(rsgProgramStoreGetDepthFunc(depthWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
-    _RS_ASSERT(rsgProgramStoreGetDepthMask(depthWriteEnable) == true);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskR(depthWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskG(depthWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskB(depthWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskA(depthWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(depthWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(depthWriteEnable) == RS_BLEND_SRC_ZERO);
-    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(depthWriteEnable) == RS_BLEND_DST_ZERO);
+    _RS_ASSERT(rsProgramStoreGetDepthFunc(depthWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsProgramStoreGetDepthMask(depthWriteEnable) == true);
+    _RS_ASSERT(rsProgramStoreGetColorMaskR(depthWriteEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskG(depthWriteEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskB(depthWriteEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskA(depthWriteEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetDitherEnabled(depthWriteEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetBlendSrcFunc(depthWriteEnable) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsProgramStoreGetBlendDstFunc(depthWriteEnable) == RS_BLEND_DST_ZERO);
 
-    _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorRWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
-    _RS_ASSERT(rsgProgramStoreGetDepthMask(colorRWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorRWriteEnable) == true);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorRWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorRWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorRWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorRWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorRWriteEnable) == RS_BLEND_SRC_ZERO);
-    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorRWriteEnable) == RS_BLEND_DST_ZERO);
+    _RS_ASSERT(rsProgramStoreGetDepthFunc(colorRWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsProgramStoreGetDepthMask(colorRWriteEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskR(colorRWriteEnable) == true);
+    _RS_ASSERT(rsProgramStoreGetColorMaskG(colorRWriteEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskB(colorRWriteEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskA(colorRWriteEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetDitherEnabled(colorRWriteEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetBlendSrcFunc(colorRWriteEnable) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsProgramStoreGetBlendDstFunc(colorRWriteEnable) == RS_BLEND_DST_ZERO);
 
-    _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorGWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
-    _RS_ASSERT(rsgProgramStoreGetDepthMask(colorGWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorGWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorGWriteEnable) == true);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorGWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorGWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorGWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorGWriteEnable) == RS_BLEND_SRC_ZERO);
-    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorGWriteEnable) == RS_BLEND_DST_ZERO);
+    _RS_ASSERT(rsProgramStoreGetDepthFunc(colorGWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsProgramStoreGetDepthMask(colorGWriteEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskR(colorGWriteEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskG(colorGWriteEnable) == true);
+    _RS_ASSERT(rsProgramStoreGetColorMaskB(colorGWriteEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskA(colorGWriteEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetDitherEnabled(colorGWriteEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetBlendSrcFunc(colorGWriteEnable) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsProgramStoreGetBlendDstFunc(colorGWriteEnable) == RS_BLEND_DST_ZERO);
 
-    _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorBWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
-    _RS_ASSERT(rsgProgramStoreGetDepthMask(colorBWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorBWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorBWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorBWriteEnable) == true);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorBWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorBWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorBWriteEnable) == RS_BLEND_SRC_ZERO);
-    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorBWriteEnable) == RS_BLEND_DST_ZERO);
+    _RS_ASSERT(rsProgramStoreGetDepthFunc(colorBWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsProgramStoreGetDepthMask(colorBWriteEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskR(colorBWriteEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskG(colorBWriteEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskB(colorBWriteEnable) == true);
+    _RS_ASSERT(rsProgramStoreGetColorMaskA(colorBWriteEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetDitherEnabled(colorBWriteEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetBlendSrcFunc(colorBWriteEnable) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsProgramStoreGetBlendDstFunc(colorBWriteEnable) == RS_BLEND_DST_ZERO);
 
-    _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorAWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
-    _RS_ASSERT(rsgProgramStoreGetDepthMask(colorAWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorAWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorAWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorAWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorAWriteEnable) == true);
-    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorAWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorAWriteEnable) == RS_BLEND_SRC_ZERO);
-    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorAWriteEnable) == RS_BLEND_DST_ZERO);
+    _RS_ASSERT(rsProgramStoreGetDepthFunc(colorAWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsProgramStoreGetDepthMask(colorAWriteEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskR(colorAWriteEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskG(colorAWriteEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskB(colorAWriteEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskA(colorAWriteEnable) == true);
+    _RS_ASSERT(rsProgramStoreGetDitherEnabled(colorAWriteEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetBlendSrcFunc(colorAWriteEnable) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsProgramStoreGetBlendDstFunc(colorAWriteEnable) == RS_BLEND_DST_ZERO);
 
-    _RS_ASSERT(rsgProgramStoreGetDepthFunc(ditherEnable) == RS_DEPTH_FUNC_ALWAYS);
-    _RS_ASSERT(rsgProgramStoreGetDepthMask(ditherEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskR(ditherEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskG(ditherEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskB(ditherEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskA(ditherEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(ditherEnable) == true);
-    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(ditherEnable) == RS_BLEND_SRC_ZERO);
-    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(ditherEnable) == RS_BLEND_DST_ZERO);
+    _RS_ASSERT(rsProgramStoreGetDepthFunc(ditherEnable) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsProgramStoreGetDepthMask(ditherEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskR(ditherEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskG(ditherEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskB(ditherEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskA(ditherEnable) == false);
+    _RS_ASSERT(rsProgramStoreGetDitherEnabled(ditherEnable) == true);
+    _RS_ASSERT(rsProgramStoreGetBlendSrcFunc(ditherEnable) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsProgramStoreGetBlendDstFunc(ditherEnable) == RS_BLEND_DST_ZERO);
 
-    _RS_ASSERT(rsgProgramStoreGetDepthFunc(blendSrc) == RS_DEPTH_FUNC_ALWAYS);
-    _RS_ASSERT(rsgProgramStoreGetDepthMask(blendSrc) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskR(blendSrc) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskG(blendSrc) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskB(blendSrc) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskA(blendSrc) == false);
-    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(blendSrc) == false);
-    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(blendSrc) == RS_BLEND_SRC_DST_COLOR);
-    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(blendSrc) == RS_BLEND_DST_ZERO);
+    _RS_ASSERT(rsProgramStoreGetDepthFunc(blendSrc) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsProgramStoreGetDepthMask(blendSrc) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskR(blendSrc) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskG(blendSrc) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskB(blendSrc) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskA(blendSrc) == false);
+    _RS_ASSERT(rsProgramStoreGetDitherEnabled(blendSrc) == false);
+    _RS_ASSERT(rsProgramStoreGetBlendSrcFunc(blendSrc) == RS_BLEND_SRC_DST_COLOR);
+    _RS_ASSERT(rsProgramStoreGetBlendDstFunc(blendSrc) == RS_BLEND_DST_ZERO);
 
-    _RS_ASSERT(rsgProgramStoreGetDepthFunc(blendDst) == RS_DEPTH_FUNC_ALWAYS);
-    _RS_ASSERT(rsgProgramStoreGetDepthMask(blendDst) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskR(blendDst) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskG(blendDst) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskB(blendDst) == false);
-    _RS_ASSERT(rsgProgramStoreGetColorMaskA(blendDst) == false);
-    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(blendDst) == false);
-    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(blendDst) == RS_BLEND_SRC_ZERO);
-    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(blendDst) == RS_BLEND_DST_DST_ALPHA);
+    _RS_ASSERT(rsProgramStoreGetDepthFunc(blendDst) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsProgramStoreGetDepthMask(blendDst) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskR(blendDst) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskG(blendDst) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskB(blendDst) == false);
+    _RS_ASSERT(rsProgramStoreGetColorMaskA(blendDst) == false);
+    _RS_ASSERT(rsProgramStoreGetDitherEnabled(blendDst) == false);
+    _RS_ASSERT(rsProgramStoreGetBlendSrcFunc(blendDst) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsProgramStoreGetBlendDstFunc(blendDst) == RS_BLEND_DST_DST_ALPHA);
 
     if (failed) {
         rsDebug("test_program_store_getters FAILED", 0);
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/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: