Merge "Import translations. DO NOT MERGE"
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 27c9c8b..197c1bd 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -231,6 +231,14 @@
             }
         }, intentFilter);
 
+        IntentFilter userFilter = new IntentFilter();
+        userFilter.addAction(Intent.ACTION_USER_REMOVED);
+        mContext.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                onUserRemoved(intent);
+            }
+        }, userFilter);
     }
 
     private UserAccounts initUser(int userId) {
@@ -347,6 +355,28 @@
         }
     }
 
+    private void onUserRemoved(Intent intent) {
+        int userId = intent.getIntExtra(Intent.EXTRA_USERID, -1);
+        if (userId < 1) return;
+
+        UserAccounts accounts;
+        synchronized (mUsers) {
+            accounts = mUsers.get(userId);
+            mUsers.remove(userId);
+        }
+        if (accounts == null) {
+            File dbFile = new File(getDatabaseName(userId));
+            dbFile.delete();
+            return;
+        }
+
+        synchronized (accounts.cacheLock) {
+            accounts.openHelper.close();
+            File dbFile = new File(getDatabaseName(userId));
+            dbFile.delete();
+        }
+    }
+
     private List<UserInfo> getAllUsers() {
         try {
             return AppGlobals.getPackageManager().getUsers();
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index f38540c..0510de1 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1215,6 +1215,18 @@
      * @hide
      */
     @Override
+    public UserInfo getUser(int userId) {
+        try {
+            return mPM.getUser(userId);
+        } catch (RemoteException re) {
+            return null;
+        }
+    }
+
+    /**
+     * @hide
+     */
+    @Override
     public boolean removeUser(int id) {
         try {
             return mPM.removeUser(id);
@@ -1228,7 +1240,10 @@
      */
     @Override
     public void updateUserName(int id, String name) {
-        // TODO:
+        try {
+            mPM.updateUserName(id, name);
+        } catch (RemoteException re) {
+        }
     }
 
     /**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 1c9ef38..2a9f1af 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2141,6 +2141,30 @@
     public static final String ACTION_PRE_BOOT_COMPLETED =
             "android.intent.action.PRE_BOOT_COMPLETED";
 
+    /**
+     * Broadcast sent to the system when a user is added. Carries an extra EXTRA_USERID that has the
+     * userid of the new user.
+     * @hide
+     */
+    public static final String ACTION_USER_ADDED =
+            "android.intent.action.USER_ADDED";
+
+    /**
+     * Broadcast sent to the system when a user is removed. Carries an extra EXTRA_USERID that has
+     * the userid of the user.
+     * @hide
+     */
+    public static final String ACTION_USER_REMOVED =
+            "android.intent.action.USER_REMOVED";
+
+    /**
+     * Broadcast sent to the system when the user switches. Carries an extra EXTRA_USERID that has
+     * the userid of the user to become the current one.
+     * @hide
+     */
+    public static final String ACTION_USER_SWITCHED =
+            "android.intent.action.USER_SWITCHED";
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Standard intent categories (see addCategory()).
@@ -2682,6 +2706,13 @@
     public static final String EXTRA_LOCAL_ONLY =
         "android.intent.extra.LOCAL_ONLY";
 
+    /**
+     * The userid carried with broadcast intents related to addition, removal and switching of users
+     * - {@link #ACTION_USER_ADDED}, {@link #ACTION_USER_REMOVED} and {@link #ACTION_USER_SWITCHED}.
+     * @hide
+     */
+    public static final String EXTRA_USERID =
+            "android.intent.extra.user_id";
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Intent flags (see mFlags variable).
@@ -6483,7 +6514,12 @@
 
         final String action = getAction();
         if (ACTION_SEND.equals(action)) {
-            final Uri stream = getParcelableExtra(EXTRA_STREAM);
+            final Uri stream;
+            try {
+                stream = getParcelableExtra(EXTRA_STREAM);
+            } catch (ClassCastException e) {
+                return;
+            }
             if (stream != null) {
                 final ClipData clipData = new ClipData(
                         null, new String[] { getType() }, new ClipData.Item(stream));
@@ -6493,7 +6529,12 @@
             }
 
         } else if (ACTION_SEND_MULTIPLE.equals(action)) {
-            final ArrayList<Uri> streams = getParcelableArrayListExtra(EXTRA_STREAM);
+            final ArrayList<Uri> streams;
+            try {
+                streams = getParcelableArrayListExtra(EXTRA_STREAM);
+            } catch (ClassCastException e) {
+                return;
+            }
             if (streams != null && streams.size() > 0) {
                 final Uri firstStream = streams.get(0);
                 final ClipData clipData = new ClipData(
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index b7dfe92..06dfe90 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -326,6 +326,13 @@
         }
     };
 
+    private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            onUserRemoved(intent);
+        }
+    };
+
     private static final String ACTION_SYNC_ALARM = "android.content.syncmanager.SYNC_ALARM";
     private final SyncHandler mSyncHandler;
 
@@ -420,6 +427,10 @@
         intentFilter.setPriority(100);
         context.registerReceiver(mShutdownIntentReceiver, intentFilter);
 
+        intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
+        mContext.registerReceiver(mUserIntentReceiver, intentFilter);
+
         if (!factoryTest) {
             mNotificationMgr = (NotificationManager)
                 context.getSystemService(Context.NOTIFICATION_SERVICE);
@@ -905,6 +916,18 @@
         }
     }
 
+    private void onUserRemoved(Intent intent) {
+        int userId = intent.getIntExtra(Intent.EXTRA_USERID, -1);
+        if (userId == -1) return;
+
+        // Clean up the storage engine database
+        mSyncStorageEngine.doDatabaseCleanup(new Account[0], userId);
+        onAccountsUpdated(null);
+        synchronized (mSyncQueue) {
+            mSyncQueue.removeUser(userId);
+        }
+    }
+
     /**
      * @hide
      */
diff --git a/core/java/android/content/SyncQueue.java b/core/java/android/content/SyncQueue.java
index 06da6fa..c18c86bf 100644
--- a/core/java/android/content/SyncQueue.java
+++ b/core/java/android/content/SyncQueue.java
@@ -117,6 +117,19 @@
         return true;
     }
 
+    public void removeUser(int userId) {
+        ArrayList<SyncOperation> opsToRemove = new ArrayList<SyncOperation>();
+        for (SyncOperation op : mOperationsMap.values()) {
+            if (op.userId == userId) {
+                opsToRemove.add(op);
+            }
+        }
+
+        for (SyncOperation op : opsToRemove) {
+            remove(op);
+        }
+    }
+
     /**
      * Remove the specified operation if it is in the queue.
      * @param operation the operation to remove
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index d89d2de..56fd5f8 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -358,6 +358,7 @@
 
     UserInfo createUser(in String name, int flags);
     boolean removeUser(int userId);
+    void updateUserName(int userId, String name);
 
     void installPackageWithVerification(in Uri packageURI, in IPackageInstallObserver observer,
             int flags, in String installerPackageName, in Uri verificationURI,
@@ -370,6 +371,7 @@
     boolean isFirstBoot();
 
     List<UserInfo> getUsers();
+    UserInfo getUser(int userId);
 
     void setPermissionEnforcement(String permission, int enforcement);
     int getPermissionEnforcement(String permission);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 55426b8..b06b4a5 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2153,7 +2153,8 @@
         if ((flags & GET_SIGNATURES) != 0) {
             packageParser.collectCertificates(pkg, 0);
         }
-        return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null);
+        return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, false,
+                COMPONENT_ENABLED_STATE_DEFAULT);
     }
 
     /**
@@ -2637,10 +2638,17 @@
     public abstract void updateUserFlags(int id, int flags);
 
     /**
-     * Returns the device identity that verifiers can use to associate their
-     * scheme to a particular device. This should not be used by anything other
-     * than a package verifier.
-     *
+     * Returns the details for the user specified by userId.
+     * @param userId the user id of the user
+     * @return UserInfo for the specified user, or null if no such user exists.
+     * @hide
+     */
+    public abstract UserInfo getUser(int userId);
+
+    /**
+     * Returns the device identity that verifiers can use to associate their scheme to a particular
+     * device. This should not be used by anything other than a package verifier.
+     * 
      * @return identity that uniquely identifies current device
      * @hide
      */
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 07d231a..eb8536f 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -230,6 +230,15 @@
         return name.endsWith(".apk");
     }
 
+    public static PackageInfo generatePackageInfo(PackageParser.Package p,
+            int gids[], int flags, long firstInstallTime, long lastUpdateTime,
+            HashSet<String> grantedPermissions) {
+
+        return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime,
+                grantedPermissions, false, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
+                UserId.getCallingUserId());
+    }
+
     /**
      * Generate and return the {@link PackageInfo} for a parsed package.
      *
@@ -238,15 +247,15 @@
      */
     public static PackageInfo generatePackageInfo(PackageParser.Package p,
             int gids[], int flags, long firstInstallTime, long lastUpdateTime,
-            HashSet<String> grantedPermissions) {
+            HashSet<String> grantedPermissions, boolean stopped, int enabledState) {
 
         return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime,
-                grantedPermissions, UserId.getCallingUserId());
+                grantedPermissions, stopped, enabledState, UserId.getCallingUserId());
     }
 
-    static PackageInfo generatePackageInfo(PackageParser.Package p,
+    public static PackageInfo generatePackageInfo(PackageParser.Package p,
             int gids[], int flags, long firstInstallTime, long lastUpdateTime,
-            HashSet<String> grantedPermissions, int userId) {
+            HashSet<String> grantedPermissions, boolean stopped, int enabledState, int userId) {
 
         PackageInfo pi = new PackageInfo();
         pi.packageName = p.packageName;
@@ -254,7 +263,7 @@
         pi.versionName = p.mVersionName;
         pi.sharedUserId = p.mSharedUserId;
         pi.sharedUserLabel = p.mSharedUserLabel;
-        pi.applicationInfo = generateApplicationInfo(p, flags);
+        pi.applicationInfo = generateApplicationInfo(p, flags, stopped, enabledState, userId);
         pi.installLocation = p.installLocation;
         pi.firstInstallTime = firstInstallTime;
         pi.lastUpdateTime = lastUpdateTime;
@@ -290,7 +299,7 @@
                     if (activity.info.enabled
                         || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
                         pi.activities[j++] = generateActivityInfo(p.activities.get(i), flags,
-                                userId);
+                                stopped, enabledState, userId);
                     }
                 }
             }
@@ -311,7 +320,8 @@
                     final Activity activity = p.receivers.get(i);
                     if (activity.info.enabled
                         || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
-                        pi.receivers[j++] = generateActivityInfo(p.receivers.get(i), flags, userId);
+                        pi.receivers[j++] = generateActivityInfo(p.receivers.get(i), flags,
+                                stopped, enabledState, userId);
                     }
                 }
             }
@@ -332,7 +342,8 @@
                     final Service service = p.services.get(i);
                     if (service.info.enabled
                         || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
-                        pi.services[j++] = generateServiceInfo(p.services.get(i), flags, userId);
+                        pi.services[j++] = generateServiceInfo(p.services.get(i), flags, stopped,
+                                enabledState, userId);
                     }
                 }
             }
@@ -353,7 +364,8 @@
                     final Provider provider = p.providers.get(i);
                     if (provider.info.enabled
                         || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
-                        pi.providers[j++] = generateProviderInfo(p.providers.get(i), flags, userId);
+                        pi.providers[j++] = generateProviderInfo(p.providers.get(i), flags, stopped,
+                                enabledState, userId);
                     }
                 }
             }
@@ -3068,11 +3080,11 @@
         // For use by package manager to keep track of where it has done dexopt.
         public boolean mDidDexOpt;
         
-        // User set enabled state.
-        public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
-
-        // Whether the package has been stopped.
-        public boolean mSetStopped = false;
+        // // User set enabled state.
+        // public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+        //
+        // // Whether the package has been stopped.
+        // public boolean mSetStopped = false;
 
         // Additional data supplied by callers.
         public Object mExtras;
@@ -3337,9 +3349,9 @@
         }
     }
 
-    private static boolean copyNeeded(int flags, Package p, Bundle metaData) {
-        if (p.mSetEnabled != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
-            boolean enabled = p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+    private static boolean copyNeeded(int flags, Package p, int enabledState, Bundle metaData) {
+        if (enabledState != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
+            boolean enabled = enabledState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
             if (p.applicationInfo.enabled != enabled) {
                 return true;
             }
@@ -3355,30 +3367,32 @@
         return false;
     }
 
-    public static ApplicationInfo generateApplicationInfo(Package p, int flags) {
-        return generateApplicationInfo(p, flags, UserId.getCallingUserId());
+    public static ApplicationInfo generateApplicationInfo(Package p, int flags, boolean stopped,
+            int enabledState) {
+        return generateApplicationInfo(p, flags, stopped, enabledState, UserId.getCallingUserId());
     }
 
-    public static ApplicationInfo generateApplicationInfo(Package p, int flags, int userId) {
+    public static ApplicationInfo generateApplicationInfo(Package p, int flags,
+            boolean stopped, int enabledState, int userId) {
         if (p == null) return null;
-        if (!copyNeeded(flags, p, null) && userId == 0) {
+        if (!copyNeeded(flags, p, enabledState, null) && userId == 0) {
             // CompatibilityMode is global state. It's safe to modify the instance
             // of the package.
             if (!sCompatibilityModeEnabled) {
                 p.applicationInfo.disableCompatibilityMode();
             }
-            if (p.mSetStopped) {
+            if (stopped) {
                 p.applicationInfo.flags |= ApplicationInfo.FLAG_STOPPED;
             } else {
                 p.applicationInfo.flags &= ~ApplicationInfo.FLAG_STOPPED;
             }
-            if (p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
+            if (enabledState == 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) {
+            } else if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+                    || enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
                 p.applicationInfo.enabled = false;
             }
-            p.applicationInfo.enabledSetting = p.mSetEnabled;
+            p.applicationInfo.enabledSetting = enabledState;
             return p.applicationInfo;
         }
 
@@ -3397,18 +3411,18 @@
         if (!sCompatibilityModeEnabled) {
             ai.disableCompatibilityMode();
         }
-        if (p.mSetStopped) {
+        if (stopped) {
             p.applicationInfo.flags |= ApplicationInfo.FLAG_STOPPED;
         } else {
             p.applicationInfo.flags &= ~ApplicationInfo.FLAG_STOPPED;
         }
-        if (p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
+        if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
             ai.enabled = true;
-        } else if (p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
-                || p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
+        } else if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+                || enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
             ai.enabled = false;
         }
-        ai.enabledSetting = p.mSetEnabled;
+        ai.enabledSetting = enabledState;
         return ai;
     }
 
@@ -3455,15 +3469,16 @@
         }
     }
 
-    public static final ActivityInfo generateActivityInfo(Activity a, int flags, int userId) {
+    public static final ActivityInfo generateActivityInfo(Activity a, int flags, boolean stopped,
+            int enabledState, int userId) {
         if (a == null) return null;
-        if (!copyNeeded(flags, a.owner, a.metaData) && userId == 0) {
+        if (!copyNeeded(flags, a.owner, enabledState, a.metaData) && userId == 0) {
             return a.info;
         }
         // Make shallow copies so we can store the metadata safely
         ActivityInfo ai = new ActivityInfo(a.info);
         ai.metaData = a.metaData;
-        ai.applicationInfo = generateApplicationInfo(a.owner, flags, userId);
+        ai.applicationInfo = generateApplicationInfo(a.owner, flags, stopped, enabledState, userId);
         return ai;
     }
 
@@ -3488,16 +3503,17 @@
         }
     }
 
-    public static final ServiceInfo generateServiceInfo(Service s, int flags, int userId) {
+    public static final ServiceInfo generateServiceInfo(Service s, int flags, boolean stopped,
+            int enabledState, int userId) {
         if (s == null) return null;
-        if (!copyNeeded(flags, s.owner, s.metaData)
+        if (!copyNeeded(flags, s.owner, enabledState, s.metaData)
                 && userId == UserId.getUserId(s.info.applicationInfo.uid)) {
             return s.info;
         }
         // Make shallow copies so we can store the metadata safely
         ServiceInfo si = new ServiceInfo(s.info);
         si.metaData = s.metaData;
-        si.applicationInfo = generateApplicationInfo(s.owner, flags, userId);
+        si.applicationInfo = generateApplicationInfo(s.owner, flags, stopped, enabledState, userId);
         return si;
     }
 
@@ -3530,9 +3546,10 @@
         }
     }
 
-    public static final ProviderInfo generateProviderInfo(Provider p, int flags, int userId) {
+    public static final ProviderInfo generateProviderInfo(Provider p, int flags, boolean stopped,
+            int enabledState, int userId) {
         if (p == null) return null;
-        if (!copyNeeded(flags, p.owner, p.metaData)
+        if (!copyNeeded(flags, p.owner, enabledState, p.metaData)
                 && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0
                         || p.info.uriPermissionPatterns == null)
                 && userId == 0) {
@@ -3544,7 +3561,7 @@
         if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) {
             pi.uriPermissionPatterns = null;
         }
-        pi.applicationInfo = generateApplicationInfo(p.owner, flags, userId);
+        pi.applicationInfo = generateApplicationInfo(p.owner, flags, stopped, enabledState, userId);
         return pi;
     }
 
diff --git a/core/java/android/webkit/DebugFlags.java b/core/java/android/webkit/DebugFlags.java
index a21d3ee..349113e 100644
--- a/core/java/android/webkit/DebugFlags.java
+++ b/core/java/android/webkit/DebugFlags.java
@@ -42,12 +42,7 @@
     public static final boolean WEB_BACK_FORWARD_LIST = false;
     public static final boolean WEB_SETTINGS = false;
     public static final boolean WEB_SYNC_MANAGER = false;
-    public static final boolean WEB_TEXT_VIEW = false;
     public static final boolean WEB_VIEW = false;
     public static final boolean WEB_VIEW_CORE = false;
-    /*
-     * Set to true to allow the WebTextView to draw on top of the web page in a
-     * different color with no background so you can see how the two line up.
-     */
-    public static final boolean DRAW_WEBTEXTVIEW = false;
+    public static final boolean MEASURE_PAGE_SWAP_FPS = false;
 }
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index ad644e4..5ae2fe0 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -4717,10 +4717,10 @@
         queueFull = nativeSetBaseLayer(mNativeClass, layer, invalRegion,
                                        showVisualIndicator, isPictureAfterFirstLayout);
 
-        if (layer == 0 || isPictureAfterFirstLayout) {
-            mWebViewCore.resumeWebKitDraw();
-        } else if (queueFull) {
+        if (queueFull) {
             mWebViewCore.pauseWebKitDraw();
+        } else {
+            mWebViewCore.resumeWebKitDraw();
         }
 
         if (mHTML5VideoViewProxy != null) {
@@ -8615,9 +8615,19 @@
         void onPageSwapOccurred(boolean notifyAnimationStarted);
     }
 
+    long mLastSwapTime;
+    double mAverageSwapFps;
+
     /** Called by JNI when pages are swapped (only occurs with hardware
      * acceleration) */
     protected void pageSwapCallback(boolean notifyAnimationStarted) {
+        if (DebugFlags.MEASURE_PAGE_SWAP_FPS) {
+            long now = System.currentTimeMillis();
+            long diff = now - mLastSwapTime;
+            mAverageSwapFps = ((1000.0 / diff) + mAverageSwapFps) / 2;
+            Log.d(LOGTAG, "page swap fps: " + mAverageSwapFps);
+            mLastSwapTime = now;
+        }
         mWebViewCore.resumeWebKitDraw();
         if (notifyAnimationStarted) {
             mWebViewCore.sendMessage(EventHub.NOTIFY_ANIMATION_STARTED);
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index b47f71d..afb2992 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -2271,6 +2271,7 @@
                 mFirstLayoutForNonStandardLoad = false;
             }
             if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "webkitDraw NEW_PICTURE_MSG_ID");
+            pauseWebKitDraw();
             Message.obtain(mWebViewClassic.mPrivateHandler,
                     WebViewClassic.NEW_PICTURE_MSG_ID, draw).sendToTarget();
         }
diff --git a/core/java/com/google/android/mms/pdu/PduPersister.java b/core/java/com/google/android/mms/pdu/PduPersister.java
index b04f890..7c937ed 100644
--- a/core/java/com/google/android/mms/pdu/PduPersister.java
+++ b/core/java/com/google/android/mms/pdu/PduPersister.java
@@ -20,6 +20,8 @@
 import com.google.android.mms.ContentType;
 import com.google.android.mms.InvalidHeaderValueException;
 import com.google.android.mms.MmsException;
+import com.google.android.mms.util.DownloadDrmHelper;
+import com.google.android.mms.util.DrmConvertSession;
 import com.google.android.mms.util.PduCache;
 import com.google.android.mms.util.PduCacheEntry;
 import com.google.android.mms.util.SqliteWrapper;
@@ -30,7 +32,11 @@
 import android.content.Context;
 import android.database.Cursor;
 import android.database.DatabaseUtils;
+import android.database.sqlite.SQLiteException;
+import android.drm.DrmManagerClient;
 import android.net.Uri;
+import android.os.FileUtils;
+import android.provider.MediaStore;
 import android.provider.Telephony;
 import android.provider.Telephony.Mms;
 import android.provider.Telephony.MmsSms;
@@ -42,6 +48,7 @@
 import android.util.Log;
 
 import java.io.ByteArrayOutputStream;
+import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
@@ -271,10 +278,12 @@
 
     private final Context mContext;
     private final ContentResolver mContentResolver;
+    private final DrmManagerClient mDrmManagerClient;
 
     private PduPersister(Context context) {
         mContext = context;
         mContentResolver = context.getContentResolver();
+        mDrmManagerClient = new DrmManagerClient(context);
      }
 
     /** Get(or create if not exist) an instance of PduPersister */
@@ -761,6 +770,9 @@
             throws MmsException {
         OutputStream os = null;
         InputStream is = null;
+        DrmConvertSession drmConvertSession = null;
+        Uri dataUri = null;
+        String path = null;
 
         try {
             byte[] data = part.getData();
@@ -773,9 +785,38 @@
                     throw new MmsException("unable to update " + uri.toString());
                 }
             } else {
+                boolean isDrm = DownloadDrmHelper.isDrmConvertNeeded(contentType);
+                if (isDrm) {
+                    if (uri != null) {
+                        try {
+                            path = convertUriToPath(mContext, uri);
+                            if (LOCAL_LOGV) {
+                                Log.v(TAG, "drm uri: " + uri + " path: " + path);
+                            }
+                            File f = new File(path);
+                            long len = f.length();
+                            if (LOCAL_LOGV) {
+                                Log.v(TAG, "drm path: " + path + " len: " + len);
+                            }
+                            if (len > 0) {
+                                // we're not going to re-persist and re-encrypt an already
+                                // converted drm file
+                                return;
+                            }
+                        } catch (Exception e) {
+                            Log.e(TAG, "Can't get file info for: " + part.getDataUri(), e);
+                        }
+                    }
+                    // We haven't converted the file yet, start the conversion
+                    drmConvertSession = DrmConvertSession.open(mContext, contentType);
+                    if (drmConvertSession == null) {
+                        throw new MmsException("Mimetype " + contentType +
+                                " can not be converted.");
+                    }
+                }
                 os = mContentResolver.openOutputStream(uri);
                 if (data == null) {
-                    Uri dataUri = part.getDataUri();
+                    dataUri = part.getDataUri();
                     if ((dataUri == null) || (dataUri == uri)) {
                         Log.w(TAG, "Can't find data for this part.");
                         return;
@@ -788,13 +829,32 @@
 
                     byte[] buffer = new byte[8192];
                     for (int len = 0; (len = is.read(buffer)) != -1; ) {
-                        os.write(buffer, 0, len);
+                        if (!isDrm) {
+                            os.write(buffer, 0, len);
+                        } else {
+                            byte[] convertedData = drmConvertSession.convert(buffer, len);
+                            if (convertedData != null) {
+                                os.write(convertedData, 0, convertedData.length);
+                            } else {
+                                throw new MmsException("Error converting drm data.");
+                            }
+                        }
                     }
                 } else {
                     if (LOCAL_LOGV) {
                         Log.v(TAG, "Saving data to: " + uri);
                     }
-                    os.write(data);
+                    if (!isDrm) {
+                        os.write(data);
+                    } else {
+                        dataUri = uri;
+                        byte[] convertedData = drmConvertSession.convert(data, data.length);
+                        if (convertedData != null) {
+                            os.write(convertedData, 0, convertedData.length);
+                        } else {
+                            throw new MmsException("Error converting drm data.");
+                        }
+                    }
                 }
             }
         } catch (FileNotFoundException e) {
@@ -818,9 +878,67 @@
                     Log.e(TAG, "IOException while closing: " + is, e);
                 } // Ignore
             }
+            if (drmConvertSession != null) {
+                drmConvertSession.close(path);
+
+                // Reset the permissions on the encrypted part file so everyone has only read
+                // permission.
+                File f = new File(path);
+                ContentValues values = new ContentValues(0);
+                SqliteWrapper.update(mContext, mContentResolver,
+                                     Uri.parse("content://mms/resetFilePerm/" + f.getName()),
+                                     values, null, null);
+            }
         }
     }
 
+    /**
+     * This method expects uri in the following format
+     *     content://media/<table_name>/<row_index> (or)
+     *     file://sdcard/test.mp4
+     *     http://test.com/test.mp4
+     *
+     * Here <table_name> shall be "video" or "audio" or "images"
+     * <row_index> the index of the content in given table
+     */
+    static public String convertUriToPath(Context context, Uri uri) {
+        String path = null;
+        if (null != uri) {
+            String scheme = uri.getScheme();
+            if (null == scheme || scheme.equals("") ||
+                    scheme.equals(ContentResolver.SCHEME_FILE)) {
+                path = uri.getPath();
+
+            } else if (scheme.equals("http")) {
+                path = uri.toString();
+
+            } else if (scheme.equals(ContentResolver.SCHEME_CONTENT)) {
+                String[] projection = new String[] {MediaStore.MediaColumns.DATA};
+                Cursor cursor = null;
+                try {
+                    cursor = context.getContentResolver().query(uri, projection, null,
+                            null, null);
+                    if (null == cursor || 0 == cursor.getCount() || !cursor.moveToFirst()) {
+                        throw new IllegalArgumentException("Given Uri could not be found" +
+                                " in media store");
+                    }
+                    int pathIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
+                    path = cursor.getString(pathIndex);
+                } catch (SQLiteException e) {
+                    throw new IllegalArgumentException("Given Uri is not formatted in a way " +
+                            "so that it can be found in media store.");
+                } finally {
+                    if (null != cursor) {
+                        cursor.close();
+                    }
+                }
+            } else {
+                throw new IllegalArgumentException("Given Uri scheme is not supported");
+            }
+        }
+        return path;
+    }
+
     private void updateAddress(
             long msgId, int type, EncodedStringValue[] array) {
         // Delete old address information and then insert new ones.
diff --git a/core/java/com/google/android/mms/util/DownloadDrmHelper.java b/core/java/com/google/android/mms/util/DownloadDrmHelper.java
new file mode 100644
index 0000000..6852eca
--- /dev/null
+++ b/core/java/com/google/android/mms/util/DownloadDrmHelper.java
@@ -0,0 +1,111 @@
+/*
+ * 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.google.android.mms.util;
+
+import android.content.Context;
+import android.drm.DrmManagerClient;
+import android.util.Log;
+
+public class DownloadDrmHelper {
+    private static final String TAG = "DownloadDrmHelper";
+
+    /** The MIME type of special DRM files */
+    public static final String MIMETYPE_DRM_MESSAGE = "application/vnd.oma.drm.message";
+
+    /** The extensions of special DRM files */
+    public static final String EXTENSION_DRM_MESSAGE = ".dm";
+
+    public static final String EXTENSION_INTERNAL_FWDL = ".fl";
+
+    /**
+     * Checks if the Media Type is a DRM Media Type
+     *
+     * @param drmManagerClient A DrmManagerClient
+     * @param mimetype Media Type to check
+     * @return True if the Media Type is DRM else false
+     */
+    public static boolean isDrmMimeType(Context context, String mimetype) {
+        boolean result = false;
+        if (context != null) {
+            try {
+                DrmManagerClient drmClient = new DrmManagerClient(context);
+                if (drmClient != null && mimetype != null && mimetype.length() > 0) {
+                    result = drmClient.canHandle("", mimetype);
+                }
+            } catch (IllegalArgumentException e) {
+                Log.w(TAG,
+                        "DrmManagerClient instance could not be created, context is Illegal.");
+            } catch (IllegalStateException e) {
+                Log.w(TAG, "DrmManagerClient didn't initialize properly.");
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Checks if the Media Type needs to be DRM converted
+     *
+     * @param mimetype Media type of the content
+     * @return True if convert is needed else false
+     */
+    public static boolean isDrmConvertNeeded(String mimetype) {
+        return MIMETYPE_DRM_MESSAGE.equals(mimetype);
+    }
+
+    /**
+     * Modifies the file extension for a DRM Forward Lock file NOTE: This
+     * function shouldn't be called if the file shouldn't be DRM converted
+     */
+    public static String modifyDrmFwLockFileExtension(String filename) {
+        if (filename != null) {
+            int extensionIndex;
+            extensionIndex = filename.lastIndexOf(".");
+            if (extensionIndex != -1) {
+                filename = filename.substring(0, extensionIndex);
+            }
+            filename = filename.concat(EXTENSION_INTERNAL_FWDL);
+        }
+        return filename;
+    }
+
+    /**
+     * Gets the original mime type of DRM protected content.
+     *
+     * @param context The context
+     * @param path Path to the file
+     * @param containingMime The current mime type of of the file i.e. the
+     *            containing mime type
+     * @return The original mime type of the file if DRM protected else the
+     *         currentMime
+     */
+    public static String getOriginalMimeType(Context context, String path, String containingMime) {
+        String result = containingMime;
+        DrmManagerClient drmClient = new DrmManagerClient(context);
+        try {
+            if (drmClient.canHandle(path, null)) {
+                result = drmClient.getOriginalMimeType(path);
+            }
+        } catch (IllegalArgumentException ex) {
+            Log.w(TAG,
+                    "Can't get original mime type since path is null or empty string.");
+        } catch (IllegalStateException ex) {
+            Log.w(TAG, "DrmManagerClient didn't initialize properly.");
+        }
+        return result;
+    }
+}
diff --git a/core/java/com/google/android/mms/util/DrmConvertSession.java b/core/java/com/google/android/mms/util/DrmConvertSession.java
new file mode 100644
index 0000000..2d8f274
--- /dev/null
+++ b/core/java/com/google/android/mms/util/DrmConvertSession.java
@@ -0,0 +1,172 @@
+/*
+ * 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.google.android.mms.util;
+
+import android.content.Context;
+import android.drm.DrmConvertedStatus;
+import android.drm.DrmManagerClient;
+import android.util.Log;
+import android.provider.Downloads;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+
+public class DrmConvertSession {
+    private DrmManagerClient mDrmClient;
+    private int mConvertSessionId;
+    private static final String TAG = "DrmConvertSession";
+
+    private DrmConvertSession(DrmManagerClient drmClient, int convertSessionId) {
+        mDrmClient = drmClient;
+        mConvertSessionId = convertSessionId;
+    }
+
+    /**
+     * Start of converting a file.
+     *
+     * @param context The context of the application running the convert session.
+     * @param mimeType Mimetype of content that shall be converted.
+     * @return A convert session or null in case an error occurs.
+     */
+    public static DrmConvertSession open(Context context, String mimeType) {
+        DrmManagerClient drmClient = null;
+        int convertSessionId = -1;
+        if (context != null && mimeType != null && !mimeType.equals("")) {
+            try {
+                drmClient = new DrmManagerClient(context);
+                try {
+                    convertSessionId = drmClient.openConvertSession(mimeType);
+                } catch (IllegalArgumentException e) {
+                    Log.w(TAG, "Conversion of Mimetype: " + mimeType
+                            + " is not supported.", e);
+                } catch (IllegalStateException e) {
+                    Log.w(TAG, "Could not access Open DrmFramework.", e);
+                }
+            } catch (IllegalArgumentException e) {
+                Log.w(TAG,
+                        "DrmManagerClient instance could not be created, context is Illegal.");
+            } catch (IllegalStateException e) {
+                Log.w(TAG, "DrmManagerClient didn't initialize properly.");
+            }
+        }
+
+        if (drmClient == null || convertSessionId < 0) {
+            return null;
+        } else {
+            return new DrmConvertSession(drmClient, convertSessionId);
+        }
+    }
+    /**
+     * Convert a buffer of data to protected format.
+     *
+     * @param buffer Buffer filled with data to convert.
+     * @param size The number of bytes that shall be converted.
+     * @return A Buffer filled with converted data, if execution is ok, in all
+     *         other case null.
+     */
+    public byte [] convert(byte[] inBuffer, int size) {
+        byte[] result = null;
+        if (inBuffer != null) {
+            DrmConvertedStatus convertedStatus = null;
+            try {
+                if (size != inBuffer.length) {
+                    byte[] buf = new byte[size];
+                    System.arraycopy(inBuffer, 0, buf, 0, size);
+                    convertedStatus = mDrmClient.convertData(mConvertSessionId, buf);
+                } else {
+                    convertedStatus = mDrmClient.convertData(mConvertSessionId, inBuffer);
+                }
+
+                if (convertedStatus != null &&
+                        convertedStatus.statusCode == DrmConvertedStatus.STATUS_OK &&
+                        convertedStatus.convertedData != null) {
+                    result = convertedStatus.convertedData;
+                }
+            } catch (IllegalArgumentException e) {
+                Log.w(TAG, "Buffer with data to convert is illegal. Convertsession: "
+                        + mConvertSessionId, e);
+            } catch (IllegalStateException e) {
+                Log.w(TAG, "Could not convert data. Convertsession: " +
+                        mConvertSessionId, e);
+            }
+        } else {
+            throw new IllegalArgumentException("Parameter inBuffer is null");
+        }
+        return result;
+    }
+
+    /**
+     * Ends a conversion session of a file.
+     *
+     * @param fileName The filename of the converted file.
+     * @return Downloads.Impl.STATUS_SUCCESS if execution is ok.
+     *         Downloads.Impl.STATUS_FILE_ERROR in case converted file can not
+     *         be accessed. Downloads.Impl.STATUS_NOT_ACCEPTABLE if a problem
+     *         occurs when accessing drm framework.
+     *         Downloads.Impl.STATUS_UNKNOWN_ERROR if a general error occurred.
+     */
+    public int close(String filename) {
+        DrmConvertedStatus convertedStatus = null;
+        int result = Downloads.Impl.STATUS_UNKNOWN_ERROR;
+        if (mDrmClient != null && mConvertSessionId >= 0) {
+            try {
+                convertedStatus = mDrmClient.closeConvertSession(mConvertSessionId);
+                if (convertedStatus == null ||
+                        convertedStatus.statusCode != DrmConvertedStatus.STATUS_OK ||
+                        convertedStatus.convertedData == null) {
+                    result = Downloads.Impl.STATUS_NOT_ACCEPTABLE;
+                } else {
+                    RandomAccessFile rndAccessFile = null;
+                    try {
+                        rndAccessFile = new RandomAccessFile(filename, "rw");
+                        rndAccessFile.seek(convertedStatus.offset);
+                        rndAccessFile.write(convertedStatus.convertedData);
+                        result = Downloads.Impl.STATUS_SUCCESS;
+                    } catch (FileNotFoundException e) {
+                        result = Downloads.Impl.STATUS_FILE_ERROR;
+                        Log.w(TAG, "File: " + filename + " could not be found.", e);
+                    } catch (IOException e) {
+                        result = Downloads.Impl.STATUS_FILE_ERROR;
+                        Log.w(TAG, "Could not access File: " + filename + " .", e);
+                    } catch (IllegalArgumentException e) {
+                        result = Downloads.Impl.STATUS_FILE_ERROR;
+                        Log.w(TAG, "Could not open file in mode: rw", e);
+                    } catch (SecurityException e) {
+                        Log.w(TAG, "Access to File: " + filename +
+                                " was denied denied by SecurityManager.", e);
+                    } finally {
+                        if (rndAccessFile != null) {
+                            try {
+                                rndAccessFile.close();
+                            } catch (IOException e) {
+                                result = Downloads.Impl.STATUS_FILE_ERROR;
+                                Log.w(TAG, "Failed to close File:" + filename
+                                        + ".", e);
+                            }
+                        }
+                    }
+                }
+            } catch (IllegalStateException e) {
+                Log.w(TAG, "Could not close convertsession. Convertsession: " +
+                        mConvertSessionId, e);
+            }
+        }
+        return result;
+    }
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index d1e3642..5ae12b6 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -60,6 +60,9 @@
     <protected-broadcast android:name="android.intent.action.REBOOT" />
     <protected-broadcast android:name="android.intent.action.DOCK_EVENT" />
     <protected-broadcast android:name="android.intent.action.MASTER_CLEAR_NOTIFICATION" />
+    <protected-broadcast android:name="android.intent.action.USER_ADDED" />
+    <protected-broadcast android:name="android.intent.action.USER_REMOVED" />
+    <protected-broadcast android:name="android.intent.action.USER_SWITCHED" />
 
     <protected-broadcast android:name="android.app.action.ENTER_CAR_MODE" />
     <protected-broadcast android:name="android.app.action.EXIT_CAR_MODE" />
@@ -1032,15 +1035,6 @@
         android:label="@string/permlab_clearAppCache"
         android:description="@string/permdesc_clearAppCache" />
 
-    <!-- Allows an application to read the low-level system log files.
-         Log entries can contain the user's private information,
-         which is why this permission is 'dangerous'. -->
-    <permission android:name="android.permission.READ_LOGS"
-        android:permissionGroup="android.permission-group.PERSONAL_INFO"
-        android:protectionLevel="dangerous"
-        android:label="@string/permlab_readLogs"
-        android:description="@string/permdesc_readLogs" />
-
     <!-- Allows an application to use any media decoder when decoding for playback
          @hide -->
     <permission android:name="android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK"
@@ -1076,6 +1070,15 @@
         android:label="@string/permlab_dump"
         android:description="@string/permdesc_dump" />
 
+    <!-- Allows an application to read the low-level system log files.
+         Log entries can contain the user's private information,
+         which is why this permission is not available to normal apps. -->
+    <permission android:name="android.permission.READ_LOGS"
+        android:permissionGroup="android.permission-group.DEVELOPMENT_TOOLS"
+        android:protectionLevel="signature|system|development"
+        android:label="@string/permlab_readLogs"
+        android:description="@string/permdesc_readLogs" />
+
     <!-- Configure an application for debugging. -->
     <permission android:name="android.permission.SET_DEBUG_APP"
         android:permissionGroup="android.permission-group.DEVELOPMENT_TOOLS"
diff --git a/data/etc/android.hardware.audio.low_latency.xml b/data/etc/android.hardware.audio.low_latency.xml
deleted file mode 100644
index 677ec1c..0000000
--- a/data/etc/android.hardware.audio.low_latency.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- This is the feature indicating low-latency audio, as specified by the
-     CDD. ONLY devices that meet the CDD's requirements may declare this
-     feature. -->
-<permissions>
-    <feature name="android.hardware.audio.low_latency" />
-</permissions>
diff --git a/data/etc/android.hardware.bluetooth.xml b/data/etc/android.hardware.bluetooth.xml
deleted file mode 100644
index 4aa1744..0000000
--- a/data/etc/android.hardware.bluetooth.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<!-- Adds the feature indicating support for the Bluetooth API -->
-<permissions>
-    <feature name="android.hardware.bluetooth" />
-</permissions>
diff --git a/data/etc/android.hardware.camera.autofocus.xml b/data/etc/android.hardware.camera.autofocus.xml
deleted file mode 100644
index d6e2b90..0000000
--- a/data/etc/android.hardware.camera.autofocus.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- This is the standard set of features for an auto-focus camera. -->
-<permissions>
-    <feature name="android.hardware.camera" />
-    <feature name="android.hardware.camera.autofocus" />
-</permissions>
diff --git a/data/etc/android.hardware.camera.flash-autofocus.xml b/data/etc/android.hardware.camera.flash-autofocus.xml
deleted file mode 100644
index 55f1900..0000000
--- a/data/etc/android.hardware.camera.flash-autofocus.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- This is the standard set of features for a camera with a flash.  Note
-     that this currently requires having auto-focus as well. -->
-<permissions>
-    <feature name="android.hardware.camera" />
-    <feature name="android.hardware.camera.autofocus" />
-    <feature name="android.hardware.camera.flash" />
-</permissions>
diff --git a/data/etc/android.hardware.camera.front.xml b/data/etc/android.hardware.camera.front.xml
deleted file mode 100644
index a5a6998..0000000
--- a/data/etc/android.hardware.camera.front.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- This is the standard set of features for a front facing camera. -->
-<permissions>
-    <feature name="android.hardware.camera.front" />
-</permissions>
diff --git a/data/etc/android.hardware.camera.xml b/data/etc/android.hardware.camera.xml
deleted file mode 100644
index 00a1ed7..0000000
--- a/data/etc/android.hardware.camera.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- This is the standard set of features for a non auto-focus camera. -->
-<permissions>
-    <feature name="android.hardware.camera" />
-</permissions>
diff --git a/data/etc/android.hardware.faketouch.multitouch.distinct.xml b/data/etc/android.hardware.faketouch.multitouch.distinct.xml
deleted file mode 100644
index b6e8d09..0000000
--- a/data/etc/android.hardware.faketouch.multitouch.distinct.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- This is the standard set of features for a indirect touch input device that supports
-     independently-trackable multiple-finger multitouch. -->
-<permissions>
-    <feature name="android.hardware.faketouch.multitouch" />
-    <feature name="android.hardware.faketouch.multitouch.distinct" />
-    <feature name="android.hardware.faketouch" />
-</permissions>
diff --git a/data/etc/android.hardware.faketouch.multitouch.jazzhand.xml b/data/etc/android.hardware.faketouch.multitouch.jazzhand.xml
deleted file mode 100644
index 7f0e70b..0000000
--- a/data/etc/android.hardware.faketouch.multitouch.jazzhand.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- This is the standard set of features for an indirect touch input device that supports
-     independently-trackable multiple-finger multitouch. -->
-<permissions>
-    <feature name="android.hardware.faketouch.multitouch" />
-    <feature name="android.hardware.faketouch.multitouch.distinct" />
-    <feature name="android.hardware.faketouch.multitouch.jazzhand" />
-    <feature name="android.hardware.faketouch" />
-</permissions>
diff --git a/data/etc/android.hardware.faketouch.xml b/data/etc/android.hardware.faketouch.xml
deleted file mode 100644
index cb99097..0000000
--- a/data/etc/android.hardware.faketouch.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- This is the standard set of features for a devices that does not have
-     a touch screen, but does have some other indirect input device such as
-     a track pad. -->
-<permissions>
-    <feature name="android.hardware.faketouch" />
-</permissions>
diff --git a/data/etc/android.hardware.location.gps.xml b/data/etc/android.hardware.location.gps.xml
deleted file mode 100644
index 72ab732..0000000
--- a/data/etc/android.hardware.location.gps.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- These are the location-related features for devices that include GPS. -->
-<permissions>
-    <feature name="android.hardware.location" />
-    <feature name="android.hardware.location.network" />
-    <feature name="android.hardware.location.gps" />
-</permissions>
diff --git a/data/etc/android.hardware.location.xml b/data/etc/android.hardware.location.xml
deleted file mode 100644
index ab901cf..0000000
--- a/data/etc/android.hardware.location.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- These are the location features for devices that do not include GPS. Note
-     that network location is required for all devices. -->
-<permissions>
-    <feature name="android.hardware.location" />
-    <feature name="android.hardware.location.network" />
-</permissions>
diff --git a/data/etc/android.hardware.nfc.xml b/data/etc/android.hardware.nfc.xml
deleted file mode 100644
index 81c4a84..0000000
--- a/data/etc/android.hardware.nfc.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- This is the standard feature indicating that the device can communicate
-     using Near-Field Communications (NFC). -->
-<permissions>
-    <feature name="android.hardware.nfc" />
-</permissions>
diff --git a/data/etc/android.hardware.sensor.accelerometer.xml b/data/etc/android.hardware.sensor.accelerometer.xml
deleted file mode 100644
index 22f18b8..0000000
--- a/data/etc/android.hardware.sensor.accelerometer.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- Feature for devices with an accelerometer sensor. -->
-<permissions>
-    <feature name="android.hardware.sensor.accelerometer" />
-</permissions>
diff --git a/data/etc/android.hardware.sensor.barometer.xml b/data/etc/android.hardware.sensor.barometer.xml
deleted file mode 100644
index ebd392d..0000000
--- a/data/etc/android.hardware.sensor.barometer.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- Feature for devices with barometer. -->
-<permissions>
-    <feature name="android.hardware.sensor.barometer" />
-</permissions>
diff --git a/data/etc/android.hardware.sensor.compass.xml b/data/etc/android.hardware.sensor.compass.xml
deleted file mode 100644
index 963847d..0000000
--- a/data/etc/android.hardware.sensor.compass.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- Feature for devices with a compass. -->
-<permissions>
-    <feature name="android.hardware.sensor.compass" />
-</permissions>
diff --git a/data/etc/android.hardware.sensor.gyroscope.xml b/data/etc/android.hardware.sensor.gyroscope.xml
deleted file mode 100644
index fe79632..0000000
--- a/data/etc/android.hardware.sensor.gyroscope.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- Feature for devices with gyroscope. -->
-<permissions>
-    <feature name="android.hardware.sensor.gyroscope" />
-</permissions>
diff --git a/data/etc/android.hardware.sensor.light.xml b/data/etc/android.hardware.sensor.light.xml
deleted file mode 100644
index 78b0fec..0000000
--- a/data/etc/android.hardware.sensor.light.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- Feature for devices with an ambient light sensor. -->
-<permissions>
-    <feature name="android.hardware.sensor.light" />
-</permissions>
diff --git a/data/etc/android.hardware.sensor.proximity.xml b/data/etc/android.hardware.sensor.proximity.xml
deleted file mode 100644
index d1948de..0000000
--- a/data/etc/android.hardware.sensor.proximity.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- Feature for devices with a proximity sensor. -->
-<permissions>
-    <feature name="android.hardware.sensor.proximity" />
-</permissions>
diff --git a/data/etc/android.hardware.telephony.cdma.xml b/data/etc/android.hardware.telephony.cdma.xml
deleted file mode 100644
index 082378d5..0000000
--- a/data/etc/android.hardware.telephony.cdma.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- This is the standard set of telephony features for a CDMA phone. -->
-<permissions>
-    <feature name="android.hardware.telephony" />
-    <feature name="android.hardware.telephony.cdma" />
-</permissions>
diff --git a/data/etc/android.hardware.telephony.gsm.xml b/data/etc/android.hardware.telephony.gsm.xml
deleted file mode 100644
index 7927fa8..0000000
--- a/data/etc/android.hardware.telephony.gsm.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- This is the standard set of telephony features for a GSM phone. -->
-<permissions>
-    <feature name="android.hardware.telephony" />
-    <feature name="android.hardware.telephony.gsm" />
-</permissions>
diff --git a/data/etc/android.hardware.touchscreen.multitouch.distinct.xml b/data/etc/android.hardware.touchscreen.multitouch.distinct.xml
deleted file mode 100644
index 35eeefd..0000000
--- a/data/etc/android.hardware.touchscreen.multitouch.distinct.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- This is the standard set of features for a touchscreen that supports
-     independently-trackable multiple-finger multitouch. -->
-<permissions>
-    <feature name="android.hardware.touchscreen" />
-    <feature name="android.hardware.touchscreen.multitouch" />
-    <feature name="android.hardware.touchscreen.multitouch.distinct" />
-    <feature name="android.hardware.faketouch" />
-</permissions>
diff --git a/data/etc/android.hardware.touchscreen.multitouch.jazzhand.xml b/data/etc/android.hardware.touchscreen.multitouch.jazzhand.xml
deleted file mode 100644
index ed6606d..0000000
--- a/data/etc/android.hardware.touchscreen.multitouch.jazzhand.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- This is the standard set of features for a touchscreen that supports
-     independently-trackable multiple-finger multitouch. -->
-<permissions>
-    <feature name="android.hardware.touchscreen" />
-    <feature name="android.hardware.touchscreen.multitouch" />
-    <feature name="android.hardware.touchscreen.multitouch.distinct" />
-    <feature name="android.hardware.touchscreen.multitouch.jazzhand" />
-    <feature name="android.hardware.faketouch" />
-</permissions>
diff --git a/data/etc/android.hardware.touchscreen.multitouch.xml b/data/etc/android.hardware.touchscreen.multitouch.xml
deleted file mode 100644
index 1d59a27..0000000
--- a/data/etc/android.hardware.touchscreen.multitouch.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- This is the standard set of features for a touchscreen that supports
-     basic multitouch capable of gestures but not fully-indendent finger
-     tracking. -->
-<permissions>
-    <feature name="android.hardware.touchscreen" />
-    <feature name="android.hardware.touchscreen.multitouch" />
-    <feature name="android.hardware.faketouch" />
-</permissions>
diff --git a/data/etc/android.hardware.touchscreen.xml b/data/etc/android.hardware.touchscreen.xml
deleted file mode 100644
index 5b5ddf9..0000000
--- a/data/etc/android.hardware.touchscreen.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- This is the standard set of features for a touchscreen that does not
-     support multitouch. -->
-<permissions>
-    <feature name="android.hardware.touchscreen" />
-    <feature name="android.hardware.faketouch" />
-</permissions>
diff --git a/data/etc/android.hardware.usb.accessory.xml b/data/etc/android.hardware.usb.accessory.xml
deleted file mode 100644
index 80a0904..0000000
--- a/data/etc/android.hardware.usb.accessory.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- This is the standard feature indicating that the device supports USB accessories. -->
-<permissions>
-    <feature name="android.hardware.usb.accessory" />
-    <library name="com.android.future.usb.accessory"
-            file="/system/framework/com.android.future.usb.accessory.jar" />
-</permissions>
diff --git a/data/etc/android.hardware.usb.host.xml b/data/etc/android.hardware.usb.host.xml
deleted file mode 100644
index b0ca82c..0000000
--- a/data/etc/android.hardware.usb.host.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- This is the standard feature indicating that the device can communicate
-    with USB devices as the USB host. -->
-<permissions>
-    <feature name="android.hardware.usb.host" />
-</permissions>
diff --git a/data/etc/android.hardware.wifi.direct.xml b/data/etc/android.hardware.wifi.direct.xml
deleted file mode 100644
index 78cb474..0000000
--- a/data/etc/android.hardware.wifi.direct.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- This is the standard feature indicating that the device includes WiFi Direct. -->
-<permissions>
-    <feature name="android.hardware.wifi.direct" />
-</permissions>
diff --git a/data/etc/android.hardware.wifi.xml b/data/etc/android.hardware.wifi.xml
deleted file mode 100644
index 512570c..0000000
--- a/data/etc/android.hardware.wifi.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- This is the standard feature indicating that the device includes WiFi. -->
-<permissions>
-    <feature name="android.hardware.wifi" />
-</permissions>
diff --git a/data/etc/android.software.sip.voip.xml b/data/etc/android.software.sip.voip.xml
deleted file mode 100644
index edd06c1..0000000
--- a/data/etc/android.software.sip.voip.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- This is the standard set of features for devices that support SIP-based VoIP. -->
-<permissions>
-    <feature name="android.software.sip" />
-    <feature name="android.software.sip.voip" />
-</permissions>
diff --git a/data/etc/android.software.sip.xml b/data/etc/android.software.sip.xml
deleted file mode 100644
index d9fcaad..0000000
--- a/data/etc/android.software.sip.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- This is the standard set of features for devices that support the SIP API. -->
-<permissions>
-    <feature name="android.software.sip" />
-</permissions>
diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
deleted file mode 100644
index 9d2a0cb..0000000
--- a/data/etc/handheld_core_hardware.xml
+++ /dev/null
@@ -1,65 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- These are the hardware components that all handheld devices
-     must include. Devices with optional hardware must also include extra
-     hardware files, per the comments below.
-
-     Handheld devices include phones, mobile Internet devices (MIDs),
-     Personal Media Players (PMPs), small tablets (7" or less), and similar
-     devices.
--->
-<permissions>
-    <feature name="android.hardware.camera" />
-    <feature name="android.hardware.location" />
-    <feature name="android.hardware.location.network" />
-    <feature name="android.hardware.sensor.compass" />
-    <feature name="android.hardware.sensor.accelerometer" />
-    <feature name="android.hardware.bluetooth" />
-    <feature name="android.hardware.touchscreen" />
-    <feature name="android.hardware.microphone" />
-    <feature name="android.hardware.screen.portrait" />
-    <feature name="android.hardware.screen.landscape" />
-    <!-- devices with GPS must include android.hardware.location.gps.xml -->
-    <!-- devices with an autofocus camera and/or flash must include either
-         android.hardware.camera.autofocus.xml or 
-         android.hardware.camera.autofocus-flash.xml -->
-    <!-- devices with a front facing camera must include
-         android.hardware.camera.front.xml -->
-    <!-- devices with WiFi must also include android.hardware.wifi.xml -->
-    <!-- devices that support multitouch must include the most appropriate one
-         of these files:
-
-         If only partial (non-independent) pointers are supported:
-         android.hardware.touchscreen.multitouch.xml
-
-         If up to 4 independently tracked pointers are supported:
-         include android.hardware.touchscreen.multitouch.distinct.xml
-
-         If 5 or more independently tracked pointers are supported:
-         include android.hardware.touchscreen.multitouch.jazzhand.xml
-
-         ONLY ONE of the above should be included. -->
-    <!-- devices with an ambient light sensor must also include
-         android.hardware.sensor.light.xml -->
-    <!-- devices with a proximity sensor must also include
-         android.hardware.sensor.proximity.xml -->
-    <!-- GSM phones must also include android.hardware.telephony.gsm.xml -->
-    <!-- CDMA phones must also include android.hardware.telephony.cdma.xml -->
-    <!-- Devices that have low-latency audio stacks suitable for apps like
-         VoIP may include android.hardware.audio.low_latency.xml. ONLY apps
-         that meet the requirements specified in the CDD may include this. -->
-</permissions>
diff --git a/data/etc/tablet_core_hardware.xml b/data/etc/tablet_core_hardware.xml
deleted file mode 100644
index bf29fe4..0000000
--- a/data/etc/tablet_core_hardware.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- These are the hardware components that all handheld devices
-     must include. Devices with optional hardware must also include extra
-     hardware files, per the comments below.
-
-     Handheld devices include phones, mobile Internet devices (MIDs),
-     Personal Media Players (PMPs), small tablets (7" or less), and similar
-     devices.
--->
-<permissions>
-    <feature name="android.hardware.location" />
-    <feature name="android.hardware.location.network" />
-    <feature name="android.hardware.sensor.compass" />
-    <feature name="android.hardware.sensor.accelerometer" />
-    <feature name="android.hardware.bluetooth" />
-    <feature name="android.hardware.touchscreen" />
-    <feature name="android.hardware.touchscreen.multitouch" />
-    <feature name="android.hardware.touchscreen.multitouch.distinct" />
-    <feature name="android.hardware.microphone" />
-    <feature name="android.hardware.screen.portrait" />
-    <feature name="android.hardware.screen.landscape" />
-    <!-- devices with GPS must include android.hardware.location.gps.xml -->
-    <!-- devices with a rear-facing camera must include one of these as appropriate:
-         android.hardware.camera.xml or 
-         android.hardware.camera.autofocus.xml or 
-         android.hardware.camera.autofocus-flash.xml -->
-    <!-- devices with a front facing camera must include
-         android.hardware.camera.front.xml -->
-    <!-- devices with WiFi must also include android.hardware.wifi.xml -->
-    <!-- devices with an ambient light sensor must also include
-         android.hardware.sensor.light.xml -->
-    <!-- devices with a proximity sensor must also include
-         android.hardware.sensor.proximity.xml -->
-    <!-- devices with a barometer must also include
-         android.hardware.sensor.barometer.xml -->
-    <!-- devices with a gyroscope must also include
-         android.hardware.sensor.gyroscope.xml -->
-    <!-- GSM phones must also include android.hardware.telephony.gsm.xml -->
-    <!-- CDMA phones must also include android.hardware.telephony.cdma.xml -->
-</permissions>
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index bcba3c2..4ebabd3 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -23,6 +23,7 @@
 
 import android.app.ActivityManagerNative;
 import android.app.AlertDialog;
+import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -31,14 +32,18 @@
 import android.content.pm.UserInfo;
 import android.media.AudioManager;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Message;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.SystemProperties;
+import android.os.Vibrator;
 import android.provider.Settings;
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
 import android.util.Log;
+import android.view.IWindowManager;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -77,6 +82,8 @@
     private ToggleAction.State mAirplaneState = ToggleAction.State.Off;
     private boolean mIsWaitingForEcmExit = false;
 
+    private IWindowManager mIWindowManager;
+
     /**
      * @param context everything needs a context :(
      */
@@ -119,7 +126,7 @@
      * @return A new dialog.
      */
     private AlertDialog createDialog() {
-        mSilentModeAction = new SilentModeAction(mAudioManager, mHandler);
+        mSilentModeAction = new SilentModeAction(mContext, mAudioManager, mHandler);
 
         mAirplaneModeOn = new ToggleAction(
                 R.drawable.ic_lock_airplane_mode,
@@ -200,6 +207,7 @@
                     public void onPress() {
                         try {
                             ActivityManagerNative.getDefault().switchUser(user.id);
+                            getWindowManager().lockNow();
                         } catch (RemoteException re) {
                             Log.e(TAG, "Couldn't switch user " + re);
                         }
@@ -540,10 +548,15 @@
 
         private final AudioManager mAudioManager;
         private final Handler mHandler;
+        private final boolean mHasVibrator;
+        private final Context mContext;
 
-        SilentModeAction(AudioManager audioManager, Handler handler) {
+        SilentModeAction(Context context, AudioManager audioManager, Handler handler) {
             mAudioManager = audioManager;
             mHandler = handler;
+            mContext = context;
+            Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
+            mHasVibrator = vibrator != null && vibrator.hasVibrator();
         }
 
         private int ringerModeToIndex(int ringerMode) {
@@ -567,6 +580,9 @@
                 // Set up click handler
                 itemView.setTag(i);
                 itemView.setOnClickListener(this);
+                if (itemView.getId() == R.id.option2 && !mHasVibrator) {
+                    itemView.setVisibility(View.GONE);
+                }
             }
             return v;
         }
@@ -667,4 +683,12 @@
         intent.putExtra("state", on);
         mContext.sendBroadcast(intent);
     }
+
+    private IWindowManager getWindowManager() {
+        if (mIWindowManager == null) {
+            IBinder b = ServiceManager.getService(Context.WINDOW_SERVICE);
+            mIWindowManager = IWindowManager.Stub.asInterface(b);
+        }
+        return mIWindowManager;
+    }
 }
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index a85b605..eb024e9 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -170,6 +170,15 @@
         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
         mContext.registerReceiver(mBroadcastReceiver, sdFilter);
+
+        IntentFilter userFilter = new IntentFilter();
+        userFilter.addAction(Intent.ACTION_USER_REMOVED);
+        mContext.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                onUserRemoved(intent.getIntExtra(Intent.EXTRA_USERID, -1));
+            }
+        }, userFilter);
     }
 
     @Override
@@ -192,19 +201,6 @@
         getImplForUser().deleteAllHosts();
     }
 
-    void cancelBroadcasts(Provider p) {
-        if (p.broadcast != null) {
-            mAlarmManager.cancel(p.broadcast);
-            long token = Binder.clearCallingIdentity();
-            try {
-                p.broadcast.cancel();
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-            p.broadcast = null;
-        }
-    }
-
     @Override
     public void bindAppWidgetId(int appWidgetId, ComponentName provider) throws RemoteException {
         getImplForUser().bindAppWidgetId(appWidgetId, provider);
@@ -222,8 +218,15 @@
         return getImplForUser().startListening(host, packageName, hostId, updatedViews);
     }
 
-    // TODO: Call this from PackageManagerService when a user is removed
-    public void removeUser(int userId) {
+    public void onUserRemoved(int userId) {
+        AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
+        if (userId < 1) return;
+
+        if (impl == null) {
+            AppWidgetServiceImpl.getSettingsFile(userId).delete();
+        } else {
+            impl.onUserRemoved();
+        }
     }
 
     private AppWidgetServiceImpl getImplForUser() {
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java
index 182a884..b24823e 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -1484,9 +1484,13 @@
         }
     }
 
+    static File getSettingsFile(int userId) {
+        return new File("/data/system/users/" + userId + "/" + SETTINGS_FILENAME);
+    }
+
     AtomicFile savedStateFile() {
         File dir = new File("/data/system/users/" + mUserId);
-        File settingsFile = new File(dir, SETTINGS_FILENAME);
+        File settingsFile = getSettingsFile(mUserId);
         if (!dir.exists()) {
             dir.mkdirs();
             if (mUserId == 0) {
@@ -1500,6 +1504,16 @@
         return new AtomicFile(settingsFile);
     }
 
+    void onUserRemoved() {
+        // prune the ones we don't want to keep
+        int N = mInstalledProviders.size();
+        for (int i = N - 1; i >= 0; i--) {
+            Provider p = mInstalledProviders.get(i);
+            cancelBroadcasts(p);
+        }
+        getSettingsFile(mUserId).delete();
+    }
+
     void addProvidersForPackageLocked(String pkgName) {
         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
         intent.setPackage(pkgName);
diff --git a/services/java/com/android/server/ClipboardService.java b/services/java/com/android/server/ClipboardService.java
index 062ab74..2e2a278 100644
--- a/services/java/com/android/server/ClipboardService.java
+++ b/services/java/com/android/server/ClipboardService.java
@@ -34,6 +34,7 @@
 import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
+import android.os.UserId;
 import android.util.Pair;
 import android.util.Slog;
 
@@ -204,7 +205,7 @@
         PackageInfo pi;
         try {
             pi = mPm.getPackageInfo(pkg, 0);
-            if (pi.applicationInfo.uid != uid) {
+            if (!UserId.isSameApp(pi.applicationInfo.uid, uid)) {
                 throw new SecurityException("Calling uid " + uid
                         + " does not own package " + pkg);
             }
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 8ee12bc..6d83f30 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -25,9 +25,11 @@
 import android.app.WallpaperInfo;
 import android.app.backup.BackupManager;
 import android.app.backup.WallpaperBackupHelper;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
@@ -36,6 +38,7 @@
 import android.content.res.Resources;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.Environment;
 import android.os.FileUtils;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -401,41 +404,48 @@
             wallpaper.wallpaperObserver.stopWatching();
         }
     }
-    
+
     public void systemReady() {
         if (DEBUG) Slog.v(TAG, "systemReady");
         WallpaperData wallpaper = mWallpaperMap.get(0);
         switchWallpaper(wallpaper);
         wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
         wallpaper.wallpaperObserver.startWatching();
-        ActivityManagerService ams = (ActivityManagerService) ServiceManager
-                .getService(Context.ACTIVITY_SERVICE);
-        ams.addUserListener(new ActivityManagerService.UserListener() {
 
+        IntentFilter userFilter = new IntentFilter();
+        userFilter.addAction(Intent.ACTION_USER_SWITCHED);
+        userFilter.addAction(Intent.ACTION_USER_REMOVED);
+        mContext.registerReceiver(new BroadcastReceiver() {
             @Override
-            public void onUserChanged(int userId) {
-                switchUser(userId);
+            public void onReceive(Context context, Intent intent) {
+                String action = intent.getAction();
+                if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+                    switchUser(intent.getIntExtra(Intent.EXTRA_USERID, 0));
+                } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
+                    removeUser(intent.getIntExtra(Intent.EXTRA_USERID, 0));
+                }
             }
-
-            @Override
-            public void onUserAdded(int userId) {
-            }
-
-            @Override
-            public void onUserRemoved(int userId) {
-            }
-
-            @Override
-            public void onUserLoggedOut(int userId) {
-            }
-
-        });
+        }, userFilter);
     }
 
     String getName() {
         return mWallpaperMap.get(0).name;
     }
 
+    void removeUser(int userId) {
+        synchronized (mLock) {
+            WallpaperData wallpaper = mWallpaperMap.get(userId);
+            if (wallpaper != null) {
+                wallpaper.wallpaperObserver.stopWatching();
+                mWallpaperMap.remove(userId);
+            }
+            File wallpaperFile = new File(getWallpaperDir(userId), WALLPAPER);
+            wallpaperFile.delete();
+            File wallpaperInfoFile = new File(getWallpaperDir(userId), WALLPAPER_INFO);
+            wallpaperInfoFile.delete();
+        }
+    }
+
     void switchUser(int userId) {
         synchronized (mLock) {
             mCurrentUserId = userId;
@@ -861,7 +871,7 @@
     }
 
     private static JournaledFile makeJournaledFile(int userId) {
-        final String base = "/data/system/users/" + userId + "/" + WALLPAPER_INFO;
+        final String base = getWallpaperDir(userId) + "/" + WALLPAPER_INFO;
         return new JournaledFile(new File(base), new File(base + ".tmp"));
     }
 
diff --git a/services/java/com/android/server/WiredAccessoryObserver.java b/services/java/com/android/server/WiredAccessoryObserver.java
index a7a46dd..9b4eddc 100644
--- a/services/java/com/android/server/WiredAccessoryObserver.java
+++ b/services/java/com/android/server/WiredAccessoryObserver.java
@@ -66,7 +66,7 @@
         public String getDevName() { return mDevName; }
 
         public String getDevPath() {
-            return String.format("DEVPATH=/devices/virtual/switch/%s", mDevName);
+            return String.format("/devices/virtual/switch/%s", mDevName);
         }
 
         public String getSwitchStatePath() {
@@ -158,7 +158,7 @@
         init();  // set initial status
         for (int i = 0; i < uEventInfo.size(); ++i) {
             UEventInfo uei = uEventInfo.get(i);
-            startObserving(uei.getDevPath());
+            startObserving("DEVPATH="+uei.getDevPath());
         }
       }
     }
@@ -168,29 +168,20 @@
         if (LOG) Slog.v(TAG, "Headset UEVENT: " + event.toString());
 
         try {
+            String devPath = event.get("DEVPATH");
             String name = event.get("SWITCH_NAME");
             int state = Integer.parseInt(event.get("SWITCH_STATE"));
-            updateState(name, state);
+            updateState(devPath, name, state);
         } catch (NumberFormatException e) {
             Slog.e(TAG, "Could not parse switch state from event " + event);
         }
     }
 
-    private synchronized final void updateState(String name, int state)
+    private synchronized final void updateState(String devPath, String name, int state)
     {
-        // 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())) {
+            if (devPath.equals(uei.getDevPath())) {
                 update(name, uei.computeNewHeadsetState(mHeadsetState, state));
                 return;
             }
@@ -213,7 +204,7 @@
                 curState = Integer.valueOf((new String(buffer, 0, len)).trim());
 
                 if (curState > 0) {
-                    updateState(uei.getDevName(), curState);
+                    updateState(uei.getDevPath(), uei.getDevName(), curState);
                 }
 
             } catch (FileNotFoundException e) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 37a594e..78f17bc 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -152,6 +152,7 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
@@ -3582,9 +3583,14 @@
                     if (doit) {
                         procs.add(app);
                     }
-                } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
-                        || app.processName.equals(packageName)
-                        || app.processName.startsWith(procNamePrefix)) {
+                // If uid is specified and the uid and process name match
+                // Or, the uid is not specified and the process name matches
+                } else if (((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
+                            && (app.processName.equals(packageName)
+                                || app.processName.startsWith(procNamePrefix)))
+                           || (uid < 0
+                               && (app.processName.equals(packageName)
+                                       || app.processName.startsWith(procNamePrefix)))) {
                     if (app.setAdj >= minOomAdj) {
                         if (!doit) {
                             return true;
@@ -3635,7 +3641,8 @@
         for (i=0; i<mMainStack.mHistory.size(); i++) {
             ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
             final boolean samePackage = r.packageName.equals(name);
-            if ((samePackage || r.task == lastTask)
+            if (r.userId == userId
+                    && (samePackage || r.task == lastTask)
                     && (r.app == null || evenPersistent || !r.app.persistent)) {
                 if (!doit) {
                     if (r.finishing) {
@@ -3685,7 +3692,7 @@
         }
 
         ArrayList<ContentProviderRecord> providers = new ArrayList<ContentProviderRecord>();
-        for (ContentProviderRecord provider : mProviderMap.getProvidersByClass(-1).values()) {
+        for (ContentProviderRecord provider : mProviderMap.getProvidersByClass(userId).values()) {
             if (provider.info.packageName.equals(name)
                     && (provider.proc == null || evenPersistent || !provider.proc.persistent)) {
                 if (!doit) {
@@ -4118,7 +4125,16 @@
                 }
             }
         }, pkgFilter);
-        
+
+        IntentFilter userFilter = new IntentFilter();
+        userFilter.addAction(Intent.ACTION_USER_REMOVED);
+        mContext.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                onUserRemoved(intent);
+            }
+        }, userFilter);
+
         synchronized (this) {
             // Ensure that any processes we had put on hold are now started
             // up.
@@ -12469,7 +12485,7 @@
 
         if (DEBUG_BROADCAST_LIGHT) Slog.v(
             TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
-            + " ordered=" + ordered);
+            + " ordered=" + ordered + " userid=" + userId);
         if ((resultTo != null) && !ordered) {
             Slog.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
         }
@@ -14593,25 +14609,6 @@
 
     private int mCurrentUserId;
     private SparseIntArray mLoggedInUsers = new SparseIntArray(5);
-    private ArrayList<UserListener> mUserListeners = new ArrayList<UserListener>(3);
-
-    public interface UserListener {
-        public void onUserChanged(int userId);
-
-        public void onUserAdded(int userId);
-
-        public void onUserRemoved(int userId);
-
-        public void onUserLoggedOut(int userId);
-    }
-
-    public void addUserListener(UserListener listener) {
-        synchronized (this) {
-            if (!mUserListeners.contains(listener)) {
-                mUserListeners.add(listener);
-            }
-        }
-    }
 
     public boolean switchUser(int userId) {
         final int callingUid = Binder.getCallingUid();
@@ -14622,8 +14619,6 @@
         if (mCurrentUserId == userId)
             return true;
 
-        ArrayList<UserListener> listeners;
-
         synchronized (this) {
             // Check if user is already logged in, otherwise check if user exists first before
             // adding to the list of logged in users.
@@ -14640,23 +14635,44 @@
                 startHomeActivityLocked(userId);
             }
 
-            listeners = (ArrayList<UserListener>) mUserListeners.clone();
         }
-        // Inform the listeners
-        for (UserListener listener : listeners) {
-            listener.onUserChanged(userId);
-        }
+
+        // Inform of user switch
+        Intent addedIntent = new Intent(Intent.ACTION_USER_SWITCHED);
+        addedIntent.putExtra(Intent.EXTRA_USERID, userId);
+        mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_ACCOUNTS);
+
         return true;
     }
 
+    private void onUserRemoved(Intent intent) {
+        int extraUserId = intent.getIntExtra(Intent.EXTRA_USERID, -1);
+        if (extraUserId < 1) return;
+
+        // Kill all the processes for the user
+        ArrayList<Pair<String, Integer>> pkgAndUids = new ArrayList<Pair<String,Integer>>();
+        synchronized (this) {
+            HashMap<String,SparseArray<ProcessRecord>> map = mProcessNames.getMap();
+            for (Entry<String, SparseArray<ProcessRecord>> uidMap : map.entrySet()) {
+                SparseArray<ProcessRecord> uids = uidMap.getValue();
+                for (int i = 0; i < uids.size(); i++) {
+                    if (UserId.getUserId(uids.keyAt(i)) == extraUserId) {
+                        pkgAndUids.add(new Pair<String,Integer>(uidMap.getKey(), uids.keyAt(i)));
+                    }
+                }
+            }
+
+            for (Pair<String,Integer> pkgAndUid : pkgAndUids) {
+                forceStopPackageLocked(pkgAndUid.first, pkgAndUid.second,
+                        false, false, true, true, extraUserId);
+            }
+        }
+    }
+
     private boolean userExists(int userId) {
         try {
-            List<UserInfo> users = AppGlobals.getPackageManager().getUsers();
-            for (UserInfo user : users) {
-                if (user.id == userId) {
-                    return true;
-                }
-            }
+            UserInfo user = AppGlobals.getPackageManager().getUser(userId);
+            return user != null;
         } catch (RemoteException re) {
             // Won't happen, in same process
         }
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 067bf28..1593707 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -134,6 +134,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
@@ -404,7 +405,7 @@
     // Delay time in millisecs
     static final int BROADCAST_DELAY = 10 * 1000;
 
-    final UserManager mUserManager;
+    static UserManager sUserManager;
 
     // Stores a list of users whose package restrictions file needs to be updated
     private HashSet<Integer> mDirtyUsers = new HashSet<Integer>();
@@ -632,7 +633,7 @@
                             packages[i] = ent.getKey();
                             components[i] = ent.getValue();
                             PackageSetting ps = mSettings.mPackages.get(ent.getKey());
-                            uids[i] = (ps != null) ? ps.uid : -1;
+                            uids[i] = (ps != null) ? ps.appId : -1;
                             i++;
                         }
                         size = i;
@@ -676,14 +677,15 @@
                             }
                             sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
                                     res.pkg.applicationInfo.packageName,
-                                    extras, null, null);
+                                    extras, null, null, UserId.USER_ALL);
                             if (update) {
                                 sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
                                         res.pkg.applicationInfo.packageName,
-                                        extras, null, null);
+                                        extras, null, null, UserId.USER_ALL);
                                 sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
                                         null, null,
-                                        res.pkg.applicationInfo.packageName, null);
+                                        res.pkg.applicationInfo.packageName, null,
+                                        UserId.USER_ALL);
                             }
                             if (res.removedInfo.args != null) {
                                 // Remove the replaced package's older resources safely now
@@ -820,6 +822,7 @@
     }
 
     void scheduleWritePackageRestrictionsLocked(int userId) {
+        if (!sUserManager.exists(userId)) return;
         mDirtyUsers.add(userId);
         if (!mHandler.hasMessages(WRITE_PACKAGE_RESTRICTIONS)) {
             mHandler.sendEmptyMessageDelayed(WRITE_PACKAGE_RESTRICTIONS, WRITE_SETTINGS_DELAY);
@@ -920,7 +923,7 @@
             mUserAppDataDir = new File(dataDir, "user");
             mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
 
-            mUserManager = new UserManager(mInstaller, mUserAppDataDir);
+            sUserManager = new UserManager(mInstaller, mUserAppDataDir);
 
             readPermissions();
 
@@ -1086,7 +1089,7 @@
                                 + " no longer exists; wiping its data";
                         reportSettingsProblem(Log.WARN, msg);
                         mInstaller.remove(ps.name, 0);
-                        mUserManager.removePackageForAllUsers(ps.name);
+                        sUserManager.removePackageForAllUsers(ps.name);
                     }
                 }
             }
@@ -1242,7 +1245,7 @@
             Slog.w(TAG, "Couldn't remove app data directory for package: "
                        + ps.name + ", retcode=" + retCode);
         } else {
-            mUserManager.removePackageForAllUsers(ps.name);
+            sUserManager.removePackageForAllUsers(ps.name);
         }
         if (ps.codePath != null) {
             if (!ps.codePath.delete()) {
@@ -1506,29 +1509,39 @@
         return cur;
     }
 
-    PackageInfo generatePackageInfo(PackageParser.Package p, int flags) {
+    PackageInfo generatePackageInfo(PackageParser.Package p, int flags, int userId) {
+        if (!sUserManager.exists(userId)) return null;
+        PackageInfo pi;
         if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
             // The package has been uninstalled but has retained data and resources.
-            return PackageParser.generatePackageInfo(p, null, flags, 0, 0, null);
+            pi = PackageParser.generatePackageInfo(p, null, flags, 0, 0, null, false, 0, userId);
+        } else {
+            final PackageSetting ps = (PackageSetting) p.mExtras;
+            if (ps == null) {
+                return null;
+            }
+            final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
+            pi = PackageParser.generatePackageInfo(p, gp.gids, flags,
+                    ps.firstInstallTime, ps.lastUpdateTime, gp.grantedPermissions,
+                    ps.getStopped(userId), ps.getEnabled(userId), userId);
+            pi.applicationInfo.enabledSetting = ps.getEnabled(userId);
+            pi.applicationInfo.enabled =
+                    pi.applicationInfo.enabledSetting == COMPONENT_ENABLED_STATE_DEFAULT
+                    || pi.applicationInfo.enabledSetting == COMPONENT_ENABLED_STATE_ENABLED;
         }
-        final PackageSetting ps = (PackageSetting)p.mExtras;
-        if (ps == null) {
-            return null;
-        }
-        final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
-        return PackageParser.generatePackageInfo(p, gp.gids, flags,
-                ps.firstInstallTime, ps.lastUpdateTime, gp.grantedPermissions);
+        return pi;
     }
 
     @Override
     public PackageInfo getPackageInfo(String packageName, int flags, int userId) {
+        if (!sUserManager.exists(userId)) return null;
         // reader
         synchronized (mPackages) {
             PackageParser.Package p = mPackages.get(packageName);
             if (DEBUG_PACKAGE_INFO)
                 Log.v(TAG, "getPackageInfo " + packageName + ": " + p);
             if (p != null) {
-                return generatePackageInfo(p, flags);
+                return generatePackageInfo(p, flags, userId);
             }
             if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
                 return generatePackageInfoFromSettingsLPw(packageName, flags, userId);
@@ -1563,6 +1576,7 @@
 
     @Override
     public int getPackageUid(String packageName, int userId) {
+        if (!sUserManager.exists(userId)) return -1;
         // reader
         synchronized (mPackages) {
             PackageParser.Package p = mPackages.get(packageName);
@@ -1673,6 +1687,7 @@
 
     private ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags,
             int userId) {
+        if (!sUserManager.exists(userId)) return null;
         PackageSetting ps = mSettings.mPackages.get(packageName);
         if (ps != null) {
             if (ps.pkg == null) {
@@ -1682,15 +1697,18 @@
                 }
                 return null;
             }
-            return PackageParser.generateApplicationInfo(ps.pkg, flags);
+            return PackageParser.generateApplicationInfo(ps.pkg, flags, ps.getStopped(userId),
+                    ps.getEnabled(userId), userId);
         }
         return null;
     }
 
     private PackageInfo generatePackageInfoFromSettingsLPw(String packageName, int flags,
             int userId) {
+        if (!sUserManager.exists(userId)) return null;
         PackageSetting ps = mSettings.mPackages.get(packageName);
         if (ps != null) {
+            PackageParser.Package pkg = new PackageParser.Package(packageName);
             if (ps.pkg == null) {
                 ps.pkg = new PackageParser.Package(packageName);
                 ps.pkg.applicationInfo.packageName = packageName;
@@ -1701,15 +1719,16 @@
                         getDataPathForPackage(ps.pkg.packageName, 0).getPath();
                 ps.pkg.applicationInfo.nativeLibraryDir = ps.nativeLibraryPathString;
             }
-            ps.pkg.mSetEnabled = ps.getEnabled(userId);
-            ps.pkg.mSetStopped = ps.getStopped(userId);
-            return generatePackageInfo(ps.pkg, flags);
+            // ps.pkg.mSetEnabled = ps.getEnabled(userId);
+            // ps.pkg.mSetStopped = ps.getStopped(userId);
+            return generatePackageInfo(ps.pkg, flags, userId);
         }
         return null;
     }
 
     @Override
     public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
+        if (!sUserManager.exists(userId)) return null;
         // writer
         synchronized (mPackages) {
             PackageParser.Package p = mPackages.get(packageName);
@@ -1717,8 +1736,11 @@
                     TAG, "getApplicationInfo " + packageName
                     + ": " + p);
             if (p != null) {
+                PackageSetting ps = mSettings.mPackages.get(packageName);
+                if (ps == null) return null;
                 // Note: isEnabledLP() does not apply here - always return info
-                return PackageParser.generateApplicationInfo(p, flags);
+                return PackageParser.generateApplicationInfo(p, flags, ps.getStopped(userId),
+                        ps.getEnabled(userId));
             }
             if ("android".equals(packageName)||"system".equals(packageName)) {
                 return mAndroidApplication;
@@ -1782,12 +1804,16 @@
 
     @Override
     public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
+        if (!sUserManager.exists(userId)) return null;
         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, userId)) {
-                return PackageParser.generateActivityInfo(a, flags, userId);
+                PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
+                if (ps == null) return null;
+                return PackageParser.generateActivityInfo(a, flags, ps.getStopped(userId),
+                        ps.getEnabled(userId), userId);
             }
             if (mResolveComponentName.equals(component)) {
                 return mResolveActivity;
@@ -1798,12 +1824,16 @@
 
     @Override
     public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) {
+        if (!sUserManager.exists(userId)) return null;
         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, userId)) {
-                return PackageParser.generateActivityInfo(a, flags, userId);
+                PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
+                if (ps == null) return null;
+                return PackageParser.generateActivityInfo(a, flags, ps.getStopped(userId),
+                        ps.getEnabled(userId), userId);
             }
         }
         return null;
@@ -1811,12 +1841,16 @@
 
     @Override
     public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
+        if (!sUserManager.exists(userId)) return null;
         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, userId)) {
-                return PackageParser.generateServiceInfo(s, flags, userId);
+                PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
+                if (ps == null) return null;
+                return PackageParser.generateServiceInfo(s, flags, ps.getStopped(userId),
+                        ps.getEnabled(userId), userId);
             }
         }
         return null;
@@ -1824,12 +1858,16 @@
 
     @Override
     public ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) {
+        if (!sUserManager.exists(userId)) return null;
         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, userId)) {
-                return PackageParser.generateProviderInfo(p, flags, userId);
+                PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
+                if (ps == null) return null;
+                return PackageParser.generateProviderInfo(p, flags, ps.getStopped(userId),
+                        ps.getEnabled(userId), userId);
             }
         }
         return null;
@@ -2253,6 +2291,7 @@
     @Override
     public ResolveInfo resolveIntent(Intent intent, String resolvedType,
             int flags, int userId) {
+        if (!sUserManager.exists(userId)) return null;
         List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, userId);
         return chooseBestActivity(intent, resolvedType, flags, query, userId);
     }
@@ -2294,6 +2333,7 @@
 
     ResolveInfo findPreferredActivity(Intent intent, String resolvedType,
             int flags, List<ResolveInfo> query, int priority, int userId) {
+        if (!sUserManager.exists(userId)) return null;
         // writer
         synchronized (mPackages) {
             if (intent.getSelector() != null) {
@@ -2389,6 +2429,7 @@
     @Override
     public List<ResolveInfo> queryIntentActivities(Intent intent,
             String resolvedType, int flags, int userId) {
+        if (!sUserManager.exists(userId)) return null;
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -2427,6 +2468,7 @@
     public List<ResolveInfo> queryIntentActivityOptions(ComponentName caller,
             Intent[] specifics, String[] specificTypes, Intent intent,
             String resolvedType, int flags, int userId) {
+        if (!sUserManager.exists(userId)) return null;
         final String resultsAction = intent.getAction();
 
         List<ResolveInfo> results = queryIntentActivities(intent, resolvedType, flags
@@ -2596,6 +2638,7 @@
     @Override
     public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags,
             int userId) {
+        if (!sUserManager.exists(userId)) return null;
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -2632,6 +2675,7 @@
     @Override
     public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) {
         List<ResolveInfo> query = queryIntentServices(intent, resolvedType, flags, userId);
+        if (!sUserManager.exists(userId)) return null;
         if (query != null) {
             if (query.size() >= 1) {
                 // If there is more than one service with the same priority,
@@ -2645,6 +2689,7 @@
     @Override
     public List<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags,
             int userId) {
+        if (!sUserManager.exists(userId)) return null;
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -2723,7 +2768,7 @@
                 } else {
                     final PackageParser.Package p = mPackages.get(packageName);
                     if (p != null) {
-                        pi = generatePackageInfo(p, flags);
+                        pi = generatePackageInfo(p, flags, userId);
                     }
                 }
 
@@ -2743,6 +2788,7 @@
     @Override
     public ParceledListSlice<ApplicationInfo> getInstalledApplications(int flags,
             String lastRead, int userId) {
+        if (!sUserManager.exists(userId)) return null;
         final ParceledListSlice<ApplicationInfo> list = new ParceledListSlice<ApplicationInfo>();
         final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
         final String[] keys;
@@ -2763,15 +2809,16 @@
                 final String packageName = keys[i++];
 
                 ApplicationInfo ai = null;
+                final PackageSetting ps = mSettings.mPackages.get(packageName);
                 if (listUninstalled) {
-                    final PackageSetting ps = mSettings.mPackages.get(packageName);
                     if (ps != null) {
                         ai = generateApplicationInfoFromSettingsLPw(ps.name, flags, userId);
                     }
                 } else {
                     final PackageParser.Package p = mPackages.get(packageName);
-                    if (p != null) {
-                        ai = PackageParser.generateApplicationInfo(p, flags, userId);
+                    if (p != null && ps != null) {
+                        ai = PackageParser.generateApplicationInfo(p, flags, ps.getStopped(userId),
+                                ps.getEnabled(userId), userId);
                     }
                 }
 
@@ -2794,13 +2841,17 @@
         // reader
         synchronized (mPackages) {
             final Iterator<PackageParser.Package> i = mPackages.values().iterator();
-            final int userId = UserId.getUserId(Binder.getCallingUid());
+            final int userId = UserId.getCallingUserId();
             while (i.hasNext()) {
                 final PackageParser.Package p = i.next();
                 if (p.applicationInfo != null
                         && (p.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) != 0
                         && (!mSafeMode || isSystemApp(p))) {
-                    finalList.add(PackageParser.generateApplicationInfo(p, flags, userId));
+                    PackageSetting ps = mSettings.mPackages.get(p.packageName);
+                    finalList.add(PackageParser.generateApplicationInfo(p, flags,
+                            ps != null ? ps.getStopped(userId) : false,
+                            ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT,
+                            userId));
                 }
             }
         }
@@ -2810,14 +2861,21 @@
 
     @Override
     public ProviderInfo resolveContentProvider(String name, int flags, int userId) {
+        if (!sUserManager.exists(userId)) return null;
         // reader
         synchronized (mPackages) {
             final PackageParser.Provider provider = mProviders.get(name);
+            PackageSetting ps = provider != null
+                    ? mSettings.mPackages.get(provider.owner.packageName)
+                    : null;
             return provider != null
                     && mSettings.isEnabledLPr(provider.info, flags, userId)
                     && (!mSafeMode || (provider.info.applicationInfo.flags
                             &ApplicationInfo.FLAG_SYSTEM) != 0)
-                    ? PackageParser.generateProviderInfo(provider, flags, userId)
+                    ? PackageParser.generateProviderInfo(provider, flags,
+                            ps != null ? ps.getStopped(userId) : false,
+                            ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT,
+                            userId)
                     : null;
         }
     }
@@ -2831,16 +2889,20 @@
         synchronized (mPackages) {
             final Iterator<Map.Entry<String, PackageParser.Provider>> i = mProviders.entrySet()
                     .iterator();
-            final int userId = UserId.getUserId(Binder.getCallingUid());
+            final int userId = UserId.getCallingUserId();
             while (i.hasNext()) {
                 Map.Entry<String, PackageParser.Provider> entry = i.next();
                 PackageParser.Provider p = entry.getValue();
+                PackageSetting ps = mSettings.mPackages.get(p.owner.packageName);
 
                 if (p.syncable
                         && (!mSafeMode || (p.info.applicationInfo.flags
                                 &ApplicationInfo.FLAG_SYSTEM) != 0)) {
                     outNames.add(entry.getKey());
-                    outInfo.add(PackageParser.generateProviderInfo(p, 0, userId));
+                    outInfo.add(PackageParser.generateProviderInfo(p, 0,
+                            ps != null ? ps.getStopped(userId) : false,
+                            ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT,
+                            userId));
                 }
             }
         }
@@ -2857,6 +2919,7 @@
                     UserId.getUserId(uid) : UserId.getCallingUserId();
             while (i.hasNext()) {
                 final PackageParser.Provider p = i.next();
+                PackageSetting ps = mSettings.mPackages.get(p.owner.packageName);
                 if (p.info.authority != null
                         && (processName == null
                                 || (p.info.processName.equals(processName)
@@ -2867,7 +2930,10 @@
                     if (finalList == null) {
                         finalList = new ArrayList<ProviderInfo>(3);
                     }
-                    finalList.add(PackageParser.generateProviderInfo(p, flags, userId));
+                    finalList.add(PackageParser.generateProviderInfo(p, flags,
+                            ps != null ? ps.getStopped(userId) : false,
+                            ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT,
+                            userId));
                 }
             }
         }
@@ -3511,7 +3577,7 @@
                 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
             }
 
-            pkg.applicationInfo.uid = pkgSetting.uid;
+            pkg.applicationInfo.uid = pkgSetting.appId;
             pkg.mExtras = pkgSetting;
 
             if (!verifySignaturesLP(pkgSetting, pkg)) {
@@ -3618,7 +3684,7 @@
                         if (ret >= 0) {
                             // TODO: Kill the processes first
                             // Remove the data directories for all users
-                            mUserManager.removePackageForAllUsers(pkgName);
+                            sUserManager.removePackageForAllUsers(pkgName);
                             // Old data gone!
                             String msg = "System package " + pkg.packageName
                                     + " has changed from uid: "
@@ -3639,7 +3705,7 @@
                                 return null;
                             }
                             // Create data directories for all users
-                            mUserManager.installPackageForAllUsers(pkgName,
+                            sUserManager.installPackageForAllUsers(pkgName,
                                     pkg.applicationInfo.uid);
                         }
                         if (!recovered) {
@@ -3681,7 +3747,7 @@
                     return null;
                 }
                 // Create data directories for all users
-                mUserManager.installPackageForAllUsers(pkgName, pkg.applicationInfo.uid);
+                sUserManager.installPackageForAllUsers(pkgName, pkg.applicationInfo.uid);
 
                 if (dataPath.exists()) {
                     pkg.applicationInfo.dataDir = dataPath.getPath();
@@ -4510,12 +4576,14 @@
             extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> {
         public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
                 boolean defaultOnly, int userId) {
+            if (!sUserManager.exists(userId)) return null;
             mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;
             return super.queryIntent(intent, resolvedType, defaultOnly, userId);
         }
 
         public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags,
                 int userId) {
+            if (!sUserManager.exists(userId)) return null;
             mFlags = flags;
             return super.queryIntent(intent, resolvedType,
                     (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId);
@@ -4523,6 +4591,7 @@
 
         public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
                 int flags, ArrayList<PackageParser.Activity> packageActivities, int userId) {
+            if (!sUserManager.exists(userId)) return null;
             if (packageActivities == null) {
                 return null;
             }
@@ -4605,6 +4674,7 @@
 
         @Override
         protected boolean isFilterStopped(PackageParser.ActivityIntentInfo filter, int userId) {
+            if (!sUserManager.exists(userId)) return true;
             PackageParser.Package p = filter.activity.owner;
             if (p != null) {
                 PackageSetting ps = (PackageSetting)p.mExtras;
@@ -4626,6 +4696,7 @@
         @Override
         protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info,
                 int match, int userId) {
+            if (!sUserManager.exists(userId)) return null;
             if (!mSettings.isEnabledLPr(info.activity.info, mFlags, userId)) {
                 return null;
             }
@@ -4635,7 +4706,11 @@
                 return null;
             }
             final ResolveInfo res = new ResolveInfo();
-            res.activityInfo = PackageParser.generateActivityInfo(activity, mFlags, userId);
+            PackageSetting ps = (PackageSetting) activity.owner.mExtras;
+            res.activityInfo = PackageParser.generateActivityInfo(activity, mFlags,
+                    ps != null ? ps.getStopped(userId) : false,
+                    ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT,
+                    userId);
             if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) {
                 res.filter = info;
             }
@@ -4696,6 +4771,7 @@
 
         public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags,
                 int userId) {
+            if (!sUserManager.exists(userId)) return null;
             mFlags = flags;
             return super.queryIntent(intent, resolvedType,
                     (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId);
@@ -4703,6 +4779,7 @@
 
         public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
                 int flags, ArrayList<PackageParser.Service> packageServices, int userId) {
+            if (!sUserManager.exists(userId)) return null;
             if (packageServices == null) {
                 return null;
             }
@@ -4780,6 +4857,7 @@
 
         @Override
         protected boolean isFilterStopped(PackageParser.ServiceIntentInfo filter, int userId) {
+            if (!sUserManager.exists(userId)) return true;
             PackageParser.Package p = filter.service.owner;
             if (p != null) {
                 PackageSetting ps = (PackageSetting)p.mExtras;
@@ -4802,6 +4880,7 @@
         @Override
         protected ResolveInfo newResult(PackageParser.ServiceIntentInfo filter,
                 int match, int userId) {
+            if (!sUserManager.exists(userId)) return null;
             final PackageParser.ServiceIntentInfo info = (PackageParser.ServiceIntentInfo)filter;
             if (!mSettings.isEnabledLPr(info.service.info, mFlags, userId)) {
                 return null;
@@ -4812,7 +4891,11 @@
                 return null;
             }
             final ResolveInfo res = new ResolveInfo();
-            res.serviceInfo = PackageParser.generateServiceInfo(service, mFlags, userId);
+            PackageSetting ps = (PackageSetting) service.owner.mExtras;
+            res.serviceInfo = PackageParser.generateServiceInfo(service, mFlags,
+                    ps != null ? ps.getStopped(userId) : false,
+                    ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT,
+                    userId);
             if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) {
                 res.filter = filter;
             }
@@ -4903,23 +4986,32 @@
     };
 
     static final void sendPackageBroadcast(String action, String pkg,
-            Bundle extras, String targetPkg, IIntentReceiver finishedReceiver) {
+            Bundle extras, String targetPkg, IIntentReceiver finishedReceiver, int userId) {
         IActivityManager am = ActivityManagerNative.getDefault();
         if (am != null) {
             try {
-                final Intent intent = new Intent(action,
-                        pkg != null ? Uri.fromParts("package", pkg, null) : null);
-                if (extras != null) {
-                    intent.putExtras(extras);
+                int[] userIds = userId == UserId.USER_ALL
+                        ? sUserManager.getUserIds() 
+                        : new int[] {userId};
+                for (int id : userIds) {
+                    final Intent intent = new Intent(action,
+                            pkg != null ? Uri.fromParts("package", pkg, null) : null);
+                    if (extras != null) {
+                        intent.putExtras(extras);
+                    }
+                    if (targetPkg != null) {
+                        intent.setPackage(targetPkg);
+                    }
+                    // Modify the UID when posting to other users
+                    int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+                    if (uid > 0 && id > 0) {
+                        uid = UserId.getUid(id, UserId.getAppId(uid));
+                        intent.putExtra(Intent.EXTRA_UID, uid);
+                    }
+                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+                    am.broadcastIntent(null, intent, null, finishedReceiver,
+                            0, null, null, null, finishedReceiver != null, false, id);
                 }
-                if (targetPkg != null) {
-                    intent.setPackage(targetPkg);
-                }
-                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-                // TODO: Fix the userId argument
-                am.broadcastIntent(null, intent, null, finishedReceiver,
-                        0, null, null, null, finishedReceiver != null, false,
-                        Binder.getOrigCallingUser());
             } catch (RemoteException ex) {
             }
         }
@@ -5062,13 +5154,13 @@
                 extras.putInt(Intent.EXTRA_UID, removedUid);
                 extras.putBoolean(Intent.EXTRA_DATA_REMOVED, false);
                 sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage,
-                        extras, null, null);
+                        extras, null, null, UserId.USER_ALL);
             }
             if (addedPackage != null) {
                 Bundle extras = new Bundle(1);
                 extras.putInt(Intent.EXTRA_UID, addedUid);
                 sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage,
-                        extras, null, null);
+                        extras, null, null, UserId.USER_ALL);
             }
         }
 
@@ -7092,11 +7184,11 @@
                 extras.putBoolean(Intent.EXTRA_REPLACING, true);
 
                 sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
-                        extras, null, null);
+                        extras, null, null, UserId.USER_ALL);
                 sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
-                        extras, null, null);
+                        extras, null, null, UserId.USER_ALL);
                 sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null,
-                        null, packageName, null);
+                        null, packageName, null, UserId.USER_ALL);
             }
         }
         // Force a gc here.
@@ -7129,14 +7221,15 @@
             }
             if (removedPackage != null) {
                 sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage,
-                        extras, null, null);
+                        extras, null, null, UserId.USER_ALL);
                 if (fullRemove && !replacing) {
                     sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED, removedPackage,
-                            extras, null, null);
+                            extras, null, null, UserId.USER_ALL);
                 }
             }
             if (removedUid >= 0) {
-                sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras, null, null);
+                sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras, null, null,
+                        UserId.getUserId(removedUid));
             }
         }
     }
@@ -7168,7 +7261,7 @@
                 // we don't consider this to be a failure of the core package deletion
             } else {
                 // TODO: Kill the processes first
-                mUserManager.removePackageForAllUsers(packageName);
+                sUserManager.removePackageForAllUsers(packageName);
             }
             schedulePackageCleaning(packageName);
         }
@@ -7732,12 +7825,14 @@
     @Override
     public void setApplicationEnabledSetting(String appPackageName,
             int newState, int flags, int userId) {
+        if (!sUserManager.exists(userId)) return;
         setEnabledSetting(appPackageName, null, newState, flags, userId);
     }
 
     @Override
     public void setComponentEnabledSetting(ComponentName componentName,
             int newState, int flags, int userId) {
+        if (!sUserManager.exists(userId)) return;
         setEnabledSetting(componentName.getPackageName(),
                 componentName.getClassName(), newState, flags, userId);
     }
@@ -7776,11 +7871,11 @@
                         + "/" + className);
             }
             // Allow root and verify that userId is not being specified by a different user
-            if (!allowedByPermission && !UserId.isSameApp(uid, pkgSetting.uid)) {
+            if (!allowedByPermission && !UserId.isSameApp(uid, pkgSetting.appId)) {
                 throw new SecurityException(
                         "Permission Denial: attempt to change component state from pid="
                         + Binder.getCallingPid()
-                        + ", uid=" + uid + ", package uid=" + pkgSetting.uid);
+                        + ", uid=" + uid + ", package uid=" + pkgSetting.appId);
             }
             if (className == null) {
                 // We're dealing with an application/package level state change
@@ -7789,7 +7884,7 @@
                     return;
                 }
                 pkgSetting.setEnabled(newState, userId);
-                pkgSetting.pkg.mSetEnabled = newState;
+                // pkgSetting.pkg.mSetEnabled = newState;
             } else {
                 // We're dealing with a component level state change
                 // First, verify that this is a valid class name.
@@ -7825,7 +7920,7 @@
                 }
             }
             mSettings.writePackageRestrictionsLPr(userId);
-            packageUid = pkgSetting.uid;
+            packageUid = UserId.getUid(userId, pkgSetting.appId);
             components = mPendingBroadcasts.get(packageName);
             final boolean newPackage = components == null;
             if (newPackage) {
@@ -7873,10 +7968,12 @@
         extras.putStringArray(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST, nameList);
         extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, killFlag);
         extras.putInt(Intent.EXTRA_UID, packageUid);
-        sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED,  packageName, extras, null, null);
+        sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED,  packageName, extras, null, null,
+                UserId.getUserId(packageUid));
     }
 
     public void setPackageStoppedState(String packageName, boolean stopped, int userId) {
+        if (!sUserManager.exists(userId)) return;
         final int uid = Binder.getCallingUid();
         final int permission = mContext.checkCallingOrSelfPermission(
                 android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
@@ -7900,6 +7997,7 @@
 
     @Override
     public int getApplicationEnabledSetting(String packageName, int userId) {
+        if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
         int uid = Binder.getCallingUid();
         checkValidCaller(uid, userId);
         // reader
@@ -7910,6 +8008,7 @@
 
     @Override
     public int getComponentEnabledSetting(ComponentName componentName, int userId) {
+        if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
         int uid = Binder.getCallingUid();
         checkValidCaller(uid, userId);
         // reader
@@ -8383,7 +8482,7 @@
                                     + " at code path: " + ps.codePathString);
                         // We do have a valid package installed on sdcard
                         processCids.put(args, ps.codePathString);
-                        int uid = ps.uid;
+                        int uid = ps.appId;
                         if (uid != -1) {
                             uidList[num++] = uid;
                         }
@@ -8436,7 +8535,7 @@
             }
             String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE
                     : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;
-            sendPackageBroadcast(action, null, extras, null, finishedReceiver);
+            sendPackageBroadcast(action, null, extras, null, finishedReceiver, UserId.USER_ALL);
         }
     }
 
@@ -8860,8 +8959,12 @@
         // TODO(kroot): Add a real permission for creating users
         enforceSystemOrRoot("Only the system can create users");
 
-        // TODO(kroot): fix this API
-        UserInfo userInfo = mUserManager.createUser(name, flags, new ArrayList<ApplicationInfo>());
+        UserInfo userInfo = sUserManager.createUser(name, flags);
+        if (userInfo != null) {
+            Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED);
+            addedIntent.putExtra(Intent.EXTRA_USERID, userInfo.id);
+            mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_ACCOUNTS);
+        }
         return userInfo;
     }
 
@@ -8869,13 +8972,34 @@
         // TODO(kroot): Add a real permission for removing users
         enforceSystemOrRoot("Only the system can remove users");
 
-        if (userId == 0) {
+        if (userId == 0 || !sUserManager.exists(userId)) {
             return false;
         }
-        mUserManager.removeUser(userId);
+
+        cleanUpUser(userId);
+
+        if (sUserManager.removeUser(userId)) {
+            // Let other services shutdown any activity
+            Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED);
+            addedIntent.putExtra(Intent.EXTRA_USERID, userId);
+            mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_ACCOUNTS);
+        }
+        sUserManager.removePackageFolders(userId);
         return true;
     }
 
+    private void cleanUpUser(int userId) {
+        // Disable all the packages for the user first
+        synchronized (mPackages) {
+            Set<Entry<String, PackageSetting>> entries = mSettings.mPackages.entrySet();
+            for (Entry<String, PackageSetting> entry : entries) {
+                entry.getValue().removeUser(userId);
+            }
+            if (mDirtyUsers.remove(userId));
+            mSettings.removeUserLPr(userId);
+        }
+    }
+
     @Override
     public VerifierDeviceIdentity getVerifierDeviceIdentity() throws RemoteException {
         mContext.enforceCallingOrSelfPermission(
@@ -8887,8 +9011,22 @@
         }
     }
 
+    @Override
     public List<UserInfo> getUsers() {
-        return mUserManager.getUsers();
+        enforceSystemOrRoot("Only the system can query users");
+        return sUserManager.getUsers();
+    }
+
+    @Override
+    public UserInfo getUser(int userId) {
+        enforceSystemOrRoot("Only the system can remove users");
+        return sUserManager.getUser(userId);
+    }
+
+    @Override
+    public void updateUserName(int userId, String name) {
+        enforceSystemOrRoot("Only the system can rename users");
+        sUserManager.updateUserName(userId, name);
     }
 
     @Override
diff --git a/services/java/com/android/server/pm/PackageSetting.java b/services/java/com/android/server/pm/PackageSetting.java
index 48ed9bf..f7f0870 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 uid;
+    int appId;
     PackageParser.Package pkg;
     SharedUserSetting sharedUser;
 
@@ -41,7 +41,7 @@
     PackageSetting(PackageSetting orig) {
         super(orig);
 
-        uid = orig.uid;
+        appId = orig.appId;
         pkg = orig.pkg;
         sharedUser = orig.sharedUser;
     }
@@ -50,6 +50,6 @@
     public String toString() {
         return "PackageSetting{"
             + Integer.toHexString(System.identityHashCode(this))
-            + " " + name + "/" + uid + "}";
+            + " " + name + "/" + appId + "}";
     }
 }
\ 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 b7cf8d6..56f2166 100644
--- a/services/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/java/com/android/server/pm/PackageSettingBase.java
@@ -273,4 +273,13 @@
             return COMPONENT_ENABLED_STATE_DEFAULT;
         }
     }
+
+    void removeUser(int userId) {
+        enabled.delete(userId);
+        stopped.delete(userId);
+        enabledComponents.delete(userId);
+        disabledComponents.delete(userId);
+        notLaunched.delete(userId);
+    }
+
 }
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index b541c8c..bb7f4fc 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -275,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.uid, p.versionCode, p.pkgFlags);
+                p.nativeLibraryPathString, p.appId, p.versionCode, p.pkgFlags);
         mDisabledSysPackages.remove(name);
         return ret;
     }
@@ -284,7 +284,7 @@
             String nativeLibraryPathString, int uid, int vc, int pkgFlags) {
         PackageSetting p = mPackages.get(name);
         if (p != null) {
-            if (p.uid == uid) {
+            if (p.appId == uid) {
                 return p;
             }
             PackageManagerService.reportSettingsProblem(Log.ERROR,
@@ -293,7 +293,7 @@
         }
         p = new PackageSetting(name, realName, codePath, resourcePath, nativeLibraryPathString,
                 vc, pkgFlags);
-        p.uid = uid;
+        p.appId = uid;
         if (addUserIdLPw(uid, p, name)) {
             mPackages.put(name, p);
             return p;
@@ -407,7 +407,7 @@
                 p.copyFrom(origPackage);
                 p.signatures = s;
                 p.sharedUser = origPackage.sharedUser;
-                p.uid = origPackage.uid;
+                p.appId = origPackage.appId;
                 p.origPackage = origPackage;
                 mRenamedPackages.put(name, origPackage.name);
                 name = origPackage.name;
@@ -435,7 +435,7 @@
                     }
                 }
                 if (sharedUser != null) {
-                    p.uid = sharedUser.userId;
+                    p.appId = sharedUser.userId;
                 } else {
                     // Clone the setting here for disabled system packages
                     PackageSetting dis = mDisabledSysPackages.get(name);
@@ -447,7 +447,7 @@
                         if (dis.signatures.mSignatures != null) {
                             p.signatures.mSignatures = dis.signatures.mSignatures.clone();
                         }
-                        p.uid = dis.uid;
+                        p.appId = dis.appId;
                         // Clone permissions
                         p.grantedPermissions = new HashSet<String>(dis.grantedPermissions);
                         // Clone component info
@@ -464,14 +464,14 @@
                             }
                         }
                         // Add new setting to list of user ids
-                        addUserIdLPw(p.uid, p, name);
+                        addUserIdLPw(p.appId, p, name);
                     } else {
                         // Assign new user id
-                        p.uid = newUserIdLPw(p);
+                        p.appId = newUserIdLPw(p);
                     }
                 }
             }
-            if (p.uid < 0) {
+            if (p.appId < 0) {
                 PackageManagerService.reportSettingsProblem(Log.WARN,
                         "Package " + name + " could not be assigned a valid uid");
                 return null;
@@ -539,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.uid != sharedUser.userId) {
+            } else if (p.appId != sharedUser.userId) {
                 PackageManagerService.reportSettingsProblem(Log.ERROR,
-                    "Package " + p.name + " was user id " + p.uid
+                    "Package " + p.name + " was user id " + p.appId
                     + " but is now user " + sharedUser
                     + " with id " + sharedUser.userId
                     + "; I am not changing its files so it will probably fail!");
@@ -549,7 +549,7 @@
 
             sharedUser.packages.add(p);
             p.sharedUser = sharedUser;
-            p.uid = sharedUser.userId;
+            p.appId = sharedUser.userId;
         }
     }
 
@@ -614,8 +614,8 @@
                     return p.sharedUser.userId;
                 }
             } else {
-                removeUserIdLPw(p.uid);
-                return p.uid;
+                removeUserIdLPw(p.appId);
+                return p.appId;
             }
         }
         return -1;
@@ -628,7 +628,7 @@
                 p.sharedUser.packages.remove(p);
                 p.sharedUser.packages.add(newp);
             } else {
-                replaceUserIdLPw(p.uid, newp);
+                replaceUserIdLPw(p.appId, newp);
             }
         }
         mPackages.put(name, newp);
@@ -1317,9 +1317,9 @@
             serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString);
         }
         if (pkg.sharedUser == null) {
-            serializer.attribute(null, "userId", Integer.toString(pkg.uid));
+            serializer.attribute(null, "userId", Integer.toString(pkg.appId));
         } else {
-            serializer.attribute(null, "sharedUserId", Integer.toString(pkg.uid));
+            serializer.attribute(null, "sharedUserId", Integer.toString(pkg.appId));
         }
         serializer.startTag(null, "perms");
         if (pkg.sharedUser == null) {
@@ -1364,9 +1364,9 @@
         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.uid));
+            serializer.attribute(null, "userId", Integer.toString(pkg.appId));
         } else {
-            serializer.attribute(null, "sharedUserId", Integer.toString(pkg.uid));
+            serializer.attribute(null, "sharedUserId", Integer.toString(pkg.appId));
         }
         if (pkg.uidError) {
             serializer.attribute(null, "uidError", "true");
@@ -1607,7 +1607,7 @@
         final Iterator<PackageSetting> disabledIt = mDisabledSysPackages.values().iterator();
         while (disabledIt.hasNext()) {
             final PackageSetting disabledPs = disabledIt.next();
-            final Object id = getUserIdLPr(disabledPs.uid);
+            final Object id = getUserIdLPr(disabledPs.appId);
             if (id != null && id instanceof SharedUserSetting) {
                 disabledPs.sharedUser = (SharedUserSetting) id;
             }
@@ -1753,10 +1753,10 @@
             }
         }
         String idStr = parser.getAttributeValue(null, "userId");
-        ps.uid = idStr != null ? Integer.parseInt(idStr) : 0;
-        if (ps.uid <= 0) {
+        ps.appId = idStr != null ? Integer.parseInt(idStr) : 0;
+        if (ps.appId <= 0) {
             String sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
-            ps.uid = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
+            ps.appId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
         }
         int outerDepth = parser.getDepth();
         int type;
@@ -2164,6 +2164,13 @@
         }
     }
 
+    void removeUserLPr(int userId) {
+        File file = getUserPackagesStateFile(userId);
+        file.delete();
+        file = getUserPackagesStateBackupFile(userId);
+        file.delete();
+    }
+
     // Returns -1 if we could not find an available UserId to assign
     private int newUserIdLPw(Object obj) {
         // Let's be stupidly inefficient for now...
@@ -2265,11 +2272,11 @@
         if (pkgSetting == null) {
             throw new IllegalArgumentException("Unknown package: " + packageName);
         }
-        if (!allowedByPermission && (appId != pkgSetting.uid)) {
+        if (!allowedByPermission && (appId != pkgSetting.appId)) {
             throw new SecurityException(
                     "Permission Denial: attempt to change stopped state from pid="
                     + Binder.getCallingPid()
-                    + ", uid=" + uid + ", package uid=" + pkgSetting.uid);
+                    + ", uid=" + uid + ", package uid=" + pkgSetting.appId);
         }
         if (DEBUG_STOPPED) {
             if (stopped) {
@@ -2285,7 +2292,7 @@
                 if (pkgSetting.installerPackageName != null) {
                     PackageManagerService.sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH,
                             pkgSetting.name, null,
-                            pkgSetting.installerPackageName, null);
+                            pkgSetting.installerPackageName, null, userId);
                 }
                 pkgSetting.setNotLaunched(false, userId);
             }
@@ -2369,7 +2376,7 @@
                 pw.println(ps.name);
             }
 
-            pw.print("    userId="); pw.print(ps.uid);
+            pw.print("    userId="); pw.print(ps.appId);
             pw.print(" gids="); pw.println(PackageManagerService.arrayToString(ps.gids));
             pw.print("    sharedUser="); pw.println(ps.sharedUser);
             pw.print("    pkg="); pw.println(ps.pkg);
@@ -2513,7 +2520,7 @@
                     pw.println(ps.name);
                 }
                 pw.print("    userId=");
-                pw.println(ps.uid);
+                pw.println(ps.appId);
                 pw.print("    sharedUser=");
                 pw.println(ps.sharedUser);
                 pw.print("    codePath=");
diff --git a/services/java/com/android/server/pm/UserManager.java b/services/java/com/android/server/pm/UserManager.java
index 959e570..4e9e666 100644
--- a/services/java/com/android/server/pm/UserManager.java
+++ b/services/java/com/android/server/pm/UserManager.java
@@ -16,6 +16,7 @@
 
 package com.android.server.pm;
 
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 
 import android.content.pm.ApplicationInfo;
@@ -58,7 +59,7 @@
     private static final String USER_INFO_DIR = "system" + File.separator + "users";
     private static final String USER_LIST_FILENAME = "userlist.xml";
 
-    private SparseArray<UserInfo> mUsers;
+    private SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
 
     private final File mUsersDir;
     private final File mUserListFile;
@@ -91,11 +92,36 @@
     }
 
     public List<UserInfo> getUsers() {
-        ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
-        for (int i = 0; i < mUsers.size(); i++) {
-            users.add(mUsers.valueAt(i));
+        synchronized (mUsers) {
+            ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
+            for (int i = 0; i < mUsers.size(); i++) {
+                users.add(mUsers.valueAt(i));
+            }
+            return users;
         }
-        return users;
+    }
+
+    public UserInfo getUser(int userId) {
+        synchronized (mUsers) {
+            UserInfo info = mUsers.get(userId);
+            return info;
+        }
+    }
+
+    public boolean exists(int userId) {
+        synchronized (mUsers) {
+            return ArrayUtils.contains(mUserIds, userId);
+        }
+    }
+
+    public void updateUserName(int userId, String name) {
+        synchronized (mUsers) {
+            UserInfo info = mUsers.get(userId);
+            if (name != null && !name.equals(info.name)) {
+                info.name = name;
+                writeUserLocked(info);
+            }
+        }
     }
 
     /**
@@ -108,9 +134,14 @@
     }
 
     private void readUserList() {
-        mUsers = new SparseArray<UserInfo>();
+        synchronized (mUsers) {
+            readUserListLocked();
+        }
+    }
+
+    private void readUserListLocked() {
         if (!mUserListFile.exists()) {
-            fallbackToSingleUser();
+            fallbackToSingleUserLocked();
             return;
         }
         FileInputStream fis = null;
@@ -126,7 +157,7 @@
 
             if (type != XmlPullParser.START_TAG) {
                 Slog.e(LOG_TAG, "Unable to read user list");
-                fallbackToSingleUser();
+                fallbackToSingleUserLocked();
                 return;
             }
 
@@ -139,11 +170,11 @@
                     }
                 }
             }
-            updateUserIds();
+            updateUserIdsLocked();
         } catch (IOException ioe) {
-            fallbackToSingleUser();
+            fallbackToSingleUserLocked();
         } catch (XmlPullParserException pe) {
-            fallbackToSingleUser();
+            fallbackToSingleUserLocked();
         } finally {
             if (fis != null) {
                 try {
@@ -154,15 +185,15 @@
         }
     }
 
-    private void fallbackToSingleUser() {
+    private void fallbackToSingleUserLocked() {
         // Create the primary user
         UserInfo primary = new UserInfo(0, "Primary",
                 UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY);
         mUsers.put(0, primary);
-        updateUserIds();
+        updateUserIdsLocked();
 
-        writeUserList();
-        writeUser(primary);
+        writeUserListLocked();
+        writeUserLocked(primary);
     }
 
     /*
@@ -172,7 +203,7 @@
      *   <name>Primary</name>
      * </user>
      */
-    private void writeUser(UserInfo userInfo) {
+    private void writeUserLocked(UserInfo userInfo) {
         FileOutputStream fos = null;
         try {
             final File mUserFile = new File(mUsersDir, userInfo.id + ".xml");
@@ -216,7 +247,7 @@
      *   <user id="2"></user>
      * </users>
      */
-    private void writeUserList() {
+    private void writeUserListLocked() {
         FileOutputStream fos = null;
         try {
             fos = new FileOutputStream(mUserListFile);
@@ -309,17 +340,19 @@
         return null;
     }
 
-    public UserInfo createUser(String name, int flags, List<ApplicationInfo> apps) {
+    public UserInfo createUser(String name, int flags) {
         int userId = getNextAvailableId();
         UserInfo userInfo = new UserInfo(userId, name, flags);
         File userPath = new File(mBaseUserPath, Integer.toString(userId));
-        if (!createPackageFolders(userId, userPath, apps)) {
+        if (!createPackageFolders(userId, userPath)) {
             return null;
         }
-        mUsers.put(userId, userInfo);
-        writeUserList();
-        writeUser(userInfo);
-        updateUserIds();
+        synchronized (mUsers) {
+            mUsers.put(userId, userInfo);
+            writeUserListLocked();
+            writeUserLocked(userInfo);
+            updateUserIdsLocked();
+        }
         return userInfo;
     }
 
@@ -328,7 +361,13 @@
      * after the user's processes have been terminated.
      * @param id the user's id
      */
-    public void removeUser(int id) {
+    public boolean removeUser(int id) {
+        synchronized (mUsers) {
+            return removeUserLocked(id);
+        }
+    }
+
+    private boolean removeUserLocked(int id) {
         // Remove from the list
         UserInfo userInfo = mUsers.get(id);
         if (userInfo != null) {
@@ -338,11 +377,11 @@
             File userFile = new File(mUsersDir, id + ".xml");
             userFile.delete();
             // Update the user list
-            writeUserList();
-            // Remove the data directories for all packages for this user
-            removePackageFolders(id);
-            updateUserIds();
+            writeUserListLocked();
+            updateUserIdsLocked();
+            return true;
         }
+        return false;
     }
 
     public void installPackageForAllUsers(String packageName, int uid) {
@@ -376,7 +415,7 @@
     /**
      * Caches the list of user ids in an array, adjusting the array size when necessary.
      */
-    private void updateUserIds() {
+    private void updateUserIdsLocked() {
         if (mUserIds == null || mUserIds.length != mUsers.size()) {
             mUserIds = new int[mUsers.size()];
         }
@@ -402,11 +441,10 @@
         return i;
     }
 
-    private boolean createPackageFolders(int id, File userPath, final List<ApplicationInfo> apps) {
+    private boolean createPackageFolders(int id, File userPath) {
         // mInstaller may not be available for unit-tests.
-        if (mInstaller == null || apps == null) return true;
+        if (mInstaller == null) return true;
 
-        final long startTime = SystemClock.elapsedRealtime();
         // Create the user path
         userPath.mkdir();
         FileUtils.setPermissions(userPath.toString(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
@@ -414,13 +452,10 @@
 
         mInstaller.cloneUserData(0, id, false);
 
-        final long stopTime = SystemClock.elapsedRealtime();
-        Log.i(LOG_TAG,
-                "Time to create " + apps.size() + " packages = " + (stopTime - startTime) + "ms");
         return true;
     }
 
-    private boolean removePackageFolders(int id) {
+    boolean removePackageFolders(int id) {
         // mInstaller may not be available for unit-tests.
         if (mInstaller == null) return true;
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index e8188e7..d736ac1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -54,7 +54,7 @@
     public void testAddUser() throws Exception {
         final UserManager details = mUserManager;
 
-        UserInfo userInfo = details.createUser("Guest 1", UserInfo.FLAG_GUEST, null);
+        UserInfo userInfo = details.createUser("Guest 1", UserInfo.FLAG_GUEST);
         assertTrue(userInfo != null);
 
         List<UserInfo> list = details.getUsers();
@@ -73,8 +73,8 @@
     public void testAdd2Users() throws Exception {
         final UserManager details = mUserManager;
 
-        UserInfo user1 = details.createUser("Guest 1", UserInfo.FLAG_GUEST, null);
-        UserInfo user2 = details.createUser("User 2", UserInfo.FLAG_ADMIN, null);
+        UserInfo user1 = details.createUser("Guest 1", UserInfo.FLAG_GUEST);
+        UserInfo user2 = details.createUser("User 2", UserInfo.FLAG_ADMIN);
 
         assertTrue(user1 != null);
         assertTrue(user2 != null);
@@ -87,7 +87,7 @@
     public void testRemoveUser() throws Exception {
         final UserManager details = mUserManager;
 
-        UserInfo userInfo = details.createUser("Guest 1", UserInfo.FLAG_GUEST, null);
+        UserInfo userInfo = details.createUser("Guest 1", UserInfo.FLAG_GUEST);
 
         details.removeUser(userInfo.id);
 
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 351c771..5610134 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -45,6 +45,7 @@
 import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.RemoteException;
 
 import java.util.List;
 
@@ -530,6 +531,14 @@
      * @hide
      */
     @Override
+    public UserInfo getUser(int userId) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
     public boolean removeUser(int id) {
         throw new UnsupportedOperationException();
     }
diff --git a/voip/java/android/net/rtp/AudioStream.java b/voip/java/android/net/rtp/AudioStream.java
index d761214..b7874f7 100644
--- a/voip/java/android/net/rtp/AudioStream.java
+++ b/voip/java/android/net/rtp/AudioStream.java
@@ -158,7 +158,7 @@
             if (type < 96 || type > 127) {
                 throw new IllegalArgumentException("Invalid type");
             }
-            if (type == mCodec.type) {
+            if (mCodec != null && type == mCodec.type) {
                 throw new IllegalArgumentException("The type is used by codec");
             }
         }