Merge "Document that circular reveal is async" into lmp-mr1-dev
diff --git a/Android.mk b/Android.mk
index 0d93ed1..51a9846 100644
--- a/Android.mk
+++ b/Android.mk
@@ -202,6 +202,8 @@
 	core/java/android/os/IUpdateLock.aidl \
 	core/java/android/os/IUserManager.aidl \
 	core/java/android/os/IVibratorService.aidl \
+	core/java/android/service/carriermessaging/ICarrierMessagingCallback.aidl \
+	core/java/android/service/carriermessaging/ICarrierMessagingService.aidl \
 	core/java/android/service/notification/INotificationListener.aidl \
 	core/java/android/service/notification/IStatusBarNotificationHolder.aidl \
 	core/java/android/service/notification/IConditionListener.aidl \
@@ -522,6 +524,8 @@
 	frameworks/base/core/java/android/view/textservice/SpellCheckerInfo.aidl \
 	frameworks/base/core/java/android/view/textservice/SentenceSuggestionsInfo.aidl \
 	frameworks/base/core/java/android/view/textservice/SuggestionsInfo.aidl \
+	frameworks/base/core/java/android/service/carriermessaging/MessagePdu.aidl \
+	frameworks/base/core/java/android/service/carriermessaging/CarrierMessagingService.aidl \
 	frameworks/base/core/java/android/service/notification/StatusBarNotification.aidl \
 	frameworks/base/core/java/android/speech/tts/Voice.aidl \
 	frameworks/base/core/java/android/app/usage/UsageEvents.aidl \
diff --git a/api/current.txt b/api/current.txt
index e129761..cc5adb2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -20,6 +20,7 @@
     field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
     field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
     field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
+    field public static final java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
     field public static final java.lang.String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
     field public static final java.lang.String BIND_DREAM_SERVICE = "android.permission.BIND_DREAM_SERVICE";
     field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
@@ -2708,7 +2709,9 @@
     method public void invalidateAuthToken(java.lang.String, java.lang.String);
     method public static android.content.Intent newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, java.lang.String[], boolean, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle);
     method public java.lang.String peekAuthToken(android.accounts.Account, java.lang.String);
-    method public android.accounts.AccountManagerFuture<java.lang.Boolean> removeAccount(android.accounts.Account, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
+    method public deprecated android.accounts.AccountManagerFuture<java.lang.Boolean> removeAccount(android.accounts.Account, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
+    method public android.accounts.AccountManagerFuture<android.os.Bundle> removeAccount(android.accounts.Account, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
+    method public boolean removeAccountExplicitly(android.accounts.Account);
     method public void removeOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener);
     method public android.accounts.AccountManagerFuture<android.accounts.Account> renameAccount(android.accounts.Account, java.lang.String, android.accounts.AccountManagerCallback<android.accounts.Account>, android.os.Handler);
     method public void setAuthToken(android.accounts.Account, java.lang.String, java.lang.String);
@@ -5399,6 +5402,7 @@
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION";
     field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
+    field public static final java.lang.String EXTRA_PROVISIONING_DONT_DISABLE_SYSTEM_APPS = "android.app.extra.PROVISIONING_DONT_DISABLE_SYSTEM_APPS";
     field public static final java.lang.String EXTRA_PROVISIONING_EMAIL_ADDRESS = "android.app.extra.PROVISIONING_EMAIL_ADDRESS";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.PROVISIONING_LOCAL_TIME";
@@ -10930,6 +10934,7 @@
     method public boolean canClip();
     method public float getAlpha();
     method public boolean isEmpty();
+    method public void offset(int, int);
     method public void set(android.graphics.Outline);
     method public void setAlpha(float);
     method public void setConvexPath(android.graphics.Path);
@@ -26891,6 +26896,83 @@
 
 }
 
+package android.service.carriermessaging {
+
+  public abstract class CarrierMessagingService extends android.app.Service {
+    ctor public CarrierMessagingService();
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public int onDownloadMms(android.net.Uri, java.lang.String);
+    method public boolean onFilterSms(android.service.carriermessaging.MessagePdu, java.lang.String, int);
+    method public android.service.carriermessaging.CarrierMessagingService.SendSmsResponse onSendDataSms(byte[], java.lang.String, java.lang.String, int);
+    method public android.service.carriermessaging.CarrierMessagingService.SendMmsResult onSendMms(android.net.Uri, java.lang.String);
+    method public java.util.List<android.service.carriermessaging.CarrierMessagingService.SendSmsResponse> onSendMultipartTextSms(java.util.List<java.lang.String>, java.lang.String, java.lang.String);
+    method public android.service.carriermessaging.CarrierMessagingService.SendSmsResponse onSendTextSms(java.lang.String, java.lang.String, java.lang.String);
+    field public static final int DOWNLOAD_STATUS_ERROR = 2; // 0x2
+    field public static final int DOWNLOAD_STATUS_OK = 0; // 0x0
+    field public static final int DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK = 1; // 0x1
+    field public static final int SEND_STATUS_ERROR = 2; // 0x2
+    field public static final int SEND_STATUS_OK = 0; // 0x0
+    field public static final int SEND_STATUS_RETRY_ON_CARRIER_NETWORK = 1; // 0x1
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.carriermessaging.CarrierMessagingService";
+  }
+
+  public static final class CarrierMessagingService.SendMmsResult {
+    ctor public CarrierMessagingService.SendMmsResult(int, byte[]);
+    method public int getResult();
+    method public byte[] getSendConfPdu();
+  }
+
+  public static final class CarrierMessagingService.SendSmsResponse implements android.os.Parcelable {
+    ctor public CarrierMessagingService.SendSmsResponse(int, byte[], int);
+    method public int describeContents();
+    method public byte[] getAckPdu();
+    method public int getErrorCode();
+    method public int getMessageRef();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.carriermessaging.CarrierMessagingService.SendSmsResponse> CREATOR;
+  }
+
+  public abstract interface ICarrierMessagingCallback implements android.os.IInterface {
+    method public abstract void onDownloadMmsComplete(int) throws android.os.RemoteException;
+    method public abstract void onFilterComplete(boolean) throws android.os.RemoteException;
+    method public abstract void onSendMmsComplete(int, byte[]) throws android.os.RemoteException;
+    method public abstract void onSendMultipartSmsComplete(int, java.util.List<android.service.carriermessaging.CarrierMessagingService.SendSmsResponse>) throws android.os.RemoteException;
+    method public abstract void onSendSmsComplete(int, android.service.carriermessaging.CarrierMessagingService.SendSmsResponse) throws android.os.RemoteException;
+  }
+
+  public static abstract class ICarrierMessagingCallback.Stub extends android.os.Binder implements android.service.carriermessaging.ICarrierMessagingCallback {
+    ctor public ICarrierMessagingCallback.Stub();
+    method public android.os.IBinder asBinder();
+    method public static android.service.carriermessaging.ICarrierMessagingCallback asInterface(android.os.IBinder);
+    method public boolean onTransact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException;
+  }
+
+  public abstract interface ICarrierMessagingService implements android.os.IInterface {
+    method public abstract void downloadMms(android.net.Uri, java.lang.String, android.service.carriermessaging.ICarrierMessagingCallback) throws android.os.RemoteException;
+    method public abstract void filterSms(android.service.carriermessaging.MessagePdu, java.lang.String, int, android.service.carriermessaging.ICarrierMessagingCallback) throws android.os.RemoteException;
+    method public abstract void sendDataSms(byte[], java.lang.String, java.lang.String, int, android.service.carriermessaging.ICarrierMessagingCallback) throws android.os.RemoteException;
+    method public abstract void sendMms(android.net.Uri, java.lang.String, android.service.carriermessaging.ICarrierMessagingCallback) throws android.os.RemoteException;
+    method public abstract void sendMultipartTextSms(java.util.List<java.lang.String>, java.lang.String, java.lang.String, android.service.carriermessaging.ICarrierMessagingCallback) throws android.os.RemoteException;
+    method public abstract void sendTextSms(java.lang.String, java.lang.String, java.lang.String, android.service.carriermessaging.ICarrierMessagingCallback) throws android.os.RemoteException;
+  }
+
+  public static abstract class ICarrierMessagingService.Stub extends android.os.Binder implements android.service.carriermessaging.ICarrierMessagingService {
+    ctor public ICarrierMessagingService.Stub();
+    method public android.os.IBinder asBinder();
+    method public static android.service.carriermessaging.ICarrierMessagingService asInterface(android.os.IBinder);
+    method public boolean onTransact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException;
+  }
+
+  public final class MessagePdu implements android.os.Parcelable {
+    ctor public MessagePdu(java.util.List<byte[]>);
+    method public int describeContents();
+    method public java.util.List<byte[]> getPdus();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.carriermessaging.MessagePdu> CREATOR;
+  }
+
+}
+
 package android.service.dreams {
 
   public class DreamService extends android.app.Service implements android.view.Window.Callback {
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 09b484b..6957435c 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -17,37 +17,37 @@
 package android.accounts;
 
 import android.app.Activity;
-import android.content.Intent;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.BroadcastReceiver;
 import android.content.res.Resources;
 import android.database.SQLException;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
-import android.os.RemoteException;
 import android.os.Parcelable;
-import android.os.Build;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.UserHandle;
-import android.util.Log;
 import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.R;
+import com.google.android.collect.Maps;
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CancellationException;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.FutureTask;
-import java.util.concurrent.TimeoutException;
 import java.util.concurrent.TimeUnit;
-import java.util.HashMap;
-import java.util.Map;
-
-import com.android.internal.R;
-import com.google.android.collect.Maps;
+import java.util.concurrent.TimeoutException;
 
 /**
  * This class provides access to a centralized registry of the user's
@@ -747,13 +747,17 @@
      *     null for the main thread
      * @return An {@link AccountManagerFuture} which resolves to a Boolean,
      *     true if the account has been successfully removed
+     * @deprecated use
+     *     {@link #removeAccount(Account, Activity, AccountManagerCallback, Handler)}
+     *     instead
      */
+    @Deprecated
     public AccountManagerFuture<Boolean> removeAccount(final Account account,
             AccountManagerCallback<Boolean> callback, Handler handler) {
         if (account == null) throw new IllegalArgumentException("account is null");
         return new Future2Task<Boolean>(handler, callback) {
             public void doWork() throws RemoteException {
-                mService.removeAccount(mResponse, account);
+                mService.removeAccount(mResponse, account, false);
             }
             public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
                 if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
@@ -765,9 +769,60 @@
     }
 
     /**
+     * Removes an account from the AccountManager. Does nothing if the account
+     * does not exist.  Does not delete the account from the server.
+     * The authenticator may have its own policies preventing account
+     * deletion, in which case the account will not be deleted.
+     *
+     * <p>This method may be called from any thread, but the returned
+     * {@link AccountManagerFuture} must not be used on the main thread.
+     *
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
+     *
+     * @param account The {@link Account} to remove
+     * @param activity The {@link Activity} context to use for launching a new
+     *     authenticator-defined sub-Activity to prompt the user to delete an
+     *     account; used only to call startActivity(); if null, the prompt
+     *     will not be launched directly, but the {@link Intent} may be
+     *     returned to the caller instead
+     * @param callback Callback to invoke when the request completes,
+     *     null for no callback
+     * @param handler {@link Handler} identifying the callback thread,
+     *     null for the main thread
+     * @return An {@link AccountManagerFuture} which resolves to a Bundle with
+     *     {@link #KEY_BOOLEAN_RESULT} if activity was specified and an account
+     *     was removed or if active. If no activity was specified, the returned
+     *     Bundle contains only {@link #KEY_INTENT} with the {@link Intent}
+     *     needed to launch the actual account removal process, if authenticator
+     *     needs the activity launch. If an error occurred,
+     *     {@link AccountManagerFuture#getResult()} throws:
+     * <ul>
+     * <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 or
+     *      adding accounts (of this type) has been disabled by policy
+     * </ul>
+     */
+    public AccountManagerFuture<Bundle> removeAccount(final Account account,
+            final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
+        if (account == null) throw new IllegalArgumentException("account is null");
+        return new AmsTask(activity, handler, callback) {
+            public void doWork() throws RemoteException {
+                mService.removeAccount(mResponse, account, activity != null);
+            }
+        }.start();
+    }
+
+    /**
      * @see #removeAccount(Account, AccountManagerCallback, Handler)
      * @hide
+     * @deprecated use
+     *     {@link #removeAccountAsUser(Account, Activity, AccountManagerCallback, Handler)}
+     *     instead
      */
+    @Deprecated
     public AccountManagerFuture<Boolean> removeAccountAsUser(final Account account,
             AccountManagerCallback<Boolean> callback, Handler handler,
             final UserHandle userHandle) {
@@ -775,7 +830,7 @@
         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());
+                mService.removeAccountAsUser(mResponse, account, false, userHandle.getIdentifier());
             }
             public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
                 if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
@@ -787,6 +842,52 @@
     }
 
     /**
+     * @see #removeAccount(Account, Activity, AccountManagerCallback, Handler)
+     * @hide
+     */
+    public AccountManagerFuture<Bundle> removeAccountAsUser(final Account account,
+            final Activity activity, AccountManagerCallback<Bundle> 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 AmsTask(activity, handler, callback) {
+            public void doWork() throws RemoteException {
+                mService.removeAccountAsUser(mResponse, account, activity != null,
+                        userHandle.getIdentifier());
+            }
+        }.start();
+    }
+
+    /**
+     * Removes an account directly. Normally used by authenticators, not
+     * directly by applications. Does not delete the account from the server.
+     * The authenticator may have its own policies preventing account deletion,
+     * in which case the account will not be deleted.
+     * <p>
+     * It is safe to call this method from the main thread.
+     * <p>
+     * This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and to have the
+     * same UID or signature as the account's authenticator.
+     *
+     * @param account The {@link Account} to delete.
+     * @return True if the account was successfully deleted, false if the
+     *         account did not exist, the account is null, or another error
+     *         occurs.
+     */
+    public boolean removeAccountExplicitly(Account account) {
+        if (account == null) throw new IllegalArgumentException("account is null");
+        try {
+            return mService.removeAccountExplicitly(account);
+        } catch (RemoteException e) {
+            // won't ever happen
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
      * 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
@@ -1342,6 +1443,40 @@
     }
 
     /**
+     * Copies an account from the primary user to another user.
+     * @param account the account to copy
+     * @param user the target user
+     * @param callback Callback to invoke when the request completes,
+     *     null for no callback
+     * @param handler {@link Handler} identifying the callback thread,
+     *     null for the main thread
+     * @return An {@link AccountManagerFuture} which resolves to a Boolean indicated wether it
+     * succeeded.
+     * @hide
+     */
+    public AccountManagerFuture<Boolean> copyAccountToUser(
+            final Account account, final UserHandle user,
+            AccountManagerCallback<Boolean> callback, Handler handler) {
+        if (account == null) throw new IllegalArgumentException("account is null");
+        if (user == null) throw new IllegalArgumentException("user is null");
+
+        return new Future2Task<Boolean>(handler, callback) {
+            @Override
+            public void doWork() throws RemoteException {
+                mService.copyAccountToUser(
+                        mResponse, account, UserHandle.USER_OWNER, user.getIdentifier());
+            }
+            @Override
+            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();
+    }
+
+    /**
      * @hide
      * Removes the shared account.
      * @param account the account to remove
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index a133788..aa41161 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -37,8 +37,13 @@
     void hasFeatures(in IAccountManagerResponse response, in Account account, in String[] features);
     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 removeAccount(in IAccountManagerResponse response, in Account account,
+        boolean expectActivityLaunch);
+    void removeAccountAsUser(in IAccountManagerResponse response, in Account account,
+        boolean expectActivityLaunch, int userId);
+    boolean removeAccountExplicitly(in Account account);
+    void copyAccountToUser(in IAccountManagerResponse response, in Account account,
+        int userFrom, int userTo);
     void invalidateAuthToken(String accountType, String authToken);
     String peekAuthToken(in Account account, String authTokenType);
     void setAuthToken(in Account account, String authTokenType, String authToken);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 756e51f..ad1cf44 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -142,8 +142,8 @@
      * {@link #ACTION_PROVISION_MANAGED_PROFILE} this package has to match the package name of the
      * application that started provisioning. The package will be set as profile owner in that case.
      *
-     * <p>This package is set as device owner when device owner provisioning is started by an Nfc
-     * message containing an Nfc record with MIME type {@link #MIME_TYPE_PROVISIONING_NFC}.
+     * <p>This package is set as device owner when device owner provisioning is started by an NFC
+     * message containing an NFC record with MIME type {@link #MIME_TYPE_PROVISIONING_NFC}.
      */
     public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME
         = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
@@ -176,11 +176,21 @@
         = "android.app.extra.PROVISIONING_EMAIL_ADDRESS";
 
     /**
+     * A Boolean extra that can be used by the mobile device management application to skip the
+     * disabling of system apps during provisioning when set to <code>true</code>.
+     *
+     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+     * provisioning via an NFC bump.
+     */
+    public static final String EXTRA_PROVISIONING_DONT_DISABLE_SYSTEM_APPS =
+            "android.app.extra.PROVISIONING_DONT_DISABLE_SYSTEM_APPS";
+
+    /**
      * A String extra holding the time zone {@link android.app.AlarmManager} that the device
      * will be set to.
      *
-     * <p>Use in an Nfc record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
-     * provisioning via an Nfc bump.
+     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+     * provisioning via an NFC bump.
      */
     public static final String EXTRA_PROVISIONING_TIME_ZONE
         = "android.app.extra.PROVISIONING_TIME_ZONE";
@@ -189,8 +199,8 @@
      * A Long extra holding the wall clock time (in milliseconds) to be set on the device's
      * {@link android.app.AlarmManager}.
      *
-     * <p>Use in an Nfc record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
-     * provisioning via an Nfc bump.
+     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+     * provisioning via an NFC bump.
      */
     public static final String EXTRA_PROVISIONING_LOCAL_TIME
         = "android.app.extra.PROVISIONING_LOCAL_TIME";
@@ -199,8 +209,8 @@
      * A String extra holding the {@link java.util.Locale} that the device will be set to.
      * Format: xx_yy, where xx is the language code, and yy the country code.
      *
-     * <p>Use in an Nfc record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
-     * provisioning via an Nfc bump.
+     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+     * provisioning via an NFC bump.
      */
     public static final String EXTRA_PROVISIONING_LOCALE
         = "android.app.extra.PROVISIONING_LOCALE";
@@ -209,8 +219,8 @@
      * A String extra holding the ssid of the wifi network that should be used during nfc device
      * owner provisioning for downloading the mobile device management application.
      *
-     * <p>Use in an Nfc record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
-     * provisioning via an Nfc bump.
+     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+     * provisioning via an NFC bump.
      */
     public static final String EXTRA_PROVISIONING_WIFI_SSID
         = "android.app.extra.PROVISIONING_WIFI_SSID";
@@ -219,8 +229,8 @@
      * A boolean extra indicating whether the wifi network in {@link #EXTRA_PROVISIONING_WIFI_SSID}
      * is hidden or not.
      *
-     * <p>Use in an Nfc record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
-     * provisioning via an Nfc bump.
+     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+     * provisioning via an NFC bump.
      */
     public static final String EXTRA_PROVISIONING_WIFI_HIDDEN
         = "android.app.extra.PROVISIONING_WIFI_HIDDEN";
@@ -229,8 +239,8 @@
      * A String extra indicating the security type of the wifi network in
      * {@link #EXTRA_PROVISIONING_WIFI_SSID}.
      *
-     * <p>Use in an Nfc record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
-     * provisioning via an Nfc bump.
+     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+     * provisioning via an NFC bump.
      */
     public static final String EXTRA_PROVISIONING_WIFI_SECURITY_TYPE
         = "android.app.extra.PROVISIONING_WIFI_SECURITY_TYPE";
@@ -239,8 +249,8 @@
      * A String extra holding the password of the wifi network in
      * {@link #EXTRA_PROVISIONING_WIFI_SSID}.
      *
-     * <p>Use in an Nfc record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
-     * provisioning via an Nfc bump.
+     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+     * provisioning via an NFC bump.
      */
     public static final String EXTRA_PROVISIONING_WIFI_PASSWORD
         = "android.app.extra.PROVISIONING_WIFI_PASSWORD";
@@ -249,8 +259,8 @@
      * A String extra holding the proxy host for the wifi network in
      * {@link #EXTRA_PROVISIONING_WIFI_SSID}.
      *
-     * <p>Use in an Nfc record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
-     * provisioning via an Nfc bump.
+     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+     * provisioning via an NFC bump.
      */
     public static final String EXTRA_PROVISIONING_WIFI_PROXY_HOST
         = "android.app.extra.PROVISIONING_WIFI_PROXY_HOST";
@@ -259,8 +269,8 @@
      * An int extra holding the proxy port for the wifi network in
      * {@link #EXTRA_PROVISIONING_WIFI_SSID}.
      *
-     * <p>Use in an Nfc record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
-     * provisioning via an Nfc bump.
+     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+     * provisioning via an NFC bump.
      */
     public static final String EXTRA_PROVISIONING_WIFI_PROXY_PORT
         = "android.app.extra.PROVISIONING_WIFI_PROXY_PORT";
@@ -269,8 +279,8 @@
      * A String extra holding the proxy bypass for the wifi network in
      * {@link #EXTRA_PROVISIONING_WIFI_SSID}.
      *
-     * <p>Use in an Nfc record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
-     * provisioning via an Nfc bump.
+     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+     * provisioning via an NFC bump.
      */
     public static final String EXTRA_PROVISIONING_WIFI_PROXY_BYPASS
         = "android.app.extra.PROVISIONING_WIFI_PROXY_BYPASS";
@@ -279,8 +289,8 @@
      * A String extra holding the proxy auto-config (PAC) URL for the wifi network in
      * {@link #EXTRA_PROVISIONING_WIFI_SSID}.
      *
-     * <p>Use in an Nfc record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
-     * provisioning via an Nfc bump.
+     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+     * provisioning via an NFC bump.
      */
     public static final String EXTRA_PROVISIONING_WIFI_PAC_URL
         = "android.app.extra.PROVISIONING_WIFI_PAC_URL";
@@ -289,8 +299,8 @@
      * A String extra holding a url that specifies the download location of the device admin
      * package. When not provided it is assumed that the device admin package is already installed.
      *
-     * <p>Use in an Nfc record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
-     * provisioning via an Nfc bump.
+     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+     * provisioning via an NFC bump.
      */
     public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION
         = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION";
@@ -299,8 +309,8 @@
      * A String extra holding a http cookie header which should be used in the http request to the
      * url specified in {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}.
      *
-     * <p>Use in an Nfc record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
-     * provisioning via an Nfc bump.
+     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+     * provisioning via an NFC bump.
      */
     public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER
         = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER";
@@ -311,8 +321,8 @@
      * the file at the download location an error will be shown to the user and the user will be
      * asked to factory reset the device.
      *
-     * <p>Use in an Nfc record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
-     * provisioning via an Nfc bump.
+     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+     * provisioning via an NFC bump.
      */
     public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM
         = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM";
@@ -328,9 +338,9 @@
      * <p> A typical use case would be a device that is owned by a company, but used by either an
      * employee or client.
      *
-     * <p> The Nfc message should be send to an unprovisioned device.
+     * <p> The NFC message should be send to an unprovisioned device.
      *
-     * <p>The Nfc record must contain a serialized {@link java.util.Properties} object which
+     * <p>The NFC record must contain a serialized {@link java.util.Properties} object which
      * contains the following properties:
      * <ul>
      * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}</li>
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 16df844..8ce1e92 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -807,9 +807,21 @@
      * {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} are used by the camera
      * device, along with android.flash.* fields, if there's
      * a flash unit for this camera device.</p>
+     * <p>Note that auto-white balance (AWB) and auto-focus (AF)
+     * behavior is device dependent when AE is in OFF mode.
+     * To have consistent behavior across different devices,
+     * it is recommended to either set AWB and AF to OFF mode
+     * or lock AWB and AF before setting AE to OFF.
+     * See {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode},
+     * {@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock}, and {@link CaptureRequest#CONTROL_AF_TRIGGER android.control.afTrigger}
+     * for more details.</p>
      * <p>LEGACY devices do not support the OFF mode and will
      * override attempts to use this value to ON.</p>
      *
+     * @see CaptureRequest#CONTROL_AF_MODE
+     * @see CaptureRequest#CONTROL_AF_TRIGGER
+     * @see CaptureRequest#CONTROL_AWB_LOCK
+     * @see CaptureRequest#CONTROL_AWB_MODE
      * @see CaptureRequest#SENSOR_EXPOSURE_TIME
      * @see CaptureRequest#SENSOR_FRAME_DURATION
      * @see CaptureRequest#SENSOR_SENSITIVITY
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 6aec72a..48af67c 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -906,7 +906,10 @@
      * <p>Whether auto-focus (AF) is currently enabled, and what
      * mode it is set to.</p>
      * <p>Only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} = AUTO and the lens is not fixed focus
-     * (i.e. <code>{@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance} &gt; 0</code>).</p>
+     * (i.e. <code>{@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance} &gt; 0</code>). Also note that
+     * when {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is OFF, the behavior of AF is device
+     * dependent. It is recommended to lock AF by using {@link CaptureRequest#CONTROL_AF_TRIGGER android.control.afTrigger} before
+     * setting {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} to OFF, or set AF mode to OFF when AE is OFF.</p>
      * <p>If the lens is controlled by the camera device auto-focus algorithm,
      * the camera device will report the current AF status in {@link CaptureResult#CONTROL_AF_STATE android.control.afState}
      * in result metadata.</p>
@@ -923,8 +926,10 @@
      * {@link CameraCharacteristics#CONTROL_AF_AVAILABLE_MODES android.control.afAvailableModes}</p>
      * <p>This key is available on all devices.</p>
      *
+     * @see CaptureRequest#CONTROL_AE_MODE
      * @see CameraCharacteristics#CONTROL_AF_AVAILABLE_MODES
      * @see CaptureResult#CONTROL_AF_STATE
+     * @see CaptureRequest#CONTROL_AF_TRIGGER
      * @see CaptureRequest#CONTROL_MODE
      * @see CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE
      * @see #CONTROL_AF_MODE_OFF
@@ -1046,7 +1051,10 @@
      * <p>When set to the ON mode, the camera device's auto-white balance
      * routine is enabled, overriding the application's selected
      * {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} and
-     * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p>
+     * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}. Note that when {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode}
+     * is OFF, the behavior of AWB is device dependent. It is recommened to
+     * also set AWB mode to OFF or lock AWB by using {@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock} before
+     * setting AE mode to OFF.</p>
      * <p>When set to the OFF mode, the camera device's auto-white balance
      * routine is disabled. The application manually controls the white
      * balance by {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains}
@@ -1077,7 +1085,9 @@
      * @see CaptureRequest#COLOR_CORRECTION_GAINS
      * @see CaptureRequest#COLOR_CORRECTION_MODE
      * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
+     * @see CaptureRequest#CONTROL_AE_MODE
      * @see CameraCharacteristics#CONTROL_AWB_AVAILABLE_MODES
+     * @see CaptureRequest#CONTROL_AWB_LOCK
      * @see CaptureRequest#CONTROL_MODE
      * @see #CONTROL_AWB_MODE_OFF
      * @see #CONTROL_AWB_MODE_AUTO
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index d208649..c5c843d 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -970,7 +970,10 @@
      * <p>Whether auto-focus (AF) is currently enabled, and what
      * mode it is set to.</p>
      * <p>Only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} = AUTO and the lens is not fixed focus
-     * (i.e. <code>{@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance} &gt; 0</code>).</p>
+     * (i.e. <code>{@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance} &gt; 0</code>). Also note that
+     * when {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is OFF, the behavior of AF is device
+     * dependent. It is recommended to lock AF by using {@link CaptureRequest#CONTROL_AF_TRIGGER android.control.afTrigger} before
+     * setting {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} to OFF, or set AF mode to OFF when AE is OFF.</p>
      * <p>If the lens is controlled by the camera device auto-focus algorithm,
      * the camera device will report the current AF status in {@link CaptureResult#CONTROL_AF_STATE android.control.afState}
      * in result metadata.</p>
@@ -987,8 +990,10 @@
      * {@link CameraCharacteristics#CONTROL_AF_AVAILABLE_MODES android.control.afAvailableModes}</p>
      * <p>This key is available on all devices.</p>
      *
+     * @see CaptureRequest#CONTROL_AE_MODE
      * @see CameraCharacteristics#CONTROL_AF_AVAILABLE_MODES
      * @see CaptureResult#CONTROL_AF_STATE
+     * @see CaptureRequest#CONTROL_AF_TRIGGER
      * @see CaptureRequest#CONTROL_MODE
      * @see CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE
      * @see #CONTROL_AF_MODE_OFF
@@ -1519,7 +1524,10 @@
      * <p>When set to the ON mode, the camera device's auto-white balance
      * routine is enabled, overriding the application's selected
      * {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} and
-     * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p>
+     * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}. Note that when {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode}
+     * is OFF, the behavior of AWB is device dependent. It is recommened to
+     * also set AWB mode to OFF or lock AWB by using {@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock} before
+     * setting AE mode to OFF.</p>
      * <p>When set to the OFF mode, the camera device's auto-white balance
      * routine is disabled. The application manually controls the white
      * balance by {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains}
@@ -1550,7 +1558,9 @@
      * @see CaptureRequest#COLOR_CORRECTION_GAINS
      * @see CaptureRequest#COLOR_CORRECTION_MODE
      * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
+     * @see CaptureRequest#CONTROL_AE_MODE
      * @see CameraCharacteristics#CONTROL_AWB_AVAILABLE_MODES
+     * @see CaptureRequest#CONTROL_AWB_LOCK
      * @see CaptureRequest#CONTROL_MODE
      * @see #CONTROL_AWB_MODE_OFF
      * @see #CONTROL_AWB_MODE_AUTO
diff --git a/core/java/android/hardware/hdmi/HdmiPortInfo.java b/core/java/android/hardware/hdmi/HdmiPortInfo.java
index e52baed..1f0f45a9 100644
--- a/core/java/android/hardware/hdmi/HdmiPortInfo.java
+++ b/core/java/android/hardware/hdmi/HdmiPortInfo.java
@@ -136,7 +136,7 @@
                     boolean cec = (source.readInt() == 1);
                     boolean arc = (source.readInt() == 1);
                     boolean mhl = (source.readInt() == 1);
-                    return new HdmiPortInfo(id, type, address, cec, arc, mhl);
+                    return new HdmiPortInfo(id, type, address, cec, mhl, arc);
                 }
 
                 @Override
@@ -172,4 +172,15 @@
         s.append("mhl: ").append(mMhlSupported);
         return s.toString();
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof HdmiPortInfo)) {
+            return false;
+        }
+        final HdmiPortInfo other = (HdmiPortInfo) o;
+        return mId == other.mId && mType == other.mType && mAddress == other.mAddress
+                && mCecSupported == other.mCecSupported && mArcSupported == other.mArcSupported
+                && mMhlSupported == other.mMhlSupported;
+    }
 }
diff --git a/core/java/android/service/carriermessaging/CarrierMessagingService.aidl b/core/java/android/service/carriermessaging/CarrierMessagingService.aidl
new file mode 100644
index 0000000..50c438a
--- /dev/null
+++ b/core/java/android/service/carriermessaging/CarrierMessagingService.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.service.carriermessaging;
+
+parcelable CarrierMessagingService.SendSmsResponse;
\ No newline at end of file
diff --git a/core/java/android/service/carriermessaging/CarrierMessagingService.java b/core/java/android/service/carriermessaging/CarrierMessagingService.java
new file mode 100644
index 0000000..101f69b
--- /dev/null
+++ b/core/java/android/service/carriermessaging/CarrierMessagingService.java
@@ -0,0 +1,370 @@
+/*
+ * 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.service.carriermessaging;
+
+import android.annotation.Nullable;
+import android.annotation.SdkConstant;
+import android.app.Service;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+
+import java.util.List;
+
+/**
+ * A service that receives calls from the system when new SMS and MMS are
+ * sent or received.
+ * <p>To extend this class, you must declare the service in your manifest file with
+ * the {@link android.Manifest.permission#BIND_CARRIER_MESSAGING_SERVICE} permission
+ * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
+ * <pre>
+ * &lt;service android:name=".MyMessagingService"
+ *          android:label="&#64;string/service_name"
+ *          android:permission="android.permission.BIND_CARRIER_MESSAGING_SERVICE">
+ *     &lt;intent-filter>
+ *         &lt;action android:name="android.service.carriermessaging.CarrierMessagingService" />
+ *     &lt;/intent-filter>
+ * &lt;/service></pre>
+ */
+public abstract class CarrierMessagingService extends Service {
+    /**
+     * The {@link android.content.Intent} that must be declared as handled by the service.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE
+            = "android.service.carriermessaging.CarrierMessagingService";
+
+    /**
+     * Indicates that an SMS or MMS message was successfully sent.
+     */
+    public static final int SEND_STATUS_OK = 0;
+
+    /**
+     * SMS/MMS sending failed. We should retry via the carrier network.
+     */
+    public static final int SEND_STATUS_RETRY_ON_CARRIER_NETWORK = 1;
+
+    /**
+     * SMS/MMS sending failed. We should not retry via the carrier network.
+     */
+    public static final int SEND_STATUS_ERROR = 2;
+
+    /**
+     * Successfully downloaded an MMS message.
+     */
+    public static final int DOWNLOAD_STATUS_OK = 0;
+
+    /**
+     * MMS downloading failed. We should retry via the carrier network.
+     */
+    public static final int DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK = 1;
+
+    /**
+     * MMS downloading failed. We should not retry via the carrier network.
+     */
+    public static final int DOWNLOAD_STATUS_ERROR = 2;
+
+    private final ICarrierMessagingWrapper mWrapper = new ICarrierMessagingWrapper();
+
+    /**
+     * Implement this method to filter SMS messages.
+     *
+     * @param pdu the PDUs of the message
+     * @param format the format of the PDUs, typically "3gpp" or "3gpp2"
+     * @param destPort the destination port of a binary SMS, this will be -1 for text SMS
+     *
+     * @return True to keep an inbound SMS message and delivered to SMS apps. False to
+     * drop the message.
+     */
+    public boolean onFilterSms(MessagePdu pdu, String format, int destPort) {
+        // optional
+        return true;
+    }
+
+    /**
+     * Implement this method to intercept text SMSs sent from the devcie.
+     *
+     * @param text the text to send
+     * @param format the format of the response PDU, typically "3gpp" or "3gpp2"
+     * @param destAddress phone number of the recipient of the message
+     *
+     * @return a {@link SendSmsResponse}.
+     */
+    public SendSmsResponse onSendTextSms(String text, String format, String destAddress) {
+        // optional
+        return null;
+    }
+
+    /**
+     * Implement this method to intercept binary SMSs sent from the device.
+     *
+     * @param data the binary content
+     * @param format format the format of the response PDU, typically "3gpp" or "3gpp2"
+     * @param destAddress phone number of the recipient of the message
+     * @param destPort the destination port
+     *
+     * @return a {@link SendSmsResponse}
+     */
+    public SendSmsResponse onSendDataSms(byte[] data, String format, String destAddress,
+            int destPort) {
+        // optional
+        return null;
+    }
+
+    /**
+     * Implement this method to intercept long SMSs sent from the device.
+     *
+     * @param parts a {@link List} of the message parts
+     * @param format format the format of the response PDU, typically "3gpp" or "3gpp2"
+     * @param destAddress phone number of the recipient of the message
+     *
+     * @return a {@link List} of {@link SendSmsResponse}, one for each message part.
+     */
+    public List<SendSmsResponse> onSendMultipartTextSms(List<String> parts, String format,
+            String destAddress) {
+        // optional
+        return null;
+    }
+
+    /**
+     * Implement this method to intercept MMSs sent from the device.
+     *
+     * @param pduUri the content provider URI of the PDU to send
+     * @param locationUrl the optional URL to send this MMS PDU. If this is not specified,
+     *                    the PDU should be sent to the default MMSC URL.
+     *
+     * @return a {@link SendMmsResult}.
+     */
+    public SendMmsResult onSendMms(Uri pduUri, @Nullable String locationUrl) {
+        // optional
+        return null;
+    }
+
+    /**
+     * Implement this method to download MMSs received.
+     *
+     * @param contentUri the content provider URI of the PDU to be downloaded.
+     * @param locationUrl the URL of the message to be downloaded.
+     *
+     * @return a {@link SendMmsResult}.
+     */
+    public int onDownloadMms(Uri contentUri, String locationUrl) {
+        // optional
+        return DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK;
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        if (!SERVICE_INTERFACE.equals(intent.getAction())) {
+            return null;
+        }
+        return mWrapper;
+    }
+
+    /**
+     * The result of sending an MMS.
+     */
+    public static final class SendMmsResult {
+        private int mResult;
+        private byte[] mSendConfPdu;
+
+        public SendMmsResult(int result, byte[] sendConfPdu) {
+            mResult = result;
+            mSendConfPdu = sendConfPdu;
+        }
+
+        /**
+         * @return the result which is one of {@link #SEND_STATUS_OK},
+         *         {@link #SEND_STATUS_RETRY_ON_CARRIER_NETWORK}, and {@link #SEND_STATUS_ERROR}
+         */
+        public int getResult() {
+            return mResult;
+        }
+
+        /**
+         * @return the SendConf PDU, which confirms that the message was sent.
+         */
+        public byte[] getSendConfPdu() {
+            return mSendConfPdu;
+        }
+    }
+
+    /**
+     * Object passed in callbacks upon successful completion of
+     * {@link ICarrierMessagingService#sendTextSms},
+     * {@link ICarrierMessagingService#sendDataSms}, and
+     * {@link ICarrierMessagingService#sendMultipartTextSms}.
+     * Contains message reference and ackPdu.
+     */
+    public static final class SendSmsResponse implements Parcelable {
+        private int mMessageRef;
+        private byte[] mAckPdu;
+        private int mErrorCode;
+
+        /**
+         * @param messageRef message reference of the just-sent SMS
+         * @param ackPdu ackPdu for the just-sent SMS
+         * @param errorCode error code. See 3GPP 27.005, 3.2.5 for GSM/UMTS,
+         *     3GPP2 N.S0005 (IS-41C) Table 171 for CDMA, -1 if unknown or not applicable.
+         */
+        public SendSmsResponse(int messageRef, byte[] ackPdu, int errorCode) {
+            mMessageRef = messageRef;
+            mAckPdu = ackPdu;
+            mErrorCode = errorCode;
+        }
+
+        /**
+         * Returns the message reference of the just-sent SMS.
+         *
+         * @return the message reference
+         */
+        public int getMessageRef() {
+            return mMessageRef;
+        }
+
+        /**
+         * Returns the ackPdu for the just-sent SMS.
+         *
+         * @return the ackPdu
+         */
+        public byte[] getAckPdu() {
+            return mAckPdu;
+        }
+
+        /**
+         * Returns the error code upon encountering an error while sending the SMS, -1 if unknown or
+         * not applicable.
+         *
+         * @return errorCode the errorCode as defined in 3GPP 27.005, 3.2.5 for GSM/UMTS, and 3GPP2
+         * N.S0005 (IS-41C) Table 171 for CDMA, -1 if unknown or not applicable.
+         */
+        public int getErrorCode() {
+            return mErrorCode;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(mMessageRef);
+            dest.writeByteArray(mAckPdu);
+            dest.writeInt(mErrorCode);
+        }
+
+        public static final Parcelable.Creator<SendSmsResponse> CREATOR
+                = new Parcelable.Creator<SendSmsResponse>() {
+                    @Override
+                    public SendSmsResponse createFromParcel(Parcel source) {
+                        return new SendSmsResponse(source.readInt(),
+                                                   source.createByteArray(),
+                                                   source.readInt());
+                    }
+
+                    @Override
+                    public SendSmsResponse[] newArray(int size) {
+                        return new SendSmsResponse[size];
+                    }
+        };
+    }
+
+    /**
+     * A wrapper around ICarrierMessagingService to enable the carrier messaging APP to implement
+     * methods it cares about in the {@link ICarrierMessagingService} interface.
+     */
+    private class ICarrierMessagingWrapper extends ICarrierMessagingService.Stub {
+        @Override
+        public void filterSms(MessagePdu pdu, String format, int destPort,
+                              ICarrierMessagingCallback callback) {
+            try {
+                callback.onFilterComplete(onFilterSms(pdu, format, destPort));
+            } catch (RemoteException ex) {
+            }
+        }
+
+        @Override
+        public void sendTextSms(String text, String format, String destAddress,
+                                ICarrierMessagingCallback callback) {
+            try {
+                SendSmsResponse sendSmsResponse = onSendTextSms(text, format, destAddress);
+                if (sendSmsResponse == null) {
+                    callback.onSendSmsComplete(SEND_STATUS_RETRY_ON_CARRIER_NETWORK, null);
+                } else {
+                    callback.onSendSmsComplete(SEND_STATUS_OK, sendSmsResponse);
+                }
+            } catch (RemoteException ex) {
+            }
+        }
+
+        @Override
+        public void sendDataSms(byte[] data, String format, String destAddress, int destPort,
+                                ICarrierMessagingCallback callback) {
+            try {
+                SendSmsResponse sendSmsResponse = onSendDataSms(data, format, destAddress,
+                        destPort);
+                if (sendSmsResponse == null) {
+                    callback.onSendSmsComplete(SEND_STATUS_RETRY_ON_CARRIER_NETWORK, null);
+                } else {
+                    callback.onSendSmsComplete(SEND_STATUS_OK, sendSmsResponse);
+                }
+            } catch (RemoteException ex) {
+            }
+        }
+
+        @Override
+        public void sendMultipartTextSms(List<String> parts, String format, String destAddress,
+                                         ICarrierMessagingCallback callback) {
+            try {
+                List<SendSmsResponse> sendSmsResponses =
+                        onSendMultipartTextSms(parts, format, destAddress);
+                if (sendSmsResponses == null) {
+                    callback.onSendMultipartSmsComplete(SEND_STATUS_RETRY_ON_CARRIER_NETWORK, null);
+                } else {
+                    callback.onSendMultipartSmsComplete(SEND_STATUS_OK, sendSmsResponses);
+                }
+            } catch (RemoteException ex) {
+            }
+        }
+
+        @Override
+        public void sendMms(Uri pduUri, String locationUrl, ICarrierMessagingCallback callback) {
+            try {
+                SendMmsResult result = onSendMms(pduUri, locationUrl);
+                if (result == null) {
+                    callback.onSendMmsComplete(SEND_STATUS_RETRY_ON_CARRIER_NETWORK, null);
+                } else {
+                    callback.onSendMmsComplete(SEND_STATUS_OK, result.getSendConfPdu());
+                }
+            } catch (RemoteException ex) {
+            }
+        }
+
+        @Override
+        public void downloadMms(Uri contentUri, String locationUrl,
+                ICarrierMessagingCallback callback) {
+            try {
+                callback.onDownloadMmsComplete(onDownloadMms(contentUri, locationUrl));
+            } catch (RemoteException ex) {
+            }
+        }
+    }
+}
diff --git a/core/java/android/service/carriermessaging/CarrierMessagingServiceManager.java b/core/java/android/service/carriermessaging/CarrierMessagingServiceManager.java
new file mode 100644
index 0000000..56ee2c1
--- /dev/null
+++ b/core/java/android/service/carriermessaging/CarrierMessagingServiceManager.java
@@ -0,0 +1,97 @@
+/*
+ * 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.service.carriermessaging;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Provides basic structure for platform to connect to the carrier messaging service.
+ * <p>
+ * <code>
+ * CarrierMessagingServiceManager carrierMessagingServiceManager =
+ *     new CarrierMessagingServiceManagerImpl();
+ * if (carrierMessagingServiceManager.bindToCarrierMessagingService(context, carrierPackageName)) {
+ *   // wait for onServiceReady callback
+ * } else {
+ *   // Unable to bind: handle error.
+ * }
+ * </code>
+ * <p> Upon completion {@link #disposeConnection} should be called to unbind the
+ * CarrierMessagingService.
+ * @hide
+ */
+public abstract class CarrierMessagingServiceManager {
+    // Populated by bindToCarrierMessagingService. bindToCarrierMessagingService must complete
+    // prior to calling disposeConnection so that mCarrierMessagingServiceConnection is initialized.
+    private volatile CarrierMessagingServiceConnection mCarrierMessagingServiceConnection;
+
+    /**
+     * Binds to the carrier messaging service under package {@code carrierPackageName}. This method
+     * should be called exactly once.
+     *
+     * @param context the context
+     * @param carrierPackageName the carrier package name
+     * @return true upon successfully binding to a carrier messaging service, false otherwise
+     */
+    public boolean bindToCarrierMessagingService(Context context, String carrierPackageName) {
+        Preconditions.checkState(mCarrierMessagingServiceConnection == null);
+
+        Intent intent = new Intent(CarrierMessagingService.SERVICE_INTERFACE);
+        intent.setPackage(carrierPackageName);
+        mCarrierMessagingServiceConnection = new CarrierMessagingServiceConnection();
+        return context.bindService(intent, mCarrierMessagingServiceConnection,
+                Context.BIND_AUTO_CREATE);
+    }
+
+    /**
+     * Unbinds the carrier messaging service. This method should be called exactly once.
+     *
+     * @param context the context
+     */
+    public void disposeConnection(Context context) {
+        Preconditions.checkNotNull(mCarrierMessagingServiceConnection);
+        context.unbindService(mCarrierMessagingServiceConnection);
+        mCarrierMessagingServiceConnection = null;
+    }
+
+    /**
+     * Implemented by subclasses to use the carrier messaging service once it is ready.
+     *
+     * @param carrierMessagingService the carirer messaing service interface
+     */
+    protected abstract void onServiceReady(ICarrierMessagingService carrierMessagingService);
+
+    /**
+     * A basic {@link ServiceConnection}.
+     */
+    private final class CarrierMessagingServiceConnection implements ServiceConnection {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            onServiceReady(ICarrierMessagingService.Stub.asInterface(service));
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+        }
+    }
+}
diff --git a/core/java/android/service/carriermessaging/ICarrierMessagingCallback.aidl b/core/java/android/service/carriermessaging/ICarrierMessagingCallback.aidl
new file mode 100644
index 0000000..da56ad1
--- /dev/null
+++ b/core/java/android/service/carriermessaging/ICarrierMessagingCallback.aidl
@@ -0,0 +1,33 @@
+/**
+ * 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.service.carriermessaging;
+
+import android.service.carriermessaging.CarrierMessagingService;
+
+/**
+ * Callback interface definition for the Carrier Messaging Service client to get informed of the
+ * result of various API invocations.
+ */
+oneway interface ICarrierMessagingCallback {
+    void onFilterComplete(boolean keepMessage);
+    void onSendSmsComplete(
+        int result, in CarrierMessagingService.SendSmsResponse sendSmsResponse);
+    void onSendMultipartSmsComplete(
+        int result, in List<CarrierMessagingService.SendSmsResponse> sendSmsResponses);
+    void onSendMmsComplete(int result, in byte[] sendConfPdu);
+    void onDownloadMmsComplete(int result);
+}
diff --git a/core/java/android/service/carriermessaging/ICarrierMessagingService.aidl b/core/java/android/service/carriermessaging/ICarrierMessagingService.aidl
new file mode 100644
index 0000000..6e9e3fa
--- /dev/null
+++ b/core/java/android/service/carriermessaging/ICarrierMessagingService.aidl
@@ -0,0 +1,103 @@
+/**
+ * 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.service.carriermessaging;
+
+import android.net.Uri;
+import android.service.carriermessaging.ICarrierMessagingCallback;
+import android.service.carriermessaging.MessagePdu;
+
+/**
+ * <p class="note"><strong>Note:</strong>
+ * This service can only be implemented by a carrier privileged app.
+ */
+oneway interface ICarrierMessagingService {
+    /**
+     * Request filtering an incoming SMS message.
+     * The service will call callback.onFilterComplete with the filtering result.
+     *
+     * @param pdu the PDUs of the message
+     * @param format the format of the PDUs, typically "3gpp" or "3gpp2"
+     * @param destPort the destination port of a data SMS. It will be -1 for text SMS
+     * @param callback the callback to notify upon completion
+     */
+    void filterSms(
+        in MessagePdu pdu, String format, int destPort, in ICarrierMessagingCallback callback);
+
+    /**
+     * Request sending a new text SMS from the device.
+     * The service will call {@link ICarrierMessagingCallback#onSendSmsComplete} with the send
+     * status.
+     *
+     * @param text the text to send
+     * @param format the format of the response PDU, typically "3gpp" or "3gpp2"
+     * @param destAddress phone number of the recipient of the message
+     * @param callback the callback to notify upon completion
+     */
+    void sendTextSms(String text, String format, String destAddress,
+            in ICarrierMessagingCallback callback);
+
+    /**
+     * Request sending a new data SMS from the device.
+     * The service will call {@link ICarrierMessagingCallback#onSendSmsComplete} with the send
+     * status.
+     *
+     * @param data the data to send
+     * @param format the format of the response PDU, typically "3gpp" or "3gpp2"
+     * @param destAddress phone number of the recipient of the message
+     * @param destPort port number of the recipient of the message
+     * @param callback the callback to notify upon completion
+     */
+    void sendDataSms(in byte[] data, String format, String destAddress, int destPort,
+            in ICarrierMessagingCallback callback);
+
+    /**
+     * Request sending a new multi-part text SMS from the device.
+     * The service will call {@link ICarrierMessagingCallback#onSendMultipartSmsComplete}
+     * with the send status.
+     *
+     * @param parts the parts of the multi-part text SMS to send
+     * @param format the format of the response PDU, typically "3gpp" or "3gpp2"
+     * @param destAddress phone number of the recipient of the message
+     * @param callback the callback to notify upon completion
+     */
+    void sendMultipartTextSms(in List<String> parts, String format, String destAddress,
+            in ICarrierMessagingCallback callback);
+
+    /**
+     * Request sending a new MMS PDU from the device.
+     * The service will call {@link ICarrierMessagingCallback#onSendMmsComplete} with the send
+     * status.
+     *
+     * @param pduUri the content provider URI of the PDU to send
+     * @param locationUrl the optional url to send this MMS PDU.
+     *         If this is not specified, PDU should be sent to the default MMSC url.
+     * @param callback the callback to notify upon completion
+     */
+    void sendMms(in Uri pduUri, String locationUrl, in ICarrierMessagingCallback callback);
+
+    /**
+     * Request downloading a new MMS.
+     * The service will call {@link ICarrierMessagingCallback#onDownloadMmsComplete} with the
+     * download status.
+     *
+     * @param pduUri the content provider URI of the PDU to be downloaded.
+     * @param locationUrl the URL of the message to be downloaded.
+     * @param callback the callback to notify upon completion
+     */
+    void downloadMms(in Uri pduUri, String locationUrl, in ICarrierMessagingCallback callback);
+}
+
diff --git a/core/java/android/service/carriermessaging/MessagePdu.aidl b/core/java/android/service/carriermessaging/MessagePdu.aidl
new file mode 100644
index 0000000..82b3fb3
--- /dev/null
+++ b/core/java/android/service/carriermessaging/MessagePdu.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.service.carriermessaging;
+
+parcelable MessagePdu;
\ No newline at end of file
diff --git a/core/java/android/service/carriermessaging/MessagePdu.java b/core/java/android/service/carriermessaging/MessagePdu.java
new file mode 100644
index 0000000..b81719f
--- /dev/null
+++ b/core/java/android/service/carriermessaging/MessagePdu.java
@@ -0,0 +1,94 @@
+/*
+ * 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.service.carriermessaging;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A parcelable list of PDUs representing contents of a possibly multi-part SMS.
+ */
+public final class MessagePdu implements Parcelable {
+    private static final int NULL_LENGTH = -1;
+
+    private final List<byte[]> mPduList;
+
+    /**
+     * @param pduList the list of message PDUs
+     */
+    public MessagePdu(List<byte[]> pduList) {
+        mPduList = pduList;
+    }
+
+    /**
+     * Returns the contents of a possibly multi-part SMS.
+     *
+     * @return the list of PDUs
+     */
+    public List<byte[]> getPdus() {
+        return mPduList;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Writes the PDU into a {@link Parcel}.
+     */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        if (mPduList == null) {
+            dest.writeInt(NULL_LENGTH);
+        } else {
+            dest.writeInt(mPduList.size());
+            for (byte[] messagePdu : mPduList) {
+                dest.writeByteArray(messagePdu);
+            }
+        }
+    }
+
+    /**
+     * Constructs a {@link MessagePdu} from a {@link Parcel}.
+     */
+    public static final Parcelable.Creator<MessagePdu> CREATOR
+            = new Parcelable.Creator<MessagePdu>() {
+                @Override
+                public MessagePdu createFromParcel(Parcel source) {
+                    int size = source.readInt();
+                    List<byte[]> pduList;
+                    if (size == NULL_LENGTH) {
+                        pduList = null;
+                    } else {
+                        pduList = new ArrayList<>(size);
+                        for (int i = 0; i < size; i++) {
+                            pduList.add(source.createByteArray());
+                        }
+                    }
+                    return new MessagePdu(pduList);
+                }
+
+                @Override
+                public MessagePdu[] newArray(int size) {
+                    return new MessagePdu[size];
+                }
+            };
+}
diff --git a/core/java/android/util/PathParser.java b/core/java/android/util/PathParser.java
index e5f3b2c..92b19be 100644
--- a/core/java/android/util/PathParser.java
+++ b/core/java/android/util/PathParser.java
@@ -280,7 +280,7 @@
          * @param path The target Path object.
          */
         public static void nodesToPath(PathDataNode[] node, Path path) {
-            float[] current = new float[4];
+            float[] current = new float[6];
             char previousCommand = 'm';
             for (int i = 0; i < node.length; i++) {
                 addCommand(path, current, previousCommand, node[i].mType, node[i].mParams);
@@ -313,6 +313,8 @@
             float currentY = current[1];
             float ctrlPointX = current[2];
             float ctrlPointY = current[3];
+            float currentSegmentStartX = current[4];
+            float currentSegmentStartY = current[5];
             float reflectiveCtrlPointX;
             float reflectiveCtrlPointY;
 
@@ -320,7 +322,15 @@
                 case 'z':
                 case 'Z':
                     path.close();
-                    return;
+                    // Path is closed here, but we need to move the pen to the
+                    // closed position. So we cache the segment's starting position,
+                    // and restore it here.
+                    currentX = currentSegmentStartX;
+                    currentY = currentSegmentStartY;
+                    ctrlPointX = currentSegmentStartX;
+                    ctrlPointY = currentSegmentStartY;
+                    path.moveTo(currentX, currentY);
+                    break;
                 case 'm':
                 case 'M':
                 case 'l':
@@ -350,17 +360,22 @@
                     incr = 7;
                     break;
             }
+
             for (int k = 0; k < val.length; k += incr) {
                 switch (cmd) {
                     case 'm': // moveto - Start a new sub-path (relative)
                         path.rMoveTo(val[k + 0], val[k + 1]);
                         currentX += val[k + 0];
                         currentY += val[k + 1];
+                        currentSegmentStartX = currentX;
+                        currentSegmentStartY = currentY;
                         break;
                     case 'M': // moveto - Start a new sub-path
                         path.moveTo(val[k + 0], val[k + 1]);
                         currentX = val[k + 0];
                         currentY = val[k + 1];
+                        currentSegmentStartX = currentX;
+                        currentSegmentStartY = currentY;
                         break;
                     case 'l': // lineto - Draw a line from the current point (relative)
                         path.rLineTo(val[k + 0], val[k + 1]);
@@ -372,10 +387,6 @@
                         currentX = val[k + 0];
                         currentY = val[k + 1];
                         break;
-                    case 'z': // closepath - Close the current subpath
-                    case 'Z': // closepath - Close the current subpath
-                        path.close();
-                        break;
                     case 'h': // horizontal lineto - Draws a horizontal line (relative)
                         path.rLineTo(val[k + 0], 0);
                         currentX += val[k + 0];
@@ -526,6 +537,8 @@
             current[1] = currentY;
             current[2] = ctrlPointX;
             current[3] = ctrlPointY;
+            current[4] = currentSegmentStartX;
+            current[5] = currentSegmentStartY;
         }
 
         private static void drawArc(Path p,
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 6de06d4..d120d79 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -885,6 +885,9 @@
 
     @Override
     public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
+        if ((start | end | (end - start) | (text.length() - end)) < 0) {
+            throw new IndexOutOfBoundsException();
+        }
         if (text instanceof String || text instanceof SpannedString ||
                 text instanceof SpannableString) {
             nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
diff --git a/core/java/android/view/InputEvent.java b/core/java/android/view/InputEvent.java
index 1ecdf30..e2ad3ad 100644
--- a/core/java/android/view/InputEvent.java
+++ b/core/java/android/view/InputEvent.java
@@ -196,6 +196,13 @@
     public abstract long getEventTimeNano();
 
     /**
+     * Marks the input event as being canceled.
+     *
+     * @hide
+     */
+    public abstract void cancel();
+
+    /**
      * Gets the unique sequence number of this event.
      * Every input event that is created or received by a process has a
      * unique sequence number.  Moreover, a new sequence number is obtained
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 0701b53..243a0fc 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -2304,6 +2304,16 @@
     }
 
     /**
+     * Set {@link #FLAG_CANCELED} flag for the key event.
+     *
+     * @hide
+     */
+    @Override
+    public final void cancel() {
+        mFlags |= FLAG_CANCELED;
+    }
+
+    /**
      * Call this during {@link Callback#onKeyDown} to have the system track
      * the key through its final up (possibly including a long press).  Note
      * that only one key can be tracked at a time -- if another key down
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index ae39b7a..1c5c41c 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -3168,6 +3168,12 @@
         return ev;
     }
 
+    /** @hide */
+    @Override
+    public final void cancel() {
+        setAction(ACTION_CANCEL);
+    }
+
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(PARCEL_TOKEN_MOTION_EVENT);
         nativeWriteToParcel(mNativePtr, out);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 9c378cf..77c1d7b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -5901,6 +5901,12 @@
                 region.op(interactiveRegion, Region.Op.INTERSECT);
             }
 
+            // Take into account the window bounds.
+            final View root = getRootView();
+            if (root != null) {
+                region.op(dx, dy, root.getWidth() + dx, root.getHeight() + dy, Region.Op.INTERSECT);
+            }
+
             // If the view is completely covered, done.
             if (region.isEmpty()) {
                 return false;
@@ -13174,7 +13180,7 @@
         }
         // Should resolve Drawables before Padding because we need the layout direction of the
         // Drawable to correctly resolve Padding.
-        if (!isDrawablesResolved()) {
+        if (!areDrawablesResolved()) {
             resolveDrawables();
         }
         if (!isPaddingResolved()) {
@@ -13438,6 +13444,14 @@
      * @hide
      */
     public void resetResolvedPadding() {
+        resetResolvedPaddingInternal();
+    }
+
+    /**
+     * Used when we only want to reset *this* view's padding and not trigger overrides
+     * in ViewGroup that reset children too.
+     */
+    void resetResolvedPaddingInternal() {
         mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED;
     }
 
@@ -15974,6 +15988,10 @@
         onResolveDrawables(layoutDirection);
     }
 
+    boolean areDrawablesResolved() {
+        return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED;
+    }
+
     /**
      * Called when layout direction has been resolved.
      *
@@ -15993,11 +16011,11 @@
      * @hide
      */
     protected void resetResolvedDrawables() {
-        mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED;
+        resetResolvedDrawablesInternal();
     }
 
-    private boolean isDrawablesResolved() {
-        return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED;
+    void resetResolvedDrawablesInternal() {
+        mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED;
     }
 
     /**
@@ -16297,10 +16315,10 @@
                 padding = new Rect();
                 sThreadLocal.set(padding);
             }
-            resetResolvedDrawables();
+            resetResolvedDrawablesInternal();
             background.setLayoutDirection(getLayoutDirection());
             if (background.getPadding(padding)) {
-                resetResolvedPadding();
+                resetResolvedPaddingInternal();
                 switch (background.getLayoutDirection()) {
                     case LAYOUT_DIRECTION_RTL:
                         mUserPaddingLeftInitial = padding.right;
@@ -16500,7 +16518,7 @@
      * @param bottom the bottom padding in pixels
      */
     public void setPadding(int left, int top, int right, int bottom) {
-        resetResolvedPadding();
+        resetResolvedPaddingInternal();
 
         mUserPaddingStart = UNDEFINED_PADDING;
         mUserPaddingEnd = UNDEFINED_PADDING;
@@ -16592,7 +16610,7 @@
      * @param bottom the bottom padding in pixels
      */
     public void setPaddingRelative(int start, int top, int end, int bottom) {
-        resetResolvedPadding();
+        resetResolvedPaddingInternal();
 
         mUserPaddingStart = start;
         mUserPaddingEnd = end;
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index b47ca37..bae0b12 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -6150,7 +6150,7 @@
         int count = getChildCount();
         for (int i = 0; i < count; i++) {
             final View child = getChildAt(i);
-            if (child.isLayoutDirectionInherited()) {
+            if (child.isLayoutDirectionInherited() && !child.isPaddingResolved()) {
                 child.resolvePadding();
             }
         }
@@ -6165,7 +6165,7 @@
         int count = getChildCount();
         for (int i = 0; i < count; i++) {
             final View child = getChildAt(i);
-            if (child.isLayoutDirectionInherited()) {
+            if (child.isLayoutDirectionInherited() && !child.areDrawablesResolved()) {
                 child.resolveDrawables();
             }
         }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 5d2a24b..fe17417 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -3596,12 +3596,19 @@
             if (mView == null || !mAdded) {
                 Slog.w(TAG, "Dropping event due to root view being removed: " + q.mEvent);
                 return true;
-            } else if (!mAttachInfo.mHasWindowFocus &&
-                  !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER) &&
-                  !isTerminalInputEvent(q.mEvent)) {
-                // If this is a focused event and the window doesn't currently have input focus,
-                // then drop this event.  This could be an event that came back from the previous
-                // stage but the window has lost focus in the meantime.
+            } else if ((!mAttachInfo.mHasWindowFocus || mStopped)
+                    && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
+                // This is a focus event and the window doesn't currently have input focus or
+                // has stopped. This could be an event that came back from the previous stage
+                // but the window has lost focus or stopped in the meantime.
+                if (isTerminalInputEvent(q.mEvent)) {
+                    // Don't drop terminal input events, however mark them as canceled.
+                    q.mEvent.cancel();
+                    Slog.w(TAG, "Cancelling event due to no window focus: " + q.mEvent);
+                    return false;
+                }
+
+                // Drop non-terminal input events.
                 Slog.w(TAG, "Dropping event due to no window focus: " + q.mEvent);
                 return true;
             }
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 7b23d8f..474ef42 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -18,8 +18,8 @@
 
 import android.annotation.SystemApi;
 import android.app.ActivityManagerInternal;
-import android.app.Application;
 import android.app.AppGlobals;
+import android.app.Application;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
@@ -34,14 +34,14 @@
 import android.text.TextUtils;
 import android.util.AndroidRuntimeException;
 import android.util.Log;
+
 import com.android.server.LocalServices;
+
 import dalvik.system.VMRuntime;
 
 import java.io.File;
 import java.util.Arrays;
 
-import com.android.internal.os.Zygote;
-
 /**
  * Top level factory, used creating all the main WebView implementation classes.
  *
@@ -91,6 +91,12 @@
             // us honest and minimize usage of WebView internals when binding the proxy.
             if (sProviderInstance != null) return sProviderInstance;
 
+            final int uid = android.os.Process.myUid();
+            if (uid == android.os.Process.ROOT_UID || uid == android.os.Process.SYSTEM_UID) {
+                throw new UnsupportedOperationException(
+                        "For security reasons, WebView is not allowed in privileged processes");
+            }
+
             Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getProvider()");
             try {
                 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()");
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 3b16aba..e6392b9 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -1005,6 +1005,12 @@
     @Override
     protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
         super.onFocusChanged(focused, direction, previouslyFocusedRect);
+
+        if (mTemporaryDetach) {
+            // If we are temporarily in the detach state, then do nothing.
+            return;
+        }
+
         // Perform validation if the view is losing focus.
         if (!focused) {
             performValidation();
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 0917b32..bc8b535 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -287,9 +287,11 @@
     private int mCurTextColor;
     private int mCurHintTextColor;
     private boolean mFreezesText;
-    private boolean mTemporaryDetach;
     private boolean mDispatchTemporaryDetach;
 
+    /** Whether this view is temporarily detached from the parent view. */
+    boolean mTemporaryDetach;
+
     private Editable.Factory mEditableFactory = Editable.Factory.getInstance();
     private Spannable.Factory mSpannableFactory = Spannable.Factory.getInstance();
 
@@ -3632,9 +3634,11 @@
         }
         if (mHintTextColor != null) {
             color = mHintTextColor.getColorForState(getDrawableState(), 0);
-            if (color != mCurHintTextColor && mText.length() == 0) {
+            if (color != mCurHintTextColor) {
                 mCurHintTextColor = color;
-                inval = true;
+                if (mText.length() == 0) {
+                    inval = true;
+                }
             }
         }
         if (inval) {
@@ -5368,9 +5372,13 @@
         final int vspace = mBottom - mTop - compoundPaddingBottom - compoundPaddingTop;
         final int maxScrollY = mLayout.getHeight() - vspace;
 
+        // Add sufficient space for cursor and tone marks
+        int cursorWidth = 2 + (int)mTextPaint.density; // adequate for Material cursors
+        int fudgedPaddingRight = Math.max(0, compoundPaddingRight - (cursorWidth - 1));
+
         float clipLeft = compoundPaddingLeft + scrollX;
         float clipTop = (scrollY == 0) ? 0 : extendedPaddingTop + scrollY;
-        float clipRight = right - left - compoundPaddingRight + scrollX;
+        float clipRight = right - left - fudgedPaddingRight + scrollX;
         float clipBottom = bottom - top + scrollY -
                 ((scrollY == maxScrollY) ? 0 : extendedPaddingBottom);
 
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index e38f3d4..d2eb8dd 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -431,7 +431,7 @@
     // read the new audio data from the native AudioRecord object
     const size_t recorderBuffSize = lpRecorder->frameCount()*lpRecorder->frameSize();
     const size_t sizeInBytes = sizeInShorts * sizeof(short);
-    ssize_t readSize = lpRecorder->read(recordBuff + offsetInShorts * sizeof(short),
+    ssize_t readSize = lpRecorder->read(recordBuff + offsetInShorts,
                                         sizeInBytes > recorderBuffSize ?
                                             recorderBuffSize : sizeInBytes);
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b03103e..4d6fc9c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2895,6 +2895,12 @@
         android:description="@string/permdesc_removeDrmCertificates"
         android:protectionLevel="signature|system" />
 
+    <!-- Must be required by a {@link android.service.carriermessaging.CarrierMessagingService}.
+         Any service that filters for this intent must be a carrier privileged app. -->
+    <permission android:name="android.permission.BIND_CARRIER_MESSAGING_SERVICE"
+        android:label="@string/permlab_bindCarrierMessagingService"
+        android:description="@string/permdesc_bindCarrierMessagingService" />
+
     <!-- The system process is explicitly the only one allowed to launch the
          confirmation UI for full backup/restore -->
     <uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
diff --git a/core/res/res/drawable/vector_drawable_progress_indeterminate_horizontal.xml b/core/res/res/drawable/vector_drawable_progress_indeterminate_horizontal.xml
index aa75a7a..912b5bf 100644
--- a/core/res/res/drawable/vector_drawable_progress_indeterminate_horizontal.xml
+++ b/core/res/res/drawable/vector_drawable_progress_indeterminate_horizontal.xml
@@ -27,7 +27,7 @@
             android:name="background_track"
             android:pathData="M -180.0,-1.0 l 360.0,0 l 0,2.0 l -360.0,0 Z"
             android:fillColor="?attr/colorControlActivated"
-            android:fillAlpha="0.1"/>
+            android:fillAlpha="?attr/disabledAlpha"/>
         <group
             android:name="rect2_grp"
             android:translateX="-197.60001"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d6bc38f..981c576 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2344,6 +2344,11 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_removeDrmCertificates">Allows an application to remove DRM certficates. Should never be needed for normal apps.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_bindCarrierMessagingService">bind to a carrier messaging service</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_bindCarrierMessagingService">Allows the holder to bind to the top-level interface of a carrier messaging service. Should never be needed for normal apps.</string>
+
     <!-- Policy administration -->
 
     <!-- Title of policy access to limiting the user's password choices -->
@@ -5113,4 +5118,7 @@
 
     <!-- Zen mode condition - line one: until next alarm. [CHAR LIMIT=NONE] -->
     <string name="zen_mode_next_alarm_line_one">Until next alarm</string>
+
+    <!-- Indication that the current volume and other effects (vibration) are being suppressed by a third party, such as a notification listener. [CHAR LIMIT=30] -->
+    <string name="muted_by">Muted by <xliff:g id="third_party">%1$s</xliff:g></string>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e1584cd..c592f49 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1994,6 +1994,7 @@
   <java-symbol type="string" name="zen_mode_next_alarm_summary" />
   <java-symbol type="string" name="zen_mode_next_alarm_line_one" />
   <java-symbol type="integer" name="config_next_alarm_condition_lookahead_threshold_hrs" />
+  <java-symbol type="string" name="muted_by" />
 
   <java-symbol type="string" name="item_is_selected" />
   <java-symbol type="string" name="day_of_week_label_typeface" />
diff --git a/core/res/res/values/themes_micro.xml b/core/res/res/values/themes_micro.xml
index f1bc5da..1ebc708 100644
--- a/core/res/res/values/themes_micro.xml
+++ b/core/res/res/values/themes_micro.xml
@@ -28,6 +28,8 @@
              to work properly. -->
         <item name="windowIsTranslucent">true</item>
         <item name="windowSwipeToDismiss">true</item>
+        <!-- Required to force windowInsets dispatch through application UI. -->
+        <item name="windowOverscan">true</item>
     </style>
 
     <style name="Theme.Micro.Light" parent="Theme.Holo.Light.NoActionBar">
@@ -44,6 +46,8 @@
              to work properly. -->
         <item name="windowIsTranslucent">true</item>
         <item name="windowSwipeToDismiss">true</item>
+        <!-- Required to force windowInsets dispatch through application UI. -->
+        <item name="windowOverscan">true</item>
     </style>
 
     <style name="Theme.Micro.Dialog" parent="Theme.Holo.Light.Dialog">
@@ -52,6 +56,8 @@
         <item name="windowFullscreen">true</item>
         <item name="textAppearance">@style/TextAppearance.Micro</item>
         <item name="textAppearanceInverse">@style/TextAppearance.Micro</item>
+        <!-- Required to force windowInsets dispatch through application UI. -->
+        <item name="windowOverscan">true</item>
     </style>
 
     <style name="Theme.Micro.Dialog.Alert">
diff --git a/docs/html/about/versions/android-5.0.jd b/docs/html/about/versions/android-5.0.jd
index 756b75f..4caa3ad 100644
--- a/docs/html/about/versions/android-5.0.jd
+++ b/docs/html/about/versions/android-5.0.jd
@@ -141,14 +141,6 @@
 the Android SDK</a>. Then use the <a href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a>
 to download the Android 5.0 SDK Platform and System Images.</p>
 
-<p style="
-    padding: 10px;
-    background: #eee;
-    width: 445px;
-    border: 1px solid #ccc;
-    margin-top: 20px;
-">To test your apps on a real device, flash a Nexus 5 or Nexus 7 with the <br>
-<a href="/preview/index.html#Start"><b>ANDROID PREVIEW SYSTEM IMAGE</b></a>.</p>
 
 <h3 id="ApiLevel">Update your target API level</h3>
 
diff --git a/docs/html/about/versions/lollipop.jd b/docs/html/about/versions/lollipop.jd
index 3ee0a86..458de49 100644
--- a/docs/html/about/versions/lollipop.jd
+++ b/docs/html/about/versions/lollipop.jd
@@ -57,16 +57,6 @@
 
 
 
-<p style="
-    padding: 10px;
-    background: #eee;
-    width: 250px;
-    border: 1px solid #ccc;
-    margin-top: 20px;
-">To test your apps on a real device, flash a Nexus 5 or Nexus 7 with the <br>
-<a href="/preview/index.html#Start"><b>ANDROID PREVIEW SYSTEM IMAGE</b></a>.</p>
-
-
 <h2 id="Material">Material design</h2>
 
 <p>Android 5.0 brings <a href="http://www.google.com/design/spec">Material design</a> to Android and gives you an expanded UI toolkit for integrating the new design patterns easily in your apps.  </p>
diff --git a/docs/html/google/gcm/ccs.jd b/docs/html/google/gcm/ccs.jd
index 7db7a74..6332b8d 100644
--- a/docs/html/google/gcm/ccs.jd
+++ b/docs/html/google/gcm/ccs.jd
@@ -263,6 +263,21 @@
 &lt;/message&gt;
 </pre>
 
+<p>Device Message Rate Exceeded:</p>
+
+<pre>&lt;message id=&quot;...&quot;&gt;
+  &lt;gcm xmlns=&quot;google:mobile:data&quot;&gt;
+  {
+    &quot;message_type&quot;:&quot;nack&quot;,
+    &quot;message_id&quot;:&quot;msgId1&quot;,
+    &quot;from&quot;:&quot;REGID&quot;,
+    &quot;error&quot;:&quot;DEVICE_MESSAGE_RATE_EXCEEDED&quot;,
+    &quot;error_description&quot;:&quot;Downstream message rate exceeded for this registration id&quot;
+  }
+  &lt;/gcm&gt;
+&lt;/message&gt;
+</pre>
+
 <p>The following table lists NACK error codes. Unless otherwise
 indicated, a NACKed message should not be retried. Unexpected NACK error codes
 should be treated the same as {@code INTERNAL_SERVER_ERROR}.</p>
@@ -303,8 +318,7 @@
 <td>{@code DEVICE_MESSAGE_RATE_EXCEEDED}</td>
 <td>The rate of messages to a particular device is too high. You should reduce
 the number of messages sent to this device and should not immediately retry
-sending to this device. This error code replaces {@code QUOTA_EXCEEDED},
-which has been deprecated.</td>
+sending to this device. This error code is replacing {@code QUOTA_EXCEEDED}.</td>
 </tr>
 <tr>
   <td>{@code SERVICE_UNAVAILABLE}</td>
diff --git a/docs/html/google/gcm/client.jd b/docs/html/google/gcm/client.jd
index 70109c6..d44ee3c 100644
--- a/docs/html/google/gcm/client.jd
+++ b/docs/html/google/gcm/client.jd
@@ -452,6 +452,21 @@
     editor.commit();
 }</pre>
 
+<h4 id="reg-errors">Handle registration errors</h4>
+
+<p>As stated above, an Android app must register with GCM servers and get a registration ID
+(regID) before it can receive messages. A given regID is not guaranteed to last indefinitely,
+so the first thing your app should always do is check to make sure it has a valid regID
+(as shown in the code snippets above).</p>
+
+<p>In addition to confirming that it has a valid regID, your app should be prepared to handle
+the registration error {@code TOO_MANY_REGISTRATIONS}. This error indicates that the device
+has too many apps registered with GCM. The error only occurs in cases where there are
+extreme numbers of apps, so it should not affect the average user. The remedy is to prompt
+the user to delete some of the other GCM-enabled apps from the device to make
+room for the new one.</p>
+
+
 <h3 id="sample-send">Send a message</h3>
 <p>When the user clicks the app's <strong>Send</strong> button, the app sends an
 upstream message using the
diff --git a/docs/html/preview/index.html b/docs/html/preview/index.html
index ed78e4d1..4f7722c 100644
--- a/docs/html/preview/index.html
+++ b/docs/html/preview/index.html
@@ -332,47 +332,11 @@
           to <code>"21"</code>, so you can upload your updated apps today.</li>
       </ul>
 
-      <p>Although the APIs for Android 5.0 are now final, the system image for end-users
-        is not available yet. So the following preview system images are available for you to
-        test your apps on a Nexus 5 or Nexus 7. These are non-final
-        builds and their use is governed by the <a href="/preview/license.html">Android L
-        Preview License Agreement</a>.</p>
-
-          <table >
-            <tbody><tr>
-              <th scope="col">Device</th>
-              <th scope="col">Download</th>
-              <th scope="col">Checksum</th>
-            </tr>
-            <tr id="hammerhead">
-              <td>Nexus 5 (GSM/LTE) <br>"hammerhead"</td>
-              <td><a href="#download" onclick="onDownload(this)">hammerhead-lpx13d-preview-f7596f51.tgz</a></td>
-              <td>MD5: <code>8d92596aa038203fc6c8ff40a0e8b560</code>
-              <br>SHA-1: <code>f7596f518a8a429f03de5bf8152fa90e738228dd</code></td>
-            </tr>
-            <tr id="razor">
-              <td>Nexus 7 [2013] (Wi-Fi) <br>"razor"</td>
-              <td><a href="#download" onclick="onDownload(this)">razor-lpx13d-preview-ae4f461f.tgz</a></td>
-              <td>MD5: <code>b2c567518d203b487cb2ac28d25b0a54</code>
-              <br><nobr>SHA-1: <code>ae4f461fabae5ff92eae0c252c34bb26d877e528</code></nobr></td>
-            </tr>
-          </tbody></table>
-        </li>
-
-        <p>For details about how to flash the system image to your device, see the
-          <a href="https://developers.google.com/android/nexus/images#instructions">flashing
-            instructions</a>.</p>
-
-        <p>If you want to uninstall the preview system image and flash your device to factory
-        specifications, download the appropriate image from
+      <p>If you previously flashed your Nexus 5 or Nexus 7 with a preview system image, you should
+        now update your device to the final factory system image.
+        Download the appropriate image from
         <a href="http://developers.google.com/android/nexus/images">Factory Images for Nexus
-          Devices</a> and follow the instructions on that page.</p>
-
-        <p class="note"><strong>Note:</strong> When the final Android 5.0 system image becomes
-          available, it will be posted on the
-        <a href="http://developers.google.com/android/nexus/images">Factory Images for Nexus
-          Devices</a> page. To continue development (and receive future system updates),
-          you should update your device with that image as soon as possible.</p>
+          Devices</a> and follow the flashing instructions on that page.</p>
 
         </div> <!-- end .wrap -->
 
diff --git a/docs/html/preview/license.html b/docs/html/preview/license.html
index ffda3ab..deb16aa 100644
--- a/docs/html/preview/license.html
+++ b/docs/html/preview/license.html
@@ -87,8 +87,8 @@
 
 <div class="jd-descr" itemprop="articleBody">
     <p>
-If you are using the <a href="/preview/index.html">Android SDK
-Preview</a>, you must agree to the following terms
+If you are using the Android SDK
+Preview, you must agree to the following terms
 and conditions. As described below, please note that the preview version of the
 Android SDK is subject to change, and that you use it at your own risk.  The
 Android SDK Preview is not a stable release, and may contain errors and defects
diff --git a/docs/html/samples/new/index.jd b/docs/html/samples/new/index.jd
index 330caa3..ba75072 100644
--- a/docs/html/samples/new/index.jd
+++ b/docs/html/samples/new/index.jd
@@ -12,99 +12,229 @@
 </p>
 
 
-<h3 id="BasicManagedProfile">BasicManagedProfile</h3>
-<div class="figure" style="width:220px">
-  <img src="{@docRoot}samples/images/BasicManagedProfile.png"
-     srcset="{@docRoot}samples/images/BasicManagedProfile@2x.png 2x"
-     alt="" height="375" />
-  <p class="img-caption">
-    <strong>Figure 1.</strong> The BasicManagedProfile sample app.
-  </p>
-</div>
+<!-- NOTE TO EDITORS: add most recent samples first -->
 
-<p>This sample demonstrates how to create a managed profile. You can also:</p>
-<ul>
-  <li>Enable or disable other apps, and set restrictions on them.</li>
-  <li>Configure intents to be forwarded between the primary account and the
-   managed profile.</li>
-  <li>Wipe all the data associated with the managed profile.</li>
-</ul>
+<h3 id="MediaBrowserService">Media Browser Service</h3>
 
-<p class="note"><strong>Note:</strong> There can be only one managed profile on
-  a device at a time.</p>
+<p>
+This sample is a simple audio media app that exposes its media
+library and provides metadata and playback controls through the new
+MediaBrowserService and MediaSession APIs from API 21.
+The sample is compatible with Android Auto and also provides a basic UI
+when not connected to a car.
+</p>
 
-<p><a href="http://github.com/googlesamples/android-BasicManagedProfile">Get it on GitHub</a></p>
+<p class="note">
+  <strong>Note:</strong> This sample is compatible with <a
+  href="http://android.com/auto">Android Auto</a>.
+</p>
 
-<h3 id="Camera2Basic">Camera2Basic</h3>
+<p><a href="http://github.com/googlesamples/android-MediaBrowserService">Get it on GitHub</a></p>
+
+
+<h3 id="MessagingService">Messaging Service</h3>
+
+<p>
+This sample shows a simple service that sends notifications using
+NotificationCompat. In addition to sending a notification, it also extends
+the notification with a CarExtender to make it compatible with Android Auto.
+Each unread conversation from a user is sent as a distinct notification.
+</p>
+
+<p class="note">
+  <strong>Note:</strong> This sample is compatible with <a
+  href="http://android.com/auto">Android Auto</a>.
+</p>
+
+<p><a href="http://github.com/googlesamples/android-MessagingService">Get it on GitHub</a></p>
+
+
+<h3 id="SpeedTracker">Speed Tracker (Wear)</h3>
+
+<p>
+This sample uses the FusedLocation APIs of Google Play Services on Android Wear 
+devices that have a hardware GPS built in. In those cases, this sample provides
+a simple screen that shows the current speed of the wearable device. User can
+set a speed limit and if the speed approaches that limit, it changes the color
+to yellow and if it exceeds the limit, it turns red. User can also enable
+recording of coordinates and when it pairs back with the phone, this data
+is synced with the phone component of the app and user can see a track
+made of those coordinates on a map on the phone.
+</p>
+
+<p><a href="http://github.com/googlesamples/android-SpeedTracker">Get it on GitHub</a></p>
+
+
+<h3 id="AppRestrictionSchema">AppRestrictionSchema</h3>
+
+<p>
+This sample shows how to use app restrictions. This application has one boolean
+restriction with a key "can_say_hello" that defines whether the only feature of this
+app (press the button to show "Hello" message) is enabled or disabled. Use
+AppRestrictionEnforcer sample to toggle the restriction.
+</p>
+
+<p><a href="http://github.com/googlesamples/android-AppRestrictionSchema">Get it on GitHub</a></p>
+
+
+<h3 id="AppRestrictionEnforcer">AppRestrictionEnforcer</h3>
+
+<p>
+This sample demonstrates how to set restrictions to other apps as a profile owner.
+Use AppRestrictionSchema sample as a app with available restrictions.
+</p>
+
+<p><a href="http://github.com/googlesamples/android-AppRestrictionEnforcer">Get it on GitHub</a></p>
+
+
+<h3 id="DocumentCentricRelinquishIdentity">DocumentCentricRelinquishIdentity</h3>
+
+<p>
+This sample shows how to relinquish identity to activities above it in the task stack.
+</p>
+
+<p><a href="http://github.com/googlesamples/android-DocumentCentricRelinquishIdentity">Get it on GitHub</a></p>
+
+
+<h3 id="DocumentCentricApps">DocumentCentricApps</h3>
+
+<p>
+This sample shows the basic usage of the new "Document Centric Apps" API.
+It let's you create new documents in the system overview menu and persists its
+state through reboots. If "Task per document" is checked a new task will be
+created for every new document in the overview menu.
+</p>
+
+<p><a href="http://github.com/googlesamples/android-DocumentCentricApps">Get it on GitHub</a></p>
+
+
+<h3 id="HdrViewfinder">HdrViewfinder</h3>
+
+<p>
+This demo implements a real-time high-dynamic-range camera viewfinder, by alternating
+the sensor's exposure time between two exposure values on even and odd frames, and then
+compositing together the latest two frames whenever a new frame is captured.
+</p>
+
+<p><a href="http://github.com/googlesamples/android-HdrViewfinder">Get it on GitHub</a></p>
+
+
+<h3 id="Interpolator">Interpolator</h3>
+
+<p>
+This sample demonstrates the use of animation interpolators and path animations for
+Material Design. It shows how an ObjectAnimator is used to animate two properties of a
+view (scale X and Y) along a path.
+</p>
+
+<p><a href="http://github.com/googlesamples/android-Interpolator">Get it on GitHub</a></p>
+
+
+<h3 id="DrawableTinting">DrawableTinting</h3>
+
+<p>Sample that shows applying tinting and color filters to Drawables both programmatically
+and as Drawable resources in XML.</p>
+<p>Tinting is set on a nine-patch drawable through the "tint" and "tintMode" parameters.
+A color state list is referenced as the tint color, which defines colors for different
+states of a View (for example disabled/enabled, focused, pressed or selected).</p>
+<p>Programmatically, tinting is applied to a Drawable through its "setColorFilter" method,
+with a reference to a color and a PorterDuff blend mode. The color and blend mode can be
+changed from the UI to see the effect of different options.</p>
+
+<p><a href="http://github.com/googlesamples/android-DrawableTinting">Get it on GitHub</a></p>
+
+
+<h3 id="LNotifications">LNotifications</h3>
+
+<p>
+This sample demonstrates how new features for notifications introduced in Android 5.0
+are used such as Heads-Up notifications, visibility, people, category and priority
+metadata. </p>
+<p><a href="http://github.com/googlesamples/android-LNotifications">Get it on GitHub</a></p>
+
+
+<h3 id="CardView">CardView</h3>
+
+<p>
+This sample demonstrates how to use the CardView UI widget introduced in Android 5.0, using the support library for backward compatibility.
+</p>
+
+<p><a href="http://github.com/googlesamples/android-CardView">Get it on GitHub</a></p>
+
+
+<h3 id="RecyclerView">RecyclerView</h3>
+
+<p>
+Demonstration of using RecyclerView with a LayoutManager to create a vertical ListView.
+</p>
+
+<p><a href="http://github.com/googlesamples/android-RecyclerView">Get it on GitHub</a></p>
+
+
+<h3 id="RevealEffectBasic">RevealEffectBasic</h3>
+
+<p>
+A sample demonstrating how to perform a reveal effect for UI elements within the Material Design framework.
+</p>
+
+<p><a href="http://github.com/googlesamples/android-RevealEffectBasic">Get it on GitHub</a></p>
+
+
+<h3 id="FloatingActionButtonBasic">FloatingActionButtonBasic</h3>
+
+<p>
+This sample shows the two sizes of Floating Action Buttons and how to interact with
+them.
+</p>
+
+<p><a href="http://github.com/googlesamples/android-FloatingActionButtonBasic">Get it on GitHub</a></p>
+
 
 <!--
+<h3 id="">SampleName</h3>
+
 <div class="figure" style="width:220px">
   <img src="" srcset="@2x.png 2x" alt="" height="375" />
   <p class="img-caption">
     <strong>Figure n.</strong> Single sentence summarizing the figure.
   </p>
 </div>
+
+<p>
+**description**
+</p>
 -->
 
-<p>This sample demonstrates the basic use of the Camera2 API. The sample code
-demonstrates how you can display camera preview and take pictures.</p>
 
-<p><a href="http://github.com/googlesamples/android-Camera2Basic">Get it on GitHub</a></p>
-
-
-<h3 id="Camera2Video">Camera2Video</h3>
+<h3 id="NavigationDrawerSample">NavigationDrawerSample</h3>
 <!--
 <div class="figure" style="width:220px">
-<img src="" srcset="@2x.png 2x" alt="" height="375" />
-    <p class="img-caption">
-    <strong>Figure n.</strong> Single sentence summarizing the figure.
-  </p>
-</div>
--->
-
-<p>This sample demonstrates how to record video using the Camera2 API.</p>
-
-<p><a href="http://github.com/googlesamples/android-Camera2Video">Get it on GitHub</a></p>
-
-<h3 id="ActivitySceneTransitionBasic">ActivitySceneTransitionBasic</h3>
-<div class="figure" style="width:220px">
-  <img src="{@docRoot}samples/images/ActivitySceneTransitionBasic.png"
-      srcset="{@docRoot}samples/images/ActivitySceneTransitionBasic@2x.png 2x"
-      alt="" height="375" />
+  <img src="" srcset="@2x.png 2x" alt="" height="375" />
   <p class="img-caption">
-    <strong>Figure 2.</strong> The ActivitySceneTransitionBasic sample app.
-  </p>
-  </div>
-
-<p> This sample demonstrates how to the use {@link android.app.Activity} scene
-transitions when transitioning from one activity to another. Uses a combination
-of <code>moveImage</code> and <code>changeBounds</code> to nicely transition
-from a grid of images to an activity with a large image and detail text. </p>
-
-<p><a href="http://github.com/googlesamples/android-ActivitySceneTransition">Get it on GitHub</a></p>
-
-<h3 id="ElevationBasic">ElevationBasic</h3>
-<!--
-<div class="figure" style="width:220px">
-<img src="" srcset="@2x.png 2x" alt="" height="375" />
-    <p class="img-caption">
     <strong>Figure n.</strong> Single sentence summarizing the figure.
   </p>
 </div>
 -->
 
 <p>
-This sample demonstrates two alternative ways to move a view in the z-axis:</p>
+This sample illustrates a common usage of the Android support library's
+{@link android.support.v4.widget.DrawerLayout} widget.
+</p>
 
-<ul>
-  <li>With a fixed elevation, using XML.</li>
-  <li>Raising the elevation when the user taps on it, using
-      <code>setTranslationZ()</code>.</li>
-</ul>
+<p><a href="http://github.com/googlesamples/android-NavigationDrawer">Get it on GitHub</a></p>
 
-<p><a href="http://github.com/googlesamples/android-ElevationBasic">Get it on GitHub</a></p>
 
-<h3 id="ElevationDrag">ElevationDrag</h3>
+<h3 id="JobSchedulerSample">JobSchedulerSample</h3>
+
+<p>
+This sample app allows the user to schedule jobs through the UI, and shows
+visual cues when the jobs are executed.
+</p>
+
+<p><a href="http://github.com/googlesamples/android-JobScheduler">Get it on GitHub</a></p>
+
+
+<h3 id="AndroidTVLeanbackSample">AndroidTVLeanbackSample</h3>
 <!--
 <div class="figure" style="width:220px">
   <img src="" srcset="@2x.png 2x" alt="" height="375" />
@@ -114,11 +244,46 @@
 </div>
 -->
 
-<p>This sample demonstrates a drag and drop action on different shapes.
-Elevation and z-translation are used to render the shadows. The views are
-clipped using different outlines.</p>
+<p>
+This sample demonstrates use of the Android TV Leanback Support Library.
+</p>
 
-<p><a href="http://github.com/googlesamples/android-ElevationDrag">Get it on GitHub</a></p>
+<p><a href="http://github.com/googlesamples/androidtv-Leanback">Get it on GitHub</a></p>
+
+
+<h3 id="Visual-Game-Controller">Visual-Game-Controller</h3>
+<!--
+<div class="figure" style="width:220px">
+  <img src="" srcset="@2x.png 2x" alt="" height="375" />
+  <p class="img-caption">
+    <strong>Figure n.</strong> Single sentence summarizing the figure.
+  </p>
+</div>
+-->
+
+<p>
+This sample displays events received from a game controller shown on the screen.
+</p>
+
+<p><a href="http://github.com/googlesamples/androidtv-VisualGameController">Get it on GitHub</a></p>
+
+
+<h3 id="GameControllerSample">GameControllerSample</h3>
+<!--
+<div class="figure" style="width:220px">
+  <img src="" srcset="@2x.png 2x" alt="" height="375" />
+  <p class="img-caption">
+    <strong>Figure n.</strong> Single sentence summarizing the figure.
+  </p>
+</div>
+-->
+
+<p>
+This sample implements a multi-player game, demonstrating game controller input
+handling.
+</p>
+
+<p><a href="http://github.com/googlesamples/androidtv-GameController">Get it on GitHub</a></p>
 
 
 <h3 id="ClippingBasic">ClippingBasic</h3>
@@ -146,7 +311,8 @@
   </p>
 </div>
 
-<h3 id="GameControllerSample">GameControllerSample</h3>
+
+<h3 id="ElevationDrag">ElevationDrag</h3>
 <!--
 <div class="figure" style="width:220px">
   <img src="" srcset="@2x.png 2x" alt="" height="375" />
@@ -156,15 +322,70 @@
 </div>
 -->
 
+<p>This sample demonstrates a drag and drop action on different shapes.
+Elevation and z-translation are used to render the shadows. The views are
+clipped using different outlines.</p>
+
+<p><a href="http://github.com/googlesamples/android-ElevationDrag">Get it on GitHub</a></p>
+
+
+<h3 id="ElevationBasic">ElevationBasic</h3>
+<!--
+<div class="figure" style="width:220px">
+<img src="" srcset="@2x.png 2x" alt="" height="375" />
+    <p class="img-caption">
+    <strong>Figure n.</strong> Single sentence summarizing the figure.
+  </p>
+</div>
+-->
+
 <p>
-This sample implements a multi-player game, demonstrating game controller input
-handling.
-</p>
+This sample demonstrates two alternative ways to move a view in the z-axis:</p>
 
-<p><a href="http://github.com/googlesamples/androidtv-GameController">Get it on GitHub</a></p>
+<ul>
+  <li>With a fixed elevation, using XML.</li>
+  <li>Raising the elevation when the user taps on it, using
+      <code>setTranslationZ()</code>.</li>
+</ul>
+
+<p><a href="http://github.com/googlesamples/android-ElevationBasic">Get it on GitHub</a></p>
 
 
-<h3 id="Visual-Game-Controller">Visual-Game-Controller</h3>
+<h3 id="ActivitySceneTransitionBasic">ActivitySceneTransitionBasic</h3>
+<div class="figure" style="width:220px">
+  <img src="{@docRoot}samples/images/ActivitySceneTransitionBasic.png"
+      srcset="{@docRoot}samples/images/ActivitySceneTransitionBasic@2x.png 2x"
+      alt="" height="375" />
+  <p class="img-caption">
+    <strong>Figure 2.</strong> The ActivitySceneTransitionBasic sample app.
+  </p>
+  </div>
+
+<p> This sample demonstrates how to the use {@link android.app.Activity} scene
+transitions when transitioning from one activity to another. Uses a combination
+of <code>moveImage</code> and <code>changeBounds</code> to nicely transition
+from a grid of images to an activity with a large image and detail text. </p>
+
+<p><a href="http://github.com/googlesamples/android-ActivitySceneTransition">Get it on GitHub</a></p>
+
+
+<h3 id="Camera2Video">Camera2Video</h3>
+<!--
+<div class="figure" style="width:220px">
+<img src="" srcset="@2x.png 2x" alt="" height="375" />
+    <p class="img-caption">
+    <strong>Figure n.</strong> Single sentence summarizing the figure.
+  </p>
+</div>
+-->
+
+<p>This sample demonstrates how to record video using the Camera2 API.</p>
+
+<p><a href="http://github.com/googlesamples/android-Camera2Video">Get it on GitHub</a></p>
+
+
+<h3 id="Camera2Basic">Camera2Basic</h3>
+
 <!--
 <div class="figure" style="width:220px">
   <img src="" srcset="@2x.png 2x" alt="" height="375" />
@@ -174,192 +395,32 @@
 </div>
 -->
 
-<p>
-This sample displays events received from a game controller shown on the screen.
-</p>
+<p>This sample demonstrates the basic use of the Camera2 API. The sample code
+demonstrates how you can display camera preview and take pictures.</p>
 
-<p><a href="http://github.com/googlesamples/androidtv-VisualGameController">Get it on GitHub</a></p>
+<p><a href="http://github.com/googlesamples/android-Camera2Basic">Get it on GitHub</a></p>
 
-<h3 id="AndroidTVLeanbackSample">AndroidTVLeanbackSample</h3>
-<!--
+
+<h3 id="BasicManagedProfile">BasicManagedProfile</h3>
 <div class="figure" style="width:220px">
-  <img src="" srcset="@2x.png 2x" alt="" height="375" />
+  <img src="{@docRoot}samples/images/BasicManagedProfile.png"
+     srcset="{@docRoot}samples/images/BasicManagedProfile@2x.png 2x"
+     alt="" height="375" />
   <p class="img-caption">
-    <strong>Figure n.</strong> Single sentence summarizing the figure.
-  </p>
-</div>
--->
-
-<p>
-This sample demonstrates use of the Android TV Leanback Support Library.
-</p>
-
-<p><a href="http://github.com/googlesamples/androidtv-Leanback">Get it on GitHub</a></p>
-
-<h3 id="JobSchedulerSample">JobSchedulerSample</h3>
-
-<p>
-This sample app allows the user to schedule jobs through the UI, and shows
-visual cues when the jobs are executed.
-</p>
-
-<p><a href="http://github.com/googlesamples/android-JobScheduler">Get it on GitHub</a></p>
-
-<h3 id="NavigationDrawerSample">NavigationDrawerSample</h3>
-<!--
-<div class="figure" style="width:220px">
-  <img src="" srcset="@2x.png 2x" alt="" height="375" />
-  <p class="img-caption">
-    <strong>Figure n.</strong> Single sentence summarizing the figure.
-  </p>
-</div>
--->
-
-<p>
-This sample illustrates a common usage of the Android support library's
-{@link android.support.v4.widget.DrawerLayout} widget.
-</p>
-
-<p><a href="http://github.com/googlesamples/android-NavigationDrawer">Get it on GitHub</a></p>
-<!--
-<h3 id="">SampleName</h3>
-
-<div class="figure" style="width:220px">
-  <img src="" srcset="@2x.png 2x" alt="" height="375" />
-  <p class="img-caption">
-    <strong>Figure n.</strong> Single sentence summarizing the figure.
+    <strong>Figure 1.</strong> The BasicManagedProfile sample app.
   </p>
 </div>
 
-<p>
-**description**
-</p>
--->
+<p>This sample demonstrates how to create a managed profile. You can also:</p>
+<ul>
+  <li>Enable or disable other apps, and set restrictions on them.</li>
+  <li>Configure intents to be forwarded between the primary account and the
+   managed profile.</li>
+  <li>Wipe all the data associated with the managed profile.</li>
+</ul>
 
-<h3 id="FloatingActionButtonBasic">FloatingActionButtonBasic</h3>
+<p class="note"><strong>Note:</strong> There can be only one managed profile on
+  a device at a time.</p>
 
-<p>
-This sample shows the two sizes of Floating Action Buttons and how to interact with
-them.
-</p>
+<p><a href="http://github.com/googlesamples/android-BasicManagedProfile">Get it on GitHub</a></p>
 
-<p><a href="http://github.com/googlesamples/android-FloatingActionButtonBasic">Get it on GitHub</a></p>
-
-<h3 id="RevealEffectBasic">RevealEffectBasic</h3>
-
-<p>
-A sample demonstrating how to perform a reveal effect for UI elements within the Material Design framework.
-</p>
-
-<p><a href="http://github.com/googlesamples/android-RevealEffectBasic">Get it on GitHub</a></p>
-
-<h3 id="RecyclerView">RecyclerView</h3>
-
-<p>
-Demonstration of using RecyclerView with a LayoutManager to create a vertical ListView.
-</p>
-
-<p><a href="http://github.com/googlesamples/android-RecyclerView">Get it on GitHub</a></p>
-
-<h3 id="CardView">CardView</h3>
-
-<p>
-This sample demonstrates how to use the CardView UI widget introduced in Android 5.0, using the support library for backward compatibility.
-</p>
-
-<p><a href="http://github.com/googlesamples/android-CardView">Get it on GitHub</a></p>
-
-<h3 id="LNotifications">LNotifications</h3>
-
-<p>
-This sample demonstrates how new features for notifications introduced in Android 5.0
-are used such as Heads-Up notifications, visibility, people, category and priority
-metadata. </p>
-<p><a href="http://github.com/googlesamples/android-LNotifications">Get it on GitHub</a></p>
-
-<h3 id="DrawableTinting">DrawableTinting</h3>
-
-<p>Sample that shows applying tinting and color filters to Drawables both programmatically
-and as Drawable resources in XML.</p>
-<p>Tinting is set on a nine-patch drawable through the "tint" and "tintMode" parameters.
-A color state list is referenced as the tint color, which defines colors for different
-states of a View (for example disabled/enabled, focused, pressed or selected).</p>
-<p>Programmatically, tinting is applied to a Drawable through its "setColorFilter" method,
-with a reference to a color and a PorterDuff blend mode. The color and blend mode can be
-changed from the UI to see the effect of different options.</p>
-
-<p><a href="http://github.com/googlesamples/android-DrawableTinting">Get it on GitHub</a></p>
-
-<h3 id="Interpolator">Interpolator</h3>
-
-<p>
-This sample demonstrates the use of animation interpolators and path animations for
-Material Design. It shows how an ObjectAnimator is used to animate two properties of a
-view (scale X and Y) along a path.
-</p>
-
-<p><a href="http://github.com/googlesamples/android-Interpolator">Get it on GitHub</a></p>
-
-<h3 id="HdrViewfinder">HdrViewfinder</h3>
-
-<p>
-This demo implements a real-time high-dynamic-range camera viewfinder, by alternating
-the sensor's exposure time between two exposure values on even and odd frames, and then
-compositing together the latest two frames whenever a new frame is captured.
-</p>
-
-<p><a href="http://github.com/googlesamples/android-HdrViewfinder">Get it on GitHub</a></p>
-
-<h3 id="DocumentCentricApps">DocumentCentricApps</h3>
-
-<p>
-This sample shows the basic usage of the new "Document Centric Apps" API.
-It let's you create new documents in the system overview menu and persists its
-state through reboots. If "Task per document" is checked a new task will be
-created for every new document in the overview menu.
-</p>
-
-<p><a href="http://github.com/googlesamples/android-DocumentCentricApps">Get it on GitHub</a></p>
-
-<h3 id="DocumentCentricRelinquishIdentity">DocumentCentricRelinquishIdentity</h3>
-
-<p>
-This sample shows how to relinquish identity to activities above it in the task stack.
-</p>
-
-<p><a href="http://github.com/googlesamples/android-DocumentCentricRelinquishIdentity">Get it on GitHub</a></p>
-
-<h3 id="AppRestrictionEnforcer">AppRestrictionEnforcer</h3>
-
-<p>
-This sample demonstrates how to set restrictions to other apps as a profile owner.
-Use AppRestrictionSchema sample as a app with available restrictions.
-</p>
-
-<p><a href="http://github.com/googlesamples/android-AppRestrictionEnforcer">Get it on GitHub</a></p>
-
-<h3 id="AppRestrictionSchema">AppRestrictionSchema</h3>
-
-<p>
-This sample shows how to use app restrictions. This application has one boolean
-restriction with a key "can_say_hello" that defines whether the only feature of this
-app (press the button to show "Hello" message) is enabled or disabled. Use
-AppRestrictionEnforcer sample to toggle the restriction.
-</p>
-
-<p><a href="http://github.com/googlesamples/android-AppRestrictionSchema">Get it on GitHub</a></p>
-
-<h3 id="SpeedTracker">Speed Tracker (Wear)</h3>
-
-<p>
-This sample uses the FusedLocation APIs of Google Play Services on Android Wear 
-devices that have a hardware GPS built in. In those cases, this sample provides
-a simple screen that shows the current speed of the wearable device. User can
-set a speed limit and if the speed approaches that limit, it changes the color
-to yellow and if it exceeds the limit, it turns red. User can also enable
-recording of coordinates and when it pairs back with the phone, this data
-is synced with the phone component of the app and user can see a track
-made of those coordinates on a map on the phone.
-</p>
-
-<p><a href="http://github.com/googlesamples/android-SpeedTracker">Get it on GitHub</a></p>
diff --git a/docs/html/training/location/index.jd b/docs/html/training/location/index.jd
index 249c42d..f0024e2 100644
--- a/docs/html/training/location/index.jd
+++ b/docs/html/training/location/index.jd
@@ -21,7 +21,8 @@
 <h2>You should also read</h2>
 <ul>
     <li>
-        <a href="{@docRoot}google/play-services/setup.html">Setup Google Play Services SDK</a>
+        <a href="{@docRoot}google/play-services/setup.html">Set Up Google Play
+        Services SDK</a>
     </li>
 </ul>
 
@@ -29,68 +30,75 @@
 </div>
 
 <p>
-    One of the unique features of mobile applications is location awareness. Mobile users bring
-    their devices with them everywhere, and adding location awareness to your app offers users a
-    more contextual experience. The new Location Services API available in Google Play services
-    facilitates adding location awareness to your app with automated location tracking,
-    geofencing, and activity recognition. This API adds significant advantages over the plaform's
-    location API.
+  One of the unique features of mobile applications is location awareness.
+  Mobile users take their devices with them everywhere, and adding location
+  awareness to your app offers users a more contextual experience. The location
+  APIs available in Google Play services facilitate adding location awareness to
+  your app with automated location tracking, geofencing, and activity
+  recognition.
 </p>
+
+<p>The
+  <a href="{@docRoot}reference/com/google/android/gms/location/package-summary.html">Google
+  Play services location APIs</a> are preferred over the Android framework
+  location APIs
+  (<a href="{@docRoot}reference/android/location/package-summary.html">android.location</a>)
+  as a way of adding location awareness to your app. If you are currently using
+  the Android framework location APIs, you are strongly encouraged to switch to
+  the Google Play services location APIs as soon as possible.
+</p>
+
 <p>
-    This class shows you how to use Location Services in your app to get the current location,
-    get periodic location updates, look up addresses, create and monitor geofences, and
-    detect user activities. The class includes sample apps and code snippets that you can use as a
-    starting point for adding location awareness to your own app.
+  This class shows you how to use the Google Play services location APIs in your
+  app to get the current location, get periodic location updates, look up
+  addresses, create and monitor geofences, and detect user activities. The class
+  includes sample apps and code snippets that you can use as a starting point
+  for adding location awareness to your app.
 </p>
+
 <p class="note">
-    <strong>Note:</strong> Since this class is based on the Google Play services client library,
-    make sure you install the latest version before using the sample apps or code snippets. To learn
-    how to set up the client library with the latest version, see
-    <a href="{@docRoot}google/play-services/setup.html">Setup</a> in the Google Play services guide.
+  <strong>Note:</strong> Since this class is based on the Google Play services
+  client library, make sure you install the latest version before using the
+  sample apps or code snippets. To learn how to set up the client library with
+  the latest version, see
+  <a href="{@docRoot}google/play-services/setup.html">Setup</a> in the Google
+  Play services guide.
 </p>
 <h2>Lessons</h2>
 <dl>
-    <dt>
-        <b><a href="retrieve-current.html">Retrieving the Current Location</a></b>
-    </dt>
-    <dd>
-        Learn how to retrieve the user's current location.
-    </dd>
-    <dt>
-        <b><a href="receive-location-updates.html">Receiving Location Updates</a></b>
-    </dt>
-    <dd>
-        Learn how to request and receive periodic location updates.
-    </dd>
-    <dt>
-        <b><a href="display-address.html">Displaying a Location Address</a></b>
-    </dt>
-    <dd>
-        Learn how to convert a location's latitude and longitude into an address (reverse
-        geocoding).
-    </dd>
-    <dt>
-        <b>
-            <a href="geofencing.html">Creating and Monitoring Geofences</a>
-        </b>
-    </dt>
-    <dd>
-        Learn how to define one or more geographic areas as locations of interest, called geofences,
-        and detect when the user is close to or inside a geofence.
-    </dd>
-    <dt>
-        <b><a href="activity-recognition.html">Recognizing the User's Current Activity</a></b>
-    </dt>
-    <dd>
-        Learn how to recognize the user's current activity, such as walking, bicycling,
-        or driving a car, and how to use this information to modify your app's location strategy.
-    </dd>
-    <dt>
-        <b><a href="location-testing.html">Testing Using Mock Locations</a></b>
-    </dt>
-    <dd>
-        Learn how to test a location-aware app by injecting mock locations into Location
-        Services. In mock mode, Location Services sends out mock locations that you inject instead
-        of sensor-based locations.
-    </dd>
+  <dt>
+    <b><a href="retrieve-current.html">Retrieving the Current Location</a></b>
+  </dt> <dd>
+     Learn how to retrieve the user's current location.
+  </dd> <dt>
+    <b><a href="receive-location-updates.html">Receiving Location
+    Updates</a></b>
+  </dt> <dd>
+     Learn how to request and receive periodic location updates.
+  </dd> <dt>
+    <b><a href="display-address.html">Displaying a Location Address</a></b>
+  </dt> <dd>
+    Learn how to convert a location's latitude and longitude into an address
+    (reverse geocoding).
+  </dd> <dt>
+    <b>
+      <a href="geofencing.html">Creating and Monitoring Geofences</a>
+    </b>
+  </dt> <dd>
+    Learn how to define one or more geographic areas as locations of interest,
+    called geofences, and detect when the user is close to or inside a geofence.
+  </dd> <dt>
+    <b><a href="activity-recognition.html">Recognizing the User's Current
+    Activity</a></b>
+  </dt> <dd>
+    Learn how to recognize the user's current activity, such as walking,
+    bicycling, or driving a car, and how to use this information to modify your
+    app's location strategy.
+  </dd> <dt>
+    <b><a href="location-testing.html">Testing Using Mock Locations</a></b>
+  </dt> <dd>
+    Learn how to test a location-aware app by injecting mock locations into
+    Location Services. In mock mode, Location Services sends out mock locations
+    that you inject instead of sensor-based locations.
+  </dd>
 </dl>
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 8279a51..499608e 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -1710,6 +1710,9 @@
      */
     public void drawText(@NonNull CharSequence text, int start, int end, float x, float y,
             @NonNull Paint paint) {
+        if ((start | end | (end - start) | (text.length() - end)) < 0) {
+            throw new IndexOutOfBoundsException();
+        }
         if (text instanceof String || text instanceof SpannedString ||
             text instanceof SpannableString) {
             native_drawText(mNativeCanvasWrapper, text.toString(), start, end, x, y,
diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java
index 4bf0b71..f76184f 100644
--- a/graphics/java/android/graphics/Outline.java
+++ b/graphics/java/android/graphics/Outline.java
@@ -221,4 +221,15 @@
         mRect = null;
         mRadius = -1.0f;
     }
+
+    /**
+     * Offsets the Outline by (dx,dy)
+     */
+    public void offset(int dx, int dy) {
+        if (mRect != null) {
+            mRect.offset(dx, dy);
+        } else if (mPath != null) {
+            mPath.offset(dx, dy);
+        }
+    }
 }
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index c40a66d..0e9823d 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -678,7 +678,7 @@
     }
 
     /**
-     * Offset the path by (dx,dy), returning true on success
+     * Offset the path by (dx,dy)
      *
      * @param dx  The amount in the X direction to offset the entire path
      * @param dy  The amount in the Y direction to offset the entire path
@@ -695,7 +695,7 @@
     }
 
     /**
-     * Offset the path by (dx,dy), returning true on success
+     * Offset the path by (dx,dy)
      *
      * @param dx The amount in the X direction to offset the entire path
      * @param dy The amount in the Y direction to offset the entire path
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index 3304b33..1ee44fb 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -497,6 +497,7 @@
 
         state.mFromDegrees = a.getFloat(R.styleable.RotateDrawable_fromDegrees, state.mFromDegrees);
         state.mToDegrees = a.getFloat(R.styleable.RotateDrawable_toDegrees, state.mToDegrees);
+        state.mCurrentDegrees = state.mFromDegrees;
 
         final Drawable dr = a.getDrawable(R.styleable.RotateDrawable_drawable);
         if (dr != null) {
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 8fc0b8e..645681a 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -2201,6 +2201,8 @@
                             listener = findFocusListener((String)msg.obj);
                         }
                         if (listener != null) {
+                            Log.d(TAG, "AudioManager dispatching onAudioFocusChange("
+                                    + msg.what + ") for " + msg.obj);
                             listener.onAudioFocusChange(msg.what);
                         }
                     }
@@ -2270,6 +2272,14 @@
      * A successful focus change request.
      */
     public static final int AUDIOFOCUS_REQUEST_GRANTED = 1;
+     /**
+      * @hide
+      * A focus change request whose granting is delayed: the request was successful, but the
+      * requester will only be granted audio focus once the condition that prevented immediate
+      * granting has ended.
+      * See {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
+      */
+    public static final int AUDIOFOCUS_REQUEST_DELAYED = 2;
 
 
     /**
@@ -2291,18 +2301,87 @@
      */
     public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) {
         int status = AUDIOFOCUS_REQUEST_FAILED;
+
+        try {
+            // status is guaranteed to be either AUDIOFOCUS_REQUEST_FAILED or
+            // AUDIOFOCUS_REQUEST_GRANTED as focus is requested without the
+            // AUDIOFOCUS_FLAG_DELAY_OK flag
+            status = requestAudioFocus(l,
+                    new AudioAttributes.Builder()
+                            .setInternalLegacyStreamType(streamType).build(),
+                    durationHint,
+                    0 /* flags, legacy behavior */);
+        } catch (IllegalArgumentException e) {
+            Log.e(TAG, "Audio focus request denied due to ", e);
+        }
+
+        return status;
+    }
+
+    // when adding new flags, add them to AUDIOFOCUS_FLAGS_ALL
+    /** @hide */
+    public static final int AUDIOFOCUS_FLAG_DELAY_OK = 0x1 << 0;
+    /** @hide */
+    public static final int AUDIOFOCUS_FLAGS_ALL = AUDIOFOCUS_FLAG_DELAY_OK;
+
+    /**
+     * @hide
+     * @param l the listener to be notified of audio focus changes. It is not allowed to be null
+     *     when the request is flagged with {@link #AUDIOFOCUS_FLAG_DELAY_OK}.
+     * @param requestAttributes non null {@link AudioAttributes} describing the main reason for
+     *     requesting audio focus.
+     * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request
+     *      is temporary, and focus will be abandonned shortly. Examples of transient requests are
+     *      for the playback of driving directions, or notifications sounds.
+     *      Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
+     *      the previous focus owner to keep playing if it ducks its audio output.
+     *      Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request
+     *      that benefits from the system not playing disruptive sounds like notifications, for
+     *      usecases such as voice memo recording, or speech recognition.
+     *      Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
+     *      as the playback of a song or a video.
+     * @param flags use 0 when not using any flags for the request, which behaves like
+     *      {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
+     *      focus is granted immediately, or the grant request fails because the system is in a
+     *      state where focus cannot change (e.g. a phone call).
+     *      Use {link #AUDIOFOCUS_FLAG_DELAY_OK} if it is ok for the requester to not be granted
+     *      audio focus immediately (as indicated by {@link #AUDIOFOCUS_REQUEST_DELAYED}) when
+     *      the system is in a state where focus cannot change, but be granted focus later when
+     *      this condition ends.
+     * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
+     *     or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
+     *     The return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus is requested
+     *     without the {@link #AUDIOFOCUS_FLAG_DELAY_OK} flag.
+     * @throws IllegalArgumentException
+     */
+    public int requestAudioFocus(OnAudioFocusChangeListener l,
+            AudioAttributes requestAttributes,
+            int durationHint,
+            int flags) throws IllegalArgumentException {
+        // parameter checking
+        if (requestAttributes == null) {
+            throw new IllegalArgumentException("Illegal null AudioAttributes argument");
+        }
         if ((durationHint < AUDIOFOCUS_GAIN) ||
                 (durationHint > AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)) {
-            Log.e(TAG, "Invalid duration hint, audio focus request denied");
-            return status;
+            throw new IllegalArgumentException("Invalid duration hint");
         }
+        if (flags != (flags & AUDIOFOCUS_FLAGS_ALL)) {
+            throw new IllegalArgumentException("Illegal flags 0x"
+                + Integer.toHexString(flags).toUpperCase());
+        }
+        if (((flags & AUDIOFOCUS_FLAG_DELAY_OK) == AUDIOFOCUS_FLAG_DELAY_OK) && (l == null)) {
+            throw new IllegalArgumentException(
+                    "Illegal null focus listener when flagged as accepting delayed focus grant");
+        }
+
+        int status = AUDIOFOCUS_REQUEST_FAILED;
         registerAudioFocusListener(l);
-        //TODO protect request by permission check?
         IAudioService service = getService();
         try {
-            status = service.requestAudioFocus(streamType, durationHint, mICallBack,
+            status = service.requestAudioFocus(requestAttributes, durationHint, mICallBack,
                     mAudioFocusDispatcher, getIdForAudioFocusListener(l),
-                    mContext.getOpPackageName() /* package name */);
+                    mContext.getOpPackageName() /* package name */, flags);
         } catch (RemoteException e) {
             Log.e(TAG, "Can't call requestAudioFocus() on AudioService due to "+e);
         }
@@ -2322,9 +2401,11 @@
     public void requestAudioFocusForCall(int streamType, int durationHint) {
         IAudioService service = getService();
         try {
-            service.requestAudioFocus(streamType, durationHint, mICallBack, null,
+            service.requestAudioFocus(new AudioAttributes.Builder()
+                        .setInternalLegacyStreamType(streamType).build(),
+                    durationHint, mICallBack, null,
                     MediaFocusControl.IN_VOICE_COMM_FOCUS_ID,
-                    mContext.getOpPackageName());
+                    mContext.getOpPackageName(), 0 /* flags, legacy behavior*/ );
         } catch (RemoteException e) {
             Log.e(TAG, "Can't call requestAudioFocusForCall() on AudioService due to "+e);
         }
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 29d4930..a80b356 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -5011,10 +5011,10 @@
     //==========================================================================================
     // Audio Focus
     //==========================================================================================
-    public int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb,
-            IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
-        return mMediaFocusControl.requestAudioFocus(mainStreamType, durationHint, cb, fd,
-                clientId, callingPackageName);
+    public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
+            IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags) {
+        return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
+                clientId, callingPackageName, flags);
     }
 
     public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId) {
diff --git a/media/java/android/media/FocusRequester.java b/media/java/android/media/FocusRequester.java
index 9a39994..682d54c 100644
--- a/media/java/android/media/FocusRequester.java
+++ b/media/java/android/media/FocusRequester.java
@@ -45,19 +45,24 @@
      */
     private final int mFocusGainRequest;
     /**
+     * the flags associated with the gain request that qualify the type of grant (e.g. accepting
+     * delay vs grant must be immediate)
+     */
+    private final int mGrantFlags;
+    /**
      * the audio focus loss received my mFocusDispatcher, is AudioManager.AUDIOFOCUS_NONE if
      *  it never lost focus.
      */
     private int mFocusLossReceived;
     /**
-     * the stream type associated with the focus request
+     * the audio attributes associated with the focus request
      */
-    private final int mStreamType;
+    private final AudioAttributes mAttributes;
 
-    FocusRequester(int streamType, int focusRequest,
+    FocusRequester(AudioAttributes aa, int focusRequest, int grantFlags,
             IAudioFocusDispatcher afl, IBinder source, String id, AudioFocusDeathHandler hdlr,
             String pn, int uid) {
-        mStreamType = streamType;
+        mAttributes = aa;
         mFocusDispatcher = afl;
         mSourceRef = source;
         mClientId = id;
@@ -65,6 +70,7 @@
         mPackageName = pn;
         mCallingUid = uid;
         mFocusGainRequest = focusRequest;
+        mGrantFlags = grantFlags;
         mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
     }
 
@@ -98,8 +104,12 @@
         return mFocusGainRequest;
     }
 
-    int getStreamType() {
-        return mStreamType;
+    int getGrantFlags() {
+        return mGrantFlags;
+    }
+
+    AudioAttributes getAudioAttributes() {
+        return mAttributes;
     }
 
 
@@ -139,9 +149,10 @@
                 + " -- pack: " + mPackageName
                 + " -- client: " + mClientId
                 + " -- gain: " + focusGainToString()
+                + " -- grant: " + mGrantFlags
                 + " -- loss: " + focusLossToString()
                 + " -- uid: " + mCallingUid
-                + " -- stream: " + mStreamType);
+                + " -- attr: " + mAttributes);
     }
 
 
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 317cc21..47a5291 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -19,6 +19,7 @@
 import android.app.PendingIntent;
 import android.bluetooth.BluetoothDevice;
 import android.content.ComponentName;
+import android.media.AudioAttributes;
 import android.media.AudioRoutesInfo;
 import android.media.IAudioFocusDispatcher;
 import android.media.IAudioRoutesObserver;
@@ -116,8 +117,8 @@
 
     boolean isBluetoothA2dpOn();
 
-    int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb,
-            IAudioFocusDispatcher fd, String clientId, String callingPackageName);
+    int requestAudioFocus(in AudioAttributes aa, int durationHint, IBinder cb,
+            IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags);
 
     int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId);
 
diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java
index c67e397..c495106 100644
--- a/media/java/android/media/MediaFocusControl.java
+++ b/media/java/android/media/MediaFocusControl.java
@@ -538,16 +538,54 @@
     /**
      * Helper function:
      * Returns true if the system is in a state where the focus can be reevaluated, false otherwise.
+     * The implementation guarantees that a state where focus cannot be immediately reassigned
+     * implies that an "exclusive" focus owner is at the top of the focus stack.
+     * Modifications to the implementation that break this assumption will cause focus requests to
+     * misbehave when honoring the AudioManager.AUDIOFOCUS_FLAG_DELAY_OK flag.
      */
     private boolean canReassignAudioFocus() {
         // focus requests are rejected during a phone call or when the phone is ringing
         // this is equivalent to IN_VOICE_COMM_FOCUS_ID having the focus
-        if (!mFocusStack.isEmpty() && mFocusStack.peek().hasSameClient(IN_VOICE_COMM_FOCUS_ID)) {
+        if (!mFocusStack.isEmpty() && isExclusiveFocusOwner(mFocusStack.peek())) {
             return false;
         }
         return true;
     }
 
+    private boolean isExclusiveFocusOwner(FocusRequester fr) {
+        return fr.hasSameClient(IN_VOICE_COMM_FOCUS_ID);
+    }
+
+    /**
+     * Helper function
+     * Pre-conditions: focus stack is not empty, there is one or more exclusive focus owner
+     *                 at the top of the focus stack
+     * Push the focus requester onto the audio focus stack at the first position immediately
+     * following the exclusive focus owners.
+     * @return {@link AudioManager#AUDIOFOCUS_REQUEST_GRANTED} or
+     *     {@link AudioManager#AUDIOFOCUS_REQUEST_DELAYED}
+     */
+    private int pushBelowExclusiveFocusOwners(FocusRequester nfr) {
+        int lastExclusiveFocusOwnerIndex = mFocusStack.size();
+        for (int index = mFocusStack.size()-1; index >= 0; index--) {
+            if (isExclusiveFocusOwner(mFocusStack.elementAt(index))) {
+                lastExclusiveFocusOwnerIndex = index;
+            }
+        }
+        if (lastExclusiveFocusOwnerIndex == mFocusStack.size()) {
+            // this should not happen, but handle it and log an error
+            Log.e(TAG, "No exclusive focus owner found in propagateFocusLossFromGain_syncAf()",
+                    new Exception());
+            // no exclusive owner, push at top of stack, focus is granted, propagate change
+            propagateFocusLossFromGain_syncAf(nfr.getGainRequest());
+            mFocusStack.push(nfr);
+            return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
+        } else {
+            mFocusStack.insertElementAt(nfr, lastExclusiveFocusOwnerIndex);
+            return AudioManager.AUDIOFOCUS_REQUEST_DELAYED;
+        }
+    }
+
     /**
      * Inner class to monitor audio focus client deaths, and remove them from the audio focus
      * stack if necessary.
@@ -581,10 +619,11 @@
         }
     }
 
-    /** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int)  */
-    protected int requestAudioFocus(int mainStreamType, int focusChangeHint, IBinder cb,
-            IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
-        Log.i(TAG, " AudioFocus  requestAudioFocus() from " + clientId);
+    /** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int, int) */
+    protected int requestAudioFocus(AudioAttributes aa, int focusChangeHint, IBinder cb,
+            IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags) {
+        Log.i(TAG, " AudioFocus  requestAudioFocus() from " + clientId + " req=" + focusChangeHint +
+                "flags=0x" + Integer.toHexString(flags));
         // we need a valid binder callback for clients
         if (!cb.pingBinder()) {
             Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting.");
@@ -597,8 +636,16 @@
         }
 
         synchronized(mAudioFocusLock) {
+            boolean focusGrantDelayed = false;
             if (!canReassignAudioFocus()) {
-                return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+                if ((flags & AudioManager.AUDIOFOCUS_FLAG_DELAY_OK) == 0) {
+                    return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+                } else {
+                    // request has AUDIOFOCUS_FLAG_DELAY_OK: focus can't be
+                    // granted right now, so the requester will be inserted in the focus stack
+                    // to receive focus later
+                    focusGrantDelayed = true;
+                }
             }
 
             // handle the potential premature death of the new holder of the focus
@@ -616,7 +663,8 @@
             if (!mFocusStack.empty() && mFocusStack.peek().hasSameClient(clientId)) {
                 // if focus is already owned by this client and the reason for acquiring the focus
                 // hasn't changed, don't do anything
-                if (mFocusStack.peek().getGainRequest() == focusChangeHint) {
+                final FocusRequester fr = mFocusStack.peek();
+                if (fr.getGainRequest() == focusChangeHint && fr.getGrantFlags() == flags) {
                     // unlink death handler so it can be gc'ed.
                     // linkToDeath() creates a JNI global reference preventing collection.
                     cb.unlinkToDeath(afdh, 0);
@@ -624,21 +672,31 @@
                 }
                 // the reason for the audio focus request has changed: remove the current top of
                 // stack and respond as if we had a new focus owner
-                FocusRequester fr = mFocusStack.pop();
-                fr.release();
+                if (!focusGrantDelayed) {
+                    mFocusStack.pop();
+                    // the entry that was "popped" is the same that was "peeked" above
+                    fr.release();
+                }
             }
 
             // focus requester might already be somewhere below in the stack, remove it
             removeFocusStackEntry(clientId, false /* signal */);
 
-            // propagate the focus change through the stack
-            if (!mFocusStack.empty()) {
-                propagateFocusLossFromGain_syncAf(focusChangeHint);
-            }
+            final FocusRequester nfr = new FocusRequester(aa, focusChangeHint, flags, fd, cb,
+                    clientId, afdh, callingPackageName, Binder.getCallingUid());
+            if (focusGrantDelayed) {
+                // focusGrantDelayed being true implies we can't reassign focus right now
+                // which implies the focus stack is not empty.
+                return pushBelowExclusiveFocusOwners(nfr);
+            } else {
+                // propagate the focus change through the stack
+                if (!mFocusStack.empty()) {
+                    propagateFocusLossFromGain_syncAf(focusChangeHint);
+                }
 
-            // push focus requester at the top of the audio focus stack
-            mFocusStack.push(new FocusRequester(mainStreamType, focusChangeHint, fd, cb,
-                    clientId, afdh, callingPackageName, Binder.getCallingUid()));
+                // push focus requester at the top of the audio focus stack
+                mFocusStack.push(nfr);
+            }
 
         }//synchronized(mAudioFocusLock)
 
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index afa0b6e..91b1018 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -37,6 +37,7 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.provider.Settings;
 import android.system.ErrnoException;
 import android.system.OsConstants;
 import android.util.Log;
@@ -968,11 +969,16 @@
      * @throws IllegalStateException if it is called in an invalid state
      */
     public void setDataSource(Context context, Uri uri, Map<String, String> headers)
-        throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
-        String scheme = uri.getScheme();
-        if(scheme == null || scheme.equals("file")) {
+            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
+        final String scheme = uri.getScheme();
+        if (ContentResolver.SCHEME_FILE.equals(scheme)) {
             setDataSource(uri.getPath());
             return;
+        } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)
+                && Settings.AUTHORITY.equals(uri.getAuthority())) {
+            // Redirect ringtones to go directly to underlying provider
+            uri = RingtoneManager.getActualDefaultRingtoneUri(context,
+                    RingtoneManager.getDefaultType(uri));
         }
 
         AssetFileDescriptor fd = null;
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index 62b4a36..b8e850a 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -469,6 +469,63 @@
     return result;
 }
 
+static bool readLongValue(int type, MtpDataPacket& packet, jlong& longValue) {
+    switch (type) {
+        case MTP_TYPE_INT8: {
+            int8_t temp;
+            if (!packet.getInt8(temp)) return false;
+            longValue = temp;
+            break;
+        }
+        case MTP_TYPE_UINT8: {
+            uint8_t temp;
+            if (!packet.getUInt8(temp)) return false;
+            longValue = temp;
+            break;
+        }
+        case MTP_TYPE_INT16: {
+            int16_t temp;
+            if (!packet.getInt16(temp)) return false;
+            longValue = temp;
+            break;
+        }
+        case MTP_TYPE_UINT16: {
+            uint16_t temp;
+            if (!packet.getUInt16(temp)) return false;
+            longValue = temp;
+            break;
+        }
+        case MTP_TYPE_INT32: {
+            int32_t temp;
+            if (!packet.getInt32(temp)) return false;
+            longValue = temp;
+            break;
+        }
+        case MTP_TYPE_UINT32: {
+            uint32_t temp;
+            if (!packet.getUInt32(temp)) return false;
+            longValue = temp;
+            break;
+        }
+        case MTP_TYPE_INT64: {
+            int64_t temp;
+            if (!packet.getInt64(temp)) return false;
+            longValue = temp;
+            break;
+        }
+        case MTP_TYPE_UINT64: {
+            uint64_t temp;
+            if (!packet.getUInt64(temp)) return false;
+            longValue = temp;
+            break;
+        }
+        default:
+            ALOGE("unsupported type in readLongValue");
+            return false;
+    }
+    return true;
+}
+
 MtpResponseCode MyMtpDatabase::setObjectPropertyValue(MtpObjectHandle handle,
                                             MtpObjectProperty property,
                                             MtpDataPacket& packet) {
@@ -480,49 +537,22 @@
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     jlong longValue = 0;
     jstring stringValue = NULL;
+    MtpResponseCode result = MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
 
-    switch (type) {
-        case MTP_TYPE_INT8:
-            longValue = packet.getInt8();
-            break;
-        case MTP_TYPE_UINT8:
-            longValue = packet.getUInt8();
-            break;
-        case MTP_TYPE_INT16:
-            longValue = packet.getInt16();
-            break;
-        case MTP_TYPE_UINT16:
-            longValue = packet.getUInt16();
-            break;
-        case MTP_TYPE_INT32:
-            longValue = packet.getInt32();
-            break;
-        case MTP_TYPE_UINT32:
-            longValue = packet.getUInt32();
-            break;
-        case MTP_TYPE_INT64:
-            longValue = packet.getInt64();
-            break;
-        case MTP_TYPE_UINT64:
-            longValue = packet.getUInt64();
-            break;
-        case MTP_TYPE_STR:
-        {
-            MtpStringBuffer buffer;
-            packet.getString(buffer);
-            stringValue = env->NewStringUTF((const char *)buffer);
-            break;
-         }
-        default:
-            ALOGE("unsupported type in setObjectPropertyValue\n");
-            return MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
+    if (type == MTP_TYPE_STR) {
+        MtpStringBuffer buffer;
+        if (!packet.getString(buffer)) goto fail;
+        stringValue = env->NewStringUTF((const char *)buffer);
+    } else {
+        if (!readLongValue(type, packet, longValue)) goto fail;
     }
 
-    jint result = env->CallIntMethod(mDatabase, method_setObjectProperty,
+    result = env->CallIntMethod(mDatabase, method_setObjectProperty,
                 (jint)handle, (jint)property, longValue, stringValue);
     if (stringValue)
         env->DeleteLocalRef(stringValue);
 
+fail:
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
     return result;
 }
@@ -610,49 +640,22 @@
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     jlong longValue = 0;
     jstring stringValue = NULL;
+    MtpResponseCode result = MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT;
 
-    switch (type) {
-        case MTP_TYPE_INT8:
-            longValue = packet.getInt8();
-            break;
-        case MTP_TYPE_UINT8:
-            longValue = packet.getUInt8();
-            break;
-        case MTP_TYPE_INT16:
-            longValue = packet.getInt16();
-            break;
-        case MTP_TYPE_UINT16:
-            longValue = packet.getUInt16();
-            break;
-        case MTP_TYPE_INT32:
-            longValue = packet.getInt32();
-            break;
-        case MTP_TYPE_UINT32:
-            longValue = packet.getUInt32();
-            break;
-        case MTP_TYPE_INT64:
-            longValue = packet.getInt64();
-            break;
-        case MTP_TYPE_UINT64:
-            longValue = packet.getUInt64();
-            break;
-        case MTP_TYPE_STR:
-        {
-            MtpStringBuffer buffer;
-            packet.getString(buffer);
-            stringValue = env->NewStringUTF((const char *)buffer);
-            break;
-         }
-        default:
-            ALOGE("unsupported type in setDevicePropertyValue\n");
-            return MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
+    if (type == MTP_TYPE_STR) {
+        MtpStringBuffer buffer;
+        if (!packet.getString(buffer)) goto fail;
+        stringValue = env->NewStringUTF((const char *)buffer);
+    } else {
+        if (!readLongValue(type, packet, longValue)) goto fail;
     }
 
-    jint result = env->CallIntMethod(mDatabase, method_setDeviceProperty,
+    result = env->CallIntMethod(mDatabase, method_setDeviceProperty,
                 (jint)property, longValue, stringValue);
     if (stringValue)
         env->DeleteLocalRef(stringValue);
 
+fail:
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
     return result;
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 34e57bc..6828301 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -37,13 +37,11 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
-import android.content.res.AssetFileDescriptor;
 import android.database.AbstractCursor;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteException;
 import android.database.sqlite.SQLiteQueryBuilder;
-import android.media.RingtoneManager;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
@@ -54,7 +52,6 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.provider.MediaStore;
 import android.provider.Settings;
 import android.provider.Settings.Secure;
 import android.text.TextUtils;
@@ -1228,77 +1225,8 @@
 
     @Override
     public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
-
-        /*
-         * When a client attempts to openFile the default ringtone or
-         * notification setting Uri, we will proxy the call to the current
-         * default ringtone's Uri (if it is in the media provider).
-         */
-        int ringtoneType = RingtoneManager.getDefaultType(uri);
-        // Above call returns -1 if the Uri doesn't match a default type
-        if (ringtoneType != -1) {
-            Context context = getContext();
-
-            // Get the current value for the default sound
-            Uri soundUri = RingtoneManager.getActualDefaultRingtoneUri(context, ringtoneType);
-
-            if (soundUri != null) {
-                // Proxy the openFile call to media provider
-                String authority = soundUri.getAuthority();
-                if (authority.equals(MediaStore.AUTHORITY)) {
-                    return context.getContentResolver().openFileDescriptor(soundUri, mode);
-                }
-            }
-        }
-
-        return super.openFile(uri, mode);
-    }
-
-    @Override
-    public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
-
-        /*
-         * When a client attempts to openFile the default ringtone or
-         * notification setting Uri, we will proxy the call to the current
-         * default ringtone's Uri (if it is in the media provider).
-         */
-        int ringtoneType = RingtoneManager.getDefaultType(uri);
-        // Above call returns -1 if the Uri doesn't match a default type
-        if (ringtoneType != -1) {
-            Context context = getContext();
-
-            // Get the current value for the default sound
-            Uri soundUri = RingtoneManager.getActualDefaultRingtoneUri(context, ringtoneType);
-
-            if (soundUri != null) {
-                // Proxy the openFile call to media provider
-                String authority = soundUri.getAuthority();
-                if (authority.equals(MediaStore.AUTHORITY)) {
-                    ParcelFileDescriptor pfd = null;
-                    try {
-                        pfd = context.getContentResolver().openFileDescriptor(soundUri, mode);
-                        return new AssetFileDescriptor(pfd, 0, -1);
-                    } catch (FileNotFoundException ex) {
-                        // fall through and open the fallback ringtone below
-                    }
-                }
-
-                try {
-                    return super.openAssetFile(soundUri, mode);
-                } catch (FileNotFoundException ex) {
-                    // Since a non-null Uri was specified, but couldn't be opened,
-                    // fall back to the built-in ringtone.
-                    return context.getResources().openRawResourceFd(
-                            com.android.internal.R.raw.fallbackring);
-                }
-            }
-            // no need to fall through and have openFile() try again, since we
-            // already know that will fail.
-            throw new FileNotFoundException(); // or return null ?
-        }
-
-        // Note that this will end up calling openFile() above.
-        return super.openAssetFile(uri, mode);
+        throw new FileNotFoundException("Direct file access no longer supported; "
+                + "ringtone playback is available through android.media.Ringtone");
     }
 
     /**
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index d72643e..b28b0c5 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -894,9 +894,6 @@
     <!-- continue action for notification educating the user about enabling notifications on the lockscreen. [CHAR LIMIT=20] -->
     <string name="hidden_notifications_setup">Set up</string>
 
-    <!-- Indication that the current volume and other effects (vibration) are being suppressed by a third party, such as a notification listener. [CHAR LIMIT=30] -->
-    <string name="muted_by">Muted by <xliff:g id="third_party">%1$s</xliff:g></string>
-
     <!-- Accessibility string for current zen mode and selected exit condition. A template that simply concatenates existing mode string and the current condition description. [CHAR LIMIT=20] -->
     <string name="zen_mode_and_condition"><xliff:g id="zen_mode" example="Priority interruptions only">%1$s</xliff:g>. <xliff:g id="exit_condition" example="For one hour">%2$s</xliff:g></string>
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index b5a6dac..bb9a105 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -138,14 +138,15 @@
             }
         }
 
-        // When we start, preload the metadata and icons associated with the recent tasks.
+        // When we start, preload the data associated with the previous recent tasks.
         // We can use a new plan since the caches will be the same.
         RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
         RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
         loader.preloadTasks(plan, true /* isTopTaskHome */);
         RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
         launchOpts.numVisibleTasks = loader.getApplicationIconCacheSize();
-        launchOpts.loadThumbnails = false;
+        launchOpts.numVisibleTaskThumbnails = loader.getThumbnailCacheSize();
+        launchOpts.onlyLoadForCache = true;
         loader.loadTasks(mContext, plan, launchOpts);
     }
 
@@ -510,6 +511,7 @@
             RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
             launchOpts.runningTaskId = topTask.id;
             launchOpts.loadThumbnails = false;
+            launchOpts.onlyLoadForCache = true;
             loader.loadTasks(mContext, sInstanceLoadPlan, launchOpts);
 
             // Try starting with a thumbnail transition
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 9a7fec4..d1eadd8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -213,10 +213,12 @@
         RecentsTaskLoadPlan plan = AlternateRecentsComponent.consumeInstanceLoadPlan();
         if (plan == null) {
             plan = loader.createLoadPlan(this);
-            loader.preloadTasks(plan, mConfig.launchedFromHome);
         }
 
         // Start loading tasks according to the load plan
+        if (plan.getTaskStack() == null) {
+            loader.preloadTasks(plan, mConfig.launchedFromHome);
+        }
         RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
         loadOpts.runningTaskId = mConfig.launchedToTaskId;
         loadOpts.numVisibleTasks = numVisibleTasks;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 41251c8..33c4b05 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -49,6 +49,7 @@
         public int runningTaskId = -1;
         public boolean loadIcons = true;
         public boolean loadThumbnails = true;
+        public boolean onlyLoadForCache = false;
         public int numVisibleTasks = 0;
         public int numVisibleTaskThumbnails = 0;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index 6fd738d..599d3ce 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -418,28 +418,36 @@
         return mMaxIconCacheSize;
     }
 
+    /** Returns the size of the thumbnail cache. */
+    public int getThumbnailCacheSize() {
+        return mMaxThumbnailCacheSize;
+    }
+
+    /** Creates a new plan for loading the recent tasks. */
     public RecentsTaskLoadPlan createLoadPlan(Context context) {
         RecentsConfiguration config = RecentsConfiguration.getInstance();
         RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(context, config, mSystemServicesProxy);
         return plan;
     }
 
+    /** Preloads recents tasks using the specified plan to store the output. */
     public void preloadTasks(RecentsTaskLoadPlan plan, boolean isTopTaskHome) {
         plan.preloadPlan(this, isTopTaskHome);
     }
 
+    /** Begins loading the heavy task data according to the specified options. */
     public void loadTasks(Context context, RecentsTaskLoadPlan plan,
             RecentsTaskLoadPlan.Options opts) {
         if (opts == null) {
             throw new RuntimeException("Requires load options");
         }
         plan.executePlan(opts, this);
-        if (opts.numVisibleTasks > 0) {
+        if (!opts.onlyLoadForCache) {
             mNumVisibleTasksLoaded = opts.numVisibleTasks;
-        }
 
-        // Start the loader
-        mLoader.start(context);
+            // Start the loader
+            mLoader.start(context);
+        }
     }
 
     /** Acquires the task resource data directly from the pool. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
new file mode 100644
index 0000000..c0d7b9b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -0,0 +1,260 @@
+/*
+ * 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 com.android.systemui.statusbar.phone;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.annotation.NonNull;
+import android.content.Context;
+import android.graphics.Color;
+import android.os.Handler;
+import android.util.Log;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+
+import com.android.systemui.doze.DozeHost;
+import com.android.systemui.doze.DozeLog;
+
+/**
+ * Controller which handles all the doze animations of the scrims.
+ */
+public class DozeScrimController {
+    private static final String TAG = "DozeScrimController";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private final DozeParameters mDozeParameters;
+    private final Interpolator mPulseInInterpolator = PhoneStatusBar.ALPHA_OUT;
+    private final Interpolator mPulseOutInterpolator = PhoneStatusBar.ALPHA_IN;
+    private final Interpolator mDozeAnimationInterpolator;
+    private final Handler mHandler = new Handler();
+    private final ScrimController mScrimController;
+
+    private boolean mDozing;
+    private DozeHost.PulseCallback mPulseCallback;
+    private Animator mInFrontAnimator;
+    private Animator mBehindAnimator;
+    private float mInFrontTarget;
+    private float mBehindTarget;
+
+    public DozeScrimController(ScrimController scrimController, Context context) {
+        mScrimController = scrimController;
+        mDozeParameters = new DozeParameters(context);
+        mDozeAnimationInterpolator = AnimationUtils.loadInterpolator(context,
+                android.R.interpolator.linear_out_slow_in);
+    }
+
+    public void setDozing(boolean dozing, boolean animate) {
+        if (mDozing == dozing) return;
+        mDozing = dozing;
+        if (mDozing) {
+            abortAnimations();
+            mScrimController.setDozeBehindAlpha(1f);
+            mScrimController.setDozeInFrontAlpha(1f);
+        } else {
+            cancelPulsing();
+            if (animate) {
+                startScrimAnimation(false /* inFront */, 0f /* target */,
+                        NotificationPanelView.DOZE_ANIMATION_DURATION, mDozeAnimationInterpolator);
+                startScrimAnimation(true /* inFront */, 0f /* target */,
+                        NotificationPanelView.DOZE_ANIMATION_DURATION, mDozeAnimationInterpolator);
+            } else {
+                abortAnimations();
+                mScrimController.setDozeBehindAlpha(0f);
+                mScrimController.setDozeInFrontAlpha(0f);
+            }
+        }
+    }
+
+    /** When dozing, fade screen contents in and out using the front scrim. */
+    public void pulse(@NonNull DozeHost.PulseCallback callback) {
+        if (callback == null) {
+            throw new IllegalArgumentException("callback must not be null");
+        }
+
+        if (!mDozing || mPulseCallback != null) {
+            // Pulse suppressed.
+            callback.onPulseFinished();
+            return;
+        }
+
+        // Begin pulse.  Note that it's very important that the pulse finished callback
+        // be invoked when we're done so that the caller can drop the pulse wakelock.
+        mPulseCallback = callback;
+        mHandler.post(mPulseIn);
+    }
+
+    public boolean isPulsing() {
+        return mPulseCallback != null;
+    }
+
+    private void cancelPulsing() {
+        if (DEBUG) Log.d(TAG, "Cancel pulsing");
+
+        if (mPulseCallback != null) {
+            mHandler.removeCallbacks(mPulseIn);
+            mHandler.removeCallbacks(mPulseOut);
+            pulseFinished();
+        }
+    }
+
+    private void pulseStarted() {
+        if (mPulseCallback != null) {
+            mPulseCallback.onPulseStarted();
+        }
+    }
+
+    private void pulseFinished() {
+        if (mPulseCallback != null) {
+            mPulseCallback.onPulseFinished();
+            mPulseCallback = null;
+        }
+    }
+
+    private void abortAnimations() {
+        if (mInFrontAnimator != null) {
+            mInFrontAnimator.cancel();
+        }
+        if (mBehindAnimator != null) {
+            mBehindAnimator.cancel();
+        }
+    }
+
+    private void startScrimAnimation(final boolean inFront, float target, long duration,
+            Interpolator interpolator) {
+        startScrimAnimation(inFront, target, duration, interpolator, 0 /* delay */,
+                null /* endRunnable */);
+    }
+
+    private void startScrimAnimation(final boolean inFront, float target, long duration,
+            Interpolator interpolator, long delay, final Runnable endRunnable) {
+        Animator current = getCurrentAnimator(inFront);
+        if (current != null) {
+            float currentTarget = getCurrentTarget(inFront);
+            if (currentTarget == target) {
+                return;
+            }
+            current.cancel();
+        }
+        ValueAnimator anim = ValueAnimator.ofFloat(getDozeAlpha(inFront), target);
+        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                float value = (float) animation.getAnimatedValue();
+                setDozeAlpha(inFront, value);
+            }
+        });
+        anim.setInterpolator(interpolator);
+        anim.setDuration(duration);
+        anim.setStartDelay(delay);
+        anim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                setCurrentAnimator(inFront, null);
+                if (endRunnable != null) {
+                    endRunnable.run();
+                }
+            }
+        });
+        anim.start();
+        setCurrentAnimator(inFront, anim);
+        setCurrentTarget(inFront, target);
+    }
+
+    private float getCurrentTarget(boolean inFront) {
+        return inFront ? mInFrontTarget : mBehindTarget;
+    }
+
+    private void setCurrentTarget(boolean inFront, float target) {
+        if (inFront) {
+            mInFrontTarget = target;
+        } else {
+            mBehindTarget = target;
+        }
+    }
+
+    private Animator getCurrentAnimator(boolean inFront) {
+        return inFront ? mInFrontAnimator : mBehindAnimator;
+    }
+
+    private void setCurrentAnimator(boolean inFront, Animator animator) {
+        if (inFront) {
+            mInFrontAnimator = animator;
+        } else {
+            mBehindAnimator = animator;
+        }
+    }
+
+    private void setDozeAlpha(boolean inFront, float alpha) {
+        if (inFront) {
+            mScrimController.setDozeInFrontAlpha(alpha);
+        } else {
+            mScrimController.setDozeBehindAlpha(alpha);
+        }
+    }
+
+    private float getDozeAlpha(boolean inFront) {
+        return inFront
+                ? mScrimController.getDozeInFrontAlpha()
+                : mScrimController.getDozeBehindAlpha();
+    }
+
+    private final Runnable mPulseIn = new Runnable() {
+        @Override
+        public void run() {
+            if (DEBUG) Log.d(TAG, "Pulse in, mDozing=" + mDozing);
+            if (!mDozing) return;
+            DozeLog.tracePulseStart();
+            startScrimAnimation(true /* inFront */, 0f, mDozeParameters.getPulseInDuration(),
+                    mPulseInInterpolator, mDozeParameters.getPulseInDelay(), mPulseInFinished);
+
+            // Signal that the pulse is ready to turn the screen on and draw.
+            pulseStarted();
+        }
+    };
+
+    private final Runnable mPulseInFinished = new Runnable() {
+        @Override
+        public void run() {
+            if (DEBUG) Log.d(TAG, "Pulse in finished, mDozing=" + mDozing);
+            if (!mDozing) return;
+            mHandler.postDelayed(mPulseOut, mDozeParameters.getPulseVisibleDuration());
+        }
+    };
+
+    private final Runnable mPulseOut = new Runnable() {
+        @Override
+        public void run() {
+            if (DEBUG) Log.d(TAG, "Pulse out, mDozing=" + mDozing);
+            if (!mDozing) return;
+            startScrimAnimation(true /* inFront */, 1f, mDozeParameters.getPulseOutDuration(),
+                    mPulseOutInterpolator, 0 /* delay */, mPulseOutFinished);
+        }
+    };
+
+    private final Runnable mPulseOutFinished = new Runnable() {
+        @Override
+        public void run() {
+            if (DEBUG) Log.d(TAG, "Pulse out finished");
+            DozeLog.tracePulseFinish();
+
+            // Signal that the pulse is all finished so we can turn the screen off now.
+            pulseFinished();
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 9d7d310..de99a82 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -23,10 +23,7 @@
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.Configuration;
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
 import android.util.AttributeSet;
-import android.util.LayoutDirection;
 import android.util.MathUtils;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
@@ -63,8 +60,6 @@
     private static final float HEADER_RUBBERBAND_FACTOR = 2.05f;
     private static final float LOCK_ICON_ACTIVE_SCALE = 1.2f;
 
-    private static final int DOZE_BACKGROUND_COLOR = 0xff000000;
-    private static final int TAG_KEY_ANIM = R.id.scrim;
     public static final long DOZE_ANIMATION_DURATION = 700;
 
     private KeyguardAffordanceHelper mAfforanceHelper;
@@ -1824,11 +1819,9 @@
         if (dozing == mDozing) return;
         mDozing = dozing;
         if (mDozing) {
-            setBackgroundColorAlpha(DOZE_BACKGROUND_COLOR, 0xff, false /*animate*/);
             mKeyguardStatusBar.setVisibility(View.INVISIBLE);
             mKeyguardBottomArea.setVisibility(View.INVISIBLE);
         } else {
-            setBackgroundColorAlpha(DOZE_BACKGROUND_COLOR, 0, animate);
             mKeyguardBottomArea.setVisibility(View.VISIBLE);
             mKeyguardStatusBar.setVisibility(View.VISIBLE);
             if (animate) {
@@ -1843,52 +1836,6 @@
         return mDozing;
     }
 
-    private void setBackgroundColorAlpha(int rgb, int targetAlpha,
-            boolean animate) {
-        int currentAlpha = getBackgroundAlpha(this);
-        if (currentAlpha == targetAlpha) {
-            return;
-        }
-        final int r = Color.red(rgb);
-        final int g = Color.green(rgb);
-        final int b = Color.blue(rgb);
-        Object runningAnim = getTag(TAG_KEY_ANIM);
-        if (runningAnim instanceof ValueAnimator) {
-            ((ValueAnimator) runningAnim).cancel();
-        }
-        if (!animate) {
-            setBackgroundColor(Color.argb(targetAlpha, r, g, b));
-            return;
-        }
-        ValueAnimator anim = ValueAnimator.ofInt(currentAlpha, targetAlpha);
-        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                int value = (int) animation.getAnimatedValue();
-                setBackgroundColor(Color.argb(value, r, g, b));
-            }
-        });
-        anim.setInterpolator(mDozeAnimationInterpolator);
-        anim.setDuration(DOZE_ANIMATION_DURATION);
-        anim.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                setTag(TAG_KEY_ANIM, null);
-            }
-        });
-        anim.start();
-        setTag(TAG_KEY_ANIM, anim);
-    }
-
-    private static int getBackgroundAlpha(View view) {
-        if (view.getBackground() instanceof ColorDrawable) {
-            ColorDrawable drawable = (ColorDrawable) view.getBackground();
-            return Color.alpha(drawable.getColor());
-        } else {
-            return 0;
-        }
-    }
-
     public void setShadeEmpty(boolean shadeEmpty) {
         mShadeEmpty = shadeEmpty;
         updateEmptyShadeView();
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 988534b..d94f122 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -414,6 +414,7 @@
 
     private ViewMediatorCallback mKeyguardViewMediatorCallback;
     private ScrimController mScrimController;
+    private DozeScrimController mDozeScrimController;
 
     private final Runnable mAutohide = new Runnable() {
         @Override
@@ -741,6 +742,7 @@
         mScrimController = new ScrimController(scrimBehind, scrimInFront, mScrimSrcModeEnabled);
         mScrimController.setBackDropView(mBackdrop);
         mStatusBarView.setScrimController(mScrimController);
+        mDozeScrimController = new DozeScrimController(mScrimController, context);
 
         mHeader = (StatusBarHeaderView) mStatusBarWindow.findViewById(R.id.header);
         mHeader.setActivityStarter(this);
@@ -3677,13 +3679,14 @@
         if (mState != StatusBarState.KEYGUARD && !mNotificationPanel.isDozing()) {
             return;
         }
-        mNotificationPanel.setDozing(mDozing, mScrimController.isPulsing() /*animate*/);
+        mNotificationPanel.setDozing(mDozing, mDozeScrimController.isPulsing() /*animate*/);
         if (mDozing) {
             mStackScroller.setDark(true, false /*animate*/);
         } else {
             mStackScroller.setDark(false, false /*animate*/);
         }
-        mScrimController.setDozing(mDozing, mScrimController.isPulsing() /*animate*/);
+        mScrimController.setDozing(mDozing);
+        mDozeScrimController.setDozing(mDozing, mDozeScrimController.isPulsing() /* animate */);
     }
 
     public void updateStackScrollerState(boolean goingToFullShade) {
@@ -4060,11 +4063,12 @@
     }
 
     public void wakeUpIfDozing(long time, boolean fromTouch) {
-        if (mDozing && mScrimController.isPulsing()) {
+        if (mDozing && mDozeScrimController.isPulsing()) {
             PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
             pm.wakeUp(time);
             if (fromTouch) {
                 mScreenOnComingFromTouch = true;
+                mNotificationPanel.setTouchDisabled(false);
             }
         }
     }
@@ -4174,7 +4178,7 @@
         }
 
         private void handlePulseWhileDozing(@NonNull PulseCallback callback) {
-            mScrimController.pulse(callback);
+            mDozeScrimController.pulse(callback);
         }
 
         private void handleStopDozing() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 10d6594..d6bd94b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -19,20 +19,15 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
-import android.annotation.NonNull;
 import android.content.Context;
 import android.graphics.Color;
-import android.util.Log;
 import android.view.View;
 import android.view.ViewTreeObserver;
 import android.view.animation.AnimationUtils;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
-import android.view.animation.PathInterpolator;
 
 import com.android.systemui.R;
-import com.android.systemui.doze.DozeHost;
-import com.android.systemui.doze.DozeLog;
 import com.android.systemui.statusbar.BackDropView;
 import com.android.systemui.statusbar.ScrimView;
 
@@ -41,9 +36,6 @@
  * security method gets shown).
  */
 public class ScrimController implements ViewTreeObserver.OnPreDrawListener {
-    private static final String TAG = "ScrimController";
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
     public static final long ANIMATION_DURATION = 220;
 
     private static final float SCRIM_BEHIND_ALPHA = 0.62f;
@@ -55,7 +47,6 @@
     private final ScrimView mScrimBehind;
     private final ScrimView mScrimInFront;
     private final UnlockMethodCache mUnlockMethodCache;
-    private final DozeParameters mDozeParameters;
 
     private boolean mKeyguardShowing;
     private float mFraction;
@@ -70,15 +61,15 @@
     private long mAnimationDelay;
     private Runnable mOnAnimationFinished;
     private boolean mAnimationStarted;
-    private boolean mDozing;
-    private boolean mPulsingOut;
-    private DozeHost.PulseCallback mPulseCallback;
     private final Interpolator mInterpolator = new DecelerateInterpolator();
     private final Interpolator mLinearOutSlowInInterpolator;
-    private final Interpolator mPulseInInterpolator = PhoneStatusBar.ALPHA_OUT;
-    private final Interpolator mPulseOutInterpolator = PhoneStatusBar.ALPHA_IN;
     private BackDropView mBackDropView;
     private boolean mScrimSrcEnabled;
+    private boolean mDozing;
+    private float mDozeInFrontAlpha;
+    private float mDozeBehindAlpha;
+    private float mCurrentInFrontAlpha;
+    private float mCurrentBehindAlpha;
 
     public ScrimController(ScrimView scrimBehind, ScrimView scrimInFront, boolean scrimSrcEnabled) {
         mScrimBehind = scrimBehind;
@@ -87,7 +78,6 @@
         mUnlockMethodCache = UnlockMethodCache.getInstance(context);
         mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
                 android.R.interpolator.linear_out_slow_in);
-        mDozeParameters = new DozeParameters(context);
         mScrimSrcEnabled = scrimSrcEnabled;
     }
 
@@ -134,60 +124,27 @@
         scheduleUpdate();
     }
 
-    public void setDozing(boolean dozing, boolean animate) {
-        if (mDozing == dozing) return;
+    public void setDozing(boolean dozing) {
         mDozing = dozing;
-        if (!mDozing) {
-            cancelPulsing();
-            mAnimateChange = animate;
-        }
         scheduleUpdate();
     }
 
-    /** When dozing, fade screen contents in and out using the front scrim. */
-    public void pulse(@NonNull DozeHost.PulseCallback callback) {
-        if (callback == null) {
-            throw new IllegalArgumentException("callback must not be null");
-        }
-
-        if (!mDozing || mPulseCallback != null) {
-            // Pulse suppressed.
-            callback.onPulseFinished();
-            return;
-        }
-
-        // Begin pulse.  Note that it's very important that the pulse finished callback
-        // be invoked when we're done so that the caller can drop the pulse wakelock.
-        mPulseCallback = callback;
-        mScrimInFront.post(mPulseIn);
+    public void setDozeInFrontAlpha(float alpha) {
+        mDozeInFrontAlpha = alpha;
+        updateScrimColor(mScrimInFront);
     }
 
-    public boolean isPulsing() {
-        return mPulseCallback != null;
+    public void setDozeBehindAlpha(float alpha) {
+        mDozeBehindAlpha = alpha;
+        updateScrimColor(mScrimBehind);
     }
 
-    private void cancelPulsing() {
-        if (DEBUG) Log.d(TAG, "Cancel pulsing");
-
-        if (mPulseCallback != null) {
-            mScrimInFront.removeCallbacks(mPulseIn);
-            mScrimInFront.removeCallbacks(mPulseOut);
-            pulseFinished();
-        }
+    public float getDozeBehindAlpha() {
+        return mDozeBehindAlpha;
     }
 
-    private void pulseStarted() {
-        if (mPulseCallback != null) {
-            mPulseCallback.onPulseStarted();
-        }
-    }
-
-    private void pulseFinished() {
-        mPulsingOut = false;
-        if (mPulseCallback != null) {
-            mPulseCallback.onPulseFinished();
-            mPulseCallback = null;
-        }
+    public float getDozeInFrontAlpha() {
+        return mDozeInFrontAlpha;
     }
 
     private void scheduleUpdate() {
@@ -223,12 +180,6 @@
         } else if (mBouncerShowing) {
             setScrimInFrontColor(SCRIM_IN_FRONT_ALPHA);
             setScrimBehindColor(0f);
-        } else if (mDozing && isPulsing() && !mPulsingOut) {
-            setScrimInFrontColor(0);
-            setScrimBehindColor(SCRIM_BEHIND_ALPHA_KEYGUARD);
-        } else if (mDozing) {
-            setScrimInFrontColor(1);
-            setScrimBehindColor(SCRIM_BEHIND_ALPHA_KEYGUARD);
         } else {
             float fraction = Math.max(0, Math.min(mFraction, 1));
             setScrimInFrontColor(0f);
@@ -272,26 +223,46 @@
             ((ValueAnimator) runningAnim).cancel();
             scrim.setTag(TAG_KEY_ANIM, null);
         }
-        int color = Color.argb((int) (alpha * 255), 0, 0, 0);
         if (mAnimateChange) {
-            startScrimAnimation(scrim, color);
+            startScrimAnimation(scrim, alpha);
         } else {
-            scrim.setScrimColor(color);
+            setCurrentScrimAlpha(scrim, alpha);
+            updateScrimColor(scrim);
         }
     }
 
-    private void startScrimAnimation(final ScrimView scrim, int targetColor) {
-        int current = Color.alpha(scrim.getScrimColor());
-        int target = Color.alpha(targetColor);
-        if (current == target) {
-            return;
+    private float getDozeAlpha(View scrim) {
+        return scrim == mScrimBehind ? mDozeBehindAlpha : mDozeInFrontAlpha;
+    }
+
+    private float getCurrentScrimAlpha(View scrim) {
+        return scrim == mScrimBehind ? mCurrentBehindAlpha : mCurrentInFrontAlpha;
+    }
+
+    private void setCurrentScrimAlpha(View scrim, float alpha) {
+        if (scrim == mScrimBehind) {
+            mCurrentBehindAlpha = alpha;
+        } else {
+            mCurrentInFrontAlpha = alpha;
         }
-        ValueAnimator anim = ValueAnimator.ofInt(current, target);
+    }
+
+    private void updateScrimColor(ScrimView scrim) {
+        float alpha1 = getCurrentScrimAlpha(scrim);
+        float alpha2 = getDozeAlpha(scrim);
+        float alpha = 1 - (1 - alpha1) * (1 - alpha2);
+        scrim.setScrimColor(Color.argb((int) (alpha * 255), 0, 0, 0));
+    }
+
+    private void startScrimAnimation(final ScrimView scrim, float target) {
+        float current = getCurrentScrimAlpha(scrim);
+        ValueAnimator anim = ValueAnimator.ofFloat(current, target);
         anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
             @Override
             public void onAnimationUpdate(ValueAnimator animation) {
-                int value = (int) animation.getAnimatedValue();
-                scrim.setScrimColor(Color.argb(value, 0, 0, 0));
+                float alpha = (float) animation.getAnimatedValue();
+                setCurrentScrimAlpha(scrim, alpha);
+                updateScrimColor(scrim);
             }
         });
         anim.setInterpolator(getInterpolator());
@@ -313,15 +284,7 @@
     }
 
     private Interpolator getInterpolator() {
-       if (mAnimateKeyguardFadingOut) {
-           return mLinearOutSlowInInterpolator;
-       } else if (isPulsing() && !mPulsingOut) {
-           return mPulseInInterpolator;
-       } else if (isPulsing()) {
-           return mPulseOutInterpolator;
-       } else {
-           return mInterpolator;
-       }
+        return mAnimateKeyguardFadingOut ? mLinearOutSlowInInterpolator : mInterpolator;
     }
 
     @Override
@@ -342,56 +305,6 @@
         return true;
     }
 
-    private final Runnable mPulseIn = new Runnable() {
-        @Override
-        public void run() {
-            if (DEBUG) Log.d(TAG, "Pulse in, mDozing=" + mDozing);
-            if (!mDozing) return;
-            DozeLog.tracePulseStart();
-            mDurationOverride = mDozeParameters.getPulseInDuration();
-            mAnimationDelay = mDozeParameters.getPulseInDelay();
-            mAnimateChange = true;
-            mOnAnimationFinished = mPulseInFinished;
-            scheduleUpdate();
-
-            // Signal that the pulse is ready to turn the screen on and draw.
-            pulseStarted();
-        }
-    };
-
-    private final Runnable mPulseInFinished = new Runnable() {
-        @Override
-        public void run() {
-            if (DEBUG) Log.d(TAG, "Pulse in finished, mDozing=" + mDozing);
-            if (!mDozing) return;
-            mScrimInFront.postDelayed(mPulseOut, mDozeParameters.getPulseVisibleDuration());
-        }
-    };
-
-    private final Runnable mPulseOut = new Runnable() {
-        @Override
-        public void run() {
-            if (DEBUG) Log.d(TAG, "Pulse out, mDozing=" + mDozing);
-            if (!mDozing) return;
-            mDurationOverride = mDozeParameters.getPulseOutDuration();
-            mAnimateChange = true;
-            mOnAnimationFinished = mPulseOutFinished;
-            mPulsingOut = true;
-            scheduleUpdate();
-        }
-    };
-
-    private final Runnable mPulseOutFinished = new Runnable() {
-        @Override
-        public void run() {
-            if (DEBUG) Log.d(TAG, "Pulse out finished");
-            DozeLog.tracePulseFinish();
-
-            // Signal that the pulse is all finished so we can turn the screen off now.
-            pulseFinished();
-        }
-    };
-
     public void setBackDropView(BackDropView backDropView) {
         mBackDropView = backDropView;
         mBackDropView.setOnVisibilityChangedRunnable(new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 9cfd26b..0caded5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -177,12 +177,21 @@
      * Construct this controller object and register for updates.
      */
     public NetworkControllerImpl(Context context) {
+        this(context, (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE),
+                (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE),
+                (WifiManager) context.getSystemService(Context.WIFI_SERVICE));
+        registerListeners();
+    }
+
+    @VisibleForTesting
+    NetworkControllerImpl(Context context, ConnectivityManager connectivityManager,
+            TelephonyManager telephonyManager, WifiManager wifiManager) {
         mContext = context;
         final Resources res = context.getResources();
 
-        mConnectivityManager =
-                (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
-        mHasMobileDataFeature = getCM().isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+        mConnectivityManager = connectivityManager;
+        mHasMobileDataFeature =
+                mConnectivityManager.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
 
         mShowPhoneRSSIForData = res.getBoolean(R.bool.config_showPhoneRSSIForData);
         mShowAtLeastThreeGees = res.getBoolean(R.bool.config_showMin3G);
@@ -203,7 +212,7 @@
         mNetworkName = mNetworkNameDefault;
 
         // wifi
-        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+        mWifiManager = wifiManager;
         Handler handler = new WifiHandler();
         mWifiChannel = new AsyncChannel();
         Messenger wifiMessenger = mWifiManager.getWifiServiceMessenger();
@@ -211,8 +220,6 @@
             mWifiChannel.connect(mContext, handler, wifiMessenger);
         }
 
-        registerListeners();
-
         // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it
         updateAirplaneMode();
 
@@ -227,13 +234,7 @@
         });
     }
 
-    @VisibleForTesting
-    protected ConnectivityManager getCM() {
-        return mConnectivityManager;
-    }
-
-    @VisibleForTesting
-    protected void registerListeners() {
+    private void registerListeners() {
         mPhone.listen(mPhoneStateListener,
                           PhoneStateListener.LISTEN_SERVICE_STATE
                         | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
@@ -1085,7 +1086,7 @@
             Log.d(TAG, "updateConnectivity: intent=" + intent);
         }
 
-        final NetworkInfo info = getCM().getActiveNetworkInfo();
+        final NetworkInfo info = mConnectivityManager.getActiveNetworkInfo();
 
         // Are we connected at all, by any interface?
         mConnected = info != null && info.isConnected();
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
index 247cc51..f12053c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
@@ -744,7 +744,7 @@
         } else {
             sc.seekbarView.setVisibility(View.GONE);
             sc.suppressorView.setVisibility(View.VISIBLE);
-            sc.suppressorView.setText(mContext.getString(com.android.systemui.R.string.muted_by,
+            sc.suppressorView.setText(mContext.getString(R.string.muted_by,
                     getSuppressorCaption(suppressor)));
             sc.icon.setImageResource(sc.iconSuppressedRes);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index b325653..ed6ddd2 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -244,7 +244,7 @@
     }
 
     private void setExitCondition(Condition exitCondition) {
-        if (sameConditionId(mExitCondition, exitCondition)) return;
+        if (Objects.equals(mExitCondition, exitCondition)) return;
         mExitCondition = exitCondition;
         refreshExitConditionText();
         updateWidgets();
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 262e071..8b87522 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -19,7 +19,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common
 
 LOCAL_PACKAGE_NAME := SystemUITests
 LOCAL_INSTRUMENTATION_FOR := SystemUI
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index c0aa31d..97605ea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -4,16 +4,19 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import android.content.Context;
 import android.content.Intent;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
+import android.net.wifi.WifiManager;
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
+import android.telephony.TelephonyManager;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
+import com.android.internal.telephony.cdma.EriInfo;
+import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl.SignalCluster;
 
 import org.mockito.ArgumentCaptor;
@@ -24,13 +27,23 @@
 
 public class NetworkControllerBaseTest extends AndroidTestCase {
     private static final String TAG = "NetworkControllerBaseTest";
+    protected static final int DEFAULT_LEVEL = 2;
+    protected static final int DEFAULT_SIGNAL_STRENGTH =
+            TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[1][DEFAULT_LEVEL];
+    protected static final int DEFAULT_QS_SIGNAL_STRENGTH =
+            TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[1][DEFAULT_LEVEL];
+    protected static final int DEFAULT_ICON = TelephonyIcons.ICON_3G;
+    protected static final int DEFAULT_QS_ICON = TelephonyIcons.QS_ICON_3G;
 
     protected NetworkControllerImpl mNetworkController;
     protected PhoneStateListener mPhoneStateListener;
     protected SignalCluster mSignalCluster;
+    protected NetworkSignalChangedCallback mNetworkSignalChangedCallback;
     private SignalStrength mSignalStrength;
     private ServiceState mServiceState;
-    private ConnectivityManager mMockCM;
+    protected ConnectivityManager mMockCm;
+    protected WifiManager mMockWm;
+    protected TelephonyManager mMockTm;
 
     @Override
     protected void setUp() throws Exception {
@@ -39,17 +52,24 @@
         System.setProperty("dexmaker.dexcache", mContext.getCacheDir().getPath());
         Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
 
-        mMockCM = mock(ConnectivityManager.class);
-        when(mMockCM.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(true);
+        mMockWm = mock(WifiManager.class);
+        mMockTm = mock(TelephonyManager.class);
+        mMockCm = mock(ConnectivityManager.class);
+        when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(true);
 
-        // TODO: Move away from fake, use spy if possible after MSIM refactor.
-        mNetworkController = new FakeNetworkControllerImpl(mContext);
-
-        mPhoneStateListener = mNetworkController.mPhoneStateListener;
         mSignalStrength = mock(SignalStrength.class);
         mServiceState = mock(ServiceState.class);
         mSignalCluster = mock(SignalCluster.class);
+        mNetworkSignalChangedCallback = mock(NetworkSignalChangedCallback.class);
+
+        mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm);
+        setupNetworkController();
+    }
+
+    protected void setupNetworkController() {
+        mPhoneStateListener = mNetworkController.mPhoneStateListener;
         mNetworkController.addSignalCluster(mSignalCluster);
+        mNetworkController.addNetworkSignalChangedCallback(mNetworkSignalChangedCallback);
     }
 
     @Override
@@ -62,13 +82,24 @@
         super.tearDown();
     }
 
+    // 2 Bars 3G GSM.
+    public void setupDefaultSignal() {
+        setIsGsm(true);
+        setVoiceRegState(ServiceState.STATE_IN_SERVICE);
+        setGsmRoaming(false);
+        setLevel(DEFAULT_LEVEL);
+        updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
+                TelephonyManager.NETWORK_TYPE_UMTS);
+        setConnectivity(100, ConnectivityManager.TYPE_MOBILE, true);
+    }
+
     public void setConnectivity(int inetCondition, int networkType, boolean isConnected) {
         Intent i = new Intent(ConnectivityManager.INET_CONDITION_ACTION);
         NetworkInfo networkInfo = mock(NetworkInfo.class);
         when(networkInfo.isConnected()).thenReturn(isConnected);
         when(networkInfo.getType()).thenReturn(networkType);
         when(networkInfo.getTypeName()).thenReturn("");
-        when(mMockCM.getActiveNetworkInfo()).thenReturn(networkInfo);
+        when(mMockCm.getActiveNetworkInfo()).thenReturn(networkInfo);
 
         i.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, inetCondition);
         mNetworkController.onReceive(mContext, i);
@@ -79,11 +110,24 @@
         updateServiceState();
     }
 
+    public void setCdmaRoaming(boolean isRoaming) {
+        when(mServiceState.getCdmaEriIconIndex()).thenReturn(isRoaming ?
+                EriInfo.ROAMING_INDICATOR_ON : EriInfo.ROAMING_INDICATOR_OFF);
+        when(mServiceState.getCdmaEriIconMode()).thenReturn(isRoaming ?
+                EriInfo.ROAMING_ICON_MODE_NORMAL : -1);
+        updateServiceState();
+    }
+
     public void setVoiceRegState(int voiceRegState) {
         when(mServiceState.getVoiceRegState()).thenReturn(voiceRegState);
         updateServiceState();
     }
 
+    public void setDataRegState(int dataRegState) {
+        when(mServiceState.getDataRegState()).thenReturn(dataRegState);
+        updateServiceState();
+    }
+
     public void setIsEmergencyOnly(boolean isEmergency) {
         when(mServiceState.isEmergencyOnly()).thenReturn(isEmergency);
         updateServiceState();
@@ -131,32 +175,49 @@
         mPhoneStateListener.onDataActivity(dataActivity);
     }
 
-    protected void verifyLastMobileDataIndicators(boolean visible, int icon) {
+    protected void verifyLastQsMobileDataIndicators(boolean visible, int icon, int typeIcon,
+            boolean dataIn, boolean dataOut, boolean noSim) {
         ArgumentCaptor<Integer> iconArg = ArgumentCaptor.forClass(Integer.class);
+        ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class);
+        ArgumentCaptor<Boolean> visibleArg = ArgumentCaptor.forClass(Boolean.class);
+        ArgumentCaptor<Boolean> dataInArg = ArgumentCaptor.forClass(Boolean.class);
+        ArgumentCaptor<Boolean> dataOutArg = ArgumentCaptor.forClass(Boolean.class);
+        ArgumentCaptor<Boolean> noSimArg = ArgumentCaptor.forClass(Boolean.class);
+
+        Mockito.verify(mNetworkSignalChangedCallback, Mockito.atLeastOnce())
+                .onMobileDataSignalChanged(visibleArg.capture(), iconArg.capture(),
+                        ArgumentCaptor.forClass(String.class).capture(),
+                        typeIconArg.capture(),
+                        dataInArg.capture(),
+                        dataOutArg.capture(),
+                        ArgumentCaptor.forClass(String.class).capture(),
+                        ArgumentCaptor.forClass(String.class).capture(),
+                        noSimArg.capture(),
+                        ArgumentCaptor.forClass(Boolean.class).capture());
+        assertEquals("Visibility in, quick settings", visible, (boolean) visibleArg.getValue());
+        assertEquals("Signal icon in, quick settings", icon, (int) iconArg.getValue());
+        assertEquals("Data icon in, quick settings", typeIcon, (int) typeIconArg.getValue());
+        assertEquals("Data direction in, in quick settings", dataIn,
+                (boolean) dataInArg.getValue());
+        assertEquals("Data direction out, in quick settings", dataOut,
+                (boolean) dataOutArg.getValue());
+        assertEquals("Sim state in quick settings", noSim, (boolean) noSimArg.getValue());
+    }
+
+    protected void verifyLastMobileDataIndicators(boolean visible, int icon, int typeIcon) {
+        ArgumentCaptor<Integer> iconArg = ArgumentCaptor.forClass(Integer.class);
+        ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class);
         ArgumentCaptor<Boolean> visibleArg = ArgumentCaptor.forClass(Boolean.class);
 
         // TODO: Verify all fields.
         Mockito.verify(mSignalCluster, Mockito.atLeastOnce()).setMobileDataIndicators(
-                visibleArg.capture(), iconArg.capture(),
-                ArgumentCaptor.forClass(Integer.class).capture(),
+                visibleArg.capture(), iconArg.capture(), typeIconArg.capture(),
                 ArgumentCaptor.forClass(String.class).capture(),
                 ArgumentCaptor.forClass(String.class).capture(),
                 ArgumentCaptor.forClass(Boolean.class).capture());
 
-        assertEquals(icon, (int) iconArg.getValue());
-        assertEquals(visible, (boolean) visibleArg.getValue());
-    }
-
-    private class FakeNetworkControllerImpl extends NetworkControllerImpl {
-        public FakeNetworkControllerImpl(Context context) {
-            super(context);
-        }
-
-        @Override
-        public ConnectivityManager getCM() {
-            return mMockCM;
-        }
-
-        public void registerListeners() {};
+        assertEquals("Signal icon in status bar", icon, (int) iconArg.getValue());
+        assertEquals("Data icon in status bar", typeIcon, (int) typeIconArg.getValue());
+        assertEquals("Visibility in status bar", visible, (boolean) visibleArg.getValue());
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
new file mode 100644
index 0000000..146e76d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -0,0 +1,99 @@
+package com.android.systemui.statusbar.policy;
+
+import android.telephony.TelephonyManager;
+
+// WARNING: Many of these tests may fail with config showMin3G.
+// TODO: Maybe fix the above.
+public class NetworkControllerDataTest extends NetworkControllerBaseTest {
+
+    public void test3gDataIcon() {
+        setupDefaultSignal();
+
+        verifyDataIndicators(TelephonyIcons.DATA_3G[1][0 /* No direction */],
+                TelephonyIcons.QS_DATA_3G[1]);
+    }
+
+    public void testRoamingDataIcon() {
+        setupDefaultSignal();
+        setGsmRoaming(true);
+
+        verifyLastMobileDataIndicators(true,
+                TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[1][DEFAULT_LEVEL],
+                TelephonyIcons.ROAMING_ICON);
+        verifyLastQsMobileDataIndicators(true,
+                TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[1][DEFAULT_LEVEL],
+                TelephonyIcons.QS_DATA_R[1], false, false, false);
+    }
+
+    public void test2gDataIcon() {
+        setupDefaultSignal();
+        updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
+                TelephonyManager.NETWORK_TYPE_GSM);
+
+        verifyDataIndicators(TelephonyIcons.DATA_G[1][0 /* No direction */],
+                TelephonyIcons.QS_DATA_G[1]);
+    }
+
+    public void testCdmaDataIcon() {
+        setupDefaultSignal();
+        updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
+                TelephonyManager.NETWORK_TYPE_CDMA);
+
+        verifyDataIndicators(TelephonyIcons.DATA_1X[1][0 /* No direction */],
+                TelephonyIcons.QS_DATA_1X[1]);
+    }
+
+    public void testEdgeDataIcon() {
+        setupDefaultSignal();
+        updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
+                TelephonyManager.NETWORK_TYPE_EDGE);
+
+        verifyDataIndicators(TelephonyIcons.DATA_E[1][0 /* No direction */],
+                TelephonyIcons.QS_DATA_E[1]);
+    }
+
+    public void testLteDataIcon() {
+        setupDefaultSignal();
+        updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
+                TelephonyManager.NETWORK_TYPE_LTE);
+
+        // WARNING: May fail depending on config.
+        verifyDataIndicators(TelephonyIcons.DATA_LTE[1][0 /* No direction */],
+                TelephonyIcons.QS_DATA_LTE[1]);
+    }
+
+    public void testHspaDataIcon() {
+        setupDefaultSignal();
+        updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
+                TelephonyManager.NETWORK_TYPE_HSPA);
+
+        // WARNING: May fail depending on config.
+        verifyDataIndicators(TelephonyIcons.DATA_H[1][0 /* No direction */],
+                TelephonyIcons.QS_DATA_H[1]);
+    }
+
+    public void testDataActivity() {
+        setupDefaultSignal();
+
+        testDataActivity(TelephonyManager.DATA_ACTIVITY_NONE, false, false);
+        testDataActivity(TelephonyManager.DATA_ACTIVITY_IN, true, false);
+        testDataActivity(TelephonyManager.DATA_ACTIVITY_OUT, false, true);
+        testDataActivity(TelephonyManager.DATA_ACTIVITY_INOUT, true, true);
+    }
+
+    private void testDataActivity(int direction, boolean in, boolean out) {
+        updateDataActivity(direction);
+
+        verifyLastMobileDataIndicators(true, DEFAULT_SIGNAL_STRENGTH, DEFAULT_ICON);
+        verifyLastQsMobileDataIndicators(true, DEFAULT_QS_SIGNAL_STRENGTH,
+                DEFAULT_QS_ICON, in, out, false);
+
+    }
+
+    private void verifyDataIndicators(int dataIcon, int qsDataIcon) {
+        verifyLastMobileDataIndicators(true, DEFAULT_SIGNAL_STRENGTH, dataIcon);
+        verifyLastQsMobileDataIndicators(true, DEFAULT_QS_SIGNAL_STRENGTH, qsDataIcon, false,
+                false, false);
+    }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
index fc2b1aa..ed76ae5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
@@ -5,33 +5,122 @@
 import android.telephony.SignalStrength;
 import android.telephony.TelephonyManager;
 
+import com.android.systemui.R;
+
+import org.mockito.Mockito;
+
 public class NetworkControllerSignalTest extends NetworkControllerBaseTest {
 
-    public void testSignalStrength() {
-        int testStrength = SignalStrength.SIGNAL_STRENGTH_MODERATE;
-        setIsGsm(true);
-        setVoiceRegState(ServiceState.STATE_IN_SERVICE);
-        setGsmRoaming(false);
-        setLevel(testStrength);
-        updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
-                TelephonyManager.NETWORK_TYPE_UMTS);
-        setConnectivity(100, ConnectivityManager.TYPE_MOBILE, true);
+    public void testNoIconWithoutMobile() {
+        // Turn off mobile network support.
+        Mockito.when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false);
+        // Create a new NetworkController as this is currently handled in constructor.
+        mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm);
+        setupNetworkController();
 
-        verifyLastMobileDataIndicators(true,
-                TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[1][testStrength]);
+        verifyLastMobileDataIndicators(false, 0, 0);
+    }
+
+    public void testSignalStrength() {
+        for (int testStrength = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+                testStrength <= SignalStrength.SIGNAL_STRENGTH_GREAT; testStrength++) {
+            setupDefaultSignal();
+            setLevel(testStrength);
+
+            verifyLastMobileDataIndicators(true,
+                    TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[1][testStrength],
+                    DEFAULT_ICON);
+
+            // Verify low inet number indexing.
+            setConnectivity(10, ConnectivityManager.TYPE_MOBILE, true);
+            verifyLastMobileDataIndicators(true,
+                    TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[0][testStrength], 0);
+        }
+    }
+
+    public void testCdmaSignalStrength() {
+        for (int testStrength = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+                testStrength <= SignalStrength.SIGNAL_STRENGTH_GREAT; testStrength++) {
+            setupDefaultSignal();
+            setCdma();
+            setLevel(testStrength);
+
+            verifyLastMobileDataIndicators(true,
+                    TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[1][testStrength],
+                    TelephonyIcons.DATA_1X[1][0 /* No direction */]);
+        }
     }
 
     public void testSignalRoaming() {
-        int testStrength = SignalStrength.SIGNAL_STRENGTH_MODERATE;
-        setIsGsm(true);
-        setVoiceRegState(ServiceState.STATE_IN_SERVICE);
-        setGsmRoaming(true);
-        setLevel(testStrength);
-        updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
-                TelephonyManager.NETWORK_TYPE_UMTS);
-        setConnectivity(100, ConnectivityManager.TYPE_MOBILE, true);
+        for (int testStrength = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+                testStrength <= SignalStrength.SIGNAL_STRENGTH_GREAT; testStrength++) {
+            setupDefaultSignal();
+            setGsmRoaming(true);
+            setLevel(testStrength);
 
-        verifyLastMobileDataIndicators(true,
-                TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[1][testStrength]);
+            verifyLastMobileDataIndicators(true,
+                    TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[1][testStrength],
+                    TelephonyIcons.ROAMING_ICON);
+        }
+    }
+
+    public void testCdmaSignalRoaming() {
+        for (int testStrength = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+                testStrength <= SignalStrength.SIGNAL_STRENGTH_GREAT; testStrength++) {
+            setupDefaultSignal();
+            setCdma();
+            setCdmaRoaming(true);
+            setLevel(testStrength);
+
+            verifyLastMobileDataIndicators(true,
+                    TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[1][testStrength],
+                    TelephonyIcons.ROAMING_ICON);
+        }
+    }
+
+    public void testQsSignalStrength() {
+        for (int testStrength = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+                testStrength <= SignalStrength.SIGNAL_STRENGTH_GREAT; testStrength++) {
+            setupDefaultSignal();
+            setLevel(testStrength);
+
+            verifyLastQsMobileDataIndicators(true,
+                    TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[1][testStrength],
+                    DEFAULT_QS_ICON, false, false, false);
+        }
+    }
+
+    public void testCdmaQsSignalStrength() {
+        for (int testStrength = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+                testStrength <= SignalStrength.SIGNAL_STRENGTH_GREAT; testStrength++) {
+            setupDefaultSignal();
+            setCdma();
+            setLevel(testStrength);
+
+            verifyLastQsMobileDataIndicators(true,
+                    TelephonyIcons.QS_TELEPHONY_SIGNAL_STRENGTH[1][testStrength],
+                    TelephonyIcons.QS_ICON_1X, false, false, false);
+        }
+    }
+
+    public void testNoRoamingWithoutSignal() {
+        setupDefaultSignal();
+        setCdma();
+        setCdmaRoaming(true);
+        setVoiceRegState(ServiceState.STATE_OUT_OF_SERVICE);
+        setDataRegState(ServiceState.STATE_OUT_OF_SERVICE);
+
+        // This exposes the bug in b/18034542, and should be switched to the commented out
+        // verification below (and pass), once the bug is fixed.
+        verifyLastMobileDataIndicators(true, R.drawable.stat_sys_signal_null,
+                TelephonyIcons.ROAMING_ICON);
+        //verifyLastMobileDataIndicators(true, R.drawable.stat_sys_signal_null, 0 /* No Icon */);
+    }
+
+    private void setCdma() {
+        setIsGsm(false);
+        updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
+                TelephonyManager.NETWORK_TYPE_CDMA);
+        setCdmaRoaming(false);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
new file mode 100644
index 0000000..4ffdff2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
@@ -0,0 +1,201 @@
+package com.android.systemui.statusbar.policy;
+
+import android.content.Intent;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+
+import com.android.systemui.R;
+
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+public class NetworkControllerWifiTest extends NetworkControllerBaseTest {
+    // These match the constants in WifiManager and need to be kept up to date.
+    private static final int MIN_RSSI = -100;
+    private static final int MAX_RSSI = -55;
+
+    // TODO: Move this into WifiIcons, remove all R.drawable from NetworkControllerImpl.
+    private static final int NULL_SIGNAL = R.drawable.stat_sys_wifi_signal_null;
+    private static final int QS_NO_NET = R.drawable.ic_qs_wifi_no_network;
+
+    public void testWifiIcon() {
+        String testSsid = "Test SSID";
+        setWifiEnabled(true);
+        verifyLastWifiIcon(false, NULL_SIGNAL);
+
+        setWifiState(true, testSsid);
+        verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[0][0]);
+
+        for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) {
+            setWifiLevel(testLevel);
+
+            setConnectivity(100, ConnectivityManager.TYPE_WIFI, true);
+            verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[1][testLevel]);
+            setConnectivity(10, ConnectivityManager.TYPE_WIFI, true);
+            verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[0][testLevel]);
+        }
+    }
+
+    public void testQsWifiIcon() {
+        String testSsid = "Test SSID";
+
+        setWifiEnabled(false);
+        verifyLastQsWifiIcon(false, false, 0, null);
+
+        setWifiEnabled(true);
+        verifyLastQsWifiIcon(true, false, QS_NO_NET, null);
+
+        setWifiState(true, testSsid);
+        for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) {
+            setWifiLevel(testLevel);
+
+            setConnectivity(100, ConnectivityManager.TYPE_WIFI, true);
+            verifyLastQsWifiIcon(true, true, WifiIcons.QS_WIFI_SIGNAL_STRENGTH[1][testLevel],
+                    testSsid);
+            setConnectivity(10, ConnectivityManager.TYPE_WIFI, true);
+            verifyLastQsWifiIcon(true, true, WifiIcons.QS_WIFI_SIGNAL_STRENGTH[0][testLevel],
+                    testSsid);
+        }
+    }
+
+    public void testQsDataDirection() {
+        // Setup normal connection
+        String testSsid = "Test SSID";
+        int testLevel = 2;
+        setWifiEnabled(true);
+        setWifiState(true, testSsid);
+        setWifiLevel(testLevel);
+        setConnectivity(100, ConnectivityManager.TYPE_WIFI, true);
+        verifyLastQsWifiIcon(true, true,
+                WifiIcons.QS_WIFI_SIGNAL_STRENGTH[1][testLevel], testSsid);
+
+        setWifiActivity(WifiManager.DATA_ACTIVITY_NONE);
+        verifyLastQsDataDirection(false, false);
+        setWifiActivity(WifiManager.DATA_ACTIVITY_IN);
+        verifyLastQsDataDirection(true, false);
+        setWifiActivity(WifiManager.DATA_ACTIVITY_OUT);
+        verifyLastQsDataDirection(false, true);
+        setWifiActivity(WifiManager.DATA_ACTIVITY_INOUT);
+        verifyLastQsDataDirection(true, true);
+    }
+
+    public void testNoDataIconDuringWifi() {
+        // Setup normal connection
+        String testSsid = "Test SSID";
+        int testLevel = 2;
+        setWifiEnabled(true);
+        setWifiState(true, testSsid);
+        setWifiLevel(testLevel);
+        setConnectivity(100, ConnectivityManager.TYPE_WIFI, true);
+        verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[1][testLevel]);
+
+        setupDefaultSignal();
+        // Still be on wifi though.
+        setConnectivity(100, ConnectivityManager.TYPE_WIFI, true);
+        verifyLastMobileDataIndicators(true, DEFAULT_SIGNAL_STRENGTH, 0 /* No icon */);
+    }
+
+    public void testRoamingIconDuringWifi() {
+        // Setup normal connection
+        String testSsid = "Test SSID";
+        int testLevel = 2;
+        setWifiEnabled(true);
+        setWifiState(true, testSsid);
+        setWifiLevel(testLevel);
+        setConnectivity(100, ConnectivityManager.TYPE_WIFI, true);
+        verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[1][testLevel]);
+
+        setupDefaultSignal();
+        setGsmRoaming(true);
+        // Still be on wifi though.
+        setConnectivity(100, ConnectivityManager.TYPE_WIFI, true);
+        verifyLastMobileDataIndicators(true,
+                TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[1][DEFAULT_LEVEL],
+                TelephonyIcons.ROAMING_ICON);
+    }
+
+    protected void setWifiActivity(int activity) {
+        // TODO: Not this, because this variable probably isn't sticking around.
+        mNetworkController.mWifiActivity = activity;
+        mNetworkController.refreshViews();
+    }
+
+    protected void setWifiLevel(int level) {
+        float amountPerLevel = (MAX_RSSI - MIN_RSSI) / (WifiIcons.WIFI_LEVEL_COUNT - 1);
+        int rssi = (int)(MIN_RSSI + level * amountPerLevel);
+        // Put RSSI in the middle of the range.
+        rssi += amountPerLevel / 2;
+        Intent i = new Intent(WifiManager.RSSI_CHANGED_ACTION);
+        i.putExtra(WifiManager.EXTRA_NEW_RSSI, rssi);
+        mNetworkController.onReceive(mContext, i);
+    }
+
+    protected void setWifiEnabled(boolean enabled) {
+        Intent i = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
+        i.putExtra(WifiManager.EXTRA_WIFI_STATE,
+                enabled ? WifiManager.WIFI_STATE_ENABLED : WifiManager.WIFI_STATE_DISABLED);
+        mNetworkController.onReceive(mContext, i);
+    }
+
+    protected void setWifiState(boolean connected, String ssid) {
+        Intent i = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+        NetworkInfo networkInfo = Mockito.mock(NetworkInfo.class);
+        Mockito.when(networkInfo.isConnected()).thenReturn(connected);
+
+        WifiInfo wifiInfo = Mockito.mock(WifiInfo.class);
+        Mockito.when(wifiInfo.getSSID()).thenReturn(ssid);
+
+        i.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
+        i.putExtra(WifiManager.EXTRA_WIFI_INFO, wifiInfo);
+        mNetworkController.onReceive(mContext, i);
+    }
+
+    protected void verifyLastQsDataDirection(boolean in, boolean out) {
+        ArgumentCaptor<Boolean> inArg = ArgumentCaptor.forClass(Boolean.class);
+        ArgumentCaptor<Boolean> outArg = ArgumentCaptor.forClass(Boolean.class);
+
+        Mockito.verify(mNetworkSignalChangedCallback, Mockito.atLeastOnce()).onWifiSignalChanged(
+                ArgumentCaptor.forClass(Boolean.class).capture(),
+                ArgumentCaptor.forClass(Boolean.class).capture(),
+                ArgumentCaptor.forClass(Integer.class).capture(),
+                inArg.capture(), outArg.capture(),
+                ArgumentCaptor.forClass(String.class).capture(),
+                ArgumentCaptor.forClass(String.class).capture());
+        assertEquals("WiFi data in, in quick settings", in, (boolean) inArg.getValue());
+        assertEquals("WiFi data out, in quick settings", out, (boolean) outArg.getValue());
+    }
+
+    protected void verifyLastQsWifiIcon(boolean enabled, boolean connected, int icon,
+            String description) {
+        ArgumentCaptor<Boolean> enabledArg = ArgumentCaptor.forClass(Boolean.class);
+        ArgumentCaptor<Boolean> connectedArg = ArgumentCaptor.forClass(Boolean.class);
+        ArgumentCaptor<Integer> iconArg = ArgumentCaptor.forClass(Integer.class);
+        ArgumentCaptor<String> descArg = ArgumentCaptor.forClass(String.class);
+
+        Mockito.verify(mNetworkSignalChangedCallback, Mockito.atLeastOnce()).onWifiSignalChanged(
+                enabledArg.capture(), connectedArg.capture(), iconArg.capture(),
+                ArgumentCaptor.forClass(Boolean.class).capture(),
+                ArgumentCaptor.forClass(Boolean.class).capture(),
+                ArgumentCaptor.forClass(String.class).capture(),
+                descArg.capture());
+        assertEquals("WiFi enabled, in quick settings", enabled, (boolean) enabledArg.getValue());
+        assertEquals("WiFi connected, in quick settings", connected,
+                (boolean) connectedArg.getValue());
+        assertEquals("WiFi signal, in quick settings", icon, (int) iconArg.getValue());
+        assertEquals("WiFI desc (ssid), in quick settings", description,
+                (String) descArg.getValue());
+    }
+
+    protected void verifyLastWifiIcon(boolean visible, int icon) {
+        ArgumentCaptor<Boolean> visibleArg = ArgumentCaptor.forClass(Boolean.class);
+        ArgumentCaptor<Integer> iconArg = ArgumentCaptor.forClass(Integer.class);
+
+        Mockito.verify(mSignalCluster, Mockito.atLeastOnce()).setWifiIndicators(
+                visibleArg.capture(), iconArg.capture(),
+                ArgumentCaptor.forClass(String.class).capture());
+        assertEquals("WiFi visible, in status bar", visible, (boolean) visibleArg.getValue());
+        assertEquals("WiFi signal, in status bar", icon, (int) iconArg.getValue());
+    }
+}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index b670584..f9a6359 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -998,6 +998,10 @@
                 }
                 break;
             case MULTI_PRESS_POWER_BRIGHTNESS_BOOST:
+                Slog.i(TAG, "Starting brightness boost.");
+                if (!interactive) {
+                    wakeUpFromPowerKey(eventTime);
+                }
                 mPowerManager.boostScreenBrightness(eventTime);
                 break;
         }
diff --git a/services/core/java/com/android/server/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java
index 29b04da..a44cb72 100644
--- a/services/core/java/com/android/server/DropBoxManagerService.java
+++ b/services/core/java/com/android/server/DropBoxManagerService.java
@@ -408,9 +408,14 @@
                         if (!newline) out.append("\n");
                     } else {
                         String text = dbe.getText(70);
-                        boolean truncated = (text.length() == 70);
-                        out.append("    ").append(text.trim().replace('\n', '/'));
-                        if (truncated) out.append(" ...");
+                        out.append("    ");
+                        if (text == null) {
+                            out.append("[null]");
+                        } else {
+                            boolean truncated = (text.length() == 70);
+                            out.append(text.trim().replace('\n', '/'));
+                            if (truncated) out.append(" ...");
+                        }
                         out.append("\n");
                     }
                 } catch (IOException e) {
diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java
index 9596b57..da50751 100644
--- a/services/core/java/com/android/server/MmsServiceBroker.java
+++ b/services/core/java/com/android/server/MmsServiceBroker.java
@@ -16,8 +16,6 @@
 
 package com.android.server;
 
-import com.android.internal.telephony.IMms;
-
 import android.Manifest;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
@@ -38,6 +36,8 @@
 import android.telephony.TelephonyManager;
 import android.util.Slog;
 
+import com.android.internal.telephony.IMms;
+
 /**
  * This class is a proxy for MmsService APIs. We need this because MmsService runs
  * in phone process and may crash anytime. This manages a connection to the actual
@@ -118,7 +118,7 @@
     }
 
     public void systemRunning() {
-        tryConnecting();
+        Slog.i(TAG, "Delay connecting to MmsService until an API is called");
     }
 
     private void tryConnecting() {
@@ -206,7 +206,7 @@
      * Throws a security exception unless the caller has carrier privilege.
      */
     private void enforceCarrierPrivilege() {
-        String[] packages = getPackageManager().getPackagesForUid(Binder.getCallingUid());
+        final String[] packages = getPackageManager().getPackagesForUid(Binder.getCallingUid());
         for (String pkg : packages) {
             if (getTelephonyManager().checkCarrierPrivilegesForPackage(pkg) ==
                     TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
@@ -216,12 +216,21 @@
         throw new SecurityException("No carrier privilege");
     }
 
+    private String getCallingPackageName() {
+        final String[] packages = getPackageManager().getPackagesForUid(Binder.getCallingUid());
+        if (packages != null && packages.length > 0) {
+            return packages[0];
+        }
+        return "unknown";
+    }
+
     // Service API calls implementation, proxied to the real MmsService in "com.android.mms.service"
     private final class BinderService extends IMms.Stub {
         @Override
         public void sendMessage(int subId, String callingPkg, Uri contentUri,
                 String locationUrl, Bundle configOverrides, PendingIntent sentIntent)
                         throws RemoteException {
+            Slog.d(TAG, "sendMessage() by " + callingPkg);
             mContext.enforceCallingPermission(Manifest.permission.SEND_SMS, "Send MMS message");
             if (getAppOpsManager().noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(),
                     callingPkg) != AppOpsManager.MODE_ALLOWED) {
@@ -235,6 +244,7 @@
         public void downloadMessage(int subId, String callingPkg, String locationUrl,
                 Uri contentUri, Bundle configOverrides,
                 PendingIntent downloadedIntent) throws RemoteException {
+            Slog.d(TAG, "downloadMessage() by " + callingPkg);
             mContext.enforceCallingPermission(Manifest.permission.RECEIVE_MMS,
                     "Download MMS message");
             if (getAppOpsManager().noteOp(AppOpsManager.OP_RECEIVE_MMS, Binder.getCallingUid(),
@@ -260,6 +270,7 @@
 
         @Override
         public Bundle getCarrierConfigValues(int subId) throws RemoteException {
+            Slog.d(TAG, "getCarrierConfigValues() by " + getCallingPackageName());
             return getServiceGuarded().getCarrierConfigValues(subId);
         }
 
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index d480f68..a2f4d56 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -77,7 +77,6 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.FgThread;
-
 import com.google.android.collect.Lists;
 import com.google.android.collect.Sets;
 
@@ -487,7 +486,7 @@
         for (Account sa : sharedAccounts) {
             if (ArrayUtils.contains(accounts, sa)) continue;
             // Account doesn't exist. Copy it now.
-            copyAccountToUser(sa, UserHandle.USER_OWNER, userId);
+            copyAccountToUser(null /*no response*/, sa, UserHandle.USER_OWNER, userId);
         }
     }
 
@@ -673,16 +672,31 @@
         }
     }
 
-    private boolean copyAccountToUser(final Account account, int userFrom, int userTo) {
+    @Override
+    public void copyAccountToUser(final IAccountManagerResponse response, final Account account,
+            int userFrom, int userTo) {
+        enforceCrossUserPermission(UserHandle.USER_ALL, "Calling copyAccountToUser requires "
+                    + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
         final UserAccounts fromAccounts = getUserAccounts(userFrom);
         final UserAccounts toAccounts = getUserAccounts(userTo);
         if (fromAccounts == null || toAccounts == null) {
-            return false;
+            if (response != null) {
+                Bundle result = new Bundle();
+                result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
+                try {
+                    response.onResult(result);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Failed to report error back to the client." + e);
+                }
+            }
+            return;
         }
 
+        Slog.d(TAG, "Copying account " + account.name
+                + " from user " + userFrom + " to user " + userTo);
         long identityToken = clearCallingIdentity();
         try {
-            new Session(fromAccounts, null, account.type, false,
+            new Session(fromAccounts, response, account.type, false,
                     false /* stripAuthTokenFromResult */) {
                 @Override
                 protected String toDebugString(long now) {
@@ -697,12 +711,10 @@
 
                 @Override
                 public void onResult(Bundle result) {
-                    if (result != null) {
-                        if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
-                            // Create a Session for the target user and pass in the bundle
-                            completeCloningAccount(result, account, toAccounts);
-                        }
-                        return;
+                    if (result != null
+                            && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
+                        // Create a Session for the target user and pass in the bundle
+                        completeCloningAccount(response, result, account, toAccounts);
                     } else {
                         super.onResult(result);
                     }
@@ -711,14 +723,13 @@
         } finally {
             restoreCallingIdentity(identityToken);
         }
-        return true;
     }
 
-    void completeCloningAccount(final Bundle result, final Account account,
-            final UserAccounts targetUser) {
+    private void completeCloningAccount(IAccountManagerResponse response,
+            final Bundle accountCredentials, final Account account, final UserAccounts targetUser) {
         long id = clearCallingIdentity();
         try {
-            new Session(targetUser, null, account.type, false,
+            new Session(targetUser, response, account.type, false,
                     false /* stripAuthTokenFromResult */) {
                 @Override
                 protected String toDebugString(long now) {
@@ -731,10 +742,10 @@
                     // Confirm that the owner's account still exists before this step.
                     UserAccounts owner = getUserAccounts(UserHandle.USER_OWNER);
                     synchronized (owner.cacheLock) {
-                        Account[] ownerAccounts = getAccounts(UserHandle.USER_OWNER);
-                        for (Account acc : ownerAccounts) {
+                        for (Account acc : getAccounts(UserHandle.USER_OWNER)) {
                             if (acc.equals(account)) {
-                                mAuthenticator.addAccountFromCredentials(this, account, result);
+                                mAuthenticator.addAccountFromCredentials(
+                                        this, account, accountCredentials);
                                 break;
                             }
                         }
@@ -743,17 +754,10 @@
 
                 @Override
                 public void onResult(Bundle result) {
-                    if (result != null) {
-                        if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
-                            // TODO: Anything?
-                        } else {
-                            // TODO: Show error notification
-                            // TODO: Should we remove the shadow account to avoid retries?
-                        }
-                        return;
-                    } else {
-                        super.onResult(result);
-                    }
+                    // TODO: Anything to do if if succedded?
+                    // TODO: If it failed: Show error notification? Should we remove the shadow
+                    // account to avoid retries?
+                    super.onResult(result);
                 }
 
                 @Override
@@ -1043,7 +1047,8 @@
     }
 
     @Override
-    public void removeAccount(IAccountManagerResponse response, Account account) {
+    public void removeAccount(IAccountManagerResponse response, Account account,
+            boolean expectActivityLaunch) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "removeAccount: " + account
                     + ", response " + response
@@ -1088,7 +1093,7 @@
         }
 
         try {
-            new RemoveAccountSession(accounts, response, account).bind();
+            new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind();
         } finally {
             restoreCallingIdentity(identityToken);
         }
@@ -1096,7 +1101,7 @@
 
     @Override
     public void removeAccountAsUser(IAccountManagerResponse response, Account account,
-            int userId) {
+            boolean expectActivityLaunch, int userId) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "removeAccount: " + account
                     + ", response " + response
@@ -1145,7 +1150,30 @@
         }
 
         try {
-            new RemoveAccountSession(accounts, response, account).bind();
+            new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind();
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+    }
+
+    @Override
+    public boolean removeAccountExplicitly(Account account) {
+        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+            Log.v(TAG, "removeAccountExplicitly: " + account
+                    + ", caller's uid " + Binder.getCallingUid()
+                    + ", pid " + Binder.getCallingPid());
+        }
+        if (account == null) throw new IllegalArgumentException("account is null");
+        checkAuthenticateAccountsPermission(account);
+
+        UserAccounts accounts = getUserAccountsForCaller();
+        int userId = Binder.getCallingUserHandle().getIdentifier();
+        if (!canUserModifyAccounts(userId) || !canUserModifyAccountsForType(userId, account.type)) {
+            return false;
+        }
+        long identityToken = clearCallingIdentity();
+        try {
+            return removeAccountInternal(accounts, account);
         } finally {
             restoreCallingIdentity(identityToken);
         }
@@ -1154,8 +1182,8 @@
     private class RemoveAccountSession extends Session {
         final Account mAccount;
         public RemoveAccountSession(UserAccounts accounts, IAccountManagerResponse response,
-                Account account) {
-            super(accounts, response, account.type, false /* expectActivityLaunch */,
+                Account account, boolean expectActivityLaunch) {
+            super(accounts, response, account.type, expectActivityLaunch,
                     true /* stripAuthTokenFromResult */);
             mAccount = account;
         }
@@ -1203,10 +1231,12 @@
         removeAccountInternal(getUserAccountsForCaller(), account);
     }
 
-    private void removeAccountInternal(UserAccounts accounts, Account account) {
+    private boolean removeAccountInternal(UserAccounts accounts, Account account) {
+        int deleted;
         synchronized (accounts.cacheLock) {
             final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
-            db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
+            deleted = db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE
+                    + "=?",
                     new String[]{account.name, account.type});
             removeAccountFromCacheLocked(accounts, account);
             sendAccountsChangedBroadcast(accounts.userId);
@@ -1226,6 +1256,7 @@
                 Binder.restoreCallingIdentity(id);
             }
         }
+        return (deleted > 0);
     }
 
     @Override
@@ -2714,7 +2745,7 @@
                     break;
 
                 case MESSAGE_COPY_SHARED_ACCOUNT:
-                    copyAccountToUser((Account) msg.obj, msg.arg1, msg.arg2);
+                    copyAccountToUser(/*no response*/ null, (Account) msg.obj, msg.arg1, msg.arg2);
                     break;
 
                 default:
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 120002e..38809cb 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -121,7 +121,7 @@
     static final boolean DEBUG_RELEASE = DEBUG || false;
     static final boolean DEBUG_SAVED_STATE = DEBUG || false;
     static final boolean DEBUG_SCREENSHOTS = DEBUG || false;
-    static final boolean DEBUG_STATES = DEBUG || true;
+    static final boolean DEBUG_STATES = DEBUG || false;
     static final boolean DEBUG_VISIBLE_BEHIND = DEBUG || false;
 
     public static final int HOME_STACK_ID = 0;
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 81cd94b..8cfb4b3 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -582,11 +582,8 @@
         state = mPowerState.getScreenState();
 
         // Use zero brightness when screen is off.
-        // Use full brightness when screen brightness is boosted.
         if (state == Display.STATE_OFF) {
             brightness = PowerManager.BRIGHTNESS_OFF;
-        } else if (mPowerRequest.boostScreenBrightness) {
-            brightness = PowerManager.BRIGHTNESS_ON;
         }
 
         // Configure auto-brightness.
@@ -601,6 +598,16 @@
                     mPowerRequest.screenAutoBrightnessAdjustment, state != Display.STATE_ON);
         }
 
+        // Apply brightness boost.
+        // We do this here after configuring auto-brightness so that we don't
+        // disable the light sensor during this temporary state.  That way when
+        // boost ends we will be able to resume normal auto-brightness behavior
+        // without any delay.
+        if (mPowerRequest.boostScreenBrightness
+                && brightness != PowerManager.BRIGHTNESS_OFF) {
+            brightness = PowerManager.BRIGHTNESS_ON;
+        }
+
         // Apply auto-brightness.
         boolean slowChange = false;
         if (brightness < 0) {
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 02c9fcb5..ba18f48 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -805,7 +805,12 @@
                         + flags + ", suggestedStream=" + suggestedStream);
 
             }
-            if (session == null) {
+            boolean preferSuggestedStream = false;
+            if (isValidLocalStreamType(suggestedStream)
+                    && AudioSystem.isStreamActive(suggestedStream, 0)) {
+                preferSuggestedStream = true;
+            }
+            if (session == null || preferSuggestedStream) {
                 if ((flags & AudioManager.FLAG_ACTIVE_MEDIA_ONLY) != 0
                         && !AudioSystem.isStreamActive(AudioManager.STREAM_MUSIC, 0)) {
                     if (DEBUG) {
@@ -959,6 +964,12 @@
             return keyCode == KeyEvent.KEYCODE_HEADSETHOOK;
         }
 
+        // we only handle public stream types, which are 0-5
+        private boolean isValidLocalStreamType(int streamType) {
+            return streamType >= AudioManager.STREAM_VOICE_CALL
+                    && streamType <= AudioManager.STREAM_NOTIFICATION;
+        }
+
         private KeyEventWakeLockReceiver mKeyEventReceiver = new KeyEventWakeLockReceiver(mHandler);
 
         class KeyEventWakeLockReceiver extends ResultReceiver implements Runnable,
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index a1085d3..5de1a64 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -260,9 +260,11 @@
             for (int i = 0; i < N; i++) {
                 final Condition c = conditions[i];
                 final ConditionRecord r = getRecordLocked(c.id, info.component);
+                final Condition oldCondition = r.condition;
+                final boolean conditionUpdate = oldCondition != null && !oldCondition.equals(c);
                 r.info = info;
                 r.condition = c;
-                // if manual, exit zen if false (or failed)
+                // if manual, exit zen if false (or failed), update if true (and changed)
                 if (r.isManual) {
                     if (c.state == Condition.STATE_FALSE || c.state == Condition.STATE_ERROR) {
                         final boolean failed = c.state == Condition.STATE_ERROR;
@@ -275,6 +277,10 @@
                                 "manualConditionExit");
                         unsubscribeLocked(r);
                         r.isManual = false;
+                    } else if (c.state == Condition.STATE_TRUE && conditionUpdate) {
+                        if (DEBUG) Slog.d(TAG, "Current condition updated, still true. old="
+                                + oldCondition + " new=" + c);
+                        setZenModeCondition(c, "conditionUpdate");
                     }
                 }
                 // if automatic, exit zen if false (or failed), enter zen if true
@@ -559,7 +565,7 @@
             // enter downtime, or update mode if reconfigured during an active downtime
             if (inDowntime && (mode == Global.ZEN_MODE_OFF || downtimeCurrent)  && config != null) {
                 final Condition condition = mDowntime.createCondition(config.toDowntimeInfo(),
-                        Condition.STATE_TRUE);
+                        config.sleepNone, Condition.STATE_TRUE);
                 mZenModeHelper.setZenMode(downtimeMode, "downtimeEnter");
                 setZenModeCondition(condition, "downtime");
             }
diff --git a/services/core/java/com/android/server/notification/DowntimeConditionProvider.java b/services/core/java/com/android/server/notification/DowntimeConditionProvider.java
index 0fb5732..097589a 100644
--- a/services/core/java/com/android/server/notification/DowntimeConditionProvider.java
+++ b/services/core/java/com/android/server/notification/DowntimeConditionProvider.java
@@ -122,7 +122,8 @@
         if (DEBUG) Slog.d(TAG, "onRequestConditions relevance=" + relevance);
         if ((relevance & Condition.FLAG_RELEVANT_NOW) != 0) {
             if (isInDowntime() && mConfig != null) {
-                notifyCondition(createCondition(mConfig.toDowntimeInfo(), Condition.STATE_TRUE));
+                notifyCondition(createCondition(mConfig.toDowntimeInfo(), mConfig.sleepNone,
+                        Condition.STATE_TRUE));
             }
         }
     }
@@ -135,7 +136,7 @@
             final int state = mConfig.toDowntimeInfo().equals(downtime) && isInDowntime()
                     ? Condition.STATE_TRUE : Condition.STATE_FALSE;
             if (DEBUG) Slog.d(TAG, "notify condition state: " + Condition.stateToString(state));
-            notifyCondition(createCondition(downtime, state));
+            notifyCondition(createCondition(downtime, mConfig.sleepNone, state));
         }
     }
 
@@ -157,14 +158,22 @@
         return mDowntimeMode != Global.ZEN_MODE_OFF;
     }
 
-    public Condition createCondition(DowntimeInfo downtime, int state) {
+    public Condition createCondition(DowntimeInfo downtime, boolean orAlarm, int state) {
         if (downtime == null) return null;
         final Uri id = ZenModeConfig.toDowntimeConditionId(downtime);
         final String skeleton = DateFormat.is24HourFormat(mContext) ? "Hm" : "hma";
         final Locale locale = Locale.getDefault();
         final String pattern = DateFormat.getBestDateTimePattern(locale, skeleton);
-        final long time = getTime(System.currentTimeMillis(), downtime.endHour, downtime.endMinute);
-        final String formatted = new SimpleDateFormat(pattern, locale).format(new Date(time));
+        final long now = System.currentTimeMillis();
+        long endTime = getTime(now, downtime.endHour, downtime.endMinute);
+        if (orAlarm) {
+            final AlarmClockInfo nextAlarm = mTracker.getNextAlarm();
+            final long nextAlarmTime = nextAlarm != null ? nextAlarm.getTriggerTime() : 0;
+            if (nextAlarmTime > now && nextAlarmTime < endTime) {
+                endTime = nextAlarmTime;
+            }
+        }
+        final String formatted = new SimpleDateFormat(pattern, locale).format(new Date(endTime));
         final String summary = mContext.getString(R.string.downtime_condition_summary, formatted);
         final String line1 = mContext.getString(R.string.downtime_condition_line_one);
         return new Condition(id, summary, line1, formatted, 0, state, Condition.FLAG_RELEVANT_NOW);
@@ -302,6 +311,11 @@
 
     private void onEvaluateNextAlarm(AlarmClockInfo nextAlarm, long wakeupTime, boolean booted) {
         if (!booted) return;  // we don't know yet
+        // update condition description if we're in downtime (mode = none)
+        if (isInDowntime() && mConfig != null && mConfig.sleepNone) {
+            notifyCondition(createCondition(mConfig.toDowntimeInfo(), true /*orAlarm*/,
+                    Condition.STATE_TRUE));
+        }
         if (nextAlarm == null) return;  // not fireable
         if (DEBUG) Slog.d(TAG, "onEvaluateNextAlarm " + mTracker.formatAlarmDebug(nextAlarm));
         if (System.currentTimeMillis() > wakeupTime) {
@@ -336,6 +350,10 @@
             } else if (Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
                 if (DEBUG) Slog.d(TAG, "timezone changed to " + TimeZone.getDefault());
                 mCalendar.setTimeZone(TimeZone.getDefault());
+                mFiredAlarms.clear();
+            } else if (Intent.ACTION_TIME_CHANGED.equals(action)) {
+                if (DEBUG) Slog.d(TAG, "time changed to " + now);
+                mFiredAlarms.clear();
             } else {
                 if (DEBUG) Slog.d(TAG, action + " fired at " + now);
             }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9a2451e..195a886 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4278,7 +4278,7 @@
                 if (pkg.mVersionCode < ps.versionCode) {
                     // The system package has been updated and the code path does not match
                     // Ignore entry. Skip it.
-                    logCriticalInfo(Log.INFO, "Package " + ps.name + " at " + scanFile
+                    Slog.i(TAG, "Package " + ps.name + " at " + scanFile
                             + " ignored: updated version " + ps.versionCode
                             + " better than this " + pkg.mVersionCode);
                     if (!updatedPkg.codePath.equals(scanFile)) {
@@ -6437,7 +6437,7 @@
             mResolveActivity.applicationInfo = pkg.applicationInfo;
             mResolveActivity.name = mCustomResolverComponentName.getClassName();
             mResolveActivity.packageName = pkg.applicationInfo.packageName;
-            mResolveActivity.processName = null;
+            mResolveActivity.processName = pkg.applicationInfo.packageName;
             mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
             mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS |
                     ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
@@ -8982,6 +8982,7 @@
                         && isVerificationEnabled(userIdentifier, installFlags)) {
                     final Intent verification = new Intent(
                             Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
+                    verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
                     verification.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
                             PACKAGE_MIME_TYPE);
                     verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index c054e6c..4d8b98f 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -1234,6 +1234,7 @@
             // Phase 0: Basic state updates.
             updateIsPoweredLocked(mDirty);
             updateStayOnLocked(mDirty);
+            updateScreenBrightnessBoostLocked(mDirty);
 
             // Phase 1: Update wakefulness.
             // Loop because the wake lock and user activity computations are influenced
@@ -1641,7 +1642,8 @@
                 || mProximityPositive
                 || (mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) != 0
                 || (mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT
-                        | USER_ACTIVITY_SCREEN_DIM)) != 0;
+                        | USER_ACTIVITY_SCREEN_DIM)) != 0
+                || mScreenBrightnessBoostInProgress;
     }
 
     /**
@@ -1828,9 +1830,6 @@
                 | DIRTY_SETTINGS | DIRTY_SCREEN_BRIGHTNESS_BOOST)) != 0) {
             mDisplayPowerRequest.policy = getDesiredScreenPolicyLocked();
 
-            // Handle screen brightness boost timeout.
-            updateScreenBrightnessBoostLocked();
-
             // Determine appropriate screen brightness and auto-brightness adjustments.
             int screenBrightness = mScreenBrightnessSettingDefault;
             float screenAutoBrightnessAdjustment = 0.0f;
@@ -1879,7 +1878,7 @@
             }
 
             mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,
-                    mRequestWaitForNegativeProximity) && !mScreenBrightnessBoostInProgress;
+                    mRequestWaitForNegativeProximity);
             mRequestWaitForNegativeProximity = false;
 
             if (DEBUG_SPEW) {
@@ -1896,20 +1895,25 @@
         return mDisplayReady && !oldDisplayReady;
     }
 
-    private void updateScreenBrightnessBoostLocked() {
-        if (mScreenBrightnessBoostInProgress) {
-            mHandler.removeMessages(MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT);
-            if (mLastScreenBrightnessBoostTime > mLastSleepTime) {
-                final long boostTimeout = mLastScreenBrightnessBoostTime +
-                        SCREEN_BRIGHTNESS_BOOST_TIMEOUT;
-                if (boostTimeout > SystemClock.uptimeMillis()) {
-                    Message msg = mHandler.obtainMessage(MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT);
-                    msg.setAsynchronous(true);
-                    mHandler.sendMessageAtTime(msg, boostTimeout);
-                    return;
+    private void updateScreenBrightnessBoostLocked(int dirty) {
+        if ((dirty & DIRTY_SCREEN_BRIGHTNESS_BOOST) != 0) {
+            if (mScreenBrightnessBoostInProgress) {
+                final long now = SystemClock.uptimeMillis();
+                mHandler.removeMessages(MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT);
+                if (mLastScreenBrightnessBoostTime > mLastSleepTime) {
+                    final long boostTimeout = mLastScreenBrightnessBoostTime +
+                            SCREEN_BRIGHTNESS_BOOST_TIMEOUT;
+                    if (boostTimeout > now) {
+                        Message msg = mHandler.obtainMessage(MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT);
+                        msg.setAsynchronous(true);
+                        mHandler.sendMessageAtTime(msg, boostTimeout);
+                        return;
+                    }
                 }
+                mScreenBrightnessBoostInProgress = false;
+                userActivityNoUpdateLocked(now,
+                        PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
             }
-            mScreenBrightnessBoostInProgress = false;
         }
     }
 
@@ -1940,7 +1944,8 @@
 
         if ((mWakeLockSummary & WAKE_LOCK_SCREEN_BRIGHT) != 0
                 || (mUserActivitySummary & USER_ACTIVITY_SCREEN_BRIGHT) != 0
-                || !mBootCompleted) {
+                || !mBootCompleted
+                || mScreenBrightnessBoostInProgress) {
             return DisplayPowerRequest.POLICY_BRIGHT;
         }
 
@@ -2037,15 +2042,13 @@
         final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0);
         final boolean needDisplaySuspendBlocker = needDisplaySuspendBlockerLocked();
         final boolean autoSuspend = !needDisplaySuspendBlocker;
+        final boolean interactive = mDisplayPowerRequest.isBrightOrDim();
 
         // Disable auto-suspend if needed.
-        if (!autoSuspend) {
-            if (mDecoupleHalAutoSuspendModeFromDisplayConfig) {
-                setHalAutoSuspendModeLocked(false);
-            }
-            if (mDecoupleHalInteractiveModeFromDisplayConfig) {
-                setHalInteractiveModeLocked(true);
-            }
+        // FIXME We should consider just leaving auto-suspend enabled forever since
+        // we already hold the necessary wakelocks.
+        if (!autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+            setHalAutoSuspendModeLocked(false);
         }
 
         // First acquire suspend blockers if needed.
@@ -2058,6 +2061,22 @@
             mHoldingDisplaySuspendBlocker = true;
         }
 
+        // Inform the power HAL about interactive mode.
+        // Although we could set interactive strictly based on the wakefulness
+        // as reported by isInteractive(), it is actually more desirable to track
+        // the display policy state instead so that the interactive state observed
+        // by the HAL more accurately tracks transitions between AWAKE and DOZING.
+        // Refer to getDesiredScreenPolicyLocked() for details.
+        if (mDecoupleHalInteractiveModeFromDisplayConfig) {
+            // When becoming non-interactive, we want to defer sending this signal
+            // until the display is actually ready so that all transitions have
+            // completed.  This is probably a good sign that things have gotten
+            // too tangled over here...
+            if (interactive || mDisplayReady) {
+                setHalInteractiveModeLocked(interactive);
+            }
+        }
+
         // Then release suspend blockers if needed.
         if (!needWakeLockSuspendBlocker && mHoldingWakeLockSuspendBlocker) {
             mWakeLockSuspendBlocker.release();
@@ -2069,13 +2088,8 @@
         }
 
         // Enable auto-suspend if needed.
-        if (autoSuspend) {
-            if (mDecoupleHalInteractiveModeFromDisplayConfig) {
-                setHalInteractiveModeLocked(false);
-            }
-            if (mDecoupleHalAutoSuspendModeFromDisplayConfig) {
-                setHalAutoSuspendModeLocked(true);
-            }
+        if (autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+            setHalAutoSuspendModeLocked(true);
         }
     }
 
@@ -2097,6 +2111,9 @@
                 return true;
             }
         }
+        if (mScreenBrightnessBoostInProgress) {
+            return true;
+        }
         // Let the system suspend if the screen is off or dozing.
         return false;
     }
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index f947b6a..7e6da8b5 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -984,12 +984,7 @@
 
                 final int visibleWindowCount = visibleWindows.size();
                 for (int i = visibleWindowCount - 1; i >= 0; i--) {
-                    WindowState windowState = visibleWindows.valueAt(i);
-
-                    // Compute the bounds in the screen.
-                    Rect boundsInScreen = mTempRect;
-                    computeWindowBoundsInScreen(windowState, boundsInScreen);
-
+                    final WindowState windowState = visibleWindows.valueAt(i);
                     final int flags = windowState.mAttrs.flags;
 
                     // If the window is not touchable - ignore.
@@ -997,6 +992,16 @@
                         continue;
                     }
 
+                    // If the window is an accessibility overlay - ignore.
+                    if (windowState.mAttrs.type ==
+                            WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
+                        continue;
+                    }
+
+                    // Compute the bounds in the screen.
+                    final Rect boundsInScreen = mTempRect;
+                    computeWindowBoundsInScreen(windowState, boundsInScreen);
+
                     // If the window is completely covered by other windows - ignore.
                     if (unaccountedSpace.quickReject(boundsInScreen)) {
                         continue;
@@ -1013,14 +1018,8 @@
                         }
                     }
 
-                    // Account for the space this window takes if the window
-                    // is not an accessibility overlay which does not change
-                    // the reported windows.
-                    if (windowState.mAttrs.type == WindowManager.LayoutParams
-                            .TYPE_ACCESSIBILITY_OVERLAY) {
-                        unaccountedSpace.op(boundsInScreen, unaccountedSpace,
-                                Region.Op.REVERSE_DIFFERENCE);
-                    }
+                    unaccountedSpace.op(boundsInScreen, unaccountedSpace,
+                            Region.Op.REVERSE_DIFFERENCE);
 
                     // We figured out what is touchable for the entire screen - done.
                     if (unaccountedSpace.isEmpty()) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index eb418ed6..bcfd7f0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2541,7 +2541,7 @@
             }
             mInputMonitor.updateInputWindowsLw(false /*force*/);
 
-            if (true || localLOGV || DEBUG_ADD_REMOVE) Slog.v(TAG, "addWindow: New client "
+            if (localLOGV || DEBUG_ADD_REMOVE) Slog.v(TAG, "addWindow: New client "
                     + client.asBinder() + ": window=" + win + " Callers=" + Debug.getCallers(5));
 
             if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false)) {
@@ -2706,8 +2706,7 @@
         mPolicy.removeWindowLw(win);
         win.removeLocked();
 
-        if (true || DEBUG_ADD_REMOVE) Slog.v(TAG, "removeWindowInnerLocked: " + win +
-                " Callers=" + Debug.getCallers(5));
+        if (DEBUG_ADD_REMOVE) Slog.v(TAG, "removeWindowInnerLocked: " + win);
         mWindowMap.remove(win.mClient.asBinder());
         if (win.mAppOp != AppOpsManager.OP_NONE) {
             mAppOps.finishOp(win.mAppOp, win.getOwningUid(), win.getOwningPackage());
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 0713772..9e51849 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -900,23 +900,25 @@
         if (DBG) Slog.d(LOG_TAG, "Handling package changes for user " + userHandle);
         DevicePolicyData policy = getUserData(userHandle);
         IPackageManager pm = AppGlobals.getPackageManager();
-        for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
-            ActiveAdmin aa = policy.mAdminList.get(i);
-            try {
-                if (pm.getPackageInfo(aa.info.getPackageName(), 0, userHandle) == null
-                        || pm.getReceiverInfo(aa.info.getComponent(), 0, userHandle) == null) {
-                    removed = true;
-                    policy.mAdminList.remove(i);
-                    policy.mAdminMap.remove(aa.info.getComponent());
+        synchronized (this) {
+            for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
+                ActiveAdmin aa = policy.mAdminList.get(i);
+                try {
+                    if (pm.getPackageInfo(aa.info.getPackageName(), 0, userHandle) == null
+                            || pm.getReceiverInfo(aa.info.getComponent(), 0, userHandle) == null) {
+                        removed = true;
+                        policy.mAdminList.remove(i);
+                        policy.mAdminMap.remove(aa.info.getComponent());
+                    }
+                } catch (RemoteException re) {
+                    // Shouldn't happen
                 }
-            } catch (RemoteException re) {
-                // Shouldn't happen
             }
-        }
-        if (removed) {
-            validatePasswordOwnerLocked(policy);
-            syncDeviceCapabilitiesLocked(policy);
-            saveSettingsLocked(policy.mUserHandle);
+            if (removed) {
+                validatePasswordOwnerLocked(policy);
+                syncDeviceCapabilitiesLocked(policy);
+                saveSettingsLocked(policy.mUserHandle);
+            }
         }
     }
 
diff --git a/services/usb/java/com/android/server/usb/UsbDebuggingManager.java b/services/usb/java/com/android/server/usb/UsbDebuggingManager.java
index cc5d004..1cf00d2 100644
--- a/services/usb/java/com/android/server/usb/UsbDebuggingManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDebuggingManager.java
@@ -207,7 +207,12 @@
 
                 case MESSAGE_ADB_CONFIRM: {
                     String key = (String)msg.obj;
-                    mFingerprints = getFingerprints(key);
+                    String fingerprints = getFingerprints(key);
+                    if ("".equals(fingerprints)) {
+                        sendResponse("NO");
+                        break;
+                    }
+                    mFingerprints = fingerprints;
                     startConfirmation(key, mFingerprints);
                     break;
                 }
@@ -224,16 +229,25 @@
         StringBuilder sb = new StringBuilder();
         MessageDigest digester;
 
+        if (key == null) {
+            return "";
+        }
+
         try {
             digester = MessageDigest.getInstance("MD5");
         } catch (Exception ex) {
-            Slog.e(TAG, "Error getting digester: " + ex);
+            Slog.e(TAG, "Error getting digester", ex);
             return "";
         }
 
         byte[] base64_data = key.split("\\s+")[0].getBytes();
-        byte[] digest = digester.digest(Base64.decode(base64_data, Base64.DEFAULT));
-
+        byte[] digest;
+        try {
+            digest = digester.digest(Base64.decode(base64_data, Base64.DEFAULT));
+        } catch (IllegalArgumentException e) {
+            Slog.e(TAG, "error doing base64 decoding", e);
+            return "";
+        }
         for (int i = 0; i < digest.length; i++) {
             sb.append(hex.charAt((digest[i] >> 4) & 0xf));
             sb.append(hex.charAt(digest[i] & 0xf));
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable30.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable30.xml
new file mode 100644
index 0000000..3dff196
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable30.xml
@@ -0,0 +1,28 @@
+<!--
+ 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"
+        android:height="48dp"
+        android:width="48dp"
+        android:viewportHeight="48"
+        android:viewportWidth="48" >
+
+    <group>
+        <path
+            android:name="plus1"
+            android:pathData="M20 16h-4v8h-8v4h8v8h4v-8h8v-4h-8zm9-3.84v3.64l5-1v21.2h4v-26z"
+            android:fillColor="#ff00ff00"/>
+    </group>
+</vector>
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
index 1cd6533..5a2e5a7 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
@@ -57,6 +57,7 @@
             R.drawable.vector_drawable27,
             R.drawable.vector_drawable28,
             R.drawable.vector_drawable29,
+            R.drawable.vector_drawable30,
     };
 
     @Override