Merge "Enable use of Surface as a native window in EGL14 wrapper." into jb-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index d246b09..c19acfe 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5075,6 +5075,7 @@
   public class ContentProviderClient {
     method public android.content.ContentProviderResult[] applyBatch(java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
     method public int bulkInsert(android.net.Uri, android.content.ContentValues[]) throws android.os.RemoteException;
+    method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle) throws android.os.RemoteException;
     method public int delete(android.net.Uri, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
     method public android.content.ContentProvider getLocalContentProvider();
     method public java.lang.String[] getStreamTypes(android.net.Uri, java.lang.String) throws android.os.RemoteException;
@@ -5319,9 +5320,10 @@
     method public abstract void revokeUriPermission(android.net.Uri, int);
     method public abstract void sendBroadcast(android.content.Intent);
     method public abstract void sendBroadcast(android.content.Intent, java.lang.String);
-    method public void sendBroadcastToUser(android.content.Intent, int);
+    method public abstract void sendBroadcastToUser(android.content.Intent, int);
     method public abstract void sendOrderedBroadcast(android.content.Intent, java.lang.String);
     method public abstract void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+    method public abstract void sendOrderedBroadcastToUser(android.content.Intent, int, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
     method public abstract void sendStickyBroadcast(android.content.Intent);
     method public abstract void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
     method public abstract void setTheme(int);
@@ -5453,8 +5455,10 @@
     method public void revokeUriPermission(android.net.Uri, int);
     method public void sendBroadcast(android.content.Intent);
     method public void sendBroadcast(android.content.Intent, java.lang.String);
+    method public void sendBroadcastToUser(android.content.Intent, int);
     method public void sendOrderedBroadcast(android.content.Intent, java.lang.String);
     method public void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+    method public void sendOrderedBroadcastToUser(android.content.Intent, int, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
     method public void sendStickyBroadcast(android.content.Intent);
     method public void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
     method public void setTheme(int);
@@ -5828,7 +5832,7 @@
     field public static final java.lang.String EXTRA_KEY_EVENT = "android.intent.extra.KEY_EVENT";
     field public static final java.lang.String EXTRA_LOCAL_ONLY = "android.intent.extra.LOCAL_ONLY";
     field public static final java.lang.String EXTRA_NOT_UNKNOWN_SOURCE = "android.intent.extra.NOT_UNKNOWN_SOURCE";
-    field public static final java.lang.String EXTRA_ORIGINATING_URI = "android.intent.extra.ORIGINATING_URI";
+    field public static final java.lang.String EXTRA_ORIGINATING_URL = "android.intent.extra.ORIGINATING_URL";
     field public static final java.lang.String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
     field public static final java.lang.String EXTRA_REFERRER = "android.intent.extra.REFERRER";
     field public static final java.lang.String EXTRA_REMOTE_INTENT_TOKEN = "android.intent.extra.remote_intent_token";
@@ -6235,6 +6239,7 @@
     field public static final int FLAG_HARDWARE_ACCELERATED = 512; // 0x200
     field public static final int FLAG_MULTIPROCESS = 1; // 0x1
     field public static final int FLAG_NO_HISTORY = 128; // 0x80
+    field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000
     field public static final int FLAG_STATE_NOT_NEEDED = 16; // 0x10
     field public static final int LAUNCH_MULTIPLE = 0; // 0x0
     field public static final int LAUNCH_SINGLE_INSTANCE = 3; // 0x3
@@ -6657,7 +6662,9 @@
     ctor public ProviderInfo(android.content.pm.ProviderInfo);
     method public int describeContents();
     field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000
     field public java.lang.String authority;
+    field public int flags;
     field public boolean grantUriPermissions;
     field public int initOrder;
     field public deprecated boolean isSyncable;
@@ -6703,7 +6710,7 @@
     method public void dump(android.util.Printer, java.lang.String);
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final int FLAG_ISOLATED_PROCESS = 2; // 0x2
-    field public static final int FLAG_SINGLE_USER = 4; // 0x4
+    field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000
     field public static final int FLAG_STOP_WITH_TASK = 1; // 0x1
     field public int flags;
     field public java.lang.String permission;
@@ -11505,6 +11512,7 @@
     method public void setVideoSource(int) throws java.lang.IllegalStateException;
     method public void start() throws java.lang.IllegalStateException;
     method public void stop() throws java.lang.IllegalStateException;
+    field public static final int MEDIA_ERROR_SERVER_DIED = 100; // 0x64
     field public static final int MEDIA_RECORDER_ERROR_UNKNOWN = 1; // 0x1
     field public static final int MEDIA_RECORDER_INFO_MAX_DURATION_REACHED = 800; // 0x320
     field public static final int MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED = 801; // 0x321
@@ -16248,6 +16256,7 @@
     method public static final int myPid();
     method public static final int myTid();
     method public static final int myUid();
+    method public static final int myUserHandle();
     method public static final void sendSignal(int, int);
     method public static final void setThreadPriority(int, int) throws java.lang.IllegalArgumentException, java.lang.SecurityException;
     method public static final void setThreadPriority(int) throws java.lang.IllegalArgumentException, java.lang.SecurityException;
@@ -21143,8 +21152,10 @@
     method public void revokeUriPermission(android.net.Uri, int);
     method public void sendBroadcast(android.content.Intent);
     method public void sendBroadcast(android.content.Intent, java.lang.String);
+    method public void sendBroadcastToUser(android.content.Intent, int);
     method public void sendOrderedBroadcast(android.content.Intent, java.lang.String);
     method public void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+    method public void sendOrderedBroadcastToUser(android.content.Intent, int, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
     method public void sendStickyBroadcast(android.content.Intent);
     method public void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
     method public void setTheme(int);
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 4311c06..4cb5270 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -782,7 +782,6 @@
         String macAlgo = null;
         byte[] macKey = null;
         byte[] tag = null;
-        String referrer = null;
 
         while ((opt=nextOption()) != null) {
             if (opt.equals("-l")) {
@@ -846,13 +845,6 @@
                     showUsage();
                     return;
                 }
-            } else if (opt.equals("--referrer")) {
-                referrer = nextOptionData();
-                if (referrer == null) {
-                    System.err.println("Error: must supply argument for --referrer");
-                    showUsage();
-                    return;
-                }
             } else {
                 System.err.println("Error: Unknown option: " + opt);
                 showUsage();
@@ -900,13 +892,6 @@
 
         final Uri apkURI;
         final Uri verificationURI;
-        final Uri referrerURI;
-
-        if (referrer != null) {
-            referrerURI = Uri.parse(referrer);
-        } else {
-            referrerURI = null;
-        }
 
         // Populate apkURI, must be present
         final String apkFilePath = nextArg();
@@ -931,7 +916,7 @@
         PackageInstallObserver obs = new PackageInstallObserver();
         try {
             mPm.installPackageWithVerification(apkURI, obs, installFlags, installerPackageName,
-                    verificationURI, null, encryptionParams, apkURI, referrerURI);
+                    verificationURI, null, encryptionParams);
 
             synchronized (obs) {
                 while (!obs.finished) {
@@ -1451,8 +1436,7 @@
         System.err.println("       pm list libraries");
         System.err.println("       pm path PACKAGE");
         System.err.println("       pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f]");
-        System.err.println("                  [--algo <algorithm name> --key <key-in-hex> --iv <IV-in-hex>]");
-        System.err.println("                  [--referrer <URI>] PATH");
+        System.err.println("                  [--algo <algorithm name> --key <key-in-hex> --iv <IV-in-hex>] PATH");
         System.err.println("       pm uninstall [-k] PACKAGE");
         System.err.println("       pm clear PACKAGE");
         System.err.println("       pm enable PACKAGE_OR_COMPONENT");
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 92b6f72..c74f823 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -529,7 +529,36 @@
             throws SecurityException {
         try {
             return ActivityManagerNative.getDefault().getRecentTasks(maxNum,
-                    flags);
+                    flags, UserId.myUserId());
+        } catch (RemoteException e) {
+            // System dead, we will be dead too soon!
+            return null;
+        }
+    }
+
+    /**
+     * Same as {@link #getRecentTasks(int, int)} but returns the recent tasks for a
+     * specific user. It requires holding
+     * the {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission.
+     * @param maxNum The maximum number of entries to return in the list.  The
+     * actual number returned may be smaller, depending on how many tasks the
+     * user has started and the maximum number the system can remember.
+     * @param flags Information about what to return.  May be any combination
+     * of {@link #RECENT_WITH_EXCLUDED} and {@link #RECENT_IGNORE_UNAVAILABLE}.
+     *
+     * @return Returns a list of RecentTaskInfo records describing each of
+     * the recent tasks.
+     *
+     * @throws SecurityException Throws SecurityException if the caller does
+     * not hold the {@link android.Manifest.permission#GET_TASKS} or the
+     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permissions.
+     * @hide
+     */
+    public List<RecentTaskInfo> getRecentTasksForUser(int maxNum, int flags, int userId)
+            throws SecurityException {
+        try {
+            return ActivityManagerNative.getDefault().getRecentTasks(maxNum,
+                    flags, userId);
         } catch (RemoteException e) {
             // System dead, we will be dead too soon!
             return null;
@@ -1840,6 +1869,18 @@
         return PackageManager.PERMISSION_DENIED;
     }
 
+    /** @hide */
+    public static int checkUidPermission(String permission, int uid) {
+        try {
+            return AppGlobals.getPackageManager()
+                    .checkUidPermission(permission, uid);
+        } catch (RemoteException e) {
+            // Should never happen, but if it does... deny!
+            Slog.e(TAG, "PackageManager is dead?!?", e);
+        }
+        return PackageManager.PERMISSION_DENIED;
+    }
+
     /**
      * Returns the usage statistics of each installed package.
      *
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index e12fa19..88e7344 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -39,6 +39,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.StrictMode;
+import android.os.UserId;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Singleton;
@@ -135,6 +136,31 @@
             return true;
         }
 
+        case START_ACTIVITY_AS_USER_TRANSACTION:
+        {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder b = data.readStrongBinder();
+            IApplicationThread app = ApplicationThreadNative.asInterface(b);
+            Intent intent = Intent.CREATOR.createFromParcel(data);
+            String resolvedType = data.readString();
+            IBinder resultTo = data.readStrongBinder();
+            String resultWho = data.readString();
+            int requestCode = data.readInt();
+            int startFlags = data.readInt();
+            String profileFile = data.readString();
+            ParcelFileDescriptor profileFd = data.readInt() != 0
+                    ? data.readFileDescriptor() : null;
+            Bundle options = data.readInt() != 0
+                    ? Bundle.CREATOR.createFromParcel(data) : null;
+            int userId = data.readInt();
+            int result = startActivityAsUser(app, intent, resolvedType,
+                    resultTo, resultWho, requestCode, startFlags,
+                    profileFile, profileFd, options, userId);
+            reply.writeNoException();
+            reply.writeInt(result);
+            return true;
+        }
+
         case START_ACTIVITY_AND_WAIT_TRANSACTION:
         {
             data.enforceInterface(IActivityManager.descriptor);
@@ -454,8 +480,9 @@
             data.enforceInterface(IActivityManager.descriptor);
             int maxNum = data.readInt();
             int fl = data.readInt();
+            int userId = data.readInt();
             List<ActivityManager.RecentTaskInfo> list = getRecentTasks(maxNum,
-                    fl);
+                    fl, userId);
             reply.writeNoException();
             reply.writeTypedList(list);
             return true;
@@ -1764,6 +1791,42 @@
         data.recycle();
         return result;
     }
+
+    public int startActivityAsUser(IApplicationThread caller, Intent intent,
+            String resolvedType, IBinder resultTo, String resultWho, int requestCode,
+            int startFlags, String profileFile,
+            ParcelFileDescriptor profileFd, Bundle options, int userId) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
+        intent.writeToParcel(data, 0);
+        data.writeString(resolvedType);
+        data.writeStrongBinder(resultTo);
+        data.writeString(resultWho);
+        data.writeInt(requestCode);
+        data.writeInt(startFlags);
+        data.writeString(profileFile);
+        if (profileFd != null) {
+            data.writeInt(1);
+            profileFd.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+        } else {
+            data.writeInt(0);
+        }
+        if (options != null) {
+            data.writeInt(1);
+            options.writeToParcel(data, 0);
+        } else {
+            data.writeInt(0);
+        }
+        data.writeInt(userId);
+        mRemote.transact(START_ACTIVITY_AS_USER_TRANSACTION, data, reply, 0);
+        reply.readException();
+        int result = reply.readInt();
+        reply.recycle();
+        data.recycle();
+        return result;
+    }
     public WaitResult startActivityAndWait(IApplicationThread caller, Intent intent,
             String resolvedType, IBinder resultTo, String resultWho,
             int requestCode, int startFlags, String profileFile,
@@ -2163,12 +2226,13 @@
         return list;
     }
     public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
-            int flags) throws RemoteException {
+            int flags, int userId) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeInt(maxNum);
         data.writeInt(flags);
+        data.writeInt(userId);
         mRemote.transact(GET_RECENT_TASKS_TRANSACTION, data, reply, 0);
         reply.readException();
         ArrayList<ActivityManager.RecentTaskInfo> list
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 9aa2505..9a50a41 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -972,24 +972,12 @@
     }
 
     @Override
-    public void installPackageWithOrigin(Uri packageURI, IPackageInstallObserver observer,
-            int flags, String installerPackageName, Uri originatingURI, Uri referrer) {
-        try {
-            mPM.installPackageWithOrigin(packageURI, observer, flags, null, originatingURI,
-                    referrer);
-        } catch (RemoteException e) {
-            // Should never happen!
-        }
-    }
-
-    @Override
     public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,
             int flags, String installerPackageName, Uri verificationURI,
-            ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams,
-            Uri originatingURI, Uri referrer) {
+            ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {
         try {
             mPM.installPackageWithVerification(packageURI, observer, flags, installerPackageName,
-                    verificationURI, manifestDigest, encryptionParams, originatingURI, referrer);
+                    verificationURI, manifestDigest, encryptionParams);
         } catch (RemoteException e) {
             // Should never happen!
         }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 3c8a290..d886278 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -893,6 +893,18 @@
         startActivity(intent, null);
     }
 
+    /** @hide */
+    @Override
+    public void startActivityAsUser(Intent intent, int userId) {
+        try {
+            ActivityManagerNative.getDefault().startActivityAsUser(
+                mMainThread.getApplicationThread(), intent,
+                intent.resolveTypeIfNeeded(getContentResolver()),
+                null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, null, null, userId);
+        } catch (RemoteException re) {
+        }
+    }
+
     @Override
     public void startActivity(Intent intent, Bundle options) {
         if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
@@ -967,18 +979,6 @@
     }
 
     @Override
-    public void sendBroadcastToUser(Intent intent, int userId) {
-        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
-        try {
-            intent.setAllowFds(false);
-            ActivityManagerNative.getDefault().broadcastIntent(mMainThread.getApplicationThread(),
-                    intent, resolvedType, null, Activity.RESULT_OK, null, null, null, false, false,
-                    userId);
-        } catch (RemoteException e) {
-        }
-    }
-
-    @Override
     public void sendBroadcast(Intent intent, String receiverPermission) {
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
@@ -1039,6 +1039,50 @@
     }
 
     @Override
+    public void sendBroadcastToUser(Intent intent, int userHandle) {
+        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+        try {
+            intent.setAllowFds(false);
+            ActivityManagerNative.getDefault().broadcastIntent(mMainThread.getApplicationThread(),
+                    intent, resolvedType, null, Activity.RESULT_OK, null, null, null, false, false,
+                    userHandle);
+        } catch (RemoteException e) {
+        }
+    }
+
+    @Override
+    public void sendOrderedBroadcastToUser(Intent intent, int userHandle,
+            BroadcastReceiver resultReceiver, Handler scheduler,
+            int initialCode, String initialData, Bundle initialExtras) {
+        IIntentReceiver rd = null;
+        if (resultReceiver != null) {
+            if (mPackageInfo != null) {
+                if (scheduler == null) {
+                    scheduler = mMainThread.getHandler();
+                }
+                rd = mPackageInfo.getReceiverDispatcher(
+                    resultReceiver, getOuterContext(), scheduler,
+                    mMainThread.getInstrumentation(), false);
+            } else {
+                if (scheduler == null) {
+                    scheduler = mMainThread.getHandler();
+                }
+                rd = new LoadedApk.ReceiverDispatcher(
+                        resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();
+            }
+        }
+        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+        try {
+            intent.setAllowFds(false);
+            ActivityManagerNative.getDefault().broadcastIntent(
+                mMainThread.getApplicationThread(), intent, resolvedType, rd,
+                initialCode, initialData, initialExtras, null,
+                true, false, userHandle);
+        } catch (RemoteException e) {
+        }
+    }
+
+    @Override
     public void sendStickyBroadcast(Intent intent) {
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
@@ -1197,7 +1241,7 @@
 
     /** @hide */
     @Override
-    public boolean bindService(Intent service, ServiceConnection conn, int flags, int userId) {
+    public boolean bindService(Intent service, ServiceConnection conn, int flags, int userHandle) {
         IServiceConnection sd;
         if (conn == null) {
             throw new IllegalArgumentException("connection is null");
@@ -1219,7 +1263,7 @@
             int res = ActivityManagerNative.getDefault().bindService(
                 mMainThread.getApplicationThread(), getActivityToken(),
                 service, service.resolveTypeIfNeeded(getContentResolver()),
-                sd, flags, userId);
+                sd, flags, userHandle);
             if (res < 0) {
                 throw new SecurityException(
                         "Not allowed to bind to service " + service);
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 17700f9..0b1c524 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -344,6 +344,13 @@
          */
         public static final int NETWORK_WIFI = 1 << 1;
 
+        /**
+         * Bit flag for {@link #setAllowedNetworkTypes} corresponding to
+         * {@link ConnectivityManager#TYPE_BLUETOOTH}.
+         * @hide
+         */
+        public static final int NETWORK_BLUETOOTH = 1 << 2;
+
         private Uri mUri;
         private Uri mDestinationUri;
         private List<Pair<String, String>> mRequestHeaders = new ArrayList<Pair<String, String>>();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 031e39b..a6d1995 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -55,6 +55,10 @@
             Intent intent, String resolvedType, IBinder resultTo, String resultWho,
             int requestCode, int flags, String profileFile,
             ParcelFileDescriptor profileFd, Bundle options) throws RemoteException;
+    public int startActivityAsUser(IApplicationThread caller,
+            Intent intent, String resolvedType, IBinder resultTo, String resultWho,
+            int requestCode, int flags, String profileFile,
+            ParcelFileDescriptor profileFd, Bundle options, int userId) throws RemoteException;
     public WaitResult startActivityAndWait(IApplicationThread caller,
             Intent intent, String resolvedType, IBinder resultTo, String resultWho,
             int requestCode, int flags, String profileFile,
@@ -102,7 +106,7 @@
     public List getTasks(int maxNum, int flags,
                          IThumbnailReceiver receiver) throws RemoteException;
     public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
-            int flags) throws RemoteException;
+            int flags, int userId) throws RemoteException;
     public ActivityManager.TaskThumbnails getTaskThumbnails(int taskId) throws RemoteException;
     public List getServices(int maxNum, int flags) throws RemoteException;
     public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState()
@@ -606,4 +610,5 @@
     int GET_LAUNCHED_FROM_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+149;
     int UNSTABLE_PROVIDER_DIED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+150;
     int IS_INTENT_SENDER_AN_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+151;
+    int START_ACTIVITY_AS_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+152;
 }
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index 5c315ce..204f963 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -231,6 +231,19 @@
         }
     }
 
+    /** See {@link ContentProvider#call(String, String, Bundle)} */
+    public Bundle call(String method, String arg, Bundle extras)
+            throws RemoteException {
+        try {
+            return mContentProvider.call(method, arg, extras);
+        } catch (DeadObjectException e) {
+            if (!mStable) {
+                mContentResolver.unstableProviderDied(mContentProvider);
+            }
+            throw e;
+        }
+    }
+
     /**
      * Call this to indicate to the system that the associated {@link ContentProvider} is no
      * longer needed by this {@link ContentProviderClient}.
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index af8b213..5a7a989 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -851,6 +851,18 @@
     public abstract void startActivity(Intent intent);
 
     /**
+     * Same as {@link #startActivity(Intent)}, but for a specific user. It requires holding
+     * the {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission.
+     * @param intent The description of the activity to start.
+     * @param userId The user id of the user to start this activity for.
+     * @throws ActivityNotFoundException
+     * @hide
+     */
+    public void startActivityAsUser(Intent intent, int userId) {
+        throw new RuntimeException("Not implemented. Must override in a subclass.");
+    }
+
+    /**
      * Launch a new activity.  You will not receive any information about when
      * the activity exits.
      *
@@ -988,18 +1000,6 @@
     public abstract void sendBroadcast(Intent intent);
 
     /**
-     * Same as #sendBroadcast(Intent intent), but for a specific user.  This broadcast
-     * can only be sent to receivers that are part of the calling application.  It
-     * requires holding the {@link android.Manifest.permission#INTERACT_ACROSS_USERS}
-     * permission.
-     * @param intent the intent to broadcast
-     * @param userId user to send the intent to
-     */
-    public void sendBroadcastToUser(Intent intent, int userId) {
-        throw new RuntimeException("Not implemented. Must override in a subclass.");
-    }
-
-    /**
      * Broadcast the given intent to all interested BroadcastReceivers, allowing
      * an optional required permission to be enforced.  This
      * call is asynchronous; it returns immediately, and you will continue
@@ -1097,6 +1097,48 @@
             Bundle initialExtras);
 
     /**
+     * Same as {@link #sendBroadcast(Intent)}, but for a specific user.  This broadcast
+     * can only be sent to receivers that are part of the calling application.  It
+     * requires holding the {@link android.Manifest.permission#INTERACT_ACROSS_USERS}
+     * permission.
+     * @param intent The intent to broadcast
+     * @param userHandle User to send the intent to.
+     * @see #sendBroadcast(Intent)
+     */
+    public abstract void sendBroadcastToUser(Intent intent, int userHandle);
+
+    /**
+     * Same as
+     * {@link #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)},
+     * but for a specific user.  This broadcast
+     * can only be sent to receivers that are part of the calling application.  It
+     * requires holding the {@link android.Manifest.permission#INTERACT_ACROSS_USERS}
+     * permission.
+     *
+     * <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.
+     *
+     * @param intent The Intent to broadcast; all receivers matching this
+     *               Intent will receive the broadcast.
+     * @param userHandle User to send the intent to.
+     * @param resultReceiver Your own BroadcastReceiver to treat as the final
+     *                       receiver of the broadcast.
+     * @param scheduler A custom Handler with which to schedule the
+     *                  resultReceiver callback; if null it will be
+     *                  scheduled in the Context's main thread.
+     * @param initialCode An initial value for the result code.  Often
+     *                    Activity.RESULT_OK.
+     * @param initialData An initial value for the result data.  Often
+     *                    null.
+     * @param initialExtras An initial value for the result extras.  Often
+     *                      null.
+     *
+     * @see #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
+     */
+    public abstract void sendOrderedBroadcastToUser(Intent intent, int userHandle,
+            BroadcastReceiver resultReceiver, Handler scheduler,
+            int initialCode, String initialData, Bundle initialExtras);
+
+    /**
      * Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the
      * Intent you are sending stays around after the broadcast is complete,
      * so that others can quickly retrieve that data through the return
@@ -1403,11 +1445,11 @@
             int flags);
 
     /**
-     * Same as {@link #bindService(Intent, ServiceConnection, int)}, but with an explicit userId
+     * Same as {@link #bindService(Intent, ServiceConnection, int)}, but with an explicit userHandle
      * argument for use by system server and other multi-user aware code.
      * @hide
      */
-    public boolean bindService(Intent service, ServiceConnection conn, int flags, int userId) {
+    public boolean bindService(Intent service, ServiceConnection conn, int flags, int userHandle) {
         throw new RuntimeException("Not implemented. Must override in a subclass.");
     }
 
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 7738132..f007720 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -276,6 +276,12 @@
         mBase.startActivity(intent);
     }
 
+    /** @hide */
+    @Override
+    public void startActivityAsUser(Intent intent, int userId) {
+        mBase.startActivityAsUser(intent, userId);
+    }
+
     @Override
     public void startActivity(Intent intent, Bundle options) {
         mBase.startActivity(intent, options);
@@ -313,11 +319,6 @@
     }
 
     @Override
-    public void sendBroadcastToUser(Intent intent, int userId) {
-        mBase.sendBroadcastToUser(intent, userId);
-    }
-
-    @Override
     public void sendBroadcast(Intent intent, String receiverPermission) {
         mBase.sendBroadcast(intent, receiverPermission);
     }
@@ -339,6 +340,19 @@
     }
 
     @Override
+    public void sendBroadcastToUser(Intent intent, int userHandle) {
+        mBase.sendBroadcastToUser(intent, userHandle);
+    }
+
+    @Override
+    public void sendOrderedBroadcastToUser(Intent intent, int userHandle,
+            BroadcastReceiver resultReceiver, Handler scheduler,
+            int initialCode, String initialData, Bundle initialExtras) {
+        mBase.sendOrderedBroadcastToUser(intent, userHandle, resultReceiver,
+                scheduler, initialCode, initialData, initialExtras);
+    }
+
+    @Override
     public void sendStickyBroadcast(Intent intent) {
         mBase.sendStickyBroadcast(intent);
     }
@@ -395,8 +409,8 @@
 
     /** @hide */
     @Override
-    public boolean bindService(Intent service, ServiceConnection conn, int flags, int userId) {
-        return mBase.bindService(service, conn, flags, userId);
+    public boolean bindService(Intent service, ServiceConnection conn, int flags, int userHandle) {
+        return mBase.bindService(service, conn, flags, userHandle);
     }
 
     @Override
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 6d2de8e..d325186 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -571,7 +571,7 @@
  *     <li> {@link #EXTRA_INITIAL_INTENTS}
  *     <li> {@link #EXTRA_INTENT}
  *     <li> {@link #EXTRA_KEY_EVENT}
- *     <li> {@link #EXTRA_ORIGINATING_URI}
+ *     <li> {@link #EXTRA_ORIGINATING_URL}
  *     <li> {@link #EXTRA_PHONE_NUMBER}
  *     <li> {@link #EXTRA_REFERRER}
  *     <li> {@link #EXTRA_REMOTE_INTENT_TOKEN}
@@ -1288,17 +1288,17 @@
             = "android.intent.extra.NOT_UNKNOWN_SOURCE";
 
     /**
-     * Used as a URI extra field with {@link #ACTION_INSTALL_PACKAGE} and
-     * {@link #ACTION_VIEW} to indicate the URI from which the local APK in the Intent
+     * Used as a string extra field with {@link #ACTION_INSTALL_PACKAGE} and
+     * {@link #ACTION_VIEW} to indicate the URL from which the local APK in the Intent
      * data field originated from.
      */
-    public static final String EXTRA_ORIGINATING_URI
-            = "android.intent.extra.ORIGINATING_URI";
+    public static final String EXTRA_ORIGINATING_URL
+            = "android.intent.extra.ORIGINATING_URL";
 
     /**
-     * Used as a URI extra field with {@link #ACTION_INSTALL_PACKAGE} and
-     * {@link #ACTION_VIEW} to indicate the HTTP referrer URI associated with the Intent
-     * data field or {@link #EXTRA_ORIGINATING_URI}.
+     * Used as a string extra field with {@link #ACTION_INSTALL_PACKAGE} and
+     * {@link #ACTION_VIEW} to indicate the HTTP referrer associated with the Intent
+     * data field or {@link #EXTRA_ORIGINATING_URL}.
      */
     public static final String EXTRA_REFERRER
             = "android.intent.extra.REFERRER";
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 35e5610..3035729 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -172,6 +172,14 @@
      */
     public static final int FLAG_IMMERSIVE = 0x0400;
     /**
+     * Bit in {@link #flags}: If set, a single instance of the receiver will
+     * run for all users on the device.  Set from the
+     * {@link android.R.attr#singleUser} attribute.  Note that this flag is
+     * only relevent for ActivityInfo structures that are describiner receiver
+     * components; it is not applied to activities.
+     */
+    public static final int FLAG_SINGLE_USER = 0x40000000;
+    /**
      * Options that have been set in the activity declaration in the
      * manifest.
      * These include:
@@ -181,7 +189,7 @@
      * {@link #FLAG_STATE_NOT_NEEDED}, {@link #FLAG_EXCLUDE_FROM_RECENTS},
      * {@link #FLAG_ALLOW_TASK_REPARENTING}, {@link #FLAG_NO_HISTORY},
      * {@link #FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS},
-     * {@link #FLAG_HARDWARE_ACCELERATED}
+     * {@link #FLAG_HARDWARE_ACCELERATED}, {@link #FLAG_SINGLE_USER}.
      */
     public int flags;
 
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 1b28a33..0d87df5 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -352,7 +352,7 @@
     String nextPackageToClean(String lastPackage);
 
     void movePackage(String packageName, IPackageMoveObserver observer, int flags);
-
+    
     boolean addPermissionAsync(in PermissionInfo info);
 
     boolean setInstallLocation(int loc);
@@ -363,14 +363,9 @@
     void setUserName(int userId, String name);
     ParcelFileDescriptor setUserIcon(int userId);
 
-    void installPackageWithOrigin(in Uri packageURI, in IPackageInstallObserver observer,
-            int flags, in String installerPackageName, in Uri originatingURI,
-            in Uri referrer);
-
     void installPackageWithVerification(in Uri packageURI, in IPackageInstallObserver observer,
             int flags, in String installerPackageName, in Uri verificationURI,
-            in ManifestDigest manifestDigest, in ContainerEncryptionParams encryptionParams,
-            in Uri originatingURI, in Uri referrer);
+            in ManifestDigest manifestDigest, in ContainerEncryptionParams encryptionParams);
 
     void verifyPendingInstall(int id, int verificationCode);
 
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index f745c89..cd7ef0e 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2196,33 +2196,6 @@
     /**
      * Similar to
      * {@link #installPackage(Uri, IPackageInstallObserver, int, String)} but
-     * with references to the location of where the package originated from.
-     *
-     * @param packageURI The location of the package file to install. This can
-     *            be a 'file:' or a 'content:' URI.
-     * @param observer An observer callback to get notified when the package
-     *            installation is complete.
-     *            {@link IPackageInstallObserver#packageInstalled(String, int)}
-     *            will be called when that happens. observer may be null to
-     *            indicate that no callback is desired.
-     * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK},
-     *            {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}
-     * @param installerPackageName Optional package name of the application that
-     *            is performing the installation. This identifies which market
-     *            the package came from.
-     * @param originatingURI URI referencing where the package was downloaded
-     *            from. May be {@code null}.
-     * @param referrer HTTP referrer URI associated with the originatingURI.
-     *            May be {@code null}.
-     * @hide
-     */
-    public abstract void installPackageWithOrigin(
-            Uri packageURI, IPackageInstallObserver observer, int flags,
-            String installerPackageName, Uri originatingURI, Uri referrer);
-
-    /**
-     * Similar to
-     * {@link #installPackage(Uri, IPackageInstallObserver, int, String)} but
      * with an extra verification file provided.
      *
      * @param packageURI The location of the package file to install. This can
@@ -2246,17 +2219,12 @@
      * @param encryptionParams if the package to be installed is encrypted,
      *            these parameters describing the encryption and authentication
      *            used. May be {@code null}.
-     * @param originatingURI URI referencing where the package was downloaded
-     *            from. May be {@code null}.
-     * @param referrer HTTP referrer URI associated with the originatingURI.
-     *            May be {@code null}.
      * @hide
      */
     public abstract void installPackageWithVerification(Uri packageURI,
             IPackageInstallObserver observer, int flags, String installerPackageName,
             Uri verificationURI, ManifestDigest manifestDigest,
-            ContainerEncryptionParams encryptionParams, Uri originatingURI,
-            Uri referrer);
+            ContainerEncryptionParams encryptionParams);
 
     /**
      * Allows a package listening to the
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 3ce7c78..d906401 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2040,7 +2040,7 @@
             return null;
         }
 
-        final boolean setExported = sa.hasValue(
+        boolean setExported = sa.hasValue(
                 com.android.internal.R.styleable.AndroidManifestActivity_exported);
         if (setExported) {
             a.info.exported = sa.getBoolean(
@@ -2166,6 +2166,21 @@
             a.info.configChanges = 0;
         }
 
+        if (receiver) {
+            if (sa.getBoolean(
+                    com.android.internal.R.styleable.AndroidManifestActivity_singleUser,
+                    false)) {
+                a.info.flags |= ServiceInfo.FLAG_SINGLE_USER;
+                if (a.info.exported) {
+                    Slog.w(TAG, "Activity exported request ignored due to singleUser: "
+                            + a.className + " at " + mArchiveSourcePath + " "
+                            + parser.getPositionDescription());
+                    a.info.exported = false;
+                }
+                setExported = true;
+            }
+        }
+
         sa.recycle();
 
         if (receiver && (owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
@@ -2428,8 +2443,18 @@
             return null;
         }
 
+        boolean providerExportedDefault = false;
+
+        if (owner.applicationInfo.targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            // For compatibility, applications targeting API level 16 or lower
+            // should have their content providers exported by default, unless they
+            // specify otherwise.
+            providerExportedDefault = true;
+        }
+
         p.info.exported = sa.getBoolean(
-                com.android.internal.R.styleable.AndroidManifestProvider_exported, true);
+                com.android.internal.R.styleable.AndroidManifestProvider_exported,
+                providerExportedDefault);
 
         String cpname = sa.getNonConfigurationString(
                 com.android.internal.R.styleable.AndroidManifestProvider_authorities, 0);
@@ -2475,6 +2500,20 @@
                 com.android.internal.R.styleable.AndroidManifestProvider_initOrder,
                 0);
 
+        p.info.flags = 0;
+
+        if (sa.getBoolean(
+                com.android.internal.R.styleable.AndroidManifestProvider_singleUser,
+                false)) {
+            p.info.flags |= ProviderInfo.FLAG_SINGLE_USER;
+            if (p.info.exported) {
+                Slog.w(TAG, "Provider exported request ignored due to singleUser: "
+                        + p.className + " at " + mArchiveSourcePath + " "
+                        + parser.getPositionDescription());
+                p.info.exported = false;
+            }
+        }
+
         sa.recycle();
 
         if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
@@ -2487,7 +2526,7 @@
         }
         
         if (cpname == null) {
-            outError[0] = "<provider> does not incude authorities attribute";
+            outError[0] = "<provider> does not include authorities attribute";
             return null;
         }
         p.info.authority = cpname.intern();
diff --git a/core/java/android/content/pm/ProviderInfo.java b/core/java/android/content/pm/ProviderInfo.java
index ec01775..a534176 100644
--- a/core/java/android/content/pm/ProviderInfo.java
+++ b/core/java/android/content/pm/ProviderInfo.java
@@ -73,7 +73,21 @@
     /** Used to control initialization order of single-process providers
      *  running in the same process.  Higher goes first. */
     public int initOrder = 0;
-    
+
+    /**
+     * Bit in {@link #flags}: If set, a single instance of the provider will
+     * run for all users on the device.  Set from the
+     * {@link android.R.attr#singleUser} attribute.
+     */
+    public static final int FLAG_SINGLE_USER = 0x40000000;
+
+    /**
+     * Options that have been set in the provider declaration in the
+     * manifest.
+     * These include: {@link #FLAG_SINGLE_USER}.
+     */
+    public int flags = 0;
+
     /**
      * Whether or not this provider is syncable.
      * @deprecated This flag is now being ignored. The current way to make a provider
@@ -95,6 +109,7 @@
         pathPermissions = orig.pathPermissions;
         multiprocess = orig.multiprocess;
         initOrder = orig.initOrder;
+        flags = orig.flags;
         isSyncable = orig.isSyncable;
     }
     
@@ -112,6 +127,7 @@
         out.writeTypedArray(pathPermissions, parcelableFlags);
         out.writeInt(multiprocess ? 1 : 0);
         out.writeInt(initOrder);
+        out.writeInt(flags);
         out.writeInt(isSyncable ? 1 : 0);
     }
 
@@ -127,8 +143,7 @@
     };
 
     public String toString() {
-        return "ContentProviderInfo{name=" + authority + " className=" + name
-            + " isSyncable=" + (isSyncable ? "true" : "false") + "}";
+        return "ContentProviderInfo{name=" + authority + " className=" + name + "}";
     }
 
     private ProviderInfo(Parcel in) {
@@ -141,6 +156,7 @@
         pathPermissions = in.createTypedArray(PathPermission.CREATOR);
         multiprocess = in.readInt() != 0;
         initOrder = in.readInt();
+        flags = in.readInt();
         isSyncable = in.readInt() != 0;
     }
 }
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index 1aaceb4..796c2a4 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -53,13 +53,14 @@
      * run for all users on the device.  Set from the
      * {@link android.R.attr#singleUser} attribute.
      */
-    public static final int FLAG_SINGLE_USER = 0x0004;
+    public static final int FLAG_SINGLE_USER = 0x40000000;
 
     /**
      * Options that have been set in the service declaration in the
      * manifest.
      * These include:
-     * {@link #FLAG_STOP_WITH_TASK}, {@link #FLAG_ISOLATED_PROCESS}.
+     * {@link #FLAG_STOP_WITH_TASK}, {@link #FLAG_ISOLATED_PROCESS},
+     * {@link #FLAG_SINGLE_USER}.
      */
     public int flags;
 
diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java
index fb04817..e7ff92d 100644
--- a/core/java/android/database/AbstractCursor.java
+++ b/core/java/android/database/AbstractCursor.java
@@ -424,6 +424,9 @@
         if (mSelfObserver != null && mSelfObserverRegistered == true) {
             mContentResolver.unregisterContentObserver(mSelfObserver);
         }
+        try {
+            if (!mClosed) close();
+        } catch(Exception e) { }
     }
 
     /**
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 7cf869c..8860e0a 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -414,6 +414,15 @@
 
         /**
          * Moar jelly beans!
+         *
+         * <p>Applications targeting this or a later release will get these
+         * new changes in behavior:</p>
+         * <ul>
+         * <li>Content Providers: The default value of {@code android:exported} is now
+         * {@code false}. See
+         * <a href="{@docRoot}guide/topics/manifest/provider-element.html#exported">
+         * the android:exported section</a> in the provider documentation for more details.</li>
+         * </ul>
          */
         public static final int JELLY_BEAN_MR1 = 17;
     }
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index a04ad93..93860aa 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -640,11 +640,24 @@
     public static final native int myTid();
 
     /**
-     * Returns the identifier of this process's user.
+     * Returns the identifier of this process's uid.  This is the kernel uid
+     * that the process is running under, which is the identity of its
+     * app-specific sandbox.  It is different from {@link #myUserHandle} in that
+     * a uid identifies a specific app sandbox in a specific user.
      */
     public static final native int myUid();
 
     /**
+     * Returns the identifier of this process's user handle.  This is the
+     * user the process is running under.  It is distinct from
+     * {@link #myUid()} in that a particular user will have multiple
+     * distinct apps running under it each with their own uid.
+     */
+    public static final int myUserHandle() {
+        return UserId.getUserId(myUid());
+    }
+
+    /**
      * Returns whether the current process is in an isolated sandbox.
      * @hide
      */
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index ce213fb..f682abe 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -407,17 +407,17 @@
             }
 
             /**
-             * Enable detection of disk reads.
+             * Enable detection of slow calls.
              */
             public Builder detectCustomSlowCalls() {
                 return enable(DETECT_CUSTOM);
             }
 
             /**
-             * Enable detection of disk reads.
+             * Disable detection of slow calls.
              */
             public Builder permitCustomSlowCalls() {
-                return enable(DETECT_CUSTOM);
+                return disable(DETECT_CUSTOM);
             }
 
             /**
diff --git a/core/java/android/os/SystemService.java b/core/java/android/os/SystemService.java
index da27db5..db58012 100644
--- a/core/java/android/os/SystemService.java
+++ b/core/java/android/os/SystemService.java
@@ -16,15 +16,53 @@
 
 package android.os;
 
-/** @hide */
-public class SystemService
-{
-        /** Request that the init daemon start a named service. */
+import com.google.android.collect.Maps;
+
+import java.util.HashMap;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Controls and utilities for low-level {@code init} services.
+ *
+ * @hide
+ */
+public class SystemService {
+
+    private static HashMap<String, State> sStates = Maps.newHashMap();
+
+    /**
+     * State of a known {@code init} service.
+     */
+    public enum State {
+        RUNNING("running"),
+        STOPPING("stopping"),
+        STOPPED("stopped"),
+        RESTARTING("restarting");
+
+        State(String state) {
+            sStates.put(state, this);
+        }
+    }
+
+    private static Object sPropertyLock = new Object();
+
+    static {
+        SystemProperties.addChangeCallback(new Runnable() {
+            @Override
+            public void run() {
+                synchronized (sPropertyLock) {
+                    sPropertyLock.notifyAll();
+                }
+            }
+        });
+    }
+
+    /** Request that the init daemon start a named service. */
     public static void start(String name) {
         SystemProperties.set("ctl.start", name);
     }
-    
-        /** Request that the init daemon stop a named service. */
+
+    /** Request that the init daemon stop a named service. */
     public static void stop(String name) {
         SystemProperties.set("ctl.stop", name);
     }
@@ -33,4 +71,77 @@
     public static void restart(String name) {
         SystemProperties.set("ctl.restart", name);
     }
+
+    /**
+     * Return current state of given service.
+     */
+    public static State getState(String service) {
+        final String rawState = SystemProperties.get("init.svc." + service);
+        final State state = sStates.get(rawState);
+        if (state != null) {
+            return state;
+        } else {
+            throw new IllegalStateException("Service " + service + " in unknown state " + rawState);
+        }
+    }
+
+    /**
+     * Check if given service is {@link State#STOPPED}.
+     */
+    public static boolean isStopped(String service) {
+        return State.STOPPED.equals(getState(service));
+    }
+
+    /**
+     * Check if given service is {@link State#RUNNING}.
+     */
+    public static boolean isRunning(String service) {
+        return State.RUNNING.equals(getState(service));
+    }
+
+    /**
+     * Wait until given service has entered specific state.
+     */
+    public static void waitForState(String service, State state, long timeoutMillis)
+            throws TimeoutException {
+        final long endMillis = SystemClock.elapsedRealtime() + timeoutMillis;
+        while (true) {
+            synchronized (sPropertyLock) {
+                final State currentState = getState(service);
+                if (state.equals(currentState)) {
+                    return;
+                }
+
+                if (SystemClock.elapsedRealtime() >= endMillis) {
+                    throw new TimeoutException("Service " + service + " currently " + currentState
+                            + "; waited " + timeoutMillis + "ms for " + state);
+                }
+
+                try {
+                    sPropertyLock.wait(timeoutMillis);
+                } catch (InterruptedException e) {
+                }
+            }
+        }
+    }
+
+    /**
+     * Wait until any of given services enters {@link State#STOPPED}.
+     */
+    public static void waitForAnyStopped(String... services)  {
+        while (true) {
+            synchronized (sPropertyLock) {
+                for (String service : services) {
+                    if (State.STOPPED.equals(getState(service))) {
+                        return;
+                    }
+                }
+
+                try {
+                    sPropertyLock.wait();
+                } catch (InterruptedException e) {
+                }
+            }
+        }
+    }
 }
diff --git a/core/java/android/os/UserId.java b/core/java/android/os/UserId.java
index 8bf6c6e..7e611df 100644
--- a/core/java/android/os/UserId.java
+++ b/core/java/android/os/UserId.java
@@ -27,8 +27,13 @@
      */
     public static final int PER_USER_RANGE = 100000;
 
+    /** A user id to indicate all users on the device */
     public static final int USER_ALL = -1;
 
+    /** A user id to indicate the currently active user */
+    public static final int USER_CURRENT = -2;
+
+
     /**
      * Enable multi-user related side effects. Set this to false if there are problems with single
      * user usecases.
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 8e123ac..0c16565 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -345,10 +345,10 @@
      * directory provider URIs by themselves. This level of indirection allows
      * Contacts Provider to implement additional system-level features and
      * optimizations. Access to Contacts Provider is protected by the
-     * READ_CONTACTS permission, but access to the directory provider is not.
-     * Therefore directory providers must reject requests coming from clients
-     * other than the Contacts Provider itself. An easy way to prevent such
-     * unauthorized access is to check the name of the calling package:
+     * READ_CONTACTS permission, but access to the directory provider is protected by
+     * BIND_DIRECTORY_SEARCH. This permission was introduced at the API level 17, for previous
+     * platform versions the provider should perform the following check to make sure the call
+     * is coming from the ContactsProvider:
      * <pre>
      * private boolean isCallerAllowed() {
      *   PackageManager pm = getContext().getPackageManager();
diff --git a/core/java/android/service/dreams/DreamManagerService.java b/core/java/android/service/dreams/DreamManagerService.java
index d6b38a1..dd177cb 100644
--- a/core/java/android/service/dreams/DreamManagerService.java
+++ b/core/java/android/service/dreams/DreamManagerService.java
@@ -5,8 +5,6 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
-import com.android.internal.view.IInputMethod;
-
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -16,34 +14,32 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.SystemClock;
 import android.provider.Settings;
-import android.util.Log;
 import android.util.Slog;
 import android.view.IWindowManager;
 import android.view.WindowManager;
 
 /**
- * 
+ *
  * @hide
  *
  */
 
-public class DreamManagerService 
-        extends IDreamManager.Stub 
+public class DreamManagerService
+        extends IDreamManager.Stub
         implements ServiceConnection
 {
     private static final boolean DEBUG = true;
     private static final String TAG = "DreamManagerService";
-    
+
     final Object mLock = new Object[0];
 
     private Context mContext;
     private IWindowManager mIWindowManager;
-    
+
     private ComponentName mCurrentDreamComponent;
     private IDreamService mCurrentDream;
-    private Binder mCurrentDreamToken; 
+    private Binder mCurrentDreamToken;
 
     public DreamManagerService(Context context) {
         if (DEBUG) Slog.v(TAG, "DreamManagerService startup");
@@ -60,6 +56,7 @@
     }
 
     // IDreamManager method
+    @Override
     public void dream() {
         ComponentName name = getDreamComponent();
         if (name != null) {
@@ -75,26 +72,26 @@
     }
 
     // IDreamManager method
+    @Override
     public void setDreamComponent(ComponentName name) {
         Settings.Secure.putString(mContext.getContentResolver(), SCREENSAVER_COMPONENT, name.flattenToString());
     }
-    
+
     // IDreamManager method
+    @Override
     public ComponentName getDreamComponent() {
-        // TODO(dsandler) don't load this every time, watch the value  
+        // TODO(dsandler) don't load this every time, watch the value
         String component = Settings.Secure.getString(mContext.getContentResolver(), SCREENSAVER_COMPONENT);
-        if (component == null) {
-            component = mContext.getResources().getString(
-                com.android.internal.R.string.config_defaultDreamComponent);
-        }
         if (component != null) {
             return ComponentName.unflattenFromString(component);
         } else {
+            // We rely on DatabaseHelper to set a sane default for us when the settings DB is upgraded
             return null;
         }
     }
-    
+
     // IDreamManager method
+    @Override
     public void testDream(ComponentName name) {
         if (DEBUG) Slog.v(TAG, "startDream name=" + name
                 + " pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
@@ -110,6 +107,7 @@
     }
 
     // IDreamManager method
+    @Override
     public void awaken() {
         if (DEBUG) Slog.v(TAG, "awaken()");
         synchronized (mLock) {
@@ -123,6 +121,7 @@
     }
 
     // IDreamManager method
+    @Override
     public boolean isDreaming() {
         return mCurrentDream != null;
     }
@@ -141,14 +140,14 @@
         mCurrentDreamComponent = componentName;
         mCurrentDreamToken = new Binder();
         try {
-            if (DEBUG) Slog.v(TAG, "Adding window token: " + mCurrentDreamToken 
+            if (DEBUG) Slog.v(TAG, "Adding window token: " + mCurrentDreamToken
                     + " for window type: " + WindowManager.LayoutParams.TYPE_DREAM);
             mIWindowManager.addWindowToken(mCurrentDreamToken,
                     WindowManager.LayoutParams.TYPE_DREAM);
         } catch (RemoteException e) {
             Slog.w(TAG, "Unable to add window token. Proceed at your own risk.");
         }
-        
+
         if (!mContext.bindService(intent, this, Context.BIND_AUTO_CREATE)) {
             Slog.w(TAG, "unable to bind service: " + componentName);
         }
@@ -172,7 +171,7 @@
         if (DEBUG) Slog.v(TAG, "disconnected: " + name + " service: " + mCurrentDream);
         // Only happens in exceptional circumstances
     }
-    
+
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
diff --git a/core/java/android/view/GLES20RenderLayer.java b/core/java/android/view/GLES20RenderLayer.java
index b5cfc11..a77425a 100644
--- a/core/java/android/view/GLES20RenderLayer.java
+++ b/core/java/android/view/GLES20RenderLayer.java
@@ -82,11 +82,17 @@
     }
 
     @Override
-    void end() {
+    void end(Canvas currentCanvas) {
+        if (currentCanvas instanceof GLES20Canvas) {
+            ((GLES20Canvas) currentCanvas).resume();
+        }
     }
 
     @Override
-    HardwareCanvas start() {
+    HardwareCanvas start(Canvas currentCanvas) {
+        if (currentCanvas instanceof GLES20Canvas) {
+            ((GLES20Canvas) currentCanvas).interrupt();
+        }
         return getCanvas();
     }
 
diff --git a/core/java/android/view/GLES20TextureLayer.java b/core/java/android/view/GLES20TextureLayer.java
index 6ad36ef..e198ef6 100644
--- a/core/java/android/view/GLES20TextureLayer.java
+++ b/core/java/android/view/GLES20TextureLayer.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
@@ -56,12 +57,12 @@
     }
 
     @Override
-    HardwareCanvas start() {
+    HardwareCanvas start(Canvas currentCanvas) {
         return null;
     }
 
     @Override
-    void end() {
+    void end(Canvas currentCanvas) {
     }
 
     SurfaceTexture getSurfaceTexture() {
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index 8fdf104..06c6e7c 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import android.graphics.Bitmap;
+import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Rect;
 
@@ -143,13 +144,15 @@
 
     /**
      * This must be invoked before drawing onto this layer.
+     * @param currentCanvas
      */
-    abstract HardwareCanvas start();
+    abstract HardwareCanvas start(Canvas currentCanvas);
     
     /**
      * This must be invoked after drawing onto this layer.
+     * @param currentCanvas
      */
-    abstract void end();
+    abstract void end(Canvas currentCanvas);
 
     /**
      * Copies this layer into the specified bitmap.
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index d3457b3..f4d40cb 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -531,7 +531,7 @@
 
                     mSurface.transferFrom(mNewSurface);
 
-                    if (visible) {
+                    if (visible && mSurface.isValid()) {
                         if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
                             mSurfaceCreated = true;
                             mIsCreating = true;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 3993432..afcbaaf 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1408,6 +1408,7 @@
                         disposeResizeBuffer();
 
                         boolean completed = false;
+                        HardwareCanvas hwRendererCanvas = mAttachInfo.mHardwareRenderer.getCanvas();
                         HardwareCanvas layerCanvas = null;
                         try {
                             if (mResizeBuffer == null) {
@@ -1417,7 +1418,7 @@
                                     mResizeBuffer.getHeight() != mHeight) {
                                 mResizeBuffer.resize(mWidth, mHeight);
                             }
-                            layerCanvas = mResizeBuffer.start();
+                            layerCanvas = mResizeBuffer.start(hwRendererCanvas);
                             layerCanvas.setViewport(mWidth, mHeight);
                             layerCanvas.onPreDraw(null);
                             final int restoreCount = layerCanvas.save();
@@ -1456,7 +1457,7 @@
                                 layerCanvas.onPostDraw();
                             }
                             if (mResizeBuffer != null) {
-                                mResizeBuffer.end();
+                                mResizeBuffer.end(hwRendererCanvas);
                                 if (!completed) {
                                     mResizeBuffer.destroy();
                                     mResizeBuffer = null;
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index a28e9ff..860e583 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -985,9 +985,13 @@
     }
 
     private void updateDrawableBounds(int w, int h) {
-        // onDraw will translate the canvas so we draw starting at 0,0
-        int right = w - mPaddingRight - mPaddingLeft;
-        int bottom = h - mPaddingBottom - mPaddingTop;
+        // onDraw will translate the canvas so we draw starting at 0,0.
+        // Subtract out padding for the purposes of the calculations below.
+        w -= mPaddingRight + mPaddingLeft;
+        h -= mPaddingTop + mPaddingBottom;
+
+        int right = w;
+        int bottom = h;
         int top = 0;
         int left = 0;
 
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 4656b8b..94e7a06 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -2332,8 +2332,8 @@
                 batteryRealtime, which);
     }
 
-    @Override public int getPhoneSignalStrengthCount(int dataType, int which) {
-        return mPhoneDataConnectionsTimer[dataType].getCountLocked(which);
+    @Override public int getPhoneSignalStrengthCount(int strengthBin, int which) {
+        return mPhoneSignalStrengthsTimer[strengthBin].getCountLocked(which);
     }
 
     @Override public long getPhoneDataConnectionTime(int dataType,
diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java
index 85e23fa..dc4ee3a 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuView.java
@@ -531,6 +531,9 @@
 
     @Override
     protected boolean hasDividerBeforeChildAt(int childIndex) {
+        if (childIndex == 0) {
+            return false;
+        }
         final View childBefore = getChildAt(childIndex - 1);
         final View child = getChildAt(childIndex);
         boolean result = false;
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index d6d2cf6..2108d0d 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -856,6 +856,7 @@
         final int paddingRight = getPaddingRight();
         final int height = maxHeight - verticalPadding;
         final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
+        final int exactHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
 
         int availableWidth = contentWidth - paddingLeft - paddingRight;
         int leftOfCenter = availableWidth / 2;
@@ -871,16 +872,14 @@
             } else {
                 homeWidthSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
             }
-            homeLayout.measure(homeWidthSpec,
-                    MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+            homeLayout.measure(homeWidthSpec, exactHeightSpec);
             final int homeWidth = homeLayout.getMeasuredWidth() + homeLayout.getStartOffset();
             availableWidth = Math.max(0, availableWidth - homeWidth);
             leftOfCenter = Math.max(0, availableWidth - homeWidth);
         }
         
         if (mMenuView != null && mMenuView.getParent() == this) {
-            availableWidth = measureChildView(mMenuView, availableWidth,
-                    childSpecHeight, 0);
+            availableWidth = measureChildView(mMenuView, availableWidth, exactHeightSpec, 0);
             rightOfCenter = Math.max(0, rightOfCenter - mMenuView.getMeasuredWidth());
         }
 
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 2bff8a1..9fc73a4 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -720,6 +720,16 @@
 // Layers
 // ----------------------------------------------------------------------------
 
+static void android_view_GLES20Canvas_interrupt(JNIEnv* env, jobject clazz,
+        OpenGLRenderer* renderer) {
+    renderer->interrupt();
+}
+
+static void android_view_GLES20Canvas_resume(JNIEnv* env, jobject clazz,
+        OpenGLRenderer* renderer) {
+    renderer->resume();
+}
+
 static OpenGLRenderer* android_view_GLES20Canvas_createLayerRenderer(JNIEnv* env,
         jobject clazz, Layer* layer) {
     if (layer) {
@@ -962,6 +972,8 @@
     { "nResetDisplayListRenderer",  "(I)V",    (void*) android_view_GLES20Canvas_resetDisplayListRenderer },
 
     { "nOutputDisplayList",      "(II)V",      (void*) android_view_GLES20Canvas_outputDisplayList },
+    { "nInterrupt",              "(I)V",       (void*) android_view_GLES20Canvas_interrupt },
+    { "nResume",                 "(I)V",       (void*) android_view_GLES20Canvas_resume },
 
     { "nCreateLayerRenderer",    "(I)I",       (void*) android_view_GLES20Canvas_createLayerRenderer },
     { "nCreateLayer",            "(IIZ[I)I",   (void*) android_view_GLES20Canvas_createLayer },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index d636713..195b1ef 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -278,6 +278,13 @@
         android:label="@string/permlab_writeContacts"
         android:description="@string/permdesc_writeContacts" />
 
+    <!-- Allows an application to execute contacts directory search.
+         This should only be used by ContactsProvider. -->
+    <!-- @hide -->
+    <permission android:name="android.permission.BIND_DIRECTORY_SEARCH"
+        android:permissionGroup="android.permission-group.PERSONAL_INFO"
+        android:protectionLevel="signature" />
+
     <!-- Allows an application to read the user's call log. -->
     <permission android:name="android.permission.READ_CALL_LOG"
         android:permissionGroup="android.permission-group.PERSONAL_INFO"
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 8bc1e79..1c3318d 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -284,7 +284,19 @@
          who do not know their particular component name) and for all
          content providers. -->
     <attr name="exported" format="boolean" />
-    
+
+    <!-- If set to true, a single instance of this component will run for
+         all users.  That instance will run as user 0, the default/primary
+         user.  When the app running is in processes for other users and interacts
+         with this component (by binding to a service for example) those processes will
+         always interact with the instance running for user 0.  Enabling
+         single user mode forces "exported" of the component to be false, to
+         help avoid introducing multi-user security bugs.  You must hold the
+         permission {@link android.Manifest.permission#INTERACT_ACROSS_USERS} in order
+         to use this feature.  This flag can only be used with services,
+         receivers, and providers; it can not be used with activities. -->
+    <attr name="singleUser" format="boolean" />
+
     <!-- Specify a specific process that the associated code is to run in.
          Use with the application tag (to supply a default process for all
          application components), or with the activity, receiver, service,
@@ -1194,6 +1206,7 @@
              component specific values). -->
         <attr name="enabled" />
         <attr name="exported" />
+        <attr name="singleUser" />
     </declare-styleable>
     
     <!-- Attributes that can be supplied in an AndroidManifest.xml
@@ -1275,16 +1288,7 @@
              that is isolated from the rest of the system.  The only communication
              with it is through the Service API (binding and starting). -->
         <attr name="isolatedProcess" format="boolean" />
-        <!-- If set to true, a single instance of this service will run for
-             all users.  That instance will run as user 0, the default/primary
-             user.  When the app running in processes for other users interacts
-             with this service (by binding to it, starting it, etc) they will
-             always interact with the instance running for user 0.  Enabling
-             single user mode forces "exported" of the service to be false, to
-             avoid introducing multi-user security bugs.  You must hold the
-             permission {@link android.Manifest.permission#INTERACT_ACROSS_USERS} in order
-             to use this feature. -->
-        <attr name="singleUser" format="boolean" />
+        <attr name="singleUser" />
     </declare-styleable>
     
     <!-- The <code>receiver</code> tag declares an
@@ -1318,8 +1322,9 @@
              component specific values). -->
         <attr name="enabled" />
         <attr name="exported" />
+        <attr name="singleUser" />
     </declare-styleable>
-    
+
     <!-- The <code>activity</code> tag declares an
          {@link android.app.Activity} class that is available
          as part of the package's application components, implementing
@@ -1372,6 +1377,7 @@
         <attr name="hardwareAccelerated" />
         <attr name="uiOptions" />
         <attr name="parentActivityName" />
+        <attr name="singleUser" />
     </declare-styleable>
     
     <!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b752471..a4bf43f 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -853,8 +853,6 @@
 
     <!-- enable screen saver feature -->
     <bool name="config_enableDreams">true</bool>
-    <!-- Name of screensaver components to look for if none has been chosen by the user -->
-    <string name="config_defaultDreamComponent" translatable="false">com.google.android.deskclock/com.android.deskclock.Screensaver</string>
 
     <!-- Base "touch slop" value used by ViewConfiguration as a
          movement threshold where scrolling should begin. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 41abd9b..965d02b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1557,7 +1557,6 @@
   <java-symbol type="style" name="Theme.Toast" />
   <java-symbol type="xml" name="storage_list" />
   <java-symbol type="bool" name="config_enableDreams" />
-  <java-symbol type="string" name="config_defaultDreamComponent" />
   <java-symbol type="string" name="enable_explore_by_touch_warning_title" />
   <java-symbol type="string" name="enable_explore_by_touch_warning_message" />
 
diff --git a/docs/html/guide/topics/manifest/provider-element.jd b/docs/html/guide/topics/manifest/provider-element.jd
index 4558800..7b4ca8f 100644
--- a/docs/html/guide/topics/manifest/provider-element.jd
+++ b/docs/html/guide/topics/manifest/provider-element.jd
@@ -97,7 +97,8 @@
 applications &mdash; "{@code true}" if it can be, and "{@code false}" if not.  
 If "{@code false}", the provider is available only to components of the 
 same application or applications with the same user ID.  The default value
-is "{@code true}".
+is "{@code true}" for applications which target API level 16 (Jelly Bean)
+and below, and "{@code false}" otherwise.
 
 <p>
 You can export a content provider but still limit access to it with the
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 483ccb2..31c38d5 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -26,20 +26,16 @@
 import android.os.RemoteException;
 import java.io.ByteArrayInputStream;
 import java.io.Closeable;
-import java.io.IOException;
 import java.security.InvalidKeyException;
-import java.security.KeyPair;
 import java.security.Principal;
 import java.security.PrivateKey;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingQueue;
-import libcore.util.Objects;
 
 import org.apache.harmony.xnet.provider.jsse.OpenSSLEngine;
 import org.apache.harmony.xnet.provider.jsse.TrustedCertificateStore;
@@ -341,20 +337,9 @@
         try {
             IKeyChainService keyChainService = keyChainConnection.getService();
             byte[] certificateBytes = keyChainService.getCertificate(alias);
-            List<X509Certificate> chain = new ArrayList<X509Certificate>();
-            chain.add(toCertificate(certificateBytes));
             TrustedCertificateStore store = new TrustedCertificateStore();
-            for (int i = 0; true; i++) {
-                X509Certificate cert = chain.get(i);
-                if (Objects.equal(cert.getSubjectX500Principal(), cert.getIssuerX500Principal())) {
-                    break;
-                }
-                X509Certificate issuer = store.findIssuer(cert);
-                if (issuer == null) {
-                    break;
-                }
-                chain.add(issuer);
-            }
+            List<X509Certificate> chain = store
+                    .getCertificateChain(toCertificate(certificateBytes));
             return chain.toArray(new X509Certificate[chain.size()]);
         } catch (RemoteException e) {
             throw new KeyChainException(e);
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 11f30fc..ccddd91 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -963,6 +963,11 @@
 uint32_t FontRenderer::getRemainingCacheCapacity() {
     uint32_t remainingCapacity = 0;
     float totalPixels = 0;
+
+    //avoid divide by zero if the size is 0
+    if (mCacheLines.size() == 0) {
+        return 0;
+    }
     for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
          remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
          totalPixels += mCacheLines[i]->mMaxWidth;
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index b1c4dfe..726b57c7 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -18,6 +18,7 @@
 
 #include <utils/threads.h>
 
+#include "Caches.h"
 #include "Debug.h"
 #include "GradientCache.h"
 #include "Properties.h"
@@ -128,9 +129,13 @@
 
 void GradientCache::getGradientInfo(const uint32_t* colors, const int count,
         GradientInfo& info) {
-    uint32_t width = 1 << (31 - __builtin_clz(256 * (count - 1)));
-    bool hasAlpha = false;
+    uint32_t width = 256 * (count - 1);
 
+    if (!Caches::getInstance().extensions.hasNPot()) {
+        width = 1 << (31 - __builtin_clz(width));
+    }
+
+    bool hasAlpha = false;
     for (int i = 0; i < count; i++) {
         if (((colors[i] >> 24) & 0xff) < 255) {
             hasAlpha = true;
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index f4e6919..d3b98a4 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -112,6 +112,21 @@
      */
     virtual void finish();
 
+    /**
+     * This method must be invoked before handing control over to a draw functor.
+     * See callDrawGLFunction() for instance.
+     *
+     * This command must not be recorded inside display lists.
+     */
+    virtual void interrupt();
+
+    /**
+     * This method must be invoked after getting control back from a draw functor.
+     *
+     * This command must not be recorded inside display lists.
+     */
+    virtual void resume();
+
     ANDROID_API status_t invokeFunctors(Rect& dirty);
     ANDROID_API void detachFunctor(Functor* functor);
     ANDROID_API void attachFunctor(Functor* functor);
@@ -219,22 +234,6 @@
     void endMark() const;
 
 protected:
-
-    /**
-     * This method must be invoked before handing control over to a draw functor.
-     * See callDrawGLFunction() for instance.
-     *
-     * This command must not be recorded inside display lists.
-     */
-    void interrupt();
-
-    /**
-     * This method must be invoked after getting control back from a draw functor.
-     *
-     * This command must not be recorded inside display lists.
-     */
-    void resume();
-
     /**
      * Compose the layer defined in the current snapshot with the layer
      * defined by the previous snapshot.
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 0e77cb2..d67bfbe 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -69,12 +69,10 @@
         "varying highp vec2 outBitmapTexCoords;\n";
 const char* gVS_Header_Varyings_PointHasBitmap =
         "varying highp vec2 outPointBitmapTexCoords;\n";
-// TODO: These values are used to sample from textures,
-//       they may need to be highp
 const char* gVS_Header_Varyings_HasGradient[6] = {
         // Linear
         "varying highp vec2 linear;\n",
-        "varying highp float linear;\n",
+        "varying float linear;\n",
 
         // Circular
         "varying highp vec2 circular;\n",
@@ -268,21 +266,21 @@
 };
 const char* gFS_Main_FetchGradient[6] = {
         // Linear
-        "    highp vec4 gradientColor = texture2D(gradientSampler, linear);\n",
+        "    vec4 gradientColor = texture2D(gradientSampler, linear);\n",
 
-        "    highp vec4 gradientColor = mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n",
+        "    vec4 gradientColor = mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n",
 
         // Circular
-        "    highp vec4 gradientColor = texture2D(gradientSampler, vec2(length(circular), 0.5));\n",
+        "    vec4 gradientColor = texture2D(gradientSampler, vec2(length(circular), 0.5));\n",
 
-        "    highp vec4 gradientColor = mix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n",
+        "    vec4 gradientColor = mix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n",
 
         // Sweep
         "    highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
-        "    highp vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n",
+        "    vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n",
 
         "    highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
-        "    highp vec4 gradientColor = mix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n"
+        "    vec4 gradientColor = mix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n"
 };
 const char* gFS_Main_FetchBitmap =
         "    vec4 bitmapColor = texture2D(bitmapSampler, outBitmapTexCoords);\n";
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 9af201d..ca2df47 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -721,12 +721,17 @@
     public native int getMaxAmplitude() throws IllegalStateException;
 
     /* Do not change this value without updating its counterpart
-     * in include/media/mediarecorder.h!
+     * in include/media/mediarecorder.h or mediaplayer.h!
      */
     /** Unspecified media recorder error.
      * @see android.media.MediaRecorder.OnErrorListener
      */
     public static final int MEDIA_RECORDER_ERROR_UNKNOWN = 1;
+    /** Media server died. In this case, the application must release the
+     * MediaRecorder object and instantiate a new one.
+     * @see android.media.MediaRecorder.OnErrorListener
+     */
+    public static final int MEDIA_ERROR_SERVER_DIED = 100;
 
     /**
      * Interface definition for a callback to be invoked when an error
@@ -741,6 +746,7 @@
          * @param what    the type of error that has occurred:
          * <ul>
          * <li>{@link #MEDIA_RECORDER_ERROR_UNKNOWN}
+         * <li>{@link #MEDIA_ERROR_SERVER_DIED}
          * </ul>
          * @param extra   an extra code, specific to the error type
          */
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index cd0da5a..a9de51f 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -151,4 +151,12 @@
     <!-- Number of retries for connecting to DHCP.
          Value here is the same as WifiStateMachine.DEFAULT_MAX_DHCP_RETRIES -->
     <integer name="def_max_dhcp_retries">9</integer>
+
+    <!-- Dreams (screen saver) default settings -->
+    <!-- Whether the feature is enabled when charging (Settings.Secure.SCREENSAVER_ENABLED) -->
+    <bool name="def_screensaver_enabled">true</bool>
+    <!-- Whether the feature activates when docked (SCREENSAVER_ACTIVATE_ON_DOCK) -->
+    <bool name="def_screensaver_activate_on_dock">true</bool>
+    <!-- ComponentName of the default screen saver (Settings.Secure.SCREENSAVER_COMPONENT) -->
+    <string name="def_screensaver_component">com.google.android.deskclock/com.android.deskclock.Screensaver</string>
 </resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 71c8c83..7c6ce73 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -65,7 +65,7 @@
     // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
     // is properly propagated through your change.  Not doing so will result in a loss of user
     // settings.
-    private static final int DATABASE_VERSION = 79;
+    private static final int DATABASE_VERSION = 80;
 
     private Context mContext;
 
@@ -1073,6 +1073,30 @@
             upgradeVersion = 79;
         }
 
+        // vvv Jelly Bean MR1 changes begin here vvv
+
+        if (upgradeVersion == 79) {
+            // update screensaver settings
+            db.beginTransaction();
+            SQLiteStatement stmt = null;
+            try {
+                stmt = db.compileStatement("INSERT OR REPLACE INTO secure(name,value)"
+                        + " VALUES(?,?);");
+                loadBooleanSetting(stmt, Settings.Secure.SCREENSAVER_ENABLED,
+                        R.bool.def_screensaver_enabled);
+                loadBooleanSetting(stmt, Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
+                        R.bool.def_screensaver_activate_on_dock);
+                loadStringSetting(stmt, Settings.Secure.SCREENSAVER_COMPONENT,
+                        R.string.def_screensaver_component);
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+                if (stmt != null) stmt.close();
+            }
+            upgradeVersion = 80;
+        }
+
+
         // *** Remember to update DATABASE_VERSION above!
 
         if (upgradeVersion != currentVersion) {
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 10849f6..51dc3b1 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -40,6 +40,7 @@
     <uses-permission android:name="android.permission.STOP_APP_SWITCHES" />
     <uses-permission android:name="android.permission.SET_SCREEN_COMPATIBILITY" />
     <uses-permission android:name="android.permission.START_ANY_ACTIVITY" />
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
 
     <!-- WindowManager -->
     <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" />
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
index fefd0e8..3e03f85 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
@@ -30,6 +30,7 @@
 import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.Process;
+import android.os.UserId;
 import android.util.Log;
 
 import com.android.systemui.R;
@@ -243,7 +244,8 @@
                 mContext.getSystemService(Context.ACTIVITY_SERVICE);
 
                 final List<ActivityManager.RecentTaskInfo> recentTasks =
-                        am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
+                        am.getRecentTasksForUser(MAX_TASKS,
+                                ActivityManager.RECENT_IGNORE_UNAVAILABLE, UserId.USER_CURRENT);
                 int numTasks = recentTasks.size();
                 ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN)
                         .addCategory(Intent.CATEGORY_HOME).resolveActivityInfo(pm, 0);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 16e9345..34474687 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -46,6 +46,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.os.UserId;
 import android.provider.Settings;
 import android.util.DisplayMetrics;
 import android.util.Log;
@@ -2222,8 +2223,8 @@
                 ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
             } catch (RemoteException e) {
             }
-            v.getContext().startActivity(new Intent(Settings.ACTION_SETTINGS)
-                    .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+            v.getContext().startActivityAsUser(new Intent(Settings.ACTION_SETTINGS)
+                    .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK), UserId.USER_CURRENT);
             animateCollapse();
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java
index 537ff66..da161a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java
@@ -19,6 +19,7 @@
 import android.app.StatusBarManager;
 import android.content.Context;
 import android.content.Intent;
+import android.os.UserId;
 import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.Slog;
@@ -117,8 +118,8 @@
     // Settings
     // ----------------------------
     private void onClickSettings() {
-        getContext().startActivity(new Intent(Settings.ACTION_SETTINGS)
-                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+        getContext().startActivityAsUser(new Intent(Settings.ACTION_SETTINGS)
+                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK), UserId.USER_CURRENT);
         getStatusBarManager().collapse();
     }
 }
diff --git a/samples/training/network-usage/AndroidManifest.xml b/samples/training/network-usage/AndroidManifest.xml
new file mode 100644
index 0000000..4b96d14
--- /dev/null
+++ b/samples/training/network-usage/AndroidManifest.xml
@@ -0,0 +1,48 @@
+<!--
+  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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.networkusage"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk android:minSdkVersion="4"
+        android:targetSdkVersion="14" />
+
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+
+    <application
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name" >
+
+        <activity
+            android:name="com.example.networkusage.NetworkActivity"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:label="SettingsActivity" android:name=".SettingsActivity">
+             <intent-filter>
+                <action android:name="android.intent.action.MANAGE_NETWORK_USAGE" />
+                <category android:name="android.intent.category.DEFAULT" />
+          </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/samples/training/network-usage/README.txt b/samples/training/network-usage/README.txt
new file mode 100644
index 0000000..cc9a7a0
--- /dev/null
+++ b/samples/training/network-usage/README.txt
@@ -0,0 +1,14 @@
+README
+======
+
+This Network Usage sample app does the following:
+
+-- Downloads an XML feed from StackOverflow.com for the most recent posts tagged "android".
+
+-- Parses the XML feed, combines feed elements with HTML markup, and displays the resulting HTML in the UI.
+
+-- Lets users control their network data usage through a settings UI. Users can choose to fetch the feed
+   when any network connection is available, or only when a Wi-Fi connection is available.
+
+-- Detects when there is a change in the device's connection status and responds accordingly. For example, if
+   the device loses its network connection, the app will not attempt to download the feed.
diff --git a/samples/training/network-usage/res/drawable-hdpi/ic_launcher.png b/samples/training/network-usage/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..8074c4c
--- /dev/null
+++ b/samples/training/network-usage/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/training/network-usage/res/drawable-ldpi/ic_launcher.png b/samples/training/network-usage/res/drawable-ldpi/ic_launcher.png
new file mode 100644
index 0000000..1095584
--- /dev/null
+++ b/samples/training/network-usage/res/drawable-ldpi/ic_launcher.png
Binary files differ
diff --git a/samples/training/network-usage/res/drawable-mdpi/ic_launcher.png b/samples/training/network-usage/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..a07c69f
--- /dev/null
+++ b/samples/training/network-usage/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/training/network-usage/res/layout/main.xml b/samples/training/network-usage/res/layout/main.xml
new file mode 100644
index 0000000..8498934
--- /dev/null
+++ b/samples/training/network-usage/res/layout/main.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical" >
+
+<WebView  xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/webview"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+/>
+</LinearLayout>
diff --git a/samples/training/network-usage/res/menu/mainmenu.xml b/samples/training/network-usage/res/menu/mainmenu.xml
new file mode 100644
index 0000000..17d44db
--- /dev/null
+++ b/samples/training/network-usage/res/menu/mainmenu.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  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.
+  -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+     <item android:id="@+id/settings"
+          android:title="@string/settings" />
+    <item android:id="@+id/refresh"
+          android:title="@string/refresh" />
+</menu>
diff --git a/samples/training/network-usage/res/values/arrays.xml b/samples/training/network-usage/res/values/arrays.xml
new file mode 100644
index 0000000..2e8b8a7
--- /dev/null
+++ b/samples/training/network-usage/res/values/arrays.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  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.
+  -->
+
+<resources>
+    <string-array name="listArray">
+        <item>Only when on Wi-Fi</item>
+        <item>On any network</item>
+    </string-array>
+    <string-array name="listValues">
+        <item>Wi-Fi</item>
+        <item>Any</item>
+    </string-array>
+</resources>
diff --git a/samples/training/network-usage/res/values/strings.xml b/samples/training/network-usage/res/values/strings.xml
new file mode 100644
index 0000000..d7c702f
--- /dev/null
+++ b/samples/training/network-usage/res/values/strings.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  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.
+  -->
+
+<resources>
+
+    <string name="app_name">NetworkUsage</string>
+
+    <!--  Menu items -->
+    <string name="settings">Settings</string>
+    <string name="refresh">Refresh</string>
+
+    <!--  NetworkActivity -->
+    <string name="page_title">Newest StackOverflow questions tagged \'android\'</string>
+    <string name="updated">Last updated:</string>
+    <string name="lost_connection">Lost connection.</string>
+    <string name="wifi_connected">Wi-Fi reconnected.</string>
+    <string name="connection_error">Unable to load content. Check your network connection.</string>
+    <string name="xml_error">Error parsing XML.</string>
+
+</resources>
diff --git a/samples/training/network-usage/res/xml/preferences.xml b/samples/training/network-usage/res/xml/preferences.xml
new file mode 100644
index 0000000..801ba79
--- /dev/null
+++ b/samples/training/network-usage/res/xml/preferences.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  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.
+  -->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+    <ListPreference
+        android:title="Download Feed"
+        android:summary="Network connectivity required to download the feed."
+        android:key="listPref"
+        android:defaultValue="Wi-Fi"
+        android:entries="@array/listArray"
+        android:entryValues="@array/listValues"
+     />
+    <CheckBoxPreference
+        android:title="Show Summaries"
+        android:defaultValue="false"
+        android:summary="Show a summary for each link."
+        android:key="summaryPref" />
+</PreferenceScreen>
diff --git a/samples/training/network-usage/src/com/example/android/networkusage/NetworkActivity.java b/samples/training/network-usage/src/com/example/android/networkusage/NetworkActivity.java
new file mode 100644
index 0000000..b7ed331
--- /dev/null
+++ b/samples/training/network-usage/src/com/example/android/networkusage/NetworkActivity.java
@@ -0,0 +1,321 @@
+/*
+ * 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.example.android.networkusage;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.webkit.WebView;
+import android.widget.Toast;
+
+import com.example.android.networkusage.R;
+import com.example.android.networkusage.StackOverflowXmlParser.Entry;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.List;
+
+
+/**
+ * Main Activity for the sample application.
+ *
+ * This activity does the following:
+ *
+ * o Presents a WebView screen to users. This WebView has a list of HTML links to the latest
+ *   questions tagged 'android' on stackoverflow.com.
+ *
+ * o Parses the StackOverflow XML feed using XMLPullParser.
+ *
+ * o Uses AsyncTask to download and process the XML feed.
+ *
+ * o Monitors preferences and the device's network connection to determine whether
+ *   to refresh the WebView content.
+ */
+public class NetworkActivity extends Activity {
+    public static final String WIFI = "Wi-Fi";
+    public static final String ANY = "Any";
+    private static final String URL =
+            "http://stackoverflow.com/feeds/tag?tagnames=android&sort=newest";
+
+    // Whether there is a Wi-Fi connection.
+    private static boolean wifiConnected = false;
+    // Whether there is a mobile connection.
+    private static boolean mobileConnected = false;
+    // Whether the display should be refreshed.
+    public static boolean refreshDisplay = true;
+
+    // The user's current network preference setting.
+    public static String sPref = null;
+
+    // The BroadcastReceiver that tracks network connectivity changes.
+    private NetworkReceiver receiver = new NetworkReceiver();
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Register BroadcastReceiver to track connection changes.
+        IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
+        receiver = new NetworkReceiver();
+        this.registerReceiver(receiver, filter);
+    }
+
+    // Refreshes the display if the network connection and the
+    // pref settings allow it.
+    @Override
+    public void onStart() {
+        super.onStart();
+
+        // Gets the user's network preference settings
+        SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
+
+        // Retrieves a string value for the preferences. The second parameter
+        // is the default value to use if a preference value is not found.
+        sPref = sharedPrefs.getString("listPref", "Wi-Fi");
+
+        updateConnectedFlags();
+
+        // Only loads the page if refreshDisplay is true. Otherwise, keeps previous
+        // display. For example, if the user has set "Wi-Fi only" in prefs and the
+        // device loses its Wi-Fi connection midway through the user using the app,
+        // you don't want to refresh the display--this would force the display of
+        // an error page instead of stackoverflow.com content.
+        if (refreshDisplay) {
+            loadPage();
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        if (receiver != null) {
+            this.unregisterReceiver(receiver);
+        }
+    }
+
+    // Checks the network connection and sets the wifiConnected and mobileConnected
+    // variables accordingly.
+    private void updateConnectedFlags() {
+        ConnectivityManager connMgr =
+                (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
+
+        NetworkInfo activeInfo = connMgr.getActiveNetworkInfo();
+        if (activeInfo != null && activeInfo.isConnected()) {
+            wifiConnected = activeInfo.getType() == ConnectivityManager.TYPE_WIFI;
+            mobileConnected = activeInfo.getType() == ConnectivityManager.TYPE_MOBILE;
+        } else {
+            wifiConnected = false;
+            mobileConnected = false;
+        }
+    }
+
+    // Uses AsyncTask subclass to download the XML feed from stackoverflow.com.
+    // This avoids UI lock up. To prevent network operations from
+    // causing a delay that results in a poor user experience, always perform
+    // network operations on a separate thread from the UI.
+    private void loadPage() {
+        if (((sPref.equals(ANY)) && (wifiConnected || mobileConnected))
+                || ((sPref.equals(WIFI)) && (wifiConnected))) {
+            // AsyncTask subclass
+            new DownloadXmlTask().execute(URL);
+        } else {
+            showErrorPage();
+        }
+    }
+
+    // Displays an error if the app is unable to load content.
+    private void showErrorPage() {
+        setContentView(R.layout.main);
+
+        // The specified network connection is not available. Displays error message.
+        WebView myWebView = (WebView) findViewById(R.id.webview);
+        myWebView.loadData(getResources().getString(R.string.connection_error),
+                "text/html", null);
+    }
+
+    // Populates the activity's options menu.
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        MenuInflater inflater = getMenuInflater();
+        inflater.inflate(R.menu.mainmenu, menu);
+        return true;
+    }
+
+    // Handles the user's menu selection.
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+        case R.id.settings:
+                Intent settingsActivity = new Intent(getBaseContext(), SettingsActivity.class);
+                startActivity(settingsActivity);
+                return true;
+        case R.id.refresh:
+                loadPage();
+                return true;
+        default:
+                return super.onOptionsItemSelected(item);
+        }
+    }
+
+    // Implementation of AsyncTask used to download XML feed from stackoverflow.com.
+    private class DownloadXmlTask extends AsyncTask<String, Void, String> {
+
+        @Override
+        protected String doInBackground(String... urls) {
+            try {
+                return loadXmlFromNetwork(urls[0]);
+            } catch (IOException e) {
+                return getResources().getString(R.string.connection_error);
+            } catch (XmlPullParserException e) {
+                return getResources().getString(R.string.xml_error);
+            }
+        }
+
+        @Override
+        protected void onPostExecute(String result) {
+            setContentView(R.layout.main);
+            // Displays the HTML string in the UI via a WebView
+            WebView myWebView = (WebView) findViewById(R.id.webview);
+            myWebView.loadData(result, "text/html", null);
+        }
+    }
+
+    // Uploads XML from stackoverflow.com, parses it, and combines it with
+    // HTML markup. Returns HTML string.
+    private String loadXmlFromNetwork(String urlString) throws XmlPullParserException, IOException {
+        InputStream stream = null;
+        StackOverflowXmlParser stackOverflowXmlParser = new StackOverflowXmlParser();
+        List<Entry> entries = null;
+        String title = null;
+        String url = null;
+        String summary = null;
+        Calendar rightNow = Calendar.getInstance();
+        DateFormat formatter = new SimpleDateFormat("MMM dd h:mmaa");
+
+        // Checks whether the user set the preference to include summary text
+        SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
+        boolean pref = sharedPrefs.getBoolean("summaryPref", false);
+
+        StringBuilder htmlString = new StringBuilder();
+        htmlString.append("<h3>" + getResources().getString(R.string.page_title) + "</h3>");
+        htmlString.append("<em>" + getResources().getString(R.string.updated) + " " +
+                formatter.format(rightNow.getTime()) + "</em>");
+
+        try {
+            stream = downloadUrl(urlString);
+            entries = stackOverflowXmlParser.parse(stream);
+        // Makes sure that the InputStream is closed after the app is
+        // finished using it.
+        } finally {
+            if (stream != null) {
+                stream.close();
+            }
+        }
+
+        // StackOverflowXmlParser returns a List (called "entries") of Entry objects.
+        // Each Entry object represents a single post in the XML feed.
+        // This section processes the entries list to combine each entry with HTML markup.
+        // Each entry is displayed in the UI as a link that optionally includes
+        // a text summary.
+        for (Entry entry : entries) {
+            htmlString.append("<p><a href='");
+            htmlString.append(entry.link);
+            htmlString.append("'>" + entry.title + "</a></p>");
+            // If the user set the preference to include summary text,
+            // adds it to the display.
+            if (pref) {
+                htmlString.append(entry.summary);
+            }
+        }
+        return htmlString.toString();
+    }
+
+    // Given a string representation of a URL, sets up a connection and gets
+    // an input stream.
+    private InputStream downloadUrl(String urlString) throws IOException {
+        URL url = new URL(urlString);
+        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+        conn.setReadTimeout(10000 /* milliseconds */);
+        conn.setConnectTimeout(15000 /* milliseconds */);
+        conn.setRequestMethod("GET");
+        conn.setDoInput(true);
+        // Starts the query
+        conn.connect();
+        InputStream stream = conn.getInputStream();
+        return stream;
+    }
+
+    /**
+     *
+     * This BroadcastReceiver intercepts the android.net.ConnectivityManager.CONNECTIVITY_ACTION,
+     * which indicates a connection change. It checks whether the type is TYPE_WIFI.
+     * If it is, it checks whether Wi-Fi is connected and sets the wifiConnected flag in the
+     * main activity accordingly.
+     *
+     */
+    public class NetworkReceiver extends BroadcastReceiver {
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            ConnectivityManager connMgr =
+                    (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+            NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
+
+            // Checks the user prefs and the network connection. Based on the result, decides
+            // whether
+            // to refresh the display or keep the current display.
+            // If the userpref is Wi-Fi only, checks to see if the device has a Wi-Fi connection.
+            if (WIFI.equals(sPref) && networkInfo != null
+                    && networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
+                // If device has its Wi-Fi connection, sets refreshDisplay
+                // to true. This causes the display to be refreshed when the user
+                // returns to the app.
+                refreshDisplay = true;
+                Toast.makeText(context, R.string.wifi_connected, Toast.LENGTH_SHORT).show();
+
+                // If the setting is ANY network and there is a network connection
+                // (which by process of elimination would be mobile), sets refreshDisplay to true.
+            } else if (ANY.equals(sPref) && networkInfo != null) {
+                refreshDisplay = true;
+
+                // Otherwise, the app can't download content--either because there is no network
+                // connection (mobile or Wi-Fi), or because the pref setting is WIFI, and there
+                // is no Wi-Fi connection.
+                // Sets refreshDisplay to false.
+            } else {
+                refreshDisplay = false;
+                Toast.makeText(context, R.string.lost_connection, Toast.LENGTH_SHORT).show();
+            }
+        }
+    }
+}
diff --git a/samples/training/network-usage/src/com/example/android/networkusage/SettingsActivity.java b/samples/training/network-usage/src/com/example/android/networkusage/SettingsActivity.java
new file mode 100644
index 0000000..73b72d2
--- /dev/null
+++ b/samples/training/network-usage/src/com/example/android/networkusage/SettingsActivity.java
@@ -0,0 +1,66 @@
+/*
+ * 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.example.android.networkusage;
+
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+import com.example.android.networkusage.R;
+
+/**
+ * This preference activity has in its manifest declaration an intent filter for
+ * the ACTION_MANAGE_NETWORK_USAGE action. This activity provides a settings UI
+ * for users to specify network settings to control data usage.
+ */
+public class SettingsActivity extends PreferenceActivity
+        implements
+            OnSharedPreferenceChangeListener {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Loads the XML preferences file.
+        addPreferencesFromResource(R.xml.preferences);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+
+        // Registers a callback to be invoked whenever a user changes a preference.
+        getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+
+        // Unregisters the listener set in onResume().
+        // It's best practice to unregister listeners when your app isn't using them to cut down on
+        // unnecessary system overhead. You do this in onPause().
+        getPreferenceScreen()
+                .getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
+    }
+
+    // Fires when the user changes a preference.
+    @Override
+    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+        // Sets refreshDisplay to true so that when the user returns to the main
+        // activity, the display refreshes to reflect the new settings.
+        NetworkActivity.refreshDisplay = true;
+    }
+}
diff --git a/samples/training/network-usage/src/com/example/android/networkusage/StackOverflowXmlParser.java b/samples/training/network-usage/src/com/example/android/networkusage/StackOverflowXmlParser.java
new file mode 100644
index 0000000..6a01098
--- /dev/null
+++ b/samples/training/network-usage/src/com/example/android/networkusage/StackOverflowXmlParser.java
@@ -0,0 +1,169 @@
+/*
+ * 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.example.android.networkusage;
+
+import android.util.Xml;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class parses XML feeds from stackoverflow.com.
+ * Given an InputStream representation of a feed, it returns a List of entries,
+ * where each list element represents a single entry (post) in the XML feed.
+ */
+public class StackOverflowXmlParser {
+    private static final String ns = null;
+
+    // We don't use namespaces
+
+    public List<Entry> parse(InputStream in) throws XmlPullParserException, IOException {
+        try {
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
+            parser.setInput(in, null);
+            parser.nextTag();
+            return readFeed(parser);
+        } finally {
+            in.close();
+        }
+    }
+
+    private List<Entry> readFeed(XmlPullParser parser) throws XmlPullParserException, IOException {
+        List<Entry> entries = new ArrayList<Entry>();
+
+        parser.require(XmlPullParser.START_TAG, ns, "feed");
+        while (parser.next() != XmlPullParser.END_TAG) {
+            if (parser.getEventType() != XmlPullParser.START_TAG) {
+                continue;
+            }
+            String name = parser.getName();
+            // Starts by looking for the entry tag
+            if (name.equals("entry")) {
+                entries.add(readEntry(parser));
+            } else {
+                skip(parser);
+            }
+        }
+        return entries;
+    }
+
+    // This class represents a single entry (post) in the XML feed.
+    // It includes the data members "title," "link," and "summary."
+    public static class Entry {
+        public final String title;
+        public final String link;
+        public final String summary;
+
+        private Entry(String title, String summary, String link) {
+            this.title = title;
+            this.summary = summary;
+            this.link = link;
+        }
+    }
+
+    // Parses the contents of an entry. If it encounters a title, summary, or link tag, hands them
+    // off
+    // to their respective &quot;read&quot; methods for processing. Otherwise, skips the tag.
+    private Entry readEntry(XmlPullParser parser) throws XmlPullParserException, IOException {
+        parser.require(XmlPullParser.START_TAG, ns, "entry");
+        String title = null;
+        String summary = null;
+        String link = null;
+        while (parser.next() != XmlPullParser.END_TAG) {
+            if (parser.getEventType() != XmlPullParser.START_TAG) {
+                continue;
+            }
+            String name = parser.getName();
+            if (name.equals("title")) {
+                title = readTitle(parser);
+            } else if (name.equals("summary")) {
+                summary = readSummary(parser);
+            } else if (name.equals("link")) {
+                link = readLink(parser);
+            } else {
+                skip(parser);
+            }
+        }
+        return new Entry(title, summary, link);
+    }
+
+    // Processes title tags in the feed.
+    private String readTitle(XmlPullParser parser) throws IOException, XmlPullParserException {
+        parser.require(XmlPullParser.START_TAG, ns, "title");
+        String title = readText(parser);
+        parser.require(XmlPullParser.END_TAG, ns, "title");
+        return title;
+    }
+
+    // Processes link tags in the feed.
+    private String readLink(XmlPullParser parser) throws IOException, XmlPullParserException {
+        String link = "";
+        parser.require(XmlPullParser.START_TAG, ns, "link");
+        String tag = parser.getName();
+        String relType = parser.getAttributeValue(null, "rel");
+        if (tag.equals("link")) {
+            if (relType.equals("alternate")) {
+                link = parser.getAttributeValue(null, "href");
+                parser.nextTag();
+            }
+        }
+        parser.require(XmlPullParser.END_TAG, ns, "link");
+        return link;
+    }
+
+    // Processes summary tags in the feed.
+    private String readSummary(XmlPullParser parser) throws IOException, XmlPullParserException {
+        parser.require(XmlPullParser.START_TAG, ns, "summary");
+        String summary = readText(parser);
+        parser.require(XmlPullParser.END_TAG, ns, "summary");
+        return summary;
+    }
+
+    // For the tags title and summary, extracts their text values.
+    private String readText(XmlPullParser parser) throws IOException, XmlPullParserException {
+        String result = "";
+        if (parser.next() == XmlPullParser.TEXT) {
+            result = parser.getText();
+            parser.nextTag();
+        }
+        return result;
+    }
+
+    // Skips tags the parser isn't interested in. Uses depth to handle nested tags. i.e.,
+    // if the next tag after a START_TAG isn't a matching END_TAG, it keeps going until it
+    // finds the matching END_TAG (as indicated by the value of "depth" being 0).
+    private void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
+        if (parser.getEventType() != XmlPullParser.START_TAG) {
+            throw new IllegalStateException();
+        }
+        int depth = 1;
+        while (depth != 0) {
+            switch (parser.next()) {
+            case XmlPullParser.END_TAG:
+                    depth--;
+                    break;
+            case XmlPullParser.START_TAG:
+                    depth++;
+                    break;
+            }
+        }
+    }
+}
diff --git a/services/common_time/common_time_server.cpp b/services/common_time/common_time_server.cpp
index 16be8f1..17f99b9 100644
--- a/services/common_time/common_time_server.cpp
+++ b/services/common_time/common_time_server.cpp
@@ -584,7 +584,7 @@
 
 static void hexDumpToString(const uint8_t* src, size_t src_len,
                             char* dst, size_t dst_len) {
-    size_t offset;
+    size_t offset = 0;
     size_t i;
 
     for (i = 0; (i < src_len) && (offset < dst_len); ++i) {
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index dc0cb75..6049b05 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -20,6 +20,13 @@
 import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
+import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
+import static android.net.ConnectivityManager.TYPE_DUMMY;
+import static android.net.ConnectivityManager.TYPE_ETHERNET;
+import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.ConnectivityManager.TYPE_WIMAX;
+import static android.net.ConnectivityManager.getNetworkTypeName;
 import static android.net.ConnectivityManager.isNetworkTypeValid;
 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
@@ -86,14 +93,13 @@
 import com.android.server.net.BaseNetworkObserver;
 import com.google.android.collect.Lists;
 import com.google.android.collect.Sets;
+
 import dalvik.system.DexClassLoader;
+
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.InvocationTargetException;
 import java.net.Inet4Address;
 import java.net.Inet6Address;
 import java.net.InetAddress;
@@ -317,6 +323,14 @@
 
     public ConnectivityService(Context context, INetworkManagementService netd,
             INetworkStatsService statsService, INetworkPolicyManager policyManager) {
+        // Currently, omitting a NetworkFactory will create one internally
+        // TODO: create here when we have cleaner WiMAX support
+        this(context, netd, statsService, policyManager, null);
+    }
+
+    public ConnectivityService(Context context, INetworkManagementService netd,
+            INetworkStatsService statsService, INetworkPolicyManager policyManager,
+            NetworkFactory netFactory) {
         if (DBG) log("ConnectivityService starting up");
 
         HandlerThread handlerThread = new HandlerThread("ConnectivityServiceThread");
@@ -324,6 +338,10 @@
         mHandler = new InternalHandler(handlerThread.getLooper());
         mTrackerHandler = new NetworkStateTrackerHandler(handlerThread.getLooper());
 
+        if (netFactory == null) {
+            netFactory = new DefaultNetworkFactory(context, mTrackerHandler);
+        }
+
         // setup our unique device name
         if (TextUtils.isEmpty(SystemProperties.get("net.hostname"))) {
             String id = Settings.Secure.getString(context.getContentResolver(),
@@ -462,59 +480,27 @@
 
         mTestMode = SystemProperties.get("cm.test.mode").equals("true")
                 && SystemProperties.get("ro.build.type").equals("eng");
-        /*
-         * Create the network state trackers for Wi-Fi and mobile
-         * data. Maybe this could be done with a factory class,
-         * but it's not clear that it's worth it, given that
-         * the number of different network types is not going
-         * to change very often.
-         */
-        for (int netType : mPriorityList) {
-            switch (mNetConfigs[netType].radio) {
-            case ConnectivityManager.TYPE_WIFI:
-                mNetTrackers[netType] = new WifiStateTracker(
-                        netType, mNetConfigs[netType].name);
-                mNetTrackers[netType].startMonitoring(context, mTrackerHandler);
-                break;
-            case ConnectivityManager.TYPE_MOBILE:
-                mNetTrackers[netType] = new MobileDataStateTracker(netType,
-                        mNetConfigs[netType].name);
-                mNetTrackers[netType].startMonitoring(context, mTrackerHandler);
-                break;
-            case ConnectivityManager.TYPE_DUMMY:
-                mNetTrackers[netType] = new DummyDataStateTracker(netType,
-                        mNetConfigs[netType].name);
-                mNetTrackers[netType].startMonitoring(context, mTrackerHandler);
-                break;
-            case ConnectivityManager.TYPE_BLUETOOTH:
-                mNetTrackers[netType] = BluetoothTetheringDataTracker.getInstance();
-                mNetTrackers[netType].startMonitoring(context, mTrackerHandler);
-                break;
-            case ConnectivityManager.TYPE_WIMAX:
-                mNetTrackers[netType] = makeWimaxStateTracker();
-                if (mNetTrackers[netType]!= null) {
-                    mNetTrackers[netType].startMonitoring(context, mTrackerHandler);
-                }
-                break;
-            case ConnectivityManager.TYPE_ETHERNET:
-                mNetTrackers[netType] = EthernetDataTracker.getInstance();
-                mNetTrackers[netType].startMonitoring(context, mTrackerHandler);
-                break;
-            default:
-                loge("Trying to create a DataStateTracker for an unknown radio type " +
-                        mNetConfigs[netType].radio);
+
+        // Create and start trackers for hard-coded networks
+        for (int targetNetworkType : mPriorityList) {
+            final NetworkConfig config = mNetConfigs[targetNetworkType];
+            final NetworkStateTracker tracker;
+            try {
+                tracker = netFactory.createTracker(targetNetworkType, config);
+                mNetTrackers[targetNetworkType] = tracker;
+            } catch (IllegalArgumentException e) {
+                Slog.e(TAG, "Problem creating " + getNetworkTypeName(targetNetworkType)
+                        + " tracker: " + e);
                 continue;
             }
-            mCurrentLinkProperties[netType] = null;
-            if (mNetTrackers[netType] != null && mNetConfigs[netType].isDefault()) {
-                mNetTrackers[netType].reconnect();
+
+            tracker.startMonitoring(context, mTrackerHandler);
+            if (config.isDefault()) {
+                tracker.reconnect();
             }
         }
 
-        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
-        INetworkManagementService nmService = INetworkManagementService.Stub.asInterface(b);
-
-        mTethering = new Tethering(mContext, nmService, statsService, this, mHandler.getLooper());
+        mTethering = new Tethering(mContext, mNetd, statsService, this, mHandler.getLooper());
         mTetheringConfigValid = ((mTethering.getTetherableUsbRegexs().length != 0 ||
                                   mTethering.getTetherableWifiRegexs().length != 0 ||
                                   mTethering.getTetherableBluetoothRegexs().length != 0) &&
@@ -523,9 +509,9 @@
         mVpn = new Vpn(mContext, new VpnCallback());
 
         try {
-            nmService.registerObserver(mTethering);
-            nmService.registerObserver(mVpn);
-            nmService.registerObserver(mDataActivityObserver);
+            mNetd.registerObserver(mTethering);
+            mNetd.registerObserver(mVpn);
+            mNetd.registerObserver(mDataActivityObserver);
         } catch (RemoteException e) {
             loge("Error registering observer :" + e);
         }
@@ -540,7 +526,53 @@
         loadGlobalProxy();
     }
 
-    private NetworkStateTracker makeWimaxStateTracker() {
+    /**
+     * Factory that creates {@link NetworkStateTracker} instances using given
+     * {@link NetworkConfig}.
+     */
+    public interface NetworkFactory {
+        public NetworkStateTracker createTracker(int targetNetworkType, NetworkConfig config);
+    }
+
+    private static class DefaultNetworkFactory implements NetworkFactory {
+        private final Context mContext;
+        private final Handler mTrackerHandler;
+
+        public DefaultNetworkFactory(Context context, Handler trackerHandler) {
+            mContext = context;
+            mTrackerHandler = trackerHandler;
+        }
+
+        @Override
+        public NetworkStateTracker createTracker(int targetNetworkType, NetworkConfig config) {
+            switch (config.radio) {
+                case TYPE_WIFI:
+                    return new WifiStateTracker(targetNetworkType, config.name);
+                case TYPE_MOBILE:
+                    return new MobileDataStateTracker(targetNetworkType, config.name);
+                case TYPE_DUMMY:
+                    return new DummyDataStateTracker(targetNetworkType, config.name);
+                case TYPE_BLUETOOTH:
+                    return BluetoothTetheringDataTracker.getInstance();
+                case TYPE_WIMAX:
+                    return makeWimaxStateTracker(mContext, mTrackerHandler);
+                case TYPE_ETHERNET:
+                    return EthernetDataTracker.getInstance();
+                default:
+                    throw new IllegalArgumentException(
+                            "Trying to create a NetworkStateTracker for an unknown radio type: "
+                            + config.radio);
+            }
+        }
+    }
+
+    /**
+     * Loads external WiMAX library and registers as system service, returning a
+     * {@link NetworkStateTracker} for WiMAX. Caller is still responsible for
+     * invoking {@link NetworkStateTracker#startMonitoring(Context, Handler)}.
+     */
+    private static NetworkStateTracker makeWimaxStateTracker(
+            Context context, Handler trackerHandler) {
         // Initialize Wimax
         DexClassLoader wimaxClassLoader;
         Class wimaxStateTrackerClass = null;
@@ -554,25 +586,25 @@
 
         NetworkStateTracker wimaxStateTracker = null;
 
-        boolean isWimaxEnabled = mContext.getResources().getBoolean(
+        boolean isWimaxEnabled = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_wimaxEnabled);
 
         if (isWimaxEnabled) {
             try {
-                wimaxJarLocation = mContext.getResources().getString(
+                wimaxJarLocation = context.getResources().getString(
                         com.android.internal.R.string.config_wimaxServiceJarLocation);
-                wimaxLibLocation = mContext.getResources().getString(
+                wimaxLibLocation = context.getResources().getString(
                         com.android.internal.R.string.config_wimaxNativeLibLocation);
-                wimaxManagerClassName = mContext.getResources().getString(
+                wimaxManagerClassName = context.getResources().getString(
                         com.android.internal.R.string.config_wimaxManagerClassname);
-                wimaxServiceClassName = mContext.getResources().getString(
+                wimaxServiceClassName = context.getResources().getString(
                         com.android.internal.R.string.config_wimaxServiceClassname);
-                wimaxStateTrackerClassName = mContext.getResources().getString(
+                wimaxStateTrackerClassName = context.getResources().getString(
                         com.android.internal.R.string.config_wimaxStateTrackerClassname);
 
                 log("wimaxJarLocation: " + wimaxJarLocation);
                 wimaxClassLoader =  new DexClassLoader(wimaxJarLocation,
-                        new ContextWrapper(mContext).getCacheDir().getAbsolutePath(),
+                        new ContextWrapper(context).getCacheDir().getAbsolutePath(),
                         wimaxLibLocation, ClassLoader.getSystemClassLoader());
 
                 try {
@@ -593,13 +625,13 @@
 
                 Constructor wmxStTrkrConst = wimaxStateTrackerClass.getConstructor
                         (new Class[] {Context.class, Handler.class});
-                wimaxStateTracker = (NetworkStateTracker)wmxStTrkrConst.newInstance(mContext,
-                        mTrackerHandler);
+                wimaxStateTracker = (NetworkStateTracker) wmxStTrkrConst.newInstance(
+                        context, trackerHandler);
 
                 Constructor wmxSrvConst = wimaxServiceClass.getDeclaredConstructor
                         (new Class[] {Context.class, wimaxStateTrackerClass});
                 wmxSrvConst.setAccessible(true);
-                IBinder svcInvoker = (IBinder)wmxSrvConst.newInstance(mContext, wimaxStateTracker);
+                IBinder svcInvoker = (IBinder)wmxSrvConst.newInstance(context, wimaxStateTracker);
                 wmxSrvConst.setAccessible(false);
 
                 ServiceManager.addService(WimaxManagerConstants.WIMAX_SERVICE, svcInvoker);
@@ -1876,6 +1908,7 @@
         // snapshot isFailover, because sendConnectedBroadcast() resets it
         boolean isFailover = info.isFailover();
         final NetworkStateTracker thisNet = mNetTrackers[type];
+        final String thisIface = thisNet.getLinkProperties().getInterfaceName();
 
         // if this is a default net and other default is running
         // kill the one not preferred
@@ -1934,10 +1967,9 @@
         sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay());
 
         // notify battery stats service about this network
-        final String iface = thisNet.getLinkProperties().getInterfaceName();
-        if (iface != null) {
+        if (thisIface != null) {
             try {
-                BatteryStatsService.getService().noteNetworkInterfaceType(iface, type);
+                BatteryStatsService.getService().noteNetworkInterfaceType(thisIface, type);
             } catch (RemoteException e) {
                 // ignored; service lives in system_server
             }
@@ -2927,11 +2959,11 @@
         }
     }
 
-    private void log(String s) {
+    private static void log(String s) {
         Slog.d(TAG, s);
     }
 
-    private void loge(String s) {
+    private static void loge(String s) {
         Slog.e(TAG, s);
     }
 
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index 8bac52c..6f050d3 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -16,6 +16,8 @@
 
 package com.android.server;
 
+import static android.provider.Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK;
+
 import com.android.server.power.PowerManagerService;
 
 import android.bluetooth.BluetoothAdapter;
@@ -51,6 +53,8 @@
     private static final String DOCK_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/dock";
     private static final String DOCK_STATE_PATH = "/sys/class/switch/dock/state";
 
+    private static final int DEFAULT_DOCK = 1;
+
     private static final int MSG_DOCK_STATE = 0;
 
     private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
@@ -131,6 +135,11 @@
         mHandler.sendEmptyMessage(MSG_DOCK_STATE);
     }
 
+    private static boolean isScreenSaverActivatedOnDock(Context context) {
+        return 0 != Settings.Secure.getInt(
+                    context.getContentResolver(), SCREENSAVER_ACTIVATE_ON_DOCK, DEFAULT_DOCK);
+    }
+
     private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
@@ -210,10 +219,12 @@
                                     Slog.w(TAG, "Unable to awaken!", e);
                                 }
                             } else {
-                                try {
-                                    mgr.dream();
-                                } catch (RemoteException e) {
-                                    Slog.w(TAG, "Unable to dream!", e);
+                                if (isScreenSaverActivatedOnDock(mContext)) {
+                                    try {
+                                        mgr.dream();
+                                    } catch (RemoteException e) {
+                                        Slog.w(TAG, "Unable to dream!", e);
+                                    }
                                 }
                             }
                         } else {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 81f0733..96cf3d3 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -702,6 +702,12 @@
         }
 
         try {
+            lockSettings.systemReady();
+        } catch (Throwable e) {
+            reportWtf("making Lock Settings Service ready", e);
+        }
+
+        try {
             wm.systemReady();
         } catch (Throwable e) {
             reportWtf("making Window Manager Service ready", e);
@@ -726,11 +732,6 @@
         } catch (Throwable e) {
             reportWtf("making Package Manager Service ready", e);
         }
-        try {
-            lockSettings.systemReady();
-        } catch (Throwable e) {
-            reportWtf("making Lock Settings Service ready", e);
-        }
 
         // These are needed to propagate to the runnable below.
         final Context contextF = context;
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index fbbff4c..df6c51e 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -478,7 +478,8 @@
         if (res.record == null) {
             return -1;
         }
-        if (mAm.isSingleton(res.record.processName, res.record.appInfo)) {
+        if (mAm.isSingleton(res.record.processName, res.record.appInfo,
+                res.record.serviceInfo.name, res.record.serviceInfo.flags)) {
             userId = 0;
             res = retrieveServiceLocked(service, resolvedType, Binder.getCallingPid(),
                     Binder.getCallingUid(), 0);
@@ -787,22 +788,9 @@
                 ComponentName name = new ComponentName(
                         sInfo.applicationInfo.packageName, sInfo.name);
                 if (userId > 0) {
-                    if (mAm.isSingleton(sInfo.processName, sInfo.applicationInfo)
-                            || (sInfo.flags&ServiceInfo.FLAG_SINGLE_USER) != 0) {
+                    if (mAm.isSingleton(sInfo.processName, sInfo.applicationInfo,
+                            sInfo.name, sInfo.flags)) {
                         userId = 0;
-                    } else if ((sInfo.flags&ServiceInfo.FLAG_SINGLE_USER) != 0) {
-                        if (mAm.checkComponentPermission(
-                                android.Manifest.permission.INTERACT_ACROSS_USERS,
-                                callingPid, callingUid, -1, true)
-                                == PackageManager.PERMISSION_GRANTED) {
-                            userId = 0;
-                        } else {
-                            String msg = "Permission Denial: Service " + name
-                                    + " requests FLAG_SINGLE_USER, but app does not hold "
-                                    + android.Manifest.permission.INTERACT_ACROSS_USERS;
-                            Slog.w(TAG, msg);
-                            throw new SecurityException(msg);
-                        }
                     }
                     sInfo = new ServiceInfo(sInfo);
                     sInfo.applicationInfo = mAm.getAppInfoForUser(sInfo.applicationInfo, userId);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 98d3482..375f7f1 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -2305,19 +2305,48 @@
             Intent intent, String resolvedType, IBinder resultTo,
             String resultWho, int requestCode, int startFlags,
             String profileFile, ParcelFileDescriptor profileFd, Bundle options) {
+        return startActivityAsUser(caller, intent, resolvedType, resultTo, resultWho, requestCode,
+                startFlags, profileFile, profileFd, options, UserId.getCallingUserId());
+    }
+
+    public final int startActivityAsUser(IApplicationThread caller,
+            Intent intent, String resolvedType, IBinder resultTo,
+            String resultWho, int requestCode, int startFlags,
+            String profileFile, ParcelFileDescriptor profileFd, Bundle options, int userId) {
         enforceNotIsolatedCaller("startActivity");
-        int userId = 0;
-        if (intent.getCategories() != null && intent.getCategories().contains(Intent.CATEGORY_HOME)) {
-            // Requesting home, set the identity to the current user
-            // HACK!
-            userId = mCurrentUserId;
-        } else {
-            // TODO: Fix this in a better way - calls coming from SystemUI should probably carry
-            // the current user's userId
-            if (Binder.getCallingUid() < Process.FIRST_APPLICATION_UID) {
-                userId = 0;
+        if (userId != UserId.getCallingUserId()) {
+            // Requesting a different user, make sure that they have the permission
+            if (checkComponentPermission(
+                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                    Binder.getCallingPid(), Binder.getCallingUid(), -1, true)
+                    == PackageManager.PERMISSION_GRANTED) {
+                // Translate to the current user id, if caller wasn't aware
+                if (userId == UserId.USER_CURRENT) {
+                    userId = mCurrentUserId;
+                }
             } else {
-                userId = Binder.getOrigCallingUser();
+                String msg = "Permission Denial: "
+                        + "Request to startActivity as user " + userId
+                        + " but is calling from user " + UserId.getCallingUserId()
+                        + "; this requires "
+                        + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+                Slog.w(TAG, msg);
+                throw new SecurityException(msg);
+            }
+        } else {
+            if (intent.getCategories() != null
+                    && intent.getCategories().contains(Intent.CATEGORY_HOME)) {
+                // Requesting home, set the identity to the current user
+                // HACK!
+                userId = mCurrentUserId;
+            } else {
+                // TODO: Fix this in a better way - calls coming from SystemUI should probably carry
+                // the current user's userId
+                if (Binder.getCallingUid() < Process.FIRST_APPLICATION_UID) {
+                    userId = 0;
+                } else {
+                    userId = Binder.getOrigCallingUser();
+                }
             }
         }
         return mMainStack.startActivityMayWait(caller, -1, intent, resolvedType,
@@ -5470,13 +5499,28 @@
     }
 
     public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
-            int flags) {
+            int flags, int userId) {
         final int callingUid = Binder.getCallingUid();
-        // If it's the system uid asking, then use the current user id.
-        // TODO: Make sure that there aren't any other legitimate calls from the system uid that
-        // require the entire list.
-        final int callingUserId = callingUid == Process.SYSTEM_UID
-                ? mCurrentUserId : UserId.getUserId(callingUid);
+        if (userId != UserId.getCallingUserId()) {
+            // Check if the caller is holding permissions for cross-user requests.
+            if (checkComponentPermission(
+                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                    Binder.getCallingPid(), callingUid, -1, true)
+                    != PackageManager.PERMISSION_GRANTED) {
+                String msg = "Permission Denial: "
+                        + "Request to get recent tasks for user " + userId
+                        + " but is calling from user " + UserId.getUserId(callingUid)
+                        + "; this requires "
+                        + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+                Slog.w(TAG, msg);
+                throw new SecurityException(msg);
+            } else {
+                if (userId == UserId.USER_CURRENT) {
+                    userId = mCurrentUserId;
+                }
+            }
+        }
+
         synchronized (this) {
             enforceCallingPermission(android.Manifest.permission.GET_TASKS,
                     "getRecentTasks()");
@@ -5485,7 +5529,7 @@
                     == PackageManager.PERMISSION_GRANTED;
 
             IPackageManager pm = AppGlobals.getPackageManager();
-            
+
             final int N = mRecentTasks.size();
             ArrayList<ActivityManager.RecentTaskInfo> res
                     = new ArrayList<ActivityManager.RecentTaskInfo>(
@@ -5493,7 +5537,7 @@
             for (int i=0; i<N && maxNum > 0; i++) {
                 TaskRecord tr = mRecentTasks.get(i);
                 // Only add calling user's recent tasks
-                if (tr.userId != callingUserId) continue;
+                if (tr.userId != userId) continue;
                 // Return the entry if desired by the caller.  We always return
                 // the first entry, because callers always expect this to be the
                 // foreground app.  We may filter others if the caller has
@@ -5521,13 +5565,13 @@
                         // Check whether this activity is currently available.
                         try {
                             if (rti.origActivity != null) {
-                                if (pm.getActivityInfo(rti.origActivity, 0, callingUserId)
+                                if (pm.getActivityInfo(rti.origActivity, 0, userId)
                                         == null) {
                                     continue;
                                 }
                             } else if (rti.baseIntent != null) {
                                 if (pm.queryIntentActivities(rti.baseIntent,
-                                        null, 0, callingUserId) == null) {
+                                        null, 0, userId) == null) {
                                     continue;
                                 }
                             }
@@ -5936,15 +5980,26 @@
             Slog.v(TAG_MU, "generateApplicationProvidersLocked, app.info.uid = " + app.uid);
         int userId = app.userId;
         if (providers != null) {
-            final int N = providers.size();
+            int N = providers.size();
             for (int i=0; i<N; i++) {
                 ProviderInfo cpi =
                     (ProviderInfo)providers.get(i);
+                boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
+                        cpi.name, cpi.flags);
+                if (singleton && UserId.getUserId(app.uid) != 0) {
+                    // This is a singleton provider, but a user besides the
+                    // default user is asking to initialize a process it runs
+                    // in...  well, no, it doesn't actually run in this process,
+                    // it runs in the process of the default user.  Get rid of it.
+                    providers.remove(i);
+                    N--;
+                    continue;
+                }
 
                 ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
                 ContentProviderRecord cpr = mProviderMap.getProviderByClass(comp, userId);
                 if (cpr == null) {
-                    cpr = new ContentProviderRecord(this, cpi, app.info, comp);
+                    cpr = new ContentProviderRecord(this, cpi, app.info, comp, singleton);
                     mProviderMap.putProviderByClass(comp, cpr);
                 }
                 if (DEBUG_MU)
@@ -6177,6 +6232,7 @@
                 Binder.restoreCallingIdentity(origId);
             }
 
+            boolean singleton;
             if (!providerRunning) {
                 try {
                     cpi = AppGlobals.getPackageManager().
@@ -6187,7 +6243,9 @@
                 if (cpi == null) {
                     return null;
                 }
-                if (isSingleton(cpi.processName, cpi.applicationInfo)) {
+                singleton = isSingleton(cpi.processName, cpi.applicationInfo,
+                        cpi.name, cpi.flags); 
+                if (singleton) {
                     userId = 0;
                 }
                 cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
@@ -6222,7 +6280,7 @@
                             return null;
                         }
                         ai = getAppInfoForUser(ai, userId);
-                        cpr = new ContentProviderRecord(this, cpi, ai, comp);
+                        cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
                     } catch (RemoteException ex) {
                         // pm is in same process, this will never happen.
                     }
@@ -10515,17 +10573,31 @@
         }
     }
 
-    boolean isSingleton(String componentProcessName, ApplicationInfo aInfo) {
+    boolean isSingleton(String componentProcessName, ApplicationInfo aInfo,
+            String className, int flags) {
         boolean result = false;
         if (UserId.getAppId(aInfo.uid) >= Process.FIRST_APPLICATION_UID) {
-            result = false;
+            if ((flags&ServiceInfo.FLAG_SINGLE_USER) != 0) {
+                if (ActivityManager.checkUidPermission(
+                        android.Manifest.permission.INTERACT_ACROSS_USERS,
+                        aInfo.uid) != PackageManager.PERMISSION_GRANTED) {
+                    ComponentName comp = new ComponentName(aInfo.packageName, className);
+                    String msg = "Permission Denial: Component " + comp.flattenToShortString()
+                            + " requests FLAG_SINGLE_USER, but app does not hold "
+                            + android.Manifest.permission.INTERACT_ACROSS_USERS;
+                    Slog.w(TAG, msg);
+                    throw new SecurityException(msg);
+                }
+                result = true;
+            }
         } else if (componentProcessName == aInfo.packageName) {
             result = (aInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0;
         } else if ("system".equals(componentProcessName)) {
             result = true;
         }
         if (DEBUG_MU) {
-            Slog.v(TAG, "isSingleton(" + componentProcessName + ", " + aInfo + ") = " + result);
+            Slog.v(TAG, "isSingleton(" + componentProcessName + ", " + aInfo
+                    + ", " + className + ", 0x" + Integer.toHexString(flags) + ") = " + result);
         }
         return result;
     }
@@ -11131,30 +11203,15 @@
         List receivers = null;
         List<BroadcastFilter> registeredReceivers = null;
         try {
-            if (intent.getComponent() != null) {
-                // Broadcast is going to one specific receiver class...
-                ActivityInfo ai = AppGlobals.getPackageManager().
-                        getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS, userId);
-                if (ai != null) {
-                    receivers = new ArrayList();
-                    ResolveInfo ri = new ResolveInfo();
-                    if (isSingleton(ai.processName, ai.applicationInfo)) {
-                        ri.activityInfo = getActivityInfoForUser(ai, 0);
-                    } else {
-                        ri.activityInfo = getActivityInfoForUser(ai, userId);
-                    }
-                    receivers.add(ri);
-                }
-            } else {
-                // Need to resolve the intent to interested receivers...
-                if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
-                         == 0) {
-                    receivers =
-                        AppGlobals.getPackageManager().queryIntentReceivers(
-                                    intent, resolvedType, STOCK_PM_FLAGS, userId);
-                }
-                registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false,
-                        userId);
+            // Need to resolve the intent to interested receivers...
+            if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
+                     == 0) {
+                receivers = AppGlobals.getPackageManager().queryIntentReceivers(
+                        intent, resolvedType, STOCK_PM_FLAGS, userId);
+            }
+            if (intent.getComponent() == null) {
+                registeredReceivers = mReceiverResolver.queryIntent(intent,
+                        resolvedType, false, userId);
             }
         } catch (RemoteException ex) {
             // pm is in same process, this will never happen.
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index c9a633e..196a259 100755
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -3014,7 +3014,8 @@
         // Collect information about the target of the Intent.
         ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags,
                 profileFile, profileFd, userId);
-        if (aInfo != null && mService.isSingleton(aInfo.processName, aInfo.applicationInfo)) {
+        if (aInfo != null && mService.isSingleton(aInfo.processName, aInfo.applicationInfo,
+                null, 0)) {
             userId = 0;
         }
         aInfo = mService.getActivityInfoForUser(aInfo, userId);
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
index c6d46fc..76ddb96 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -20,12 +20,15 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 
+import android.app.ActivityManager;
 import android.app.AppGlobals;
 import android.content.ComponentName;
 import android.content.IIntentReceiver;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -249,7 +252,7 @@
                 finishReceiverLocked(br, br.resultCode, br.resultData,
                         br.resultExtras, br.resultAbort, true);
                 scheduleBroadcastsLocked();
-                // We need to reset the state if we fails to start the receiver.
+                // We need to reset the state if we failed to start the receiver.
                 br.state = BroadcastRecord.IDLE;
                 throw new RuntimeException(e.getMessage());
             }
@@ -659,6 +662,9 @@
 
             ResolveInfo info =
                 (ResolveInfo)nextReceiver;
+            ComponentName component = new ComponentName(
+                    info.activityInfo.applicationInfo.packageName,
+                    info.activityInfo.name);
 
             boolean skip = false;
             if (r.onlySendToCaller) {
@@ -667,6 +673,7 @@
                             + r.intent.toString()
                             + " from " + r.callerPackage + " (pid="
                             + r.callingPid + ", uid=" + r.callingUid + ")"
+                            + " to " + component.flattenToShortString()
                             + " not allowed to go to different app "
                             + info.activityInfo.applicationInfo.uid);
                     skip = true;
@@ -682,16 +689,14 @@
                             + " from " + r.callerPackage + " (pid=" + r.callingPid
                             + ", uid=" + r.callingUid + ")"
                             + " is not exported from uid " + info.activityInfo.applicationInfo.uid
-                            + " due to receiver " + info.activityInfo.packageName
-                            + "/" + info.activityInfo.name);
+                            + " due to receiver " + component.flattenToShortString());
                 } else {
                     Slog.w(TAG, "Permission Denial: broadcasting "
                             + r.intent.toString()
                             + " from " + r.callerPackage + " (pid=" + r.callingPid
                             + ", uid=" + r.callingUid + ")"
                             + " requires " + info.activityInfo.permission
-                            + " due to receiver " + info.activityInfo.packageName
-                            + "/" + info.activityInfo.name);
+                            + " due to receiver " + component.flattenToShortString());
                 }
                 skip = true;
             }
@@ -707,13 +712,33 @@
                 if (perm != PackageManager.PERMISSION_GRANTED) {
                     Slog.w(TAG, "Permission Denial: receiving "
                             + r.intent + " to "
-                            + info.activityInfo.applicationInfo.packageName
+                            + component.flattenToShortString()
                             + " requires " + r.requiredPermission
                             + " due to sender " + r.callerPackage
                             + " (uid " + r.callingUid + ")");
                     skip = true;
                 }
             }
+            boolean isSingleton = false;
+            try {
+                isSingleton = mService.isSingleton(info.activityInfo.processName,
+                        info.activityInfo.applicationInfo,
+                        info.activityInfo.name, info.activityInfo.flags);
+            } catch (SecurityException e) {
+                Slog.w(TAG, e.getMessage());
+                skip = true;
+            }
+            if ((info.activityInfo.flags&ActivityInfo.FLAG_SINGLE_USER) != 0) {
+                if (ActivityManager.checkUidPermission(
+                        android.Manifest.permission.INTERACT_ACROSS_USERS,
+                        info.activityInfo.applicationInfo.uid)
+                                != PackageManager.PERMISSION_GRANTED) {
+                    Slog.w(TAG, "Permission Denial: Receiver " + component.flattenToShortString()
+                            + " requests FLAG_SINGLE_USER, but app does not hold "
+                            + android.Manifest.permission.INTERACT_ACROSS_USERS);
+                    skip = true;
+                }
+            }
             if (r.curApp != null && r.curApp.crashing) {
                 // If the target process is crashing, just skip it.
                 if (DEBUG_BROADCAST)  Slog.v(TAG,
@@ -736,14 +761,9 @@
 
             r.state = BroadcastRecord.APP_RECEIVE;
             String targetProcess = info.activityInfo.processName;
-            r.curComponent = new ComponentName(
-                    info.activityInfo.applicationInfo.packageName,
-                    info.activityInfo.name);
-            if (r.callingUid != Process.SYSTEM_UID) {
-                boolean isSingleton = mService.isSingleton(info.activityInfo.processName,
-                        info.activityInfo.applicationInfo);
-                int targetUserId = isSingleton ? 0 : UserId.getUserId(r.callingUid);
-                info.activityInfo = mService.getActivityInfoForUser(info.activityInfo,targetUserId);
+            r.curComponent = component;
+            if (r.callingUid != Process.SYSTEM_UID && isSingleton) {
+                info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, 0);
             }
             r.curReceiver = info.activityInfo;
             if (DEBUG_MU && r.callingUid > UserId.PER_USER_RANGE) {
diff --git a/services/java/com/android/server/am/ContentProviderRecord.java b/services/java/com/android/server/am/ContentProviderRecord.java
index fb21b06..c80d63a 100644
--- a/services/java/com/android/server/am/ContentProviderRecord.java
+++ b/services/java/com/android/server/am/ContentProviderRecord.java
@@ -38,6 +38,7 @@
     final int uid;
     final ApplicationInfo appInfo;
     final ComponentName name;
+    final boolean singleton;
     public IContentProvider provider;
     public boolean noReleaseNeeded;
     // All attached clients
@@ -54,12 +55,13 @@
     String shortStringName;
 
     public ContentProviderRecord(ActivityManagerService _service, ProviderInfo _info,
-            ApplicationInfo ai, ComponentName _name) {
+            ApplicationInfo ai, ComponentName _name, boolean _singleton) {
         service = _service;
         info = _info;
         uid = ai.uid;
         appInfo = ai;
         name = _name;
+        singleton = _singleton;
         noReleaseNeeded = uid == 0 || uid == Process.SYSTEM_UID;
     }
 
@@ -69,6 +71,7 @@
         uid = cpr.uid;
         appInfo = cpr.appInfo;
         name = cpr.name;
+        singleton = cpr.singleton;
         noReleaseNeeded = cpr.noReleaseNeeded;
     }
 
@@ -150,6 +153,9 @@
             pw.print(prefix); pw.print("uid="); pw.print(uid);
                     pw.print(" provider="); pw.println(provider);
         }
+        if (singleton) {
+            pw.print(prefix); pw.print("singleton="); pw.println(singleton);
+        }
         pw.print(prefix); pw.print("authority="); pw.println(info.authority);
         if (full) {
             if (info.isSyncable || info.multiprocess || info.initOrder != 0) {
diff --git a/services/java/com/android/server/am/ProviderMap.java b/services/java/com/android/server/am/ProviderMap.java
index d148ec3..f4d0f9b 100644
--- a/services/java/com/android/server/am/ProviderMap.java
+++ b/services/java/com/android/server/am/ProviderMap.java
@@ -44,9 +44,9 @@
 
     private static final boolean DBG = false;
 
-    private final HashMap<String, ContentProviderRecord> mGlobalByName
+    private final HashMap<String, ContentProviderRecord> mSingletonByName
             = new HashMap<String, ContentProviderRecord>();
-    private final HashMap<ComponentName, ContentProviderRecord> mGlobalByClass
+    private final HashMap<ComponentName, ContentProviderRecord> mSingletonByClass
             = new HashMap<ComponentName, ContentProviderRecord>();
 
     private final SparseArray<HashMap<String, ContentProviderRecord>> mProvidersByNamePerUser
@@ -63,7 +63,7 @@
             Slog.i(TAG, "getProviderByName: " + name + " , callingUid = " + Binder.getCallingUid());
         }
         // Try to find it in the global list
-        ContentProviderRecord record = mGlobalByName.get(name);
+        ContentProviderRecord record = mSingletonByName.get(name);
         if (record != null) {
             return record;
         }
@@ -81,7 +81,7 @@
             Slog.i(TAG, "getProviderByClass: " + name + ", callingUid = " + Binder.getCallingUid());
         }
         // Try to find it in the global list
-        ContentProviderRecord record = mGlobalByClass.get(name);
+        ContentProviderRecord record = mSingletonByClass.get(name);
         if (record != null) {
             return record;
         }
@@ -95,8 +95,8 @@
             Slog.i(TAG, "putProviderByName: " + name + " , callingUid = " + Binder.getCallingUid()
                 + ", record uid = " + record.appInfo.uid);
         }
-        if (record.appInfo.uid < Process.FIRST_APPLICATION_UID) {
-            mGlobalByName.put(name, record);
+        if (record.singleton) {
+            mSingletonByName.put(name, record);
         } else {
             final int userId = UserId.getUserId(record.appInfo.uid);
             getProvidersByName(userId).put(name, record);
@@ -108,8 +108,8 @@
             Slog.i(TAG, "putProviderByClass: " + name + " , callingUid = " + Binder.getCallingUid()
                 + ", record uid = " + record.appInfo.uid);
         }
-        if (record.appInfo.uid < Process.FIRST_APPLICATION_UID) {
-            mGlobalByClass.put(name, record);
+        if (record.singleton) {
+            mSingletonByClass.put(name, record);
         } else {
             final int userId = UserId.getUserId(record.appInfo.uid);
             getProvidersByClass(userId).put(name, record);
@@ -117,10 +117,10 @@
     }
 
     void removeProviderByName(String name, int optionalUserId) {
-        if (mGlobalByName.containsKey(name)) {
+        if (mSingletonByName.containsKey(name)) {
             if (DBG)
                 Slog.i(TAG, "Removing from globalByName name=" + name);
-            mGlobalByName.remove(name);
+            mSingletonByName.remove(name);
         } else {
             // TODO: Verify this works, i.e., the caller happens to be from the correct user
             if (DBG)
@@ -132,10 +132,10 @@
     }
 
     void removeProviderByClass(ComponentName name, int optionalUserId) {
-        if (mGlobalByClass.containsKey(name)) {
+        if (mSingletonByClass.containsKey(name)) {
             if (DBG)
                 Slog.i(TAG, "Removing from globalByClass name=" + name);
-            mGlobalByClass.remove(name);
+            mSingletonByClass.remove(name);
         } else {
             if (DBG)
                 Slog.i(TAG,
@@ -197,37 +197,30 @@
     }
 
     void dumpProvidersLocked(PrintWriter pw, boolean dumpAll) {
-        boolean needSep = false;
-        if (mGlobalByClass.size() > 0) {
-            if (needSep)
-                pw.println(" ");
-            pw.println("  Published content providers (by class):");
-            dumpProvidersByClassLocked(pw, dumpAll, mGlobalByClass);
+        if (mSingletonByClass.size() > 0) {
+            pw.println("");
+            pw.println("  Published single-user content providers (by class):");
+            dumpProvidersByClassLocked(pw, dumpAll, mSingletonByClass);
         }
 
-        if (mProvidersByClassPerUser.size() > 1) {
-            pw.println("");
-            for (int i = 0; i < mProvidersByClassPerUser.size(); i++) {
-                HashMap<ComponentName, ContentProviderRecord> map = mProvidersByClassPerUser.valueAt(i);
-                pw.println("  User " + mProvidersByClassPerUser.keyAt(i) + ":");
-                dumpProvidersByClassLocked(pw, dumpAll, map);
-                pw.println(" ");
-            }
-        } else if (mProvidersByClassPerUser.size() == 1) {
-            HashMap<ComponentName, ContentProviderRecord> map = mProvidersByClassPerUser.valueAt(0);
+        pw.println("");
+        for (int i = 0; i < mProvidersByClassPerUser.size(); i++) {
+            HashMap<ComponentName, ContentProviderRecord> map = mProvidersByClassPerUser.valueAt(i);
+            pw.println("  Published user " + mProvidersByClassPerUser.keyAt(i)
+                    + " content providers (by class):");
             dumpProvidersByClassLocked(pw, dumpAll, map);
+            pw.println(" ");
         }
-        needSep = true;
 
         if (dumpAll) {
-            pw.println(" ");
-            pw.println("  Authority to provider mappings:");
-            dumpProvidersByNameLocked(pw, mGlobalByName);
+            pw.println("");
+            pw.println("  Single-user authority to provider mappings:");
+            dumpProvidersByNameLocked(pw, mSingletonByName);
 
             for (int i = 0; i < mProvidersByNamePerUser.size(); i++) {
-                if (i > 0) {
-                    pw.println("  User " + mProvidersByNamePerUser.keyAt(i) + ":");
-                }
+                pw.println("");
+                pw.println("  User " + mProvidersByNamePerUser.keyAt(i)
+                        + " authority to provider mappings:");
                 dumpProvidersByNameLocked(pw, mProvidersByNamePerUser.valueAt(i));
             }
         }
@@ -328,6 +321,4 @@
             }
         }
     }
-
-
 }
diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java
index d788eba..1232846 100644
--- a/services/java/com/android/server/connectivity/Vpn.java
+++ b/services/java/com/android/server/connectivity/Vpn.java
@@ -25,7 +25,6 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
@@ -39,7 +38,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.SystemClock;
-import android.os.SystemProperties;
+import android.os.SystemService;
 import android.util.Log;
 
 import com.android.internal.R;
@@ -485,8 +484,7 @@
 
                 // Wait for the daemons to stop.
                 for (String daemon : mDaemons) {
-                    String key = "init.svc." + daemon;
-                    while (!"stopped".equals(SystemProperties.get(key, "stopped"))) {
+                    while (!SystemService.isStopped(daemon)) {
                         checkpoint(true);
                     }
                 }
@@ -519,11 +517,10 @@
 
                     // Start the daemon.
                     String daemon = mDaemons[i];
-                    SystemProperties.set("ctl.start", daemon);
+                    SystemService.start(daemon);
 
                     // Wait for the daemon to start.
-                    String key = "init.svc." + daemon;
-                    while (!"running".equals(SystemProperties.get(key))) {
+                    while (!SystemService.isRunning(daemon)) {
                         checkpoint(true);
                     }
 
@@ -579,8 +576,7 @@
                     // Check if a running daemon is dead.
                     for (int i = 0; i < mDaemons.length; ++i) {
                         String daemon = mDaemons[i];
-                        if (mArguments[i] != null && !"running".equals(
-                                SystemProperties.get("init.svc." + daemon))) {
+                        if (mArguments[i] != null && !SystemService.isRunning(daemon)) {
                             throw new IllegalStateException(daemon + " is dead");
                         }
                     }
@@ -647,7 +643,7 @@
                 // Kill the daemons if they fail to stop.
                 if (mInfo.state == LegacyVpnInfo.STATE_INITIALIZING) {
                     for (String daemon : mDaemons) {
-                        SystemProperties.set("ctl.stop", daemon);
+                        SystemService.stop(daemon);
                     }
                 }
 
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index cbc3c51..180081b 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -5335,21 +5335,13 @@
             final Uri packageURI, final IPackageInstallObserver observer, final int flags,
             final String installerPackageName) {
         installPackageWithVerification(packageURI, observer, flags, installerPackageName, null,
-                null, null, null, null);
-    }
-
-    public void installPackageWithOrigin(
-            Uri packageURI, IPackageInstallObserver observer, int flags,
-            String installerPackageName, Uri originatingURI, Uri referrer) {
-        installPackageWithVerification(packageURI, observer, flags, installerPackageName, null,
-                null, null, originatingURI, referrer);
+                null, null);
     }
 
     @Override
     public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,
             int flags, String installerPackageName, Uri verificationURI,
-            ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams,
-            Uri originatingURI, Uri referrer) {
+            ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
 
         final int uid = Binder.getCallingUid();
@@ -5367,7 +5359,7 @@
 
         final Message msg = mHandler.obtainMessage(INIT_COPY);
         msg.obj = new InstallParams(packageURI, observer, filteredFlags, installerPackageName,
-                verificationURI, manifestDigest, encryptionParams, originatingURI, referrer);
+                verificationURI, manifestDigest, encryptionParams);
         mHandler.sendMessage(msg);
     }
 
@@ -5803,13 +5795,11 @@
         private int mRet;
         private File mTempPackage;
         final ContainerEncryptionParams encryptionParams;
-        final Uri originatingURI;
-        final Uri referrer;
 
         InstallParams(Uri packageURI,
                 IPackageInstallObserver observer, int flags,
                 String installerPackageName, Uri verificationURI, ManifestDigest manifestDigest,
-                ContainerEncryptionParams encryptionParams, Uri originatingURI, Uri referrer) {
+                ContainerEncryptionParams encryptionParams) {
             this.mPackageURI = packageURI;
             this.flags = flags;
             this.observer = observer;
@@ -5817,8 +5807,6 @@
             this.verificationURI = verificationURI;
             this.manifestDigest = manifestDigest;
             this.encryptionParams = encryptionParams;
-            this.originatingURI = originatingURI;
-            this.referrer = referrer;
         }
 
         private int installLocationPolicy(PackageInfoLite pkgLite, int flags) {
@@ -6014,14 +6002,6 @@
                                 verificationURI);
                     }
 
-                    if (originatingURI != null) {
-                        verification.putExtra(Intent.EXTRA_ORIGINATING_URI, originatingURI);
-                    }
-
-                    if (referrer != null) {
-                        verification.putExtra(Intent.EXTRA_REFERRER, referrer);
-                    }
-
                     final PackageVerificationState verificationState = new PackageVerificationState(
                             requiredUid, args);
 
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index 295f324..81a2c14 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -9,7 +9,8 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
     easymocklib \
-    guava
+    guava \
+    littlemock
 
 LOCAL_JAVA_LIBRARIES := android.test.runner services
 
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
new file mode 100644
index 0000000..93ea6a2
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
+import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.ConnectivityManager.getNetworkTypeName;
+import static android.net.NetworkStateTracker.EVENT_STATE_CHANGED;
+import static com.google.testing.littlemock.LittleMock.anyInt;
+import static com.google.testing.littlemock.LittleMock.createCaptor;
+import static com.google.testing.littlemock.LittleMock.doNothing;
+import static com.google.testing.littlemock.LittleMock.doReturn;
+import static com.google.testing.littlemock.LittleMock.doThrow;
+import static com.google.testing.littlemock.LittleMock.eq;
+import static com.google.testing.littlemock.LittleMock.isA;
+import static com.google.testing.littlemock.LittleMock.mock;
+import static com.google.testing.littlemock.LittleMock.reset;
+import static com.google.testing.littlemock.LittleMock.verify;
+
+import android.content.Context;
+import android.net.INetworkPolicyManager;
+import android.net.INetworkStatsService;
+import android.net.LinkProperties;
+import android.net.NetworkConfig;
+import android.net.NetworkInfo;
+import android.net.NetworkInfo.DetailedState;
+import android.net.NetworkStateTracker;
+import android.net.RouteInfo;
+import android.os.Handler;
+import android.os.INetworkManagementService;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+import android.util.LogPrinter;
+
+import com.google.testing.littlemock.ArgumentCaptor;
+
+import java.net.InetAddress;
+import java.util.concurrent.Future;
+
+/**
+ * Tests for {@link ConnectivityService}.
+ */
+@LargeTest
+public class ConnectivityServiceTest extends AndroidTestCase {
+    private static final String TAG = "ConnectivityServiceTest";
+
+    private static final String MOBILE_IFACE = "rmnet3";
+    private static final String WIFI_IFACE = "wlan6";
+
+    private static final RouteInfo MOBILE_ROUTE_V4 = RouteInfo.makeHostRoute(parse("10.0.0.33"));
+    private static final RouteInfo MOBILE_ROUTE_V6 = RouteInfo.makeHostRoute(parse("fd00::33"));
+
+    private static final RouteInfo WIFI_ROUTE_V4 = RouteInfo.makeHostRoute(
+            parse("192.168.0.66"), parse("192.168.0.1"));
+    private static final RouteInfo WIFI_ROUTE_V6 = RouteInfo.makeHostRoute(
+            parse("fd00::66"), parse("fd00::"));
+
+    private INetworkManagementService mNetManager;
+    private INetworkStatsService mStatsService;
+    private INetworkPolicyManager mPolicyService;
+    private ConnectivityService.NetworkFactory mNetFactory;
+
+    private BroadcastInterceptingContext mServiceContext;
+    private ConnectivityService mService;
+
+    private MockNetwork mMobile;
+    private MockNetwork mWifi;
+
+    private Handler mTrackerHandler;
+
+    private static class MockNetwork {
+        public NetworkStateTracker tracker;
+        public NetworkInfo info;
+        public LinkProperties link;
+
+        public MockNetwork(int type) {
+            tracker = mock(NetworkStateTracker.class);
+            info = new NetworkInfo(type, -1, getNetworkTypeName(type), null);
+            link = new LinkProperties();
+        }
+
+        public void doReturnDefaults() {
+            // TODO: eventually CS should make defensive copies
+            doReturn(new NetworkInfo(info)).when(tracker).getNetworkInfo();
+            doReturn(new LinkProperties(link)).when(tracker).getLinkProperties();
+
+            // fallback to default TCP buffers
+            doReturn("").when(tracker).getTcpBufferSizesPropName();
+        }
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        mServiceContext = new BroadcastInterceptingContext(getContext());
+
+        mNetManager = mock(INetworkManagementService.class);
+        mStatsService = mock(INetworkStatsService.class);
+        mPolicyService = mock(INetworkPolicyManager.class);
+        mNetFactory = mock(ConnectivityService.NetworkFactory.class);
+
+        mMobile = new MockNetwork(TYPE_MOBILE);
+        mWifi = new MockNetwork(TYPE_WIFI);
+
+        // omit most network trackers
+        doThrow(new IllegalArgumentException("Not supported in test environment"))
+                .when(mNetFactory).createTracker(anyInt(), isA(NetworkConfig.class));
+
+        doReturn(mMobile.tracker)
+                .when(mNetFactory).createTracker(eq(TYPE_MOBILE), isA(NetworkConfig.class));
+        doReturn(mWifi.tracker)
+                .when(mNetFactory).createTracker(eq(TYPE_WIFI), isA(NetworkConfig.class));
+
+        final ArgumentCaptor<Handler> trackerHandler = createCaptor();
+        doNothing().when(mMobile.tracker)
+                .startMonitoring(isA(Context.class), trackerHandler.capture());
+
+        mService = new ConnectivityService(
+                mServiceContext, mNetManager, mStatsService, mPolicyService, mNetFactory);
+        mService.systemReady();
+
+        mTrackerHandler = trackerHandler.getValue();
+        mTrackerHandler.getLooper().setMessageLogging(new LogPrinter(Log.INFO, TAG));
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    public void testMobileConnectedAddedRoutes() throws Exception {
+        Future<?> nextConnBroadcast;
+
+        // bring up mobile network
+        mMobile.info.setDetailedState(DetailedState.CONNECTED, null, null);
+        mMobile.link.setInterfaceName(MOBILE_IFACE);
+        mMobile.link.addRoute(MOBILE_ROUTE_V4);
+        mMobile.link.addRoute(MOBILE_ROUTE_V6);
+        mMobile.doReturnDefaults();
+
+        nextConnBroadcast = mServiceContext.nextBroadcastIntent(CONNECTIVITY_ACTION_IMMEDIATE);
+        mTrackerHandler.obtainMessage(EVENT_STATE_CHANGED, mMobile.info).sendToTarget();
+        nextConnBroadcast.get();
+
+        // verify that both routes were added and DNS was flushed
+        verify(mNetManager).addRoute(eq(MOBILE_IFACE), eq(MOBILE_ROUTE_V4));
+        verify(mNetManager).addRoute(eq(MOBILE_IFACE), eq(MOBILE_ROUTE_V6));
+        verify(mNetManager).flushInterfaceDnsCache(MOBILE_IFACE);
+
+    }
+
+    public void testMobileWifiHandoff() throws Exception {
+        Future<?> nextConnBroadcast;
+
+        // bring up mobile network
+        mMobile.info.setDetailedState(DetailedState.CONNECTED, null, null);
+        mMobile.link.setInterfaceName(MOBILE_IFACE);
+        mMobile.link.addRoute(MOBILE_ROUTE_V4);
+        mMobile.link.addRoute(MOBILE_ROUTE_V6);
+        mMobile.doReturnDefaults();
+
+        nextConnBroadcast = mServiceContext.nextBroadcastIntent(CONNECTIVITY_ACTION_IMMEDIATE);
+        mTrackerHandler.obtainMessage(EVENT_STATE_CHANGED, mMobile.info).sendToTarget();
+        nextConnBroadcast.get();
+
+        reset(mNetManager);
+
+        // now bring up wifi network
+        mWifi.info.setDetailedState(DetailedState.CONNECTED, null, null);
+        mWifi.link.setInterfaceName(WIFI_IFACE);
+        mWifi.link.addRoute(WIFI_ROUTE_V4);
+        mWifi.link.addRoute(WIFI_ROUTE_V6);
+        mWifi.doReturnDefaults();
+
+        // expect that mobile will be torn down
+        doReturn(true).when(mMobile.tracker).teardown();
+
+        nextConnBroadcast = mServiceContext.nextBroadcastIntent(CONNECTIVITY_ACTION_IMMEDIATE);
+        mTrackerHandler.obtainMessage(EVENT_STATE_CHANGED, mWifi.info).sendToTarget();
+        nextConnBroadcast.get();
+
+        // verify that wifi routes added, and teardown requested
+        verify(mNetManager).addRoute(eq(WIFI_IFACE), eq(WIFI_ROUTE_V4));
+        verify(mNetManager).addRoute(eq(WIFI_IFACE), eq(WIFI_ROUTE_V6));
+        verify(mNetManager).flushInterfaceDnsCache(WIFI_IFACE);
+        verify(mMobile.tracker).teardown();
+
+        reset(mNetManager, mMobile.tracker);
+
+        // tear down mobile network, as requested
+        mMobile.info.setDetailedState(DetailedState.DISCONNECTED, null, null);
+        mMobile.link.clear();
+        mMobile.doReturnDefaults();
+
+        nextConnBroadcast = mServiceContext.nextBroadcastIntent(CONNECTIVITY_ACTION_IMMEDIATE);
+        mTrackerHandler.obtainMessage(EVENT_STATE_CHANGED, mMobile.info).sendToTarget();
+        nextConnBroadcast.get();
+
+        verify(mNetManager).removeRoute(eq(MOBILE_IFACE), eq(MOBILE_ROUTE_V4));
+        verify(mNetManager).removeRoute(eq(MOBILE_IFACE), eq(MOBILE_ROUTE_V6));
+
+    }
+
+    private static InetAddress parse(String addr) {
+        return InetAddress.parseNumericAddress(addr);
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index 79872f3..10ac153 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -90,6 +90,7 @@
     public static final int CMD_SET_USER_DATA_ENABLE = BASE + 30;
     public static final int CMD_SET_DEPENDENCY_MET = BASE + 31;
     public static final int CMD_SET_POLICY_DATA_ENABLE = BASE + 32;
+    public static final int EVENT_ICC_CHANGED = BASE + 33;
 
     /***** Constants *****/
 
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 92c6676..9acffa3 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -285,11 +285,6 @@
     }
 
     @Override
-    public void sendBroadcastToUser(Intent intent, int userId) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
     public void sendBroadcast(Intent intent, String receiverPermission) {
         throw new UnsupportedOperationException();
     }
@@ -308,6 +303,18 @@
     }
 
     @Override
+    public void sendBroadcastToUser(Intent intent, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void sendOrderedBroadcastToUser(Intent intent, int userId,
+            BroadcastReceiver resultReceiver, Handler scheduler,
+            int initialCode, String initialData, Bundle initialExtras) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public void sendStickyBroadcast(Intent intent) {
         throw new UnsupportedOperationException();
     }
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index b1224d3..0399b3b 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -563,17 +563,7 @@
     @Override
     public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,
             int flags, String installerPackageName, Uri verificationURI,
-            ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams,
-            Uri originatingURI, Uri referrer) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * @hide
-     */
-    @Override
-    public void installPackageWithOrigin(Uri packageURI, IPackageInstallObserver observer,
-            int flags, String installerPackageName, Uri originatingURI, Uri referrer) {
+            ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {
         throw new UnsupportedOperationException();
     }
 
diff --git a/tests/ActivityTests/AndroidManifest.xml b/tests/ActivityTests/AndroidManifest.xml
index 6f00095..9dfe4a1 100644
--- a/tests/ActivityTests/AndroidManifest.xml
+++ b/tests/ActivityTests/AndroidManifest.xml
@@ -33,5 +33,11 @@
         </service>
         <receiver android:name="UserTarget">
         </receiver>
+        <receiver android:name="SingleUserReceiver"
+            android:singleUser="true" android:exported="true" >
+        </receiver>
+        <provider android:name="SingleUserProvider"
+            android:authorities="com.google.android.test.activity.single_user"
+            android:singleUser="true" android:exported="true" />
     </application>
 </manifest>
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
index bcef2d9..0ec1f13 100644
--- a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
+++ b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
@@ -22,16 +22,20 @@
 import android.app.ActivityManager;
 import android.app.AlertDialog;
 import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
+import android.content.ContentProviderClient;
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.RemoteException;
 import android.graphics.Bitmap;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 import android.widget.ScrollView;
+import android.widget.Toast;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
@@ -43,6 +47,18 @@
 
     ActivityManager mAm;
 
+    class BroadcastResultReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            Bundle res = getResultExtras(true);
+            int user = res.getInt("user", -1);
+            Toast.makeText(ActivityTestMain.this,
+                    "Receiver executed as user "
+                    + (user >= 0 ? Integer.toString(user) : "unknown"),
+                    Toast.LENGTH_LONG).show();
+        }
+    }
+
     private void addThumbnail(LinearLayout container, Bitmap bm,
             final ActivityManager.RecentTaskInfo task,
             final ActivityManager.TaskThumbnails thumbs, final int subIndex) {
@@ -134,8 +150,35 @@
         });
         menu.add("Send!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
             @Override public boolean onMenuItemClick(MenuItem item) {
+                Intent intent = new Intent(ActivityTestMain.this, SingleUserReceiver.class);
+                sendOrderedBroadcast(intent, null, new BroadcastResultReceiver(), 
+                        null, Activity.RESULT_OK, null, null);
+                return true;
+            }
+        });
+        menu.add("Call!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+            @Override public boolean onMenuItemClick(MenuItem item) {
+                ContentProviderClient cpl = getContentResolver().acquireContentProviderClient(
+                        SingleUserProvider.AUTHORITY);
+                Bundle res = null;
+                try {
+                    res = cpl.call("getuser", null, null);
+                } catch (RemoteException e) {
+                }
+                int user = res != null ? res.getInt("user", -1) : -1;
+                Toast.makeText(ActivityTestMain.this,
+                        "Provider executed as user "
+                        + (user >= 0 ? Integer.toString(user) : "unknown"),
+                        Toast.LENGTH_LONG).show();
+                cpl.release();
+                return true;
+            }
+        });
+        menu.add("Send to user 1!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+            @Override public boolean onMenuItemClick(MenuItem item) {
                 Intent intent = new Intent(ActivityTestMain.this, UserTarget.class);
-                sendBroadcastToUser(intent, 1);
+                sendOrderedBroadcastToUser(intent, 1, new BroadcastResultReceiver(), 
+                        null, Activity.RESULT_OK, null, null);
                 return true;
             }
         });
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/SingleUserProvider.java b/tests/ActivityTests/src/com/google/android/test/activity/SingleUserProvider.java
new file mode 100644
index 0000000..83785e4
--- /dev/null
+++ b/tests/ActivityTests/src/com/google/android/test/activity/SingleUserProvider.java
@@ -0,0 +1,66 @@
+/*
+ * 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.test.activity;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Process;
+
+public class SingleUserProvider extends ContentProvider {
+    static final String AUTHORITY = "com.google.android.test.activity.single_user";
+
+    @Override
+    public boolean onCreate() {
+        return true;
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+            String sortOrder) {
+        return null;
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        return null;
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        return null;
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        return 0;
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        return 0;
+    }
+
+    @Override
+    public Bundle call(String method, String arg, Bundle extras) {
+        Bundle res = new Bundle();
+        res.putInt("user", Process.myUserHandle());
+        return res;
+    }
+}
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/SingleUserReceiver.java b/tests/ActivityTests/src/com/google/android/test/activity/SingleUserReceiver.java
new file mode 100644
index 0000000..9295cf48
--- /dev/null
+++ b/tests/ActivityTests/src/com/google/android/test/activity/SingleUserReceiver.java
@@ -0,0 +1,32 @@
+/*
+ * 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.test.activity;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Process;
+
+public class SingleUserReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        Bundle res = getResultExtras(true);
+        res.putInt("user", Process.myUserHandle());
+        setResultExtras(res);
+    }
+}
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/UserTarget.java b/tests/ActivityTests/src/com/google/android/test/activity/UserTarget.java
index 9890483..9c6a9f1 100644
--- a/tests/ActivityTests/src/com/google/android/test/activity/UserTarget.java
+++ b/tests/ActivityTests/src/com/google/android/test/activity/UserTarget.java
@@ -19,11 +19,16 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.os.Bundle;
+import android.os.Process;
 import android.util.Log;
 
 public class UserTarget extends BroadcastReceiver {
     @Override
     public void onReceive(Context context, Intent intent) {
         Log.i("ActivityTest", "Received: " + intent);
+        Bundle res = getResultExtras(true);
+        res.putInt("user", Process.myUserHandle());
+        setResultExtras(res);
     }
 }
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index fad5993..1857033 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -33,6 +33,15 @@
         <meta-data android:name="android.graphics.renderThread" android:value="true" />
 
         <activity
+                android:name="TextPathActivity"
+                android:label="_TextPath">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <activity
                 android:name="GradientStopsActivity"
                 android:label="_GradientStops">
             <intent-filter>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextPathActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TextPathActivity.java
new file mode 100644
index 0000000..35a1fc9
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TextPathActivity.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ScrollView;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class TextPathActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        ScrollView scroller = new ScrollView(this);
+        scroller.addView(new CustomTextView(this));
+        setContentView(scroller);
+    }
+
+    static class CustomTextView extends View {
+        private final Paint mHugePaint;
+
+        CustomTextView(Context c) {
+            super(c);
+
+            mHugePaint = new Paint();
+            mHugePaint.setAntiAlias(true);
+            mHugePaint.setColor(0xff000000);
+            mHugePaint.setTextSize(300f);
+        }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), 3000);
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+            canvas.drawRGB(255, 255, 255);
+
+            Path path = new Path();
+
+            canvas.translate(100.0f, 300.0f);
+            drawTextAsPath(canvas, "Hello", path);
+
+            canvas.translate(0.0f, 400.0f);
+            drawTextAsPath(canvas, "OpenGL", path);
+        }
+
+        private void drawTextAsPath(Canvas canvas, String text, Path path) {
+            int count = text.length();
+            mHugePaint.getTextPath(text, 0, count, 0, 0, path);
+            path.close();
+            canvas.drawPath(path, mHugePaint);
+        }
+    }
+}
diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp
index 0dba950..dcbe7db 100644
--- a/tools/aapt/XMLNode.cpp
+++ b/tools/aapt/XMLNode.cpp
@@ -511,7 +511,8 @@
             namespaces.pop();
         } else if (code == ResXMLTree::TEXT) {
             size_t len;
-            printf("%sC: \"%s\"\n", prefix.string(), String8(block->getText(&len)).string());
+            printf("%sC: \"%s\"\n", prefix.string(),
+                    ResTable::normalizeForOutput(String8(block->getText(&len)).string()).string());
         }
     }
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 3ae660d..c4a6906 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -1187,6 +1187,18 @@
     }
 
     @Override
+    public void sendBroadcastToUser(Intent intent, int userId) {
+        // pass
+    }
+
+    @Override
+    public void sendOrderedBroadcastToUser(Intent intent, int userId,
+            BroadcastReceiver resultReceiver, Handler scheduler,
+            int initialCode, String initialData, Bundle initialExtras) {
+        // pass
+    }
+
+    @Override
     public void sendStickyBroadcast(Intent arg0) {
         // pass