Merge "Create DPM APIs for cross profile callerId" into lmp-dev
diff --git a/Android.mk b/Android.mk
index 9cda341..7a8907e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -241,6 +241,7 @@
 	core/java/android/view/IWindowManager.aidl \
 	core/java/android/view/IWindowSession.aidl \
 	core/java/android/view/IWindowSessionCallback.aidl \
+	core/java/android/webkit/IWebViewUpdateService.aidl \
 	core/java/android/speech/IRecognitionListener.aidl \
 	core/java/android/speech/IRecognitionService.aidl \
 	core/java/android/speech/tts/ITextToSpeechCallback.aidl \
diff --git a/api/current.txt b/api/current.txt
index 213834f..fac1d8c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -16552,6 +16552,7 @@
     method public java.lang.String getId();
     method public android.content.Intent getIntentForSettingsActivity();
     method public android.content.Intent getIntentForSetupActivity();
+    method public java.lang.String getParentId();
     method public android.content.pm.ServiceInfo getServiceInfo();
     method public int getType();
     method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
@@ -27255,6 +27256,7 @@
     method public deprecated int playEarcon(java.lang.String, int, java.util.HashMap<java.lang.String, java.lang.String>);
     method public int playSilence(long, int, java.util.HashMap<java.lang.String, java.lang.String>, java.lang.String);
     method public deprecated int playSilence(long, int, java.util.HashMap<java.lang.String, java.lang.String>);
+    method public int setAudioAttributes(android.media.AudioAttributes);
     method public deprecated int setEngineByPackageName(java.lang.String);
     method public int setLanguage(java.util.Locale);
     method public deprecated int setOnUtteranceCompletedListener(android.speech.tts.TextToSpeech.OnUtteranceCompletedListener);
@@ -28031,6 +28033,7 @@
     method public int getState();
     method public void hold();
     method public void phoneAccountClicked();
+    method public void phoneAccountSelected(android.telecomm.PhoneAccount);
     method public void playDtmfTone(char);
     method public void postDialContinue(boolean);
     method public void reject(boolean, java.lang.String);
@@ -28044,6 +28047,7 @@
     field public static final int STATE_DISCONNECTED = 7; // 0x7
     field public static final int STATE_HOLDING = 3; // 0x3
     field public static final int STATE_NEW = 0; // 0x0
+    field public static final int STATE_PRE_DIAL_WAIT = 8; // 0x8
     field public static final int STATE_RINGING = 2; // 0x2
   }
 
@@ -28131,6 +28135,7 @@
     enum_constant public static final android.telecomm.CallState DISCONNECTED;
     enum_constant public static final android.telecomm.CallState NEW;
     enum_constant public static final android.telecomm.CallState ON_HOLD;
+    enum_constant public static final android.telecomm.CallState PRE_DIAL_WAIT;
     enum_constant public static final android.telecomm.CallState RINGING;
   }
 
@@ -28275,6 +28280,7 @@
     method public void holdCall(java.lang.String);
     method public void mute(boolean);
     method public void phoneAccountClicked(java.lang.String);
+    method public void phoneAccountSelected(java.lang.String, android.telecomm.PhoneAccount);
     method public void playDtmfTone(java.lang.String, char);
     method public void postDialContinue(java.lang.String, boolean);
     method public void rejectCall(java.lang.String, boolean, java.lang.String);
@@ -31164,6 +31170,36 @@
     field public static final int WEEKDAY_WEDNESDAY = 4; // 0x4
   }
 
+  public static abstract class TtsSpan.Builder {
+    ctor public TtsSpan.Builder(java.lang.String);
+    method public android.text.style.TtsSpan build();
+    method public C setIntArgument(java.lang.String, int);
+    method public C setLongArgument(java.lang.String, long);
+    method public C setStringArgument(java.lang.String, java.lang.String);
+  }
+
+  public static class TtsSpan.CardinalBuilder extends android.text.style.TtsSpan.SemioticClassBuilder {
+    ctor public TtsSpan.CardinalBuilder();
+    ctor public TtsSpan.CardinalBuilder(long);
+    ctor public TtsSpan.CardinalBuilder(java.lang.String);
+    method public android.text.style.TtsSpan.CardinalBuilder setNumber(long);
+    method public android.text.style.TtsSpan.CardinalBuilder setNumber(java.lang.String);
+  }
+
+  public static class TtsSpan.SemioticClassBuilder extends android.text.style.TtsSpan.Builder {
+    ctor public TtsSpan.SemioticClassBuilder(java.lang.String);
+    method public C setAnimacy(java.lang.String);
+    method public C setCase(java.lang.String);
+    method public C setGender(java.lang.String);
+    method public C setMultiplicity(java.lang.String);
+  }
+
+  public static class TtsSpan.TextBuilder extends android.text.style.TtsSpan.SemioticClassBuilder {
+    ctor public TtsSpan.TextBuilder();
+    ctor public TtsSpan.TextBuilder(java.lang.String);
+    method public android.text.style.TtsSpan.TextBuilder setText(java.lang.String);
+  }
+
   public class TypefaceSpan extends android.text.style.MetricAffectingSpan implements android.text.ParcelableSpan {
     ctor public TypefaceSpan(java.lang.String);
     ctor public TypefaceSpan(android.os.Parcel);
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 806a55b..aab6e80 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -155,6 +155,8 @@
 
     /** @hide */
     public static final int ERROR_CODE_USER_RESTRICTED = 100;
+    /** @hide */
+    public static final int ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE = 101;
 
     /**
      * Bundle key used for the {@link String} account name in results
@@ -678,8 +680,7 @@
      * @param handler {@link Handler} identifying the callback thread,
      *     null for the main thread
      * @return An {@link AccountManagerFuture} which resolves to a Boolean,
-     *     true if the account has been successfully removed,
-     *     false if the authenticator forbids deleting this account.
+     *     true if the account has been successfully removed
      */
     public AccountManagerFuture<Boolean> removeAccount(final Account account,
             AccountManagerCallback<Boolean> callback, Handler handler) {
@@ -698,6 +699,28 @@
     }
 
     /**
+     * @see #removeAccount(Account, AccountManagerCallback, Handler)
+     * @hide
+     */
+    public AccountManagerFuture<Boolean> removeAccountAsUser(final Account account,
+            AccountManagerCallback<Boolean> callback, Handler handler,
+            final UserHandle userHandle) {
+        if (account == null) throw new IllegalArgumentException("account is null");
+        if (userHandle == null) throw new IllegalArgumentException("userHandle is null");
+        return new Future2Task<Boolean>(handler, callback) {
+            public void doWork() throws RemoteException {
+                mService.removeAccountAsUser(mResponse, account, userHandle.getIdentifier());
+            }
+            public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
+                if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
+                    throw new AuthenticatorException("no result in response");
+                }
+                return bundle.getBoolean(KEY_BOOLEAN_RESULT);
+            }
+        }.start();
+    }
+
+    /**
      * Removes an auth token from the AccountManager's cache.  Does nothing if
      * the auth token is not currently in the cache.  Applications must call this
      * method when the auth token is found to have expired or otherwise become
@@ -1183,7 +1206,8 @@
      * <li> {@link AuthenticatorException} if no authenticator was registered for
      *      this account type or the authenticator failed to respond
      * <li> {@link OperationCanceledException} if the operation was canceled for
-     *      any reason, including the user canceling the creation process
+     *      any reason, including the user canceling the creation process or adding accounts
+     *      (of this type) has been disabled by policy
      * <li> {@link IOException} if the authenticator experienced an I/O problem
      *      creating a new account, usually because of network trouble
      * </ul>
@@ -1208,6 +1232,30 @@
     }
 
     /**
+     * @see #addAccount(String, String, String[], Bundle, Activity, AccountManagerCallback, Handler)
+     * @hide
+     */
+    public AccountManagerFuture<Bundle> addAccountAsUser(final String accountType,
+            final String authTokenType, final String[] requiredFeatures,
+            final Bundle addAccountOptions, final Activity activity,
+            AccountManagerCallback<Bundle> callback, Handler handler, final UserHandle userHandle) {
+        if (accountType == null) throw new IllegalArgumentException("accountType is null");
+        if (userHandle == null) throw new IllegalArgumentException("userHandle is null");
+        final Bundle optionsIn = new Bundle();
+        if (addAccountOptions != null) {
+            optionsIn.putAll(addAccountOptions);
+        }
+        optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
+
+        return new AmsTask(activity, handler, callback) {
+            public void doWork() throws RemoteException {
+                mService.addAccountAsUser(mResponse, accountType, authTokenType,
+                        requiredFeatures, activity != null, optionsIn, userHandle.getIdentifier());
+            }
+        }.start();
+    }
+
+    /**
      * Adds a shared account from the primary user to a secondary user. Adding the shared account
      * doesn't take effect immediately. When the target user starts up, any pending shared accounts
      * are attempted to be copied to the target user from the primary via calls to the
@@ -1608,8 +1656,10 @@
             }
 
             public void onError(int code, String message) {
-                if (code == ERROR_CODE_CANCELED || code == ERROR_CODE_USER_RESTRICTED) {
-                    // the authenticator indicated that this request was canceled, do so now
+                if (code == ERROR_CODE_CANCELED || code == ERROR_CODE_USER_RESTRICTED
+                        || code == ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
+                    // the authenticator indicated that this request was canceled or we were
+                    // forbidden to fulfill; cancel now
                     cancel(true /* mayInterruptIfRunning */);
                     return;
                 }
@@ -1668,7 +1718,10 @@
             }
 
             public void onError(int code, String message) {
-                if (code == ERROR_CODE_CANCELED) {
+                if (code == ERROR_CODE_CANCELED || code == ERROR_CODE_USER_RESTRICTED
+                        || code == ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) {
+                    // the authenticator indicated that this request was canceled or we were
+                    // forbidden to fulfill; cancel now
                     cancel(true /* mayInterruptIfRunning */);
                     return;
                 }
diff --git a/core/java/android/accounts/AccountManagerFuture.java b/core/java/android/accounts/AccountManagerFuture.java
index af00a08..77670d9 100644
--- a/core/java/android/accounts/AccountManagerFuture.java
+++ b/core/java/android/accounts/AccountManagerFuture.java
@@ -84,7 +84,8 @@
      * will be thrown rather than the call returning normally.
      * @return the actual result
      * @throws android.accounts.OperationCanceledException if the request was canceled for any
-     * reason
+     * reason (including if it is forbidden
+     * by policy to modify an account (of that type))
      * @throws android.accounts.AuthenticatorException if there was an error communicating with
      * the authenticator or if the authenticator returned an invalid response
      * @throws java.io.IOException if the authenticator returned an error response that indicates
diff --git a/core/java/android/accounts/CantAddAccountActivity.java b/core/java/android/accounts/CantAddAccountActivity.java
index e1717a6..4ac2beb 100644
--- a/core/java/android/accounts/CantAddAccountActivity.java
+++ b/core/java/android/accounts/CantAddAccountActivity.java
@@ -19,6 +19,7 @@
 import android.app.Activity;
 import android.os.Bundle;
 import android.view.View;
+import android.widget.TextView;
 
 import com.android.internal.R;
 
@@ -27,11 +28,26 @@
  * Just shows an error message about the account restrictions for the limited user.
  */
 public class CantAddAccountActivity extends Activity {
+    public static final String EXTRA_ERROR_CODE = "android.accounts.extra.ERROR_CODE";
+    public static final int MISSING = -1;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.app_not_authorized);
+
+        int errorCode = getIntent().getIntExtra(EXTRA_ERROR_CODE, MISSING);
+        if (errorCode != MISSING) {
+            TextView errorText = (TextView) findViewById(R.id.description);
+            switch (errorCode) {
+                case AccountManager.ERROR_CODE_USER_RESTRICTED:
+                    errorText.setText(R.string.app_no_restricted_accounts);
+                    break;
+                default:
+                    // TODO: Get better message. See: http://b/14642886
+                    errorText.setText(R.string.error_message_title);
+            }
+        }
     }
 
     public void onCancelButtonClicked(View view) {
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index 1373dc8..a04875d 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -38,6 +38,7 @@
     void getAccountsByFeatures(in IAccountManagerResponse response, String accountType, in String[] features);
     boolean addAccountExplicitly(in Account account, String password, in Bundle extras);
     void removeAccount(in IAccountManagerResponse response, in Account account);
+    void removeAccountAsUser(in IAccountManagerResponse response, in Account account, int userId);
     void invalidateAuthToken(String accountType, String authToken);
     String peekAuthToken(in Account account, String authTokenType);
     void setAuthToken(in Account account, String authTokenType, String authToken);
@@ -52,6 +53,9 @@
     void addAccount(in IAccountManagerResponse response, String accountType,
         String authTokenType, in String[] requiredFeatures, boolean expectActivityLaunch,
         in Bundle options);
+    void addAccountAsUser(in IAccountManagerResponse response, String accountType,
+        String authTokenType, in String[] requiredFeatures, boolean expectActivityLaunch,
+        in Bundle options, int userId);
     void updateCredentials(in IAccountManagerResponse response, in Account account,
         String authTokenType, boolean expectActivityLaunch, in Bundle options);
     void editProperties(in IAccountManagerResponse response, String accountType,
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index d3aa950..71ad0c9 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2637,9 +2637,17 @@
      * @see #setAccountManagementDisabled
      */
     public String[] getAccountTypesWithManagementDisabled() {
+        return getAccountTypesWithManagementDisabledAsUser(UserHandle.getCallingUserId());
+    }
+
+    /**
+     * @see #getAccountTypesWithManagementDisabled()
+     * @hide
+     */
+    public String[] getAccountTypesWithManagementDisabledAsUser(int userId) {
         if (mService != null) {
             try {
-                return mService.getAccountTypesWithManagementDisabled();
+                return mService.getAccountTypesWithManagementDisabledAsUser(userId);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 46b8755..9b1979f 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -146,6 +146,7 @@
 
     void setAccountManagementDisabled(in ComponentName who, in String accountType, in boolean disabled);
     String[] getAccountTypesWithManagementDisabled();
+    String[] getAccountTypesWithManagementDisabledAsUser(int userId);
 
     void setLockTaskPackages(in String[] packages);
     String[] getLockTaskPackages();
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index ab33d75..833dc21 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -836,10 +836,6 @@
             pkg.baseCodePath = apkPath;
             pkg.mSignatures = null;
 
-            // TODO: Remove this when the WebView can load resources dynamically. b/11505352
-            pkg.usesOptionalLibraries = ArrayUtils.add(pkg.usesOptionalLibraries,
-                    "com.android.webview");
-
             return pkg;
 
         } catch (PackageParserException e) {
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 3a30123..2684e6c 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -100,7 +100,7 @@
         synchronized (sSync) {
             if (sSystem == null) {
                 AssetManager system = new AssetManager(true);
-                system.makeStringBlocks(false);
+                system.makeStringBlocks(null);
                 sSystem = system;
             }
         }
@@ -246,21 +246,21 @@
         if (mStringBlocks == null) {
             synchronized (this) {
                 if (mStringBlocks == null) {
-                    makeStringBlocks(true);
+                    makeStringBlocks(sSystem.mStringBlocks);
                 }
             }
         }
     }
 
-    /*package*/ final void makeStringBlocks(boolean copyFromSystem) {
-        final int sysNum = copyFromSystem ? sSystem.mStringBlocks.length : 0;
+    /*package*/ final void makeStringBlocks(StringBlock[] seed) {
+        final int seedNum = (seed != null) ? seed.length : 0;
         final int num = getStringBlockCount();
         mStringBlocks = new StringBlock[num];
         if (localLOGV) Log.v(TAG, "Making string blocks for " + this
                 + ": " + num);
         for (int i=0; i<num; i++) {
-            if (i < sysNum) {
-                mStringBlocks[i] = sSystem.mStringBlocks[i];
+            if (i < seedNum) {
+                mStringBlocks[i] = seed[i];
             } else {
                 mStringBlocks[i] = new StringBlock(getNativeStringBlock(i), true);
             }
@@ -610,8 +610,11 @@
      * {@hide}
      */
     public final int addAssetPath(String path) {
-        int res = addAssetPathNative(path);
-        return res;
+        synchronized (this) {
+            int res = addAssetPathNative(path);
+            makeStringBlocks(mStringBlocks);
+            return res;
+        }
     }
 
     private native final int addAssetPathNative(String path);
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 8caea25..afac239 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -131,6 +131,12 @@
     public static final int PACKAGE_INFO_GID = 1032;
 
     /**
+     * Defines the UID/GID for the shared RELRO file updater process.
+     * @hide
+     */
+    public static final int SHARED_RELRO_UID = 1037;
+
+    /**
      * Defines the start of a range of UIDs (and GIDs), going from this
      * number to {@link #LAST_APPLICATION_UID} that are reserved for assigning
      * to applications.
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 707d31a..7bbac2c 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -138,7 +138,8 @@
     public static final String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials";
 
     /**
-     * Key for user restrictions. Specifies if a user is disallowed from removing users.
+     * Key for user restrictions. Specifies if a user is disallowed from removing itself and other
+     * users.
      * The default value is <code>false</code>.
      * <p/>
      * Type: Boolean
diff --git a/core/java/android/speech/tts/AudioPlaybackQueueItem.java b/core/java/android/speech/tts/AudioPlaybackQueueItem.java
index c13b47f..b4ac429 100644
--- a/core/java/android/speech/tts/AudioPlaybackQueueItem.java
+++ b/core/java/android/speech/tts/AudioPlaybackQueueItem.java
@@ -54,7 +54,11 @@
         final UtteranceProgressDispatcher dispatcher = getDispatcher();
 
         dispatcher.dispatchOnStart();
-        mPlayer = MediaPlayer.create(mContext, mUri);
+
+        int sessionId = mAudioParams.mSessionId;
+        mPlayer = MediaPlayer.create(
+                mContext, mUri, null, mAudioParams.mAudioAttributes,
+                sessionId > 0 ? sessionId : AudioSystem.AUDIO_SESSION_ALLOCATE);
         if (mPlayer == null) {
             dispatcher.dispatchOnError(TextToSpeech.ERROR_OUTPUT);
             return;
@@ -76,11 +80,8 @@
                     mDone.open();
                 }
             });
-            mPlayer.setAudioStreamType(mAudioParams.mStreamType);
+
             setupVolume(mPlayer, mAudioParams.mVolume, mAudioParams.mPan);
-            if (mAudioParams.mSessionId != AudioSystem.AUDIO_SESSION_ALLOCATE) {
-                mPlayer.setAudioSessionId(mAudioParams.mSessionId);
-            }
             mPlayer.start();
             mDone.block();
             finish();
diff --git a/core/java/android/speech/tts/BlockingAudioTrack.java b/core/java/android/speech/tts/BlockingAudioTrack.java
index b405de0..dc4e9d3 100644
--- a/core/java/android/speech/tts/BlockingAudioTrack.java
+++ b/core/java/android/speech/tts/BlockingAudioTrack.java
@@ -2,6 +2,7 @@
 
 package android.speech.tts;
 
+import android.media.AudioAttributes;
 import android.media.AudioFormat;
 import android.media.AudioTrack;
 import android.speech.tts.TextToSpeechService.AudioOutputParams;
@@ -214,9 +215,14 @@
                 = AudioTrack.getMinBufferSize(mSampleRateInHz, channelConfig, mAudioFormat);
         int bufferSizeInBytes = Math.max(MIN_AUDIO_BUFFER_SIZE, minBufferSizeInBytes);
 
-        AudioTrack audioTrack = new AudioTrack(mAudioParams.mStreamType, mSampleRateInHz,
-                channelConfig, mAudioFormat, bufferSizeInBytes, AudioTrack.MODE_STREAM,
+        AudioFormat audioFormat = (new AudioFormat.Builder())
+                .setChannelMask(channelConfig)
+                .setEncoding(mAudioFormat)
+                .setSampleRate(mSampleRateInHz).build();
+        AudioTrack audioTrack = new AudioTrack(mAudioParams.mAudioAttributes,
+                audioFormat, bufferSizeInBytes, AudioTrack.MODE_STREAM,
                 mAudioParams.mSessionId);
+
         if (audioTrack.getState() != AudioTrack.STATE_INITIALIZED) {
             Log.w(TAG, "Unable to create audio track.");
             audioTrack.release();
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 46077ed..d8b9b5f 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.net.Uri;
 import android.os.AsyncTask;
@@ -524,6 +525,17 @@
         public static final String KEY_PARAM_STREAM = "streamType";
 
         /**
+         * Parameter key to specify the audio attributes to be used when
+         * speaking text or playing back a file. The value should be set
+         * using {@link TextToSpeech#setAudioAttributes(AudioAttributes)}.
+         *
+         * @see TextToSpeech#speak(String, int, HashMap)
+         * @see TextToSpeech#playEarcon(String, int, HashMap)
+         * @hide
+         */
+        public static final String KEY_PARAM_AUDIO_ATTRIBUTES = "audioAttributes";
+
+        /**
          * Parameter key to identify an utterance in the
          * {@link TextToSpeech.OnUtteranceCompletedListener} after text has been
          * spoken, a file has been played back or a silence duration has elapsed.
@@ -1357,6 +1369,25 @@
     }
 
     /**
+     * Sets the audio attributes to be used when speaking text or playing
+     * back a file.
+     *
+     * @param audioAttributes Valid AudioAttributes instance.
+     *
+     * @return {@link #ERROR} or {@link #SUCCESS}.
+     */
+    public int setAudioAttributes(AudioAttributes audioAttributes) {
+        if (audioAttributes != null) {
+            synchronized (mStartLock) {
+                mParams.putParcelable(Engine.KEY_PARAM_AUDIO_ATTRIBUTES,
+                    audioAttributes);
+            }
+            return SUCCESS;
+        }
+        return ERROR;
+    }
+
+    /**
      * @return the engine currently in use by this TextToSpeech instance.
      * @hide
      */
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index a0743f7..4fea109 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -17,7 +17,7 @@
 
 import android.app.Service;
 import android.content.Intent;
-import android.media.AudioManager;
+import android.media.AudioAttributes;
 import android.media.AudioSystem;
 import android.net.Uri;
 import android.os.Binder;
@@ -608,12 +608,6 @@
         public final int mSessionId;
 
         /**
-         * Audio stream type. Must be one of the STREAM_ contants defined in
-         * {@link android.media.AudioManager}.
-         */
-        public final int mStreamType;
-
-        /**
          * Volume, in the range [0.0f, 1.0f]. The default value is
          * {@link TextToSpeech.Engine#DEFAULT_VOLUME} (1.0f).
          */
@@ -625,42 +619,62 @@
          */
         public final float mPan;
 
+
+        /**
+         * Audio attributes, set by {@link TextToSpeech#setAudioAttributes}
+         * or created from the value of {@link TextToSpeech.Engine#KEY_PARAM_STREAM}.
+         */
+        public final AudioAttributes mAudioAttributes;
+
         /** Create AudioOutputParams with default values */
         AudioOutputParams() {
             mSessionId = AudioSystem.AUDIO_SESSION_ALLOCATE;
-            mStreamType = Engine.DEFAULT_STREAM;
             mVolume = Engine.DEFAULT_VOLUME;
             mPan = Engine.DEFAULT_PAN;
+            mAudioAttributes = null;
         }
 
-        AudioOutputParams(int sessionId, int streamType, float volume, float pan) {
+        AudioOutputParams(int sessionId, float volume, float pan,
+                AudioAttributes audioAttributes) {
             mSessionId = sessionId;
-            mStreamType = streamType;
             mVolume = volume;
             mPan = pan;
+            mAudioAttributes = audioAttributes;
         }
 
         /** Create AudioOutputParams from A {@link SynthesisRequest#getParams()} bundle */
-        static AudioOutputParams createFromV1ParamsBundle(Bundle paramsBundle) {
+        static AudioOutputParams createFromV1ParamsBundle(Bundle paramsBundle,
+                boolean isSpeech) {
             if (paramsBundle == null) {
                 return new AudioOutputParams();
             }
 
+            AudioAttributes audioAttributes =
+                    (AudioAttributes) paramsBundle.getParcelable(
+                            Engine.KEY_PARAM_AUDIO_ATTRIBUTES);
+            if (audioAttributes == null) {
+                int streamType = paramsBundle.getInt(
+                        Engine.KEY_PARAM_STREAM, Engine.DEFAULT_STREAM);
+                audioAttributes = (new AudioAttributes.Builder())
+                        .setLegacyStreamType(streamType)
+                        .setContentType((isSpeech ?
+                                AudioAttributes.CONTENT_TYPE_SPEECH :
+                                AudioAttributes.CONTENT_TYPE_SONIFICATION))
+                        .build();
+            }
+
             return new AudioOutputParams(
                     paramsBundle.getInt(
                             Engine.KEY_PARAM_SESSION_ID,
                             AudioSystem.AUDIO_SESSION_ALLOCATE),
-                    paramsBundle.getInt(
-                            Engine.KEY_PARAM_STREAM,
-                            Engine.DEFAULT_STREAM),
                     paramsBundle.getFloat(
                             Engine.KEY_PARAM_VOLUME,
                             Engine.DEFAULT_VOLUME),
                     paramsBundle.getFloat(
                             Engine.KEY_PARAM_PAN,
-                            Engine.DEFAULT_PAN));
+                            Engine.DEFAULT_PAN),
+                    audioAttributes);
         }
-
     }
 
 
@@ -832,7 +846,7 @@
         }
 
         AudioOutputParams getAudioParams() {
-            return AudioOutputParams.createFromV1ParamsBundle(mParams);
+            return AudioOutputParams.createFromV1ParamsBundle(mParams, true);
         }
     }
 
@@ -1005,6 +1019,11 @@
         public String getUtteranceId() {
             return getStringParam(mParams, Engine.KEY_PARAM_UTTERANCE_ID, null);
         }
+
+        @Override
+        AudioOutputParams getAudioParams() {
+            return AudioOutputParams.createFromV1ParamsBundle(mParams, false);
+        }
     }
 
     private class SilenceSpeechItem extends UtteranceSpeechItem {
diff --git a/core/java/android/text/style/TtsSpan.java b/core/java/android/text/style/TtsSpan.java
index 04b2da5..3ab3b31 100644
--- a/core/java/android/text/style/TtsSpan.java
+++ b/core/java/android/text/style/TtsSpan.java
@@ -22,10 +22,13 @@
 import android.text.TextUtils;
 
 /**
- * A span that supplies additional meta-data intended for text-to-speech rendering
- * of the associated text.  If the text is being processed by a text-to-speech
- * engine, the engine may use the data in this span in addition to or instead of
- * its associated text.
+ * A span that supplies additional meta-data for the associated text intended
+ * for text-to-speech engines.  If the text is being processed by a
+ * text-to-speech engine, the engine may use the data in this span in addition
+ * to or instead of its associated text.
+ *
+ * The inner classes are there for convenience and provide builders for each
+ * TtsSpan type.
  */
 public class TtsSpan implements ParcelableSpan {
     private final String mType;
@@ -432,10 +435,18 @@
         mArgs = src.readPersistableBundle();
     }
 
+    /**
+     * Returns the type.
+     * @return The type of this instance.
+     */
     public String getType() {
         return mType;
     }
 
+    /**
+     * Returns a bundle of the arguments set.
+     * @return The bundle of the arguments set.
+     */
     public PersistableBundle getArgs() {
         return mArgs;
     }
@@ -455,4 +466,217 @@
     public int getSpanTypeId() {
         return TextUtils.TTS_SPAN;
     }
+
+    /**
+     * A simple builder for TtsSpans.
+     * This builder can be used directly, but the more specific subclasses of
+     * this builder like {@link TtsSpan.TextBuilder} and
+     * {@link TtsSpan.CardinalBuilder} are likely more useful.
+     *
+     * This class uses generics so methods from this class can return instances of
+     * its child classes, resulting in a fluent API (CRTP pattern).
+     */
+    public static abstract class Builder<C extends Builder<C>> {
+        // Holds the type of this class.
+        private final String mType;
+
+        // Holds the arguments of this class. It only stores objects of type
+        // String, Integer and Long.
+        private PersistableBundle mArgs = new PersistableBundle();
+
+        public Builder(String type) {
+            mType = type;
+        }
+
+        /**
+         * Returns a TtsSpan built from the parameters set by the setter
+         * methods.
+         * @return A TtsSpan built with parameters of this builder.
+         */
+        public TtsSpan build() {
+            return new TtsSpan(mType, mArgs);
+        }
+
+        /**
+         * Sets an argument to a string value.
+         * @param arg The argument name.
+         * @param value The value the argument should be set to.
+         * @return This instance.
+         */
+        @SuppressWarnings("unchecked")
+        public C setStringArgument(String arg, String value) {
+            mArgs.putString(arg, value);
+            return (C) this;
+        }
+
+        /**
+         * Sets an argument to an int value.
+         * @param arg The argument name.
+         * @param value The value the argument should be set to.
+         */
+        @SuppressWarnings("unchecked")
+        public C setIntArgument(String arg, int value) {
+            mArgs.putInt(arg, value);
+            return (C) this;
+        }
+
+        /**
+         * Sets an argument to a long value.
+         * @param arg The argument name.
+         * @param value The value the argument should be set to.
+         */
+        @SuppressWarnings("unchecked")
+        public C setLongArgument(String arg, long value) {
+            mArgs.putLong(arg, value);
+            return (C) this;
+        }
+    }
+
+    /**
+     * A builder for TtsSpans, has setters for morphosyntactic features.
+     * This builder can be used directly, but the more specific subclasses of
+     * this builder like {@link TtsSpan.TextBuilder} and
+     * {@link TtsSpan.CardinalBuilder} are likely more useful.
+     */
+    public static class SemioticClassBuilder<C extends SemioticClassBuilder<C>>
+            extends Builder<C> {
+
+        public SemioticClassBuilder(String type) {
+            super(type);
+        }
+
+        /**
+         * Sets the gender information for this instance.
+         * @param gender Can any of {@link TtsSpan#GENDER_NEUTRAL},
+         *     {@link TtsSpan#GENDER_MALE} and {@link TtsSpan#GENDER_FEMALE}.
+         * @return This instance.
+         */
+        public C setGender(String gender) {
+            return setStringArgument(TtsSpan.ARG_GENDER, gender);
+        }
+
+        /**
+         * Sets the animacy information for this instance.
+         * @param animacy Can be any of {@link TtsSpan#ANIMACY_ANIMATE} and
+         *     {@link TtsSpan#ANIMACY_INANIMATE}.
+         * @return This instance.
+         */
+        public C setAnimacy(String animacy) {
+            return setStringArgument(TtsSpan.ARG_ANIMACY, animacy);
+        }
+
+        /**
+         * Sets the multiplicity information for this instance.
+         * @param multiplicity Can be any of
+         *     {@link TtsSpan#MULTIPLICITY_SINGLE},
+         *     {@link TtsSpan#MULTIPLICITY_DUAL} and
+         *     {@link TtsSpan#MULTIPLICITY_PLURAL}.
+         * @return This instance.
+         */
+        public C setMultiplicity(String multiplicity) {
+            return setStringArgument(TtsSpan.ARG_MULTIPLICITY, multiplicity);
+        }
+
+        /**
+         * Sets the grammatical case information for this instance.
+         * @param grammaticalCase Can be any of {@link TtsSpan#CASE_NOMINATIVE},
+         *     {@link TtsSpan#CASE_ACCUSATIVE}, {@link TtsSpan#CASE_DATIVE},
+         *     {@link TtsSpan#CASE_ABLATIVE}, {@link TtsSpan#CASE_GENITIVE},
+         *     {@link TtsSpan#CASE_VOCATIVE}, {@link TtsSpan#CASE_LOCATIVE} and
+         *     {@link TtsSpan#CASE_INSTRUMENTAL}.
+         * @return This instance.
+         */
+        public C setCase(String grammaticalCase) {
+            return setStringArgument(TtsSpan.ARG_CASE, grammaticalCase);
+        }
+    }
+
+    /**
+     * A builder for TtsSpans of type {@link TtsSpan #TYPE_TEXT}.
+     */
+    public static class TextBuilder extends SemioticClassBuilder<TextBuilder> {
+
+        /**
+         * Creates a TtsSpan of type {@link TtsSpan#TYPE_TEXT}.
+         */
+        public TextBuilder() {
+            super(TtsSpan.TYPE_TEXT);
+        }
+
+        /**
+         * Creates a TtsSpan of type {@link TtsSpan#TYPE_TEXT} and sets the
+         * {@link TtsSpan#ARG_TEXT} argument.
+         * @param text The text to be synthesized.
+         * @see #setText(String)
+         */
+        public TextBuilder(String text) {
+            this();
+            setText(text);
+        }
+
+        /**
+         * Sets the {@link TtsSpan#ARG_TEXT} argument, the text to be
+         * synthesized.
+         * @param text The string that will be synthesized.
+         * @return This instance.
+         */
+        public TextBuilder setText(String text) {
+            return setStringArgument(TtsSpan.ARG_TEXT, text);
+        }
+    }
+
+    /**
+     * A builder for TtsSpans of type {@link TtsSpan #TYPE_CARDINAL}.
+     */
+    public static class CardinalBuilder extends SemioticClassBuilder<CardinalBuilder> {
+
+        /**
+         * Creates a TtsSpan of type {@link TtsSpan#TYPE_CARDINAL}.
+         */
+        public CardinalBuilder() {
+            super(TtsSpan.TYPE_CARDINAL);
+        }
+
+        /**
+         * Creates a TtsSpan of type {@link TtsSpan#TYPE_CARDINAL} and sets the
+         * {@link TtsSpan#ARG_NUMBER} argument.
+         * @param number The number to synthesize.
+         * @see #setNumber(long)
+         */
+        public CardinalBuilder(long number) {
+            this();
+            setNumber(number);
+        }
+
+        /**
+         * Creates a TtsSpan of type {@link TtsSpan#TYPE_CARDINAL} and sets the
+         * {@link TtsSpan#ARG_NUMBER} argument.
+         * @param number The number to synthesize.
+         * @see #setNumber(String)
+         */
+        public CardinalBuilder(String number) {
+            this();
+            setNumber(number);
+        }
+
+        /**
+         * Convenience method that converts the number to a String and set it to
+         * the value for {@link TtsSpan#ARG_NUMBER}.
+         * @param number The number that will be synthesized.
+         * @return This instance.
+         */
+        public CardinalBuilder setNumber(long number) {
+            return setNumber(String.valueOf(number));
+        }
+
+        /**
+         * Sets the {@link TtsSpan#ARG_NUMBER} argument.
+         * @param number A non-empty string of digits with an optional
+         *     leading + or -.
+         * @return This instance.
+         */
+        public CardinalBuilder setNumber(String number) {
+            return setStringArgument(TtsSpan.ARG_NUMBER, number);
+        }
+    }
 }
diff --git a/core/java/android/webkit/IWebViewUpdateService.aidl b/core/java/android/webkit/IWebViewUpdateService.aidl
new file mode 100644
index 0000000..a77459b
--- /dev/null
+++ b/core/java/android/webkit/IWebViewUpdateService.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+/**
+ * Private service to wait for the updatable WebView to be ready for use.
+ * @hide
+ */
+interface IWebViewUpdateService {
+
+    /**
+     * Used by the relro file creator to notify the service that it's done.
+     */
+    void notifyRelroCreationCompleted(boolean is64Bit, boolean success);
+
+    /**
+     * Used by WebViewFactory to block loading of WebView code until
+     * preparations are complete.
+     */
+    void waitForRelroCreationCompleted(boolean is64Bit);
+
+}
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index aaf0a75..13be453 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -16,9 +16,18 @@
 
 package android.webkit;
 
+import android.os.Build;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.StrictMode;
 import android.util.AndroidRuntimeException;
 import android.util.Log;
+import dalvik.system.VMRuntime;
+
+import java.io.File;
+
+import com.android.internal.os.Zygote;
 
 /**
  * Top level factory, used creating all the main WebView implementation classes.
@@ -33,25 +42,26 @@
     private static final String NULL_WEBVIEW_FACTORY =
             "com.android.webview.nullwebview.NullWebViewFactoryProvider";
 
+    // TODO(torne): we need to use a system property instead of hardcoding the library paths to
+    // enable it to be changed when a webview update apk is installed.
+    private static final String CHROMIUM_WEBVIEW_NATIVE_LIB_32 =
+            "/system/lib/libwebviewchromium.so";
+    private static final String CHROMIUM_WEBVIEW_NATIVE_LIB_64 =
+            "/system/lib64/libwebviewchromium.so";
+    private static final String CHROMIUM_WEBVIEW_NATIVE_RELRO_32 =
+            "/data/misc/shared_relro/libwebviewchromium32.relro";
+    private static final String CHROMIUM_WEBVIEW_NATIVE_RELRO_64 =
+            "/data/misc/shared_relro/libwebviewchromium64.relro";
+
     private static final String LOGTAG = "WebViewFactory";
 
     private static final boolean DEBUG = false;
 
-    private static class Preloader {
-        static WebViewFactoryProvider sPreloadedProvider;
-        static {
-            try {
-                sPreloadedProvider = getFactoryClass().newInstance();
-            } catch (Exception e) {
-                Log.w(LOGTAG, "error preloading provider", e);
-            }
-        }
-    }
-
     // Cache the factory both for efficiency, and ensure any one process gets all webviews from the
     // same provider.
     private static WebViewFactoryProvider sProviderInstance;
     private static final Object sProviderLock = new Object();
+    private static boolean sAddressSpaceReserved = false;
 
     static WebViewFactoryProvider getProvider() {
         synchronized (sProviderLock) {
@@ -59,6 +69,8 @@
             // us honest and minimize usage of WebView internals when binding the proxy.
             if (sProviderInstance != null) return sProviderInstance;
 
+            loadNativeLibrary();
+
             Class<WebViewFactoryProvider> providerClass;
             try {
                 providerClass = getFactoryClass();
@@ -67,15 +79,6 @@
                 throw new AndroidRuntimeException(e);
             }
 
-            // This implicitly loads Preloader even if it wasn't preloaded at boot.
-            if (Preloader.sPreloadedProvider != null &&
-                Preloader.sPreloadedProvider.getClass() == providerClass) {
-                sProviderInstance = Preloader.sPreloadedProvider;
-                if (DEBUG) Log.v(LOGTAG, "Using preloaded provider: " + sProviderInstance);
-                return sProviderInstance;
-            }
-
-            // The preloaded provider isn't the one we wanted; construct our own.
             StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
             try {
                 sProviderInstance = providerClass.newInstance();
@@ -98,4 +101,121 @@
             return (Class<WebViewFactoryProvider>) Class.forName(NULL_WEBVIEW_FACTORY);
         }
     }
+
+    /**
+     * Perform any WebView loading preparations that must happen in the zygote.
+     * Currently, this means allocating address space to load the real JNI library later.
+     */
+    public static void prepareWebViewInZygote() {
+        try {
+            System.loadLibrary("webviewchromium_loader");
+            sAddressSpaceReserved = nativeReserveAddressSpace(CHROMIUM_WEBVIEW_NATIVE_LIB_32,
+                                                              CHROMIUM_WEBVIEW_NATIVE_LIB_64);
+            if (sAddressSpaceReserved) {
+                if (DEBUG) Log.v(LOGTAG, "address space reserved");
+            } else {
+                Log.e(LOGTAG, "reserving address space failed");
+            }
+        } catch (Throwable e) {
+            // Log and discard errors at this stage as we must not crash the zygote.
+            Log.e(LOGTAG, "error preparing native loader", e);
+        }
+    }
+
+    /**
+     * Perform any WebView loading preparations that must happen at boot from the system server,
+     * after the package manager has started.
+     * This must be called in the system server.
+     * Currently, this means spawning the child processes which will create the relro files.
+     */
+    public static void prepareWebViewInSystemServer() {
+        if (DEBUG) Log.v(LOGTAG, "creating relro files");
+        if (new File(CHROMIUM_WEBVIEW_NATIVE_LIB_64).exists()) {
+            createRelroFile(Build.SUPPORTED_64_BIT_ABIS[0]);
+        }
+        if (new File(CHROMIUM_WEBVIEW_NATIVE_LIB_32).exists()) {
+            createRelroFile(Build.SUPPORTED_32_BIT_ABIS[0]);
+        }
+    }
+
+    private static void createRelroFile(String abi) {
+        try {
+            Process.start("android.webkit.WebViewFactory$RelroFileCreator",
+                          "WebViewLoader-" + abi,
+                          Process.SHARED_RELRO_UID,
+                          Process.SHARED_RELRO_UID,
+                          null,
+                          0,                 // TODO(torne): do we need to set debug flags?
+                          Zygote.MOUNT_EXTERNAL_NONE,
+                          Build.VERSION.SDK_INT,
+                          null,
+                          abi,
+                          null);
+        } catch (Throwable e) {
+            // Log and discard errors as we must not crash the system server.
+            Log.e(LOGTAG, "error starting relro file creator for abi " + abi, e);
+        }
+    }
+
+    private static class RelroFileCreator {
+        // Called in an unprivileged child process to create the relro file.
+        public static void main(String[] args) {
+            if (!sAddressSpaceReserved) {
+                Log.e(LOGTAG, "can't create relro file; address space not reserved");
+                return;
+            }
+            boolean result = nativeCreateRelroFile(CHROMIUM_WEBVIEW_NATIVE_LIB_32,
+                                                   CHROMIUM_WEBVIEW_NATIVE_LIB_64,
+                                                   CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
+                                                   CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
+            if (!result) {
+                Log.e(LOGTAG, "failed to create relro file");
+            } else if (DEBUG) {
+                Log.v(LOGTAG, "created relro file");
+            }
+            try {
+                getUpdateService().notifyRelroCreationCompleted(VMRuntime.getRuntime().is64Bit(),
+                                                                result);
+            } catch (RemoteException e) {
+                Log.e(LOGTAG, "error notifying update service", e);
+            }
+
+            // Must explicitly exit or else this process will just sit around after we return.
+            System.exit(0);
+        }
+    }
+
+    private static void loadNativeLibrary() {
+        if (!sAddressSpaceReserved) {
+            Log.e(LOGTAG, "can't load with relro file; address space not reserved");
+            return;
+        }
+
+        try {
+            getUpdateService().waitForRelroCreationCompleted(VMRuntime.getRuntime().is64Bit());
+        } catch (RemoteException e) {
+            Log.e(LOGTAG, "error waiting for relro creation, proceeding without", e);
+            return;
+        }
+
+        boolean result = nativeLoadWithRelroFile(CHROMIUM_WEBVIEW_NATIVE_LIB_32,
+                                                 CHROMIUM_WEBVIEW_NATIVE_LIB_64,
+                                                 CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
+                                                 CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
+        if (!result) {
+            Log.w(LOGTAG, "failed to load with relro file, proceeding without");
+        } else if (DEBUG) {
+            Log.v(LOGTAG, "loaded with relro file");
+        }
+    }
+
+    private static IWebViewUpdateService getUpdateService() {
+        return IWebViewUpdateService.Stub.asInterface(ServiceManager.getService("webviewupdate"));
+    }
+
+    private static native boolean nativeReserveAddressSpace(String lib32, String lib64);
+    private static native boolean nativeCreateRelroFile(String lib32, String lib64,
+                                                        String relro32, String relro64);
+    private static native boolean nativeLoadWithRelroFile(String lib32, String lib64,
+                                                          String relro32, String relro64);
 }
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 5ce658b..eea4201 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -34,6 +34,7 @@
 import android.system.OsConstants;
 import android.util.EventLog;
 import android.util.Log;
+import android.webkit.WebViewFactory;
 
 import dalvik.system.VMRuntime;
 
@@ -250,6 +251,9 @@
         preloadClasses();
         preloadResources();
         preloadOpenGL();
+        // Ask the WebViewFactory to do any initialization that must run in the zygote process,
+        // for memory sharing purposes.
+        WebViewFactory.prepareWebViewInZygote();
         Log.d(TAG, "end preload");
     }
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 658ef96..c9fd6c4 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -834,9 +834,10 @@
         android:label="@string/permlab_changeWimaxState" />
 
     <!-- Allows applications to act as network scorers. @hide @SystemApi-->
+    <!-- TODO: Change protection level to normal when unhiding this API. -->
     <permission android:name="android.permission.SCORE_NETWORKS"
         android:permissionGroup="android.permission-group.NETWORK"
-        android:protectionLevel="normal"
+        android:protectionLevel="signature|system"
         android:description="@string/permdesc_scoreNetworks"
         android:label="@string/permlab_scoreNetworks" />
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 08d354c..aaadc16 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -876,6 +876,7 @@
   <java-symbol type="string" name="config_customResolverActivity" />
   <java-symbol type="string" name="config_appsAuthorizedForSharedAccounts" />
   <java-symbol type="string" name="error_message_title" />
+  <java-symbol type="string" name="app_no_restricted_accounts" />
   <java-symbol type="string" name="action_bar_home_description_format" />
   <java-symbol type="string" name="action_bar_home_subtitle_description_format" />
   <java-symbol type="string" name="wireless_display_route_description" />
diff --git a/include/androidfw/AssetManager.h b/include/androidfw/AssetManager.h
index 610528c..99b3195 100644
--- a/include/androidfw/AssetManager.h
+++ b/include/androidfw/AssetManager.h
@@ -278,6 +278,7 @@
     const ResTable* getResTable(bool required = true) const;
     void setLocaleLocked(const char* locale);
     void updateResourceParamsLocked() const;
+    bool appendPathToResTable(const asset_path& ap) const;
 
     Asset* openIdmapLocked(const struct asset_path& ap) const;
 
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 4ba20d7..de6a33c 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -231,6 +231,10 @@
     }
 #endif
 
+    if (mResources != NULL) {
+        appendPathToResTable(ap);
+    }
+
     return true;
 }
 
@@ -596,6 +600,96 @@
         return kFileTypeRegular;
 }
 
+bool AssetManager::appendPathToResTable(const asset_path& ap) const {
+    Asset* ass = NULL;
+    ResTable* sharedRes = NULL;
+    bool shared = true;
+    bool onlyEmptyResources = true;
+    MY_TRACE_BEGIN(ap.path.string());
+    Asset* idmap = openIdmapLocked(ap);
+    size_t nextEntryIdx = mResources->getTableCount();
+    ALOGV("Looking for resource asset in '%s'\n", ap.path.string());
+    if (ap.type != kFileTypeDirectory) {
+        if (nextEntryIdx == 0) {
+            // The first item is typically the framework resources,
+            // which we want to avoid parsing every time.
+            sharedRes = const_cast<AssetManager*>(this)->
+                mZipSet.getZipResourceTable(ap.path);
+            if (sharedRes != NULL) {
+                // skip ahead the number of system overlay packages preloaded
+                nextEntryIdx = sharedRes->getTableCount();
+            }
+        }
+        if (sharedRes == NULL) {
+            ass = const_cast<AssetManager*>(this)->
+                mZipSet.getZipResourceTableAsset(ap.path);
+            if (ass == NULL) {
+                ALOGV("loading resource table %s\n", ap.path.string());
+                ass = const_cast<AssetManager*>(this)->
+                    openNonAssetInPathLocked("resources.arsc",
+                                             Asset::ACCESS_BUFFER,
+                                             ap);
+                if (ass != NULL && ass != kExcludedAsset) {
+                    ass = const_cast<AssetManager*>(this)->
+                        mZipSet.setZipResourceTableAsset(ap.path, ass);
+                }
+            }
+            
+            if (nextEntryIdx == 0 && ass != NULL) {
+                // If this is the first resource table in the asset
+                // manager, then we are going to cache it so that we
+                // can quickly copy it out for others.
+                ALOGV("Creating shared resources for %s", ap.path.string());
+                sharedRes = new ResTable();
+                sharedRes->add(ass, idmap, nextEntryIdx + 1, false);
+#ifdef HAVE_ANDROID_OS
+                const char* data = getenv("ANDROID_DATA");
+                LOG_ALWAYS_FATAL_IF(data == NULL, "ANDROID_DATA not set");
+                String8 overlaysListPath(data);
+                overlaysListPath.appendPath(kResourceCache);
+                overlaysListPath.appendPath("overlays.list");
+                addSystemOverlays(overlaysListPath.string(), ap.path, sharedRes, nextEntryIdx);
+#endif
+                sharedRes = const_cast<AssetManager*>(this)->
+                    mZipSet.setZipResourceTable(ap.path, sharedRes);
+            }
+        }
+    } else {
+        ALOGV("loading resource table %s\n", ap.path.string());
+        ass = const_cast<AssetManager*>(this)->
+            openNonAssetInPathLocked("resources.arsc",
+                                     Asset::ACCESS_BUFFER,
+                                     ap);
+        shared = false;
+    }
+
+    if ((ass != NULL || sharedRes != NULL) && ass != kExcludedAsset) {
+        ALOGV("Installing resource asset %p in to table %p\n", ass, mResources);
+        if (sharedRes != NULL) {
+            ALOGV("Copying existing resources for %s", ap.path.string());
+            mResources->add(sharedRes);
+        } else {
+            ALOGV("Parsing resources for %s", ap.path.string());
+            mResources->add(ass, idmap, nextEntryIdx + 1, !shared);
+        }
+        onlyEmptyResources = false;
+
+        if (!shared) {
+            delete ass;
+        }
+    } else {
+        ALOGV("Installing empty resources in to table %p\n", mResources);
+        mResources->addEmpty(nextEntryIdx + 1);
+    }
+
+    if (idmap != NULL) {
+        delete idmap;
+    }
+    MY_TRACE_END();
+
+    return onlyEmptyResources;
+}
+
 const ResTable* AssetManager::getResTable(bool required) const
 {
     ResTable* rt = mResources;
@@ -625,90 +719,8 @@
     bool onlyEmptyResources = true;
     const size_t N = mAssetPaths.size();
     for (size_t i=0; i<N; i++) {
-        Asset* ass = NULL;
-        ResTable* sharedRes = NULL;
-        bool shared = true;
-        const asset_path& ap = mAssetPaths.itemAt(i);
-        MY_TRACE_BEGIN(ap.path.string());
-        Asset* idmap = openIdmapLocked(ap);
-        ALOGV("Looking for resource asset in '%s'\n", ap.path.string());
-        if (ap.type != kFileTypeDirectory) {
-            if (i == 0) {
-                // The first item is typically the framework resources,
-                // which we want to avoid parsing every time.
-                sharedRes = const_cast<AssetManager*>(this)->
-                    mZipSet.getZipResourceTable(ap.path);
-                if (sharedRes != NULL) {
-                    // skip ahead the number of system overlay packages preloaded
-                    i += sharedRes->getTableCount() - 1;
-                }
-            }
-            if (sharedRes == NULL) {
-                ass = const_cast<AssetManager*>(this)->
-                    mZipSet.getZipResourceTableAsset(ap.path);
-                if (ass == NULL) {
-                    ALOGV("loading resource table %s\n", ap.path.string());
-                    ass = const_cast<AssetManager*>(this)->
-                        openNonAssetInPathLocked("resources.arsc",
-                                                 Asset::ACCESS_BUFFER,
-                                                 ap);
-                    if (ass != NULL && ass != kExcludedAsset) {
-                        ass = const_cast<AssetManager*>(this)->
-                            mZipSet.setZipResourceTableAsset(ap.path, ass);
-                    }
-                }
-                
-                if (i == 0 && ass != NULL) {
-                    // If this is the first resource table in the asset
-                    // manager, then we are going to cache it so that we
-                    // can quickly copy it out for others.
-                    ALOGV("Creating shared resources for %s", ap.path.string());
-                    sharedRes = new ResTable();
-                    sharedRes->add(ass, idmap, i + 1, false);
-#ifdef HAVE_ANDROID_OS
-                    const char* data = getenv("ANDROID_DATA");
-                    LOG_ALWAYS_FATAL_IF(data == NULL, "ANDROID_DATA not set");
-                    String8 overlaysListPath(data);
-                    overlaysListPath.appendPath(kResourceCache);
-                    overlaysListPath.appendPath("overlays.list");
-                    addSystemOverlays(overlaysListPath.string(), ap.path, sharedRes, i);
-#endif
-                    sharedRes = const_cast<AssetManager*>(this)->
-                        mZipSet.setZipResourceTable(ap.path, sharedRes);
-                }
-            }
-        } else {
-            ALOGV("loading resource table %s\n", ap.path.string());
-            ass = const_cast<AssetManager*>(this)->
-                openNonAssetInPathLocked("resources.arsc",
-                                         Asset::ACCESS_BUFFER,
-                                         ap);
-            shared = false;
-        }
-
-        if ((ass != NULL || sharedRes != NULL) && ass != kExcludedAsset) {
-            ALOGV("Installing resource asset %p in to table %p\n", ass, mResources);
-            if (sharedRes != NULL) {
-                ALOGV("Copying existing resources for %s", ap.path.string());
-                mResources->add(sharedRes);
-            } else {
-                ALOGV("Parsing resources for %s", ap.path.string());
-                mResources->add(ass, idmap, i + 1, !shared);
-            }
-            onlyEmptyResources = false;
-
-            if (!shared) {
-                delete ass;
-            }
-        } else {
-            ALOGV("Installing empty resources in to table %p\n", mResources);
-            mResources->addEmpty(i + 1);
-        }
-
-        if (idmap != NULL) {
-            delete idmap;
-        }
-        MY_TRACE_END();
+        bool empty = appendPathToResTable(mAssetPaths.itemAt(i));
+        onlyEmptyResources = onlyEmptyResources && empty;
     }
 
     if (required && onlyEmptyResources) {
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 8e3c444..548ec91 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -198,6 +198,7 @@
         drawDeferDisabled = !strcasecmp(property, "true");
         INIT_LOGD("  Draw defer %s", drawDeferDisabled ? "disabled" : "enabled");
     } else {
+        drawDeferDisabled = false;
         INIT_LOGD("  Draw defer enabled");
     }
 
@@ -205,6 +206,7 @@
         drawReorderDisabled = !strcasecmp(property, "true");
         INIT_LOGD("  Draw reorder %s", drawReorderDisabled ? "disabled" : "enabled");
     } else {
+        drawReorderDisabled = false;
         INIT_LOGD("  Draw reorder enabled");
     }
 
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index 3dc9ffb..37f166b 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -76,6 +76,7 @@
 
     private final ResolveInfo mService;
     private final String mId;
+    private final String mParentId;
 
     // Attributes from XML meta data.
     private String mSetupActivity;
@@ -114,7 +115,7 @@
                         "Meta-data does not start with tv-input-service tag in " + si.name);
             }
 
-            TvInputInfo input = new TvInputInfo(context, service);
+            TvInputInfo input = new TvInputInfo(context, service, null);
             TypedArray sa = res.obtainAttributes(attrs,
                     com.android.internal.R.styleable.TvInputService);
             input.mSetupActivity = sa.getString(
@@ -154,10 +155,11 @@
      * @param service The ResolveInfo returned from the package manager about this TV input service.
      * @hide
      */
-    private TvInputInfo(Context context, ResolveInfo service) {
+    private TvInputInfo(Context context, ResolveInfo service, String parentId) {
         mService = service;
         ServiceInfo si = service.serviceInfo;
         mId = generateInputIdForComponentName(new ComponentName(si.packageName, si.name));
+        mParentId = parentId;
     }
 
     /**
@@ -169,6 +171,24 @@
     }
 
     /**
+     * Returns the parent input ID.
+     * <p>
+     * When a part of the functionalities of a TV input is actually provided by another TV input,
+     * we can describe this relationship as the depending input having a "parent". It is primarily
+     * used for controlling underlying hardware when the current input itself does not have direct
+     * access to it. Examples include a TV input for a specific HDMI CEC logical device having a
+     * generic HDMI input as its parent and a HDMI-paired virtual input whose video stream comes
+     * from an external settop box. Applications may group inputs by parent ID to provide an easier
+     * access to similar inputs.
+     *
+     * @return the ID of the parent input, if exists. Returns {@code null} if the parent input is
+     *         not specified.
+     */
+    public String getParentId() {
+        return mParentId;
+    }
+
+    /**
      * Returns the information of the service that implements this TV input.
      */
     public ServiceInfo getServiceInfo() {
@@ -260,9 +280,7 @@
         }
 
         TvInputInfo obj = (TvInputInfo) o;
-        return mId.equals(obj.mId)
-                && mService.serviceInfo.packageName.equals(obj.mService.serviceInfo.packageName)
-                && mService.serviceInfo.name.equals(obj.mService.serviceInfo.name);
+        return mId.equals(obj.mId);
     }
 
     @Override
@@ -281,9 +299,11 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeString(mId);
+        dest.writeString(mParentId);
         mService.writeToParcel(dest, flags);
         dest.writeString(mSetupActivity);
         dest.writeString(mSettingsActivity);
+        dest.writeInt(mType);
     }
 
     /**
@@ -317,8 +337,10 @@
 
     private TvInputInfo(Parcel in) {
         mId = in.readString();
+        mParentId = in.readString();
         mService = ResolveInfo.CREATOR.createFromParcel(in);
         mSetupActivity = in.readString();
         mSettingsActivity = in.readString();
+        mType = in.readInt();
     }
 }
diff --git a/packages/SystemUI/res/color/qs_user_detail_name.xml b/packages/SystemUI/res/color/qs_user_detail_name.xml
new file mode 100644
index 0000000..8ddb9be
--- /dev/null
+++ b/packages/SystemUI/res/color/qs_user_detail_name.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright (C) 2014 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_activated="true" android:color="#ffffffff" />
+    <item android:color="#66ffffff" /> <!-- 40% white -->
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_account_circle_qs.xml b/packages/SystemUI/res/drawable/ic_account_circle_qs.xml
new file mode 100644
index 0000000..0d5cd2e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_account_circle_qs.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright (C) 2014 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item android:state_activated="true" android:drawable="@drawable/ic_account_circle" />
+    <item android:drawable="@drawable/ic_account_circle_qs_muted" />
+</selector>
diff --git a/packages/SystemUI/res/drawable/ic_account_circle_qs_muted.xml b/packages/SystemUI/res/drawable/ic_account_circle_qs_muted.xml
new file mode 100644
index 0000000..afcddf1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_account_circle_qs_muted.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright (C) 2014 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
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="24dp"
+        android:height="24dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <group
+        android:scaleX="1.2"
+        android:scaleY="1.2"
+        android:pivotX="12.0"
+        android:pivotY="12.0">
+    <path
+        android:fill="@color/qs_user_detail_icon_muted"
+        android:pathData="M12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM12.0,5.0c1.7,0.0 3.0,1.3 3.0,3.0c0.0,1.7 -1.3,3.0 -3.0,3.0c-1.7,0.0 -3.0,-1.3 -3.0,-3.0C9.0,6.3 10.3,5.0 12.0,5.0zM12.0,19.2c-2.5,0.0 -4.7,-1.3 -6.0,-3.2c0.0,-2.0 4.0,-3.1 6.0,-3.1c2.0,0.0 6.0,1.1 6.0,3.1C16.7,17.9 14.5,19.2 12.0,19.2z"/>
+    </group>
+</vector>
diff --git a/packages/SystemUI/res/layout/qs_user_detail_item.xml b/packages/SystemUI/res/layout/qs_user_detail_item.xml
index 00b3645..29d92e5 100644
--- a/packages/SystemUI/res/layout/qs_user_detail_item.xml
+++ b/packages/SystemUI/res/layout/qs_user_detail_item.xml
@@ -16,6 +16,7 @@
   ~ limitations under the License
   -->
 
+<!-- LinearLayout -->
 <com.android.systemui.qs.tiles.UserDetailItemView
         xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:systemui="http://schemas.android.com/apk/res-auto"
@@ -39,6 +40,6 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:textSize="14sp"
-            android:text="@string/guest_nickname"/>
+            android:textColor="@color/qs_user_detail_name" />
 
 </com.android.systemui.qs.tiles.UserDetailItemView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/zen_mode_panel.xml b/packages/SystemUI/res/layout/zen_mode_panel.xml
index 11f50ee..8b1c2b7 100644
--- a/packages/SystemUI/res/layout/zen_mode_panel.xml
+++ b/packages/SystemUI/res/layout/zen_mode_panel.xml
@@ -78,4 +78,11 @@
         android:orientation="vertical"
         android:paddingTop="3dp" />
 
+    <TextView
+        android:id="@+id/zen_alarm_warning"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="@dimen/qs_panel_padding"
+        android:gravity="center"
+        android:textAppearance="@style/TextAppearance.QS.DetailItemPrimary" />
 </com.android.systemui.volume.ZenModePanel>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index adab243..a1064fd 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -38,6 +38,7 @@
     <color name="system_secondary_color">#ff384248</color>
     <color name="system_accent_color">#ff80CBC4</color><!-- deep teal 200 -->
     <color name="system_warning_color">#fff4511e</color><!-- deep orange 600 -->
+    <color name="qs_text">#FFFFFFFF</color>
     <color name="qs_tile_divider">#29ffffff</color><!-- 16% white -->
     <color name="qs_tile_text">#B3FFFFFF</color><!-- 70% white -->
     <color name="qs_subhead">#66FFFFFF</color><!-- 40% white -->
@@ -46,6 +47,7 @@
     <color name="data_usage_graph_track">#33FFFFFF</color><!-- 20% white -->
     <color name="data_usage_graph_warning">#FFFFFFFF</color>
     <color name="status_bar_clock_color">#FFFFFFFF</color>
+    <color name="qs_user_detail_icon_muted">#4DB0BEC5</color> <!-- 30% blue grey 200-->
 
     <!-- Tint color for the content on the notification overflow card. -->
     <color name="keyguard_overflow_content_color">#ff686868</color>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 28b0853..c8c8e9a 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -617,8 +617,8 @@
     <!-- Description of the left direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] -->
     <string name="description_direction_left">"Slide left for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string>
 
-    <!-- Zen mode: No interruptions title, with a warning about alarms and timers. [CHAR LIMIT=60] -->
-    <string name="zen_no_interruptions_with_warning">No interruptions, including alarms and timers</string>
+    <!-- Zen mode: No interruptions title, with a warning about alarms. [CHAR LIMIT=60] -->
+    <string name="zen_no_interruptions_with_warning">No interruptions, including alarms</string>
 
     <!-- Zen mode: No interruptions. [CHAR LIMIT=40] -->
     <string name="zen_no_interruptions">No interruptions</string>
@@ -626,6 +626,15 @@
     <!-- Zen mode: Only important interruptions. [CHAR LIMIT=40] -->
     <string name="zen_important_interruptions">Priority interruptions only</string>
 
+    <!-- Zen mode: Next alarm information - just a time. [CHAR LIMIT=40] -->
+    <string name="zen_alarm_information_time">Your next alarm is at <xliff:g id="alarm_time" example="5:00 PM">%s</xliff:g></string>
+
+    <!-- Zen mode: Next alarm information - day and time. [CHAR LIMIT=40] -->
+    <string name="zen_alarm_information_day_time">Your next alarm is <xliff:g id="alarm_day_and_time" example="Fri 5:00 PM">%s</xliff:g></string>
+
+    <!-- Zen mode: Next alarm warning. [CHAR LIMIT=40] -->
+    <string name="zen_alarm_warning">You won\'t hear your alarm at <xliff:g id="alarm_time" example="5:00 PM">%s</xliff:g></string>
+
     <!-- Text for overflow card on Keyguard when there is not enough space for all notifications on Keyguard. [CHAR LIMIT=1] -->
     <string name="keyguard_more_overflow_text">+<xliff:g id="number_of_notifications" example="5">%d</xliff:g></string>
 
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 708d3e8..5cc987a 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -154,7 +154,7 @@
 
     <style name="TextAppearance.QS">
         <item name="android:textStyle">normal</item>
-        <item name="android:textColor">#ffffff</item>
+        <item name="android:textColor">@color/qs_text</item>
         <item name="android:fontFamily">sans-serif</item>
     </style>
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index ec5f28c..3c647ed 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -89,7 +89,7 @@
                 name = item.info.name;
             }
             if (item.picture == null) {
-                v.bind(name, mContext.getDrawable(R.drawable.ic_account_circle));
+                v.bind(name, mContext.getDrawable(R.drawable.ic_account_circle_qs));
             } else {
                 v.bind(name, item.picture);
             }
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 8564409..72c12d6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -549,6 +549,8 @@
 
         mDozeServiceHost = new DozeServiceHost();
         putComponent(DozeService.Host.class, mDozeServiceHost);
+
+        setControllerUsers();
     }
 
     // ================================================================================
@@ -2797,6 +2799,13 @@
         animateCollapsePanels();
         updateNotifications();
         resetUserSetupObserver();
+        setControllerUsers();
+    }
+
+    private void setControllerUsers() {
+        if (mZenModeController != null) {
+            mZenModeController.setUserId(mCurrentUserId);
+        }
     }
 
     private void resetUserSetupObserver() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index dc06ec2..574d536 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -285,9 +285,6 @@
         mDateExpanded.setVisibility(mExpanded && !mOverscrolled ? View.VISIBLE : View.GONE);
         mSettingsButton.setVisibility(mExpanded && !mOverscrolled ? View.VISIBLE : View.GONE);
         mQsDetailHeader.setVisibility(mExpanded ? View.VISIBLE : View.GONE);
-        if (mStatusIcons != null) {
-            mStatusIcons.setVisibility(!mExpanded || mOverscrolled ? View.VISIBLE : View.GONE);
-        }
         if (mSignalCluster != null) {
             mSignalCluster.setVisibility(!mExpanded || mOverscrolled ? View.VISIBLE : View.GONE);
         }
@@ -440,12 +437,13 @@
     public void attachSystemIcons(LinearLayout systemIcons) {
         mSystemIconsContainer.addView(systemIcons);
         mStatusIcons = systemIcons.findViewById(R.id.statusIcons);
+        mStatusIcons.addOnLayoutChangeListener(mStatusIconsChanged);
         mSignalCluster = systemIcons.findViewById(R.id.signal_cluster);
     }
 
     public void onSystemIconsDetached() {
         if (mStatusIcons != null) {
-            mStatusIcons.setVisibility(View.VISIBLE);
+            mStatusIcons.removeOnLayoutChangeListener(mStatusIconsChanged);
         }
         if (mSignalCluster != null) {
             mSignalCluster.setVisibility(View.VISIBLE);
@@ -530,6 +528,23 @@
         // here.
     }
 
+    private final OnLayoutChangeListener mStatusIconsChanged = new OnLayoutChangeListener() {
+        private final Rect mClipBounds = new Rect();
+
+        @Override
+        public void onLayoutChange(View v, int left, int top, int right,
+                int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
+            // Hide the statusIcons in the header by clipping them.  Can't touch visibility since
+            // they are mirrored to the real status bar.
+            final Rect r = mSystemIconsContainer.getClipBounds();
+            if (r == null || r.left != right) {
+                mClipBounds.set(right, 0, mSystemIconsContainer.getWidth(),
+                        mSystemIconsContainer.getHeight());
+                mSystemIconsContainer.setClipBounds(mClipBounds);
+            }
+        }
+    };
+
     private final QSPanel.Callback mQsPanelCallback = new QSPanel.Callback() {
         @Override
         public void onToggleStateChanged(final boolean state) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java
index 6f2642a..93561aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UserAvatarView.java
@@ -216,4 +216,17 @@
             super.invalidateDrawable(dr);
         }
     }
+
+    @Override
+    protected boolean verifyDrawable(Drawable who) {
+        return who == mDrawable || super.verifyDrawable(who);
+    }
+
+    @Override
+    protected void drawableStateChanged() {
+        super.drawableStateChanged();
+        if (mDrawable != null && mDrawable.isStateful()) {
+            mDrawable.setState(getDrawableState());
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
index 61902a2..2e97d18 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
@@ -27,11 +27,13 @@
     void requestConditions(boolean request);
     void setExitConditionId(Uri exitConditionId);
     Uri getExitConditionId();
-    boolean hasNextAlarm();
+    long getNextAlarm();
+    void setUserId(int userId);
 
     public static class Callback {
         public void onZenChanged(int zen) {}
         public void onExitConditionChanged(Uri exitConditionId) {}
         public void onConditionsChanged(Condition[] conditions) {}
+        public void onNextAlarmChanged() {}
     }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index 7703966..ae037f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -16,19 +16,25 @@
 
 package com.android.systemui.statusbar.policy;
 
+import android.app.AlarmClockInfo;
+import android.app.AlarmManager;
 import android.app.INotificationManager;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.provider.Settings.Global;
 import android.service.notification.Condition;
 import android.service.notification.IConditionListener;
 import android.service.notification.ZenModeConfig;
+import android.util.Log;
 import android.util.Slog;
 
-import com.android.internal.widget.LockPatternUtils;
 import com.android.systemui.qs.GlobalSetting;
 
 import java.util.ArrayList;
@@ -36,8 +42,8 @@
 
 /** Platform implementation of the zen mode controller. **/
 public class ZenModeControllerImpl implements ZenModeController {
-    private static final String TAG = "ZenModeControllerImpl";
-    private static final boolean DEBUG = false;
+    private static final String TAG = "ZenModeController";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
     private final Context mContext;
@@ -45,13 +51,13 @@
     private final GlobalSetting mConfigSetting;
     private final INotificationManager mNoMan;
     private final LinkedHashMap<Uri, Condition> mConditions = new LinkedHashMap<Uri, Condition>();
-    private final LockPatternUtils mUtils;
+    private final AlarmManager mAlarmManager;
 
+    private int mUserId;
     private boolean mRequesting;
 
     public ZenModeControllerImpl(Context context, Handler handler) {
         mContext = context;
-        mUtils = new LockPatternUtils(mContext);
         mModeSetting = new GlobalSetting(mContext, handler, Global.ZEN_MODE) {
             @Override
             protected void handleValueChanged(int value) {
@@ -68,6 +74,7 @@
         mConfigSetting.setListening(true);
         mNoMan = INotificationManager.Stub.asInterface(
                 ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
     }
 
     @Override
@@ -126,8 +133,22 @@
     }
 
     @Override
-    public boolean hasNextAlarm() {
-        return mUtils.getNextAlarm() != null;
+    public long getNextAlarm() {
+        final AlarmClockInfo info = mAlarmManager.getNextAlarmClock(mUserId);
+        return info != null ? info.getTriggerTime() : 0;
+    }
+
+    @Override
+    public void setUserId(int userId) {
+        mUserId = userId;
+        mContext.registerReceiverAsUser(mReceiver, new UserHandle(mUserId),
+                new IntentFilter(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED), null, null);
+    }
+
+    private void fireNextAlarmChanged() {
+        for (Callback cb : mCallbacks) {
+            cb.onNextAlarmChanged();
+        }
     }
 
     private void fireZenChanged(int zen) {
@@ -169,4 +190,13 @@
             updateConditions(conditions);
         }
     };
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED.equals(intent.getAction())) {
+                fireNextAlarmChanged();
+            }
+        }
+    };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index cf04219..33cf3b6 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -30,6 +30,8 @@
 import android.provider.Settings.Global;
 import android.service.notification.Condition;
 import android.service.notification.ZenModeConfig;
+import android.text.format.DateFormat;
+import android.text.format.Time;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.LayoutInflater;
@@ -46,7 +48,10 @@
 import com.android.systemui.R;
 import com.android.systemui.statusbar.policy.ZenModeController;
 
+import java.text.SimpleDateFormat;
 import java.util.Arrays;
+import java.util.Date;
+import java.util.Locale;
 import java.util.Objects;
 
 public class ZenModePanel extends LinearLayout {
@@ -75,6 +80,8 @@
     private final H mHandler = new H();
     private final Favorites mFavorites;
     private final Interpolator mFastOutSlowInInterpolator;
+    private final int mTextColor;
+    private final int mAccentColor;
 
     private char mLogTag = '?';
     private String mTag;
@@ -85,6 +92,7 @@
     private TextView mZenSubheadExpanded;
     private View mMoreSettings;
     private LinearLayout mZenConditions;
+    private TextView mAlarmWarning;
 
     private Callback mCallback;
     private ZenModeController mController;
@@ -92,8 +100,10 @@
     private Uri mExitConditionId;
     private int mBucketIndex = -1;
     private boolean mExpanded;
-    private int mAttachedZen;
+    private int mSessionZen;
+    private Uri mSessionExitConditionId;
     private String mExitConditionText;
+    private long mNextAlarm;
 
     public ZenModePanel(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -102,6 +112,8 @@
         mInflater = LayoutInflater.from(mContext.getApplicationContext());
         mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(mContext,
                 android.R.interpolator.fast_out_slow_in);
+        mTextColor = mContext.getResources().getColor(R.color.qs_text);
+        mAccentColor = mContext.getResources().getColor(R.color.system_accent_color);
         updateTag();
         if (DEBUG) Log.d(mTag, "new ZenModePanel");
     }
@@ -144,14 +156,17 @@
         });
 
         mZenConditions = (LinearLayout) findViewById(R.id.zen_conditions);
+        mAlarmWarning = (TextView) findViewById(R.id.zen_alarm_warning);
     }
 
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         if (DEBUG) Log.d(mTag, "onAttachedToWindow");
-        mAttachedZen = getSelectedZen(-1);
+        mSessionZen = getSelectedZen(-1);
+        mSessionExitConditionId = mExitConditionId;
         refreshExitConditionText();
+        refreshNextAlarm();
         updateWidgets();
     }
 
@@ -159,7 +174,8 @@
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
         if (DEBUG) Log.d(mTag, "onDetachedFromWindow");
-        mAttachedZen = -1;
+        mSessionZen = -1;
+        mSessionExitConditionId = null;
         setExpanded(false);
     }
 
@@ -202,7 +218,7 @@
         updateTag();
         setExitConditionId(mController.getExitConditionId());
         refreshExitConditionText();
-        mAttachedZen = getSelectedZen(-1);
+        mSessionZen = getSelectedZen(-1);
         handleUpdateZen(mController.getZen());
         if (DEBUG) Log.d(mTag, "init mExitConditionId=" + mExitConditionId);
         mZenConditions.removeAllViews();
@@ -213,6 +229,7 @@
         if (Objects.equals(mExitConditionId, exitConditionId)) return;
         mExitConditionId = exitConditionId;
         refreshExitConditionText();
+        updateWidgets();
     }
 
     private void refreshExitConditionText() {
@@ -248,9 +265,9 @@
     }
 
     private void handleUpdateZen(int zen) {
-        if (mAttachedZen != -1 && mAttachedZen != zen) {
+        if (mSessionZen != -1 && mSessionZen != zen) {
             setExpanded(zen != Global.ZEN_MODE_OFF);
-            mAttachedZen = zen;
+            mSessionZen = zen;
         }
         mZenButtons.setSelectedValue(zen);
         updateWidgets();
@@ -267,12 +284,34 @@
         final boolean zenImportant = zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         final boolean zenNone = zen == Global.ZEN_MODE_NO_INTERRUPTIONS;
         final boolean foreverSelected = mExitConditionId == null;
+        final boolean hasNextAlarm = mNextAlarm != 0;
 
         mZenSubhead.setVisibility(!zenOff && (mExpanded || !foreverSelected) ? VISIBLE : GONE);
         mZenSubheadExpanded.setVisibility(mExpanded ? VISIBLE : GONE);
         mZenSubheadCollapsed.setVisibility(!mExpanded ? VISIBLE : GONE);
         mMoreSettings.setVisibility(zenImportant && mExpanded ? VISIBLE : GONE);
         mZenConditions.setVisibility(!zenOff && mExpanded ? VISIBLE : GONE);
+        mAlarmWarning.setVisibility(zenNone && mExpanded && hasNextAlarm ? VISIBLE : GONE);
+
+        if (zenNone && mExpanded && hasNextAlarm) {
+            final long exitTime = ZenModeConfig.tryParseCountdownConditionId(mExitConditionId);
+            final long now = System.currentTimeMillis();
+            final boolean alarmToday = time(mNextAlarm).yearDay == time(now).yearDay;
+            final String skeleton = (alarmToday ? "" : "E")
+                    + (DateFormat.is24HourFormat(mContext) ? "Hm" : "hma");
+            final String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton);
+            final String alarm = new SimpleDateFormat(pattern).format(new Date(mNextAlarm));
+            final boolean isWarning = exitTime > 0 && mNextAlarm > now && mNextAlarm < exitTime;
+            if (isWarning) {
+                mAlarmWarning.setText(mContext.getString(R.string.zen_alarm_warning, alarm));
+                mAlarmWarning.setTextColor(mAccentColor);
+            } else {
+                mAlarmWarning.setText(mContext.getString(alarmToday
+                        ? R.string.zen_alarm_information_time
+                        : R.string.zen_alarm_information_day_time, alarm));
+                mAlarmWarning.setTextColor(mTextColor);
+            }
+        }
 
         if (zenNone) {
             mZenSubheadExpanded.setText(R.string.zen_no_interruptions_with_warning);
@@ -283,6 +322,12 @@
         }
     }
 
+    private static Time time(long millis) {
+        final Time t = new Time();
+        t.set(millis);
+        return t;
+    }
+
     private Condition parseExistingTimeCondition(Uri conditionId) {
         final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
         if (time == 0) return null;
@@ -308,6 +353,15 @@
                 Condition.FLAG_RELEVANT_NOW);
     }
 
+    private void refreshNextAlarm() {
+        mNextAlarm = mController.getNextAlarm();
+    }
+
+    private void handleNextAlarmChanged() {
+        refreshNextAlarm();
+        updateWidgets();
+    }
+
     private void handleUpdateConditions(Condition[] conditions) {
         final int newCount = conditions == null ? 0 : conditions.length;
         if (DEBUG) Log.d(mTag, "handleUpdateConditions newCount=" + newCount);
@@ -328,6 +382,8 @@
         // are we left without anything selected?  if so, set a default
         for (int i = 0; i < mZenConditions.getChildCount(); i++) {
             if (getConditionTagAt(i).rb.isChecked()) {
+                if (DEBUG) Log.d(mTag, "Not selecting a default, checked="
+                        + getConditionTagAt(i).conditionId);
                 return;
             }
         }
@@ -371,7 +427,7 @@
         }
         tag.conditionId = condition != null ? condition.id : null;
         tag.rb.setEnabled(enabled);
-        if (Objects.equals(tag.conditionId, mExitConditionId)) {
+        if (mSessionExitConditionId != null && mSessionExitConditionId.equals(tag.conditionId)) {
             tag.rb.setChecked(true);
         }
         tag.rb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@@ -484,6 +540,7 @@
         } else if (ZenModeConfig.isValidCountdownConditionId(conditionId) && mBucketIndex != -1) {
             mFavorites.setMinuteIndex(mBucketIndex);
         }
+        mSessionExitConditionId = conditionId;
     }
 
     private void fireMoreSettings() {
@@ -518,12 +575,18 @@
         public void onExitConditionChanged(Uri exitConditionId) {
             mHandler.obtainMessage(H.EXIT_CONDITION_CHANGED, exitConditionId).sendToTarget();
         }
+
+        @Override
+        public void onNextAlarmChanged() {
+            mHandler.sendEmptyMessage(H.NEXT_ALARM_CHANGED);
+        }
     };
 
     private final class H extends Handler {
         private static final int UPDATE_CONDITIONS = 1;
         private static final int EXIT_CONDITION_CHANGED = 2;
         private static final int UPDATE_ZEN = 3;
+        private static final int NEXT_ALARM_CHANGED = 4;
 
         private H() {
             super(Looper.getMainLooper());
@@ -532,12 +595,14 @@
         @Override
         public void handleMessage(Message msg) {
             if (msg.what == UPDATE_CONDITIONS) {
-                handleUpdateConditions((Condition[])msg.obj);
+                handleUpdateConditions((Condition[]) msg.obj);
                 checkForDefault();
             } else if (msg.what == EXIT_CONDITION_CHANGED) {
-                handleExitConditionChanged((Uri)msg.obj);
+                handleExitConditionChanged((Uri) msg.obj);
             } else if (msg.what == UPDATE_ZEN) {
                 handleUpdateZen(msg.arg1);
+            } else if (msg.what == NEXT_ALARM_CHANGED) {
+                handleNextAlarmChanged();
             }
         }
     }
@@ -601,7 +666,6 @@
             if (value != null && mZenButtons.isShown()) {
                 if (DEBUG) Log.d(mTag, "mZenButtonsCallback selected=" + value);
                 mController.setZen((Integer) value);
-                mController.setExitConditionId(null);
             }
         }
     };
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index edeb5b4..abbaacc 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -2271,6 +2271,22 @@
         }
 
         @Override
+        public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
+            if (mOutsetBottom != null) {
+                final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
+                int bottom = (int) mOutsetBottom.getDimension(metrics);
+                WindowInsets newInsets = insets.replaceSystemWindowInsets(
+                        insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(),
+                        insets.getSystemWindowInsetRight(),
+                        insets.getSystemWindowInsetBottom() + bottom);
+                return super.dispatchApplyWindowInsets(newInsets);
+            } else {
+                return super.dispatchApplyWindowInsets(insets);
+            }
+        }
+
+
+        @Override
         public boolean onTouchEvent(MotionEvent event) {
             return onInterceptTouchEvent(event);
         }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 608aa44..a3c84c6 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -1706,7 +1706,8 @@
     @Override
     public boolean isForceHiding(WindowManager.LayoutParams attrs) {
         return (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 ||
-                (isKeyguardHostWindow(attrs) && isKeyguardSecureIncludingHidden());
+                (isKeyguardHostWindow(attrs) && isKeyguardSecureIncludingHidden()) ||
+                (attrs.type == TYPE_KEYGUARD_SCRIM);
     }
 
     @Override
diff --git a/preloaded-classes b/preloaded-classes
index 4413cd3..b3fc517 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -1208,7 +1208,6 @@
 android.webkit.WebViewClient
 android.webkit.WebViewDatabase
 android.webkit.WebViewFactory
-android.webkit.WebViewFactory$Preloader
 android.webkit.WebViewFactoryProvider
 android.webkit.WebViewFactoryProvider$Statics
 android.webkit.WebViewProvider
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index e152ebe..36d67ee 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -871,18 +871,85 @@
         checkManageAccountsPermission();
         UserHandle user = Binder.getCallingUserHandle();
         UserAccounts accounts = getUserAccountsForCaller();
-        if (!canUserModifyAccounts(Binder.getCallingUid(), account.type)) {
+        int userId = Binder.getCallingUserHandle().getIdentifier();
+        if (!canUserModifyAccounts(userId)) {
             try {
+                // TODO: This should be ERROR_CODE_USER_RESTRICTED instead. See http://b/16322768
                 response.onError(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,
                         "User cannot modify accounts");
             } catch (RemoteException re) {
             }
             return;
         }
+        if (!canUserModifyAccountsForType(userId, account.type)) {
+            try {
+                response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
+                        "User cannot modify accounts of this type (policy).");
+            } catch (RemoteException re) {
+            }
+            return;
+        }
 
         long identityToken = clearCallingIdentity();
 
         cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
+        synchronized (accounts.credentialsPermissionNotificationIds) {
+            for (Pair<Pair<Account, String>, Integer> pair:
+                accounts.credentialsPermissionNotificationIds.keySet()) {
+                if (account.equals(pair.first.first)) {
+                    int id = accounts.credentialsPermissionNotificationIds.get(pair);
+                    cancelNotification(id, user);
+                }
+            }
+        }
+
+        try {
+            new RemoveAccountSession(accounts, response, account).bind();
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    @Override
+    public void removeAccountAsUser(IAccountManagerResponse response, Account account,
+            int userId) {
+        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+            Log.v(TAG, "removeAccount: " + account
+                    + ", response " + response
+                    + ", caller's uid " + Binder.getCallingUid()
+                    + ", pid " + Binder.getCallingPid()
+                    + ", for user id " + userId);
+        }
+        if (response == null) throw new IllegalArgumentException("response is null");
+        if (account == null) throw new IllegalArgumentException("account is null");
+
+        // Only allow the system process to modify accounts of other users
+        enforceCrossUserPermission(userId, "User " + UserHandle.getCallingUserId()
+                    + " trying to remove account for " + userId);
+        checkManageAccountsPermission();
+
+        UserAccounts accounts = getUserAccounts(userId);
+        if (!canUserModifyAccounts(userId)) {
+            try {
+                response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
+                        "User cannot modify accounts");
+            } catch (RemoteException re) {
+            }
+            return;
+        }
+        if (!canUserModifyAccountsForType(userId, account.type)) {
+            try {
+                response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
+                        "User cannot modify accounts of this type (policy).");
+            } catch (RemoteException re) {
+            }
+            return;
+        }
+
+        UserHandle user = new UserHandle(userId);
+        long identityToken = clearCallingIdentity();
+
+        cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
         synchronized(accounts.credentialsPermissionNotificationIds) {
             for (Pair<Pair<Account, String>, Integer> pair:
                 accounts.credentialsPermissionNotificationIds.keySet()) {
@@ -1526,20 +1593,23 @@
         checkManageAccountsPermission();
 
         // Is user disallowed from modifying accounts?
-        if (!canUserModifyAccounts(Binder.getCallingUid(), accountType)) {
+        int userId = Binder.getCallingUserHandle().getIdentifier();
+        if (!canUserModifyAccounts(userId)) {
             try {
                 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
                         "User is not allowed to add an account!");
             } catch (RemoteException re) {
             }
-            Intent cantAddAccount = new Intent(mContext, CantAddAccountActivity.class);
-            cantAddAccount.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            long identityToken = clearCallingIdentity();
+            showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED);
+            return;
+        }
+        if (!canUserModifyAccountsForType(userId, accountType)) {
             try {
-                mContext.startActivityAsUser(cantAddAccount, UserHandle.CURRENT);
-            } finally {
-                restoreCallingIdentity(identityToken);
+                response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
+                        "User cannot modify accounts of this type (policy).");
+            } catch (RemoteException re) {
             }
+            showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE);
             return;
         }
 
@@ -1576,6 +1646,92 @@
     }
 
     @Override
+    public void addAccountAsUser(final IAccountManagerResponse response, final String accountType,
+            final String authTokenType, final String[] requiredFeatures,
+            final boolean expectActivityLaunch, final Bundle optionsIn, int userId) {
+        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+            Log.v(TAG, "addAccount: accountType " + accountType
+                    + ", response " + response
+                    + ", authTokenType " + authTokenType
+                    + ", requiredFeatures " + stringArrayToString(requiredFeatures)
+                    + ", expectActivityLaunch " + expectActivityLaunch
+                    + ", caller's uid " + Binder.getCallingUid()
+                    + ", pid " + Binder.getCallingPid()
+                    + ", for user id " + userId);
+        }
+        if (response == null) throw new IllegalArgumentException("response is null");
+        if (accountType == null) throw new IllegalArgumentException("accountType is null");
+        checkManageAccountsPermission();
+
+        // Only allow the system process to add accounts of other users
+        enforceCrossUserPermission(userId, "User " + UserHandle.getCallingUserId()
+                    + " trying to add account for " + userId);
+
+        // Is user disallowed from modifying accounts?
+        if (!canUserModifyAccounts(userId)) {
+            try {
+                response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
+                        "User is not allowed to add an account!");
+            } catch (RemoteException re) {
+            }
+            showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED);
+            return;
+        }
+        if (!canUserModifyAccountsForType(userId, accountType)) {
+            try {
+                response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
+                        "User cannot modify accounts of this type (policy).");
+            } catch (RemoteException re) {
+            }
+            showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE);
+            return;
+        }
+
+        UserAccounts accounts = getUserAccounts(userId);
+        final int pid = Binder.getCallingPid();
+        final int uid = Binder.getCallingUid();
+        final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
+        options.putInt(AccountManager.KEY_CALLER_UID, uid);
+        options.putInt(AccountManager.KEY_CALLER_PID, pid);
+
+        long identityToken = clearCallingIdentity();
+        try {
+            new Session(accounts, response, accountType, expectActivityLaunch,
+                    true /* stripAuthTokenFromResult */) {
+                @Override
+                public void run() throws RemoteException {
+                    mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
+                            options);
+                }
+
+                @Override
+                protected String toDebugString(long now) {
+                    return super.toDebugString(now) + ", addAccount"
+                            + ", accountType " + accountType
+                            + ", requiredFeatures "
+                            + (requiredFeatures != null
+                              ? TextUtils.join(",", requiredFeatures)
+                              : null);
+                }
+            }.bind();
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    private void showCantAddAccount(int errorCode) {
+        Intent cantAddAccount = new Intent(mContext, CantAddAccountActivity.class);
+        cantAddAccount.putExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, errorCode);
+        cantAddAccount.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        long identityToken = clearCallingIdentity();
+        try {
+            mContext.startActivity(cantAddAccount);
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    @Override
     public void confirmCredentialsAsUser(IAccountManagerResponse response,
             final Account account, final Bundle options, final boolean expectActivityLaunch,
             int userId) {
@@ -2766,18 +2922,18 @@
                 Manifest.permission.USE_CREDENTIALS);
     }
 
-    private boolean canUserModifyAccounts(int callingUid, String accountType) {
-        if (callingUid != Process.myUid()) {
-            if (getUserManager().getUserRestrictions(
-                    new UserHandle(UserHandle.getUserId(callingUid)))
-                    .getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
-                return false;
-            }
+    private boolean canUserModifyAccounts(int userId) {
+        if (getUserManager().getUserRestrictions(new UserHandle(userId))
+                .getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
+            return false;
         }
+        return true;
+    }
 
+    private boolean canUserModifyAccountsForType(int userId, String accountType) {
         DevicePolicyManager dpm = (DevicePolicyManager) mContext
                 .getSystemService(Context.DEVICE_POLICY_SERVICE);
-        String[] typesArray = dpm.getAccountTypesWithManagementDisabled();
+        String[] typesArray = dpm.getAccountTypesWithManagementDisabledAsUser(userId);
         for (String forbiddenType : typesArray) {
             if (forbiddenType.equals(accountType)) {
                 return false;
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 65cb6c9..09cf392 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -269,13 +269,39 @@
 
             Intent launchIntent = new Intent(Intent.ACTION_MAIN);
             launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
-            launchIntent.setComponent(component);
             launchIntent.setSourceBounds(sourceBounds);
             launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            launchIntent.setPackage(component.getPackageName());
 
             long ident = Binder.clearCallingIdentity();
             try {
-                mContext.startActivityAsUser(launchIntent, opts, user);
+                IPackageManager pm = AppGlobals.getPackageManager();
+                ActivityInfo info = pm.getActivityInfo(component, 0, user.getIdentifier());
+                if (!info.exported) {
+                    throw new SecurityException("Cannot launch non-exported components "
+                            + component);
+                }
+
+                // Check that the component actually has Intent.CATEGORY_LAUCNCHER
+                // as calling startActivityAsUser ignores the category and just
+                // resolves based on the component if present.
+                List<ResolveInfo> apps = mPm.queryIntentActivitiesAsUser(launchIntent,
+                        PackageManager.NO_CROSS_PROFILE, // We only want the apps for this user
+                        user.getIdentifier());
+                final int size = apps.size();
+                for (int i = 0; i < size; ++i) {
+                    ActivityInfo activityInfo = apps.get(i).activityInfo;
+                    if (activityInfo.packageName.equals(component.getPackageName()) &&
+                            activityInfo.name.equals(component.getClassName())) {
+                        // Found an activity with category launcher that matches
+                        // this component so ok to launch.
+                        launchIntent.setComponent(component);
+                        mContext.startActivityAsUser(launchIntent, opts, user);
+                        return;
+                    }
+                }
+                throw new SecurityException("Attempt to launch activity without "
+                        + " category Intent.CATEGORY_LAUNCHER " + component);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index a3fd1df..e16894e 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3171,25 +3171,34 @@
         file.delete();
         file = getUserPackagesStateBackupFile(userId);
         file.delete();
-        removeCrossProfileIntentFiltersToUserLPr(userId);
+        removeCrossProfileIntentFiltersLPw(userId);
         removeCrossProfilePackagesLPw(userId);
     }
 
-    void removeCrossProfileIntentFiltersToUserLPr(int targetUserId) {
-        for (int i = 0; i < mCrossProfileIntentResolvers.size(); i++) {
-            int sourceUserId = mCrossProfileIntentResolvers.keyAt(i);
-            CrossProfileIntentResolver cpir = mCrossProfileIntentResolvers.get(sourceUserId);
-            boolean needsWriting = false;
-            HashSet<CrossProfileIntentFilter> cpifs =
-                    new HashSet<CrossProfileIntentFilter>(cpir.filterSet());
-            for (CrossProfileIntentFilter cpif : cpifs) {
-                if (cpif.getTargetUserId() == targetUserId) {
-                    needsWriting = true;
-                    cpir.removeFilter(cpif);
-                }
+    void removeCrossProfileIntentFiltersLPw(int userId) {
+        synchronized (mCrossProfileIntentResolvers) {
+            // userId is the source user
+            if (mCrossProfileIntentResolvers.get(userId) != null) {
+                mCrossProfileIntentResolvers.remove(userId);
+                writePackageRestrictionsLPr(userId);
             }
-            if (needsWriting) {
-                writePackageRestrictionsLPr(sourceUserId);
+            // userId is the target user
+            int count = mCrossProfileIntentResolvers.size();
+            for (int i = 0; i < count; i++) {
+                int sourceUserId = mCrossProfileIntentResolvers.keyAt(i);
+                CrossProfileIntentResolver cpir = mCrossProfileIntentResolvers.get(sourceUserId);
+                boolean needsWriting = false;
+                HashSet<CrossProfileIntentFilter> cpifs =
+                        new HashSet<CrossProfileIntentFilter>(cpir.filterSet());
+                for (CrossProfileIntentFilter cpif : cpifs) {
+                    if (cpif.getTargetUserId() == userId) {
+                        needsWriting = true;
+                        cpir.removeFilter(cpif);
+                    }
+                }
+                if (needsWriting) {
+                    writePackageRestrictionsLPr(sourceUserId);
+                }
             }
         }
     }
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 3882769..43469ba 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -52,7 +52,6 @@
 import android.util.Xml;
 
 import com.android.internal.app.IAppOpsService;
-import com.android.internal.content.PackageMonitor;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 
@@ -241,7 +240,6 @@
     }
 
     void systemReady() {
-        mUserPackageMonitor.register(mContext, null, UserHandle.ALL, false);
         userForeground(UserHandle.USER_OWNER);
         mAppOpsService = IAppOpsService.Stub.asInterface(
                 ServiceManager.getService(Context.APP_OPS_SERVICE));
@@ -1039,11 +1037,10 @@
     }
 
     /**
-     * Removes all the restrictions files (res_<packagename>) for a given user, if all is true,
-     * else removes only those packages that have been uninstalled.
+     * Removes all the restrictions files (res_<packagename>) for a given user.
      * Does not do any permissions checking.
      */
-    private void cleanAppRestrictions(int userId, boolean all) {
+    private void cleanAppRestrictions(int userId) {
         synchronized (mPackagesLock) {
             File dir = Environment.getUserSystemDirectory(userId);
             String[] files = dir.list();
@@ -1052,14 +1049,7 @@
                 if (fileName.startsWith(RESTRICTIONS_FILE_PREFIX)) {
                     File resFile = new File(dir, fileName);
                     if (resFile.exists()) {
-                        if (all) {
-                            resFile.delete();
-                        } else {
-                            String pkg = restrictionsFileNameToPackage(fileName);
-                            if (!isPackageInstalled(pkg, userId)) {
-                                resFile.delete();
-                            }
-                        }
+                        resFile.delete();
                     }
                 }
             }
@@ -1326,15 +1316,21 @@
             checkManageUsersPermission("Only system can set restrictions for other users/apps");
         }
         synchronized (mPackagesLock) {
-            // Write the restrictions to XML
-            writeApplicationRestrictionsLocked(packageName, restrictions, userId);
+            if (restrictions == null || restrictions.isEmpty()) {
+                cleanAppRestrictionsForPackage(packageName, userId);
+            } else {
+                // Write the restrictions to XML
+                writeApplicationRestrictionsLocked(packageName, restrictions, userId);
+            }
         }
 
-        // Notify package of changes via an intent - only sent to explicitly registered receivers.
-        Intent changeIntent = new Intent(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);
-        changeIntent.setPackage(packageName);
-        changeIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-        mContext.sendBroadcastAsUser(changeIntent, new UserHandle(userId));
+        if (isPackageInstalled(packageName, userId)) {
+            // Notify package of changes via an intent - only sent to explicitly registered receivers.
+            Intent changeIntent = new Intent(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);
+            changeIntent.setPackage(packageName);
+            changeIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+            mContext.sendBroadcastAsUser(changeIntent, new UserHandle(userId));
+        }
     }
 
     @Override
@@ -1437,7 +1433,7 @@
             // Remove restrictions pin
             setRestrictionsChallenge(null);
             // Remove any app restrictions
-            cleanAppRestrictions(userHandle, true);
+            cleanAppRestrictions(userHandle);
         }
         if (unblockApps) {
             unblockAllAppsForUser(userHandle);
@@ -1691,12 +1687,6 @@
                 user.lastLoggedInTime = now;
                 writeUserLocked(user);
             }
-            // If this is not a restricted profile and there is no restrictions pin, clean up
-            // all restrictions files that might have been left behind, else clean up just the
-            // ones with uninstalled packages
-            RestrictionsPinState pinState = mRestrictionsPinStates.get(userId);
-            final long salt = pinState == null ? 0 : pinState.salt;
-            cleanAppRestrictions(userId, (!user.isRestricted() && salt == 0));
         }
     }
 
@@ -1772,17 +1762,4 @@
             }
         }
     }
-
-    private PackageMonitor mUserPackageMonitor = new PackageMonitor() {
-        @Override
-        public void onPackageRemoved(String pkg, int uid) {
-            final int userId = this.getChangingUserId();
-            // Package could be disappearing because it is being blocked, so also check if
-            // it has been uninstalled.
-            final boolean uninstalled = isPackageDisappearing(pkg) == PACKAGE_PERMANENT_CHANGE;
-            if (uninstalled && userId >= 0 && !isPackageInstalled(pkg, userId)) {
-                cleanAppRestrictionsForPackage(pkg, userId);
-            }
-        }
-    };
 }
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
new file mode 100644
index 0000000..e8ae97c
--- /dev/null
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -0,0 +1,78 @@
+/*
+ * 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.webkit;
+
+import android.os.Binder;
+import android.os.Process;
+import android.util.Log;
+import android.webkit.IWebViewUpdateService;
+
+/**
+ * Private service to wait for the updatable WebView to be ready for use.
+ * @hide
+ */
+public class WebViewUpdateService extends IWebViewUpdateService.Stub {
+
+    private static final String TAG = "WebViewUpdateService";
+
+    private boolean mRelroReady32Bit = false;
+    private boolean mRelroReady64Bit = false;
+
+    public WebViewUpdateService() {
+    }
+
+    /**
+     * The shared relro process calls this to notify us that it's done trying to create a relro
+     * file.
+     */
+    public void notifyRelroCreationCompleted(boolean is64Bit, boolean success) {
+        // Verify that the caller is the shared relro process.
+        if (Binder.getCallingUid() != Process.SHARED_RELRO_UID) {
+            return;
+        }
+
+        synchronized (this) {
+            if (is64Bit) {
+                mRelroReady64Bit = true;
+            } else {
+                mRelroReady32Bit = true;
+            }
+            this.notifyAll();
+        }
+    }
+
+    /**
+     * WebViewFactory calls this to block WebView loading until the relro file is created.
+     */
+    public void waitForRelroCreationCompleted(boolean is64Bit) {
+        synchronized (this) {
+            if (is64Bit) {
+                while (!mRelroReady64Bit) {
+                    try {
+                        this.wait();
+                    } catch (InterruptedException e) {}
+                }
+            } else {
+                while (!mRelroReady32Bit) {
+                    try {
+                        this.wait();
+                    } catch (InterruptedException e) {}
+                }
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index a5959d4..fa22ded 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -11173,17 +11173,17 @@
         public void waitForAllWindowsDrawn(Runnable callback, long timeout) {
             synchronized (mWindowMap) {
                 mWaitingForDrawnCallback = callback;
-                final WindowList windows = getDefaultWindowListLocked();
-                for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
-                    final WindowState win = windows.get(winNdx);
-                    if (win.mHasSurface && win.isWinVisibleLw()) {
-                        if (!win.mIsWallpaper) {
-                            // Don't force wallpaper to redraw.
+                for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+                    final WindowList windows =
+                            mDisplayContents.valueAt(displayNdx).getWindowList();
+                    for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+                        final WindowState win = windows.get(winNdx);
+                        if (win.mHasSurface && win.isWinVisibleLw() && !win.mIsWallpaper) {
                             win.mWinAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
+                            // Force add to mResizingWindows.
+                            win.mLastContentInsets.set(-1, -1, -1, -1);
+                            mWaitingForDrawn.add(win);
                         }
-                        // Force add to mResizingWindows.
-                        win.mLastContentInsets.set(-1, -1, -1, -1);
-                        mWaitingForDrawn.add(win);
                     }
                 }
                 requestTraversalLocked();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index f051fce..12ed920 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -55,7 +55,9 @@
 import android.media.AudioManager;
 import android.media.IAudioService;
 import android.net.ConnectivityManager;
+import android.net.Uri;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.database.ContentObserver;
 import android.net.ProxyInfo;
 import android.os.Binder;
 import android.os.Bundle;
@@ -136,6 +138,7 @@
     private static final boolean DBG = false;
 
     private static final String ATTR_PERMISSION_PROVIDER = "permission-provider";
+    private static final String ATTR_SETUP_COMPLETE = "setup-complete";
 
     final Context mContext;
     final UserManager mUserManager;
@@ -174,6 +177,7 @@
             }
         }
     }
+
     public static class DevicePolicyData {
         int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
         int mActivePasswordLength = 0;
@@ -188,6 +192,7 @@
         int mUserHandle;
         int mPasswordOwner = -1;
         long mLastMaximumTimeToLock = -1;
+        boolean mUserSetupComplete = false;
 
         final HashMap<ComponentName, ActiveAdmin> mAdminMap
                 = new HashMap<ComponentName, ActiveAdmin>();
@@ -985,6 +990,10 @@
                 out.attribute(null, ATTR_PERMISSION_PROVIDER,
                         policy.mRestrictionsProvider.flattenToString());
             }
+            if (policy.mUserSetupComplete) {
+                out.attribute(null, ATTR_SETUP_COMPLETE,
+                        Boolean.toString(true));
+            }
 
             final int N = policy.mAdminList.size();
             for (int i=0; i<N; i++) {
@@ -1086,6 +1095,10 @@
             if (permissionProvider != null) {
                 policy.mRestrictionsProvider = ComponentName.unflattenFromString(permissionProvider);
             }
+            String userSetupComplete = parser.getAttributeValue(null, ATTR_SETUP_COMPLETE);
+            if (userSetupComplete != null && Boolean.toString(true).equals(userSetupComplete)) {
+                policy.mUserSetupComplete = true;
+            }
 
             type = parser.next();
             int outerDepth = parser.getDepth();
@@ -1278,6 +1291,10 @@
                 }
             }
         }
+        // Register an observer for watching for user setup complete.
+        new SetupContentObserver(mHandler).register(mContext.getContentResolver());
+        // Initialize the user setup state, to handle the upgrade case.
+        updateUserSetupComplete();
     }
 
     private void cleanUpOldUsers() {
@@ -3908,11 +3925,17 @@
 
     @Override
     public String[] getAccountTypesWithManagementDisabled() {
+        return getAccountTypesWithManagementDisabledAsUser(UserHandle.getCallingUserId());
+    }
+
+    @Override
+    public String[] getAccountTypesWithManagementDisabledAsUser(int userId) {
+        enforceCrossUserPermission(userId);
         if (!mHasFeature) {
             return null;
         }
         synchronized (this) {
-            DevicePolicyData policy = getUserData(UserHandle.getCallingUserId());
+            DevicePolicyData policy = getUserData(userId);
             final int N = policy.mAdminList.size();
             HashSet<String> resultSet = new HashSet<String>();
             for (int i = 0; i < N; i++) {
@@ -4183,4 +4206,50 @@
             return audioManager.isMasterMute();
         }
     }
+
+    /**
+     * We need to update the internal state of whether a user has completed setup once. After
+     * that, we ignore any changes that reset the Settings.Secure.USER_SETUP_COMPLETE changes
+     * as we don't trust any apps that might try to reset it.
+     * <p>
+     * Unfortunately, we don't know which user's setup state was changed, so we write all of
+     * them.
+     */
+    void updateUserSetupComplete() {
+        List<UserInfo> users = mUserManager.getUsers(true);
+        ContentResolver resolver = mContext.getContentResolver();
+        final int N = users.size();
+        for (int i = 0; i < N; i++) {
+            int userHandle = users.get(i).id;
+            if (Settings.Secure.getIntForUser(resolver, Settings.Secure.USER_SETUP_COMPLETE, 0,
+                    userHandle) != 0) {
+                DevicePolicyData policy = getUserData(userHandle);
+                policy.mUserSetupComplete = true;
+                synchronized (this) {
+                    saveSettingsLocked(userHandle);
+                }
+            }
+        }
+    }
+
+    private class SetupContentObserver extends ContentObserver {
+
+        private final Uri mUserSetupComplete = Settings.Secure.getUriFor(
+                Settings.Secure.USER_SETUP_COMPLETE);
+
+        public SetupContentObserver(Handler handler) {
+            super(handler);
+        }
+
+        void register(ContentResolver resolver) {
+            resolver.registerContentObserver(mUserSetupComplete, false, this, UserHandle.USER_ALL);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            if (mUserSetupComplete.equals(uri)) {
+                updateUserSetupComplete();
+            }
+        }
+    }
 }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 8d38827..a6030cf 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -49,6 +49,7 @@
 import android.util.Log;
 import android.util.Slog;
 import android.view.WindowManager;
+import android.webkit.WebViewFactory;
 
 import com.android.internal.R;
 import com.android.internal.os.BinderInternal;
@@ -91,6 +92,7 @@
 import com.android.server.twilight.TwilightService;
 import com.android.server.usb.UsbService;
 import com.android.server.wallpaper.WallpaperManagerService;
+import com.android.server.webkit.WebViewUpdateService;
 import com.android.server.wm.WindowManagerService;
 
 import dalvik.system.VMRuntime;
@@ -408,6 +410,12 @@
             Slog.i(TAG, "Reading configuration...");
             SystemConfig.getInstance();
 
+            Slog.i(TAG, "WebView Update Service");
+            ServiceManager.addService("webviewupdate", new WebViewUpdateService());
+
+            Slog.i(TAG, "WebViewFactory preparation");
+            WebViewFactory.prepareWebViewInSystemServer();
+
             Slog.i(TAG, "Scheduling Policy");
             ServiceManager.addService("scheduling_policy", new SchedulingPolicyService());
 
diff --git a/telecomm/java/android/telecomm/Call.java b/telecomm/java/android/telecomm/Call.java
index 9f38d0d..5a41acb 100644
--- a/telecomm/java/android/telecomm/Call.java
+++ b/telecomm/java/android/telecomm/Call.java
@@ -62,6 +62,11 @@
      */
     public static final int STATE_DISCONNECTED = 7;
 
+    /**
+     * The state of an outgoing {@code Call}, but waiting for user input before proceeding.
+     */
+    public static final int STATE_PRE_DIAL_WAIT = 8;
+
     public static class Details {
         private final Uri mHandle;
         private final int mHandlePresentation;
@@ -430,6 +435,15 @@
     }
 
     /**
+     * Notifies this {@code Call} the a {@code PhoneAccount} has been selected and to proceed
+     * with placing an outgoing call.
+     */
+    public void phoneAccountSelected(PhoneAccount account) {
+        mInCallAdapter.phoneAccountSelected(mTelecommCallId, account);
+
+    }
+
+    /**
      * Instructs this {@code Call} to enter a conference.
      */
     public void conference() {
@@ -703,6 +717,8 @@
         switch (inCallCallState) {
             case NEW:
                 return STATE_NEW;
+            case PRE_DIAL_WAIT:
+                return STATE_PRE_DIAL_WAIT;
             case DIALING:
                 return STATE_DIALING;
             case RINGING:
diff --git a/telecomm/java/android/telecomm/CallState.java b/telecomm/java/android/telecomm/CallState.java
index a464da5..7abf4ab 100644
--- a/telecomm/java/android/telecomm/CallState.java
+++ b/telecomm/java/android/telecomm/CallState.java
@@ -32,6 +32,14 @@
     NEW,
 
     /**
+     * Indicates that the call is about to go into the outgoing and dialing state but is waiting for
+     * user input before it proceeds. For example, where no default {@link PhoneAccount} is set,
+     * this is the state where the InCallUI is waiting for the user to select a {@link PhoneAccount}
+     * to call from.
+     */
+    PRE_DIAL_WAIT,
+
+    /**
      * Indicates that a call is outgoing and in the dialing state. A call transitions to this state
      * once an outgoing call has begun (e.g., user presses the dial button in Dialer). Calls in this
      * state usually transition to {@link #ACTIVE} if the call was answered or {@link #DISCONNECTED}
diff --git a/telecomm/java/android/telecomm/InCallAdapter.java b/telecomm/java/android/telecomm/InCallAdapter.java
index 66cf1df..f228046 100644
--- a/telecomm/java/android/telecomm/InCallAdapter.java
+++ b/telecomm/java/android/telecomm/InCallAdapter.java
@@ -200,6 +200,19 @@
     }
 
     /**
+     * Instructs Telecomm to add a PhoneAccount to the specified call
+     *
+     * @param callId The identifier of the call
+     * @param account The PhoneAccount through which to place the call
+     */
+    public void phoneAccountSelected(String callId, PhoneAccount account) {
+        try {
+            mAdapter.phoneAccountSelected(callId, account);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
      * Instructs Telecomm to conference the specified call.
      *
      * @param callId The unique ID of the call.
diff --git a/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl
index ce0309f..b5b239b 100644
--- a/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl
@@ -17,6 +17,7 @@
 package com.android.internal.telecomm;
 
 import android.telecomm.CallAudioState;
+import android.telecomm.PhoneAccount;
 
 /**
  * Internal remote callback interface for in-call services.
@@ -48,6 +49,8 @@
 
     void phoneAccountClicked(String callId);
 
+    void phoneAccountSelected(String callId, in PhoneAccount account);
+
     void conference(String callId);
 
     void splitFromConference(String callId);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 5e6cb14..6e1ee78 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -24,7 +24,6 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
-import android.telecomm.PhoneAccount;
 import android.util.Log;
 
 import com.android.internal.telecomm.ITelecommService;