Merge "ImageSwitcher -> ImageView in appcompat inflate"
diff --git a/api/current.txt b/api/current.txt
index 64838a4..69a3000 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2844,6 +2844,7 @@
   public class AccountManager {
     method public android.accounts.AccountManagerFuture<android.os.Bundle> addAccount(java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle);
+    method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle, int[]);
     method public void addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean);
     method public java.lang.String blockingGetAuthToken(android.accounts.Account, java.lang.String, boolean) throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
     method public void clearPassword(android.accounts.Account);
@@ -2862,10 +2863,13 @@
     method public android.accounts.AuthenticatorDescription[] getAuthenticatorTypes();
     method public java.lang.String getPassword(android.accounts.Account);
     method public java.lang.String getPreviousName(android.accounts.Account);
+    method public int[] getRequestingUidsForType(java.lang.String);
     method public java.lang.String getUserData(android.accounts.Account, java.lang.String);
     method public android.accounts.AccountManagerFuture<java.lang.Boolean> hasFeatures(android.accounts.Account, java.lang.String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
     method public void invalidateAuthToken(java.lang.String, java.lang.String);
+    method public boolean isAccountVisible(android.accounts.Account, int);
     method public android.accounts.AccountManagerFuture<java.lang.Boolean> isCredentialsUpdateSuggested(android.accounts.Account, java.lang.String, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
+    method public boolean makeAccountVisible(android.accounts.Account, int);
     method public static deprecated 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 static android.content.Intent newChooseAccountIntent(android.accounts.Account, java.util.List<android.accounts.Account>, java.lang.String[], java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle);
     method public boolean notifyAccountAuthenticated(android.accounts.Account);
@@ -2873,6 +2877,7 @@
     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 boolean removeAccountVisibility(android.accounts.Account, int);
     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);
@@ -22572,8 +22577,10 @@
     method public java.util.List<android.media.session.MediaSession.QueueItem> getQueue();
     method public java.lang.CharSequence getQueueTitle();
     method public int getRatingType();
+    method public int getRepeatMode();
     method public android.app.PendingIntent getSessionActivity();
     method public android.media.session.MediaSession.Token getSessionToken();
+    method public boolean getShuffleMode();
     method public android.media.session.MediaController.TransportControls getTransportControls();
     method public void registerCallback(android.media.session.MediaController.Callback);
     method public void registerCallback(android.media.session.MediaController.Callback, android.os.Handler);
@@ -22590,8 +22597,10 @@
     method public void onPlaybackStateChanged(android.media.session.PlaybackState);
     method public void onQueueChanged(java.util.List<android.media.session.MediaSession.QueueItem>);
     method public void onQueueTitleChanged(java.lang.CharSequence);
+    method public void onRepeatModeChanged(int);
     method public void onSessionDestroyed();
     method public void onSessionEvent(java.lang.String, android.os.Bundle);
+    method public void onShuffleModeChanged(boolean);
   }
 
   public static final class MediaController.PlaybackInfo {
@@ -22620,6 +22629,8 @@
     method public void sendCustomAction(android.media.session.PlaybackState.CustomAction, android.os.Bundle);
     method public void sendCustomAction(java.lang.String, android.os.Bundle);
     method public void setRating(android.media.Rating);
+    method public void setRepeatMode(int);
+    method public void setShuffleMode(boolean);
     method public void skipToNext();
     method public void skipToPrevious();
     method public void skipToQueueItem(long);
@@ -22646,7 +22657,9 @@
     method public void setQueue(java.util.List<android.media.session.MediaSession.QueueItem>);
     method public void setQueueTitle(java.lang.CharSequence);
     method public void setRatingType(int);
+    method public void setRepeatMode(int);
     method public void setSessionActivity(android.app.PendingIntent);
+    method public void setShuffleMode(boolean);
     field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
     field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
   }
@@ -22669,6 +22682,8 @@
     method public void onRewind();
     method public void onSeekTo(long);
     method public void onSetRating(android.media.Rating);
+    method public void onSetRepeatMode(int);
+    method public void onSetShuffleMode(boolean);
     method public void onSkipToNext();
     method public void onSkipToPrevious();
     method public void onSkipToQueueItem(long);
@@ -22729,12 +22744,17 @@
     field public static final long ACTION_REWIND = 8L; // 0x8L
     field public static final long ACTION_SEEK_TO = 256L; // 0x100L
     field public static final long ACTION_SET_RATING = 128L; // 0x80L
+    field public static final long ACTION_SET_REPEAT_MODE = 262144L; // 0x40000L
+    field public static final long ACTION_SET_SHUFFLE_MODE = 524288L; // 0x80000L
     field public static final long ACTION_SKIP_TO_NEXT = 32L; // 0x20L
     field public static final long ACTION_SKIP_TO_PREVIOUS = 16L; // 0x10L
     field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
     field public static final long ACTION_STOP = 1L; // 0x1L
     field public static final android.os.Parcelable.Creator<android.media.session.PlaybackState> CREATOR;
     field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
+    field public static final int REPEAT_MODE_ALL = 2; // 0x2
+    field public static final int REPEAT_MODE_NONE = 0; // 0x0
+    field public static final int REPEAT_MODE_ONE = 1; // 0x1
     field public static final int STATE_BUFFERING = 6; // 0x6
     field public static final int STATE_CONNECTING = 8; // 0x8
     field public static final int STATE_ERROR = 7; // 0x7
diff --git a/api/system-current.txt b/api/system-current.txt
index c7a05b2..d5eb5fa 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -2958,6 +2958,7 @@
   public class AccountManager {
     method public android.accounts.AccountManagerFuture<android.os.Bundle> addAccount(java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle);
+    method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle, int[]);
     method public void addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean);
     method public java.lang.String blockingGetAuthToken(android.accounts.Account, java.lang.String, boolean) throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
     method public void clearPassword(android.accounts.Account);
@@ -2977,10 +2978,13 @@
     method public android.accounts.AuthenticatorDescription[] getAuthenticatorTypes();
     method public java.lang.String getPassword(android.accounts.Account);
     method public java.lang.String getPreviousName(android.accounts.Account);
+    method public int[] getRequestingUidsForType(java.lang.String);
     method public java.lang.String getUserData(android.accounts.Account, java.lang.String);
     method public android.accounts.AccountManagerFuture<java.lang.Boolean> hasFeatures(android.accounts.Account, java.lang.String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
     method public void invalidateAuthToken(java.lang.String, java.lang.String);
+    method public boolean isAccountVisible(android.accounts.Account, int);
     method public android.accounts.AccountManagerFuture<java.lang.Boolean> isCredentialsUpdateSuggested(android.accounts.Account, java.lang.String, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
+    method public boolean makeAccountVisible(android.accounts.Account, int);
     method public static deprecated 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 static android.content.Intent newChooseAccountIntent(android.accounts.Account, java.util.List<android.accounts.Account>, java.lang.String[], java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle);
     method public boolean notifyAccountAuthenticated(android.accounts.Account);
@@ -2988,6 +2992,7 @@
     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 boolean removeAccountVisibility(android.accounts.Account, int);
     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);
@@ -24158,8 +24163,10 @@
     method public java.util.List<android.media.session.MediaSession.QueueItem> getQueue();
     method public java.lang.CharSequence getQueueTitle();
     method public int getRatingType();
+    method public int getRepeatMode();
     method public android.app.PendingIntent getSessionActivity();
     method public android.media.session.MediaSession.Token getSessionToken();
+    method public boolean getShuffleMode();
     method public android.media.session.MediaController.TransportControls getTransportControls();
     method public void registerCallback(android.media.session.MediaController.Callback);
     method public void registerCallback(android.media.session.MediaController.Callback, android.os.Handler);
@@ -24176,8 +24183,10 @@
     method public void onPlaybackStateChanged(android.media.session.PlaybackState);
     method public void onQueueChanged(java.util.List<android.media.session.MediaSession.QueueItem>);
     method public void onQueueTitleChanged(java.lang.CharSequence);
+    method public void onRepeatModeChanged(int);
     method public void onSessionDestroyed();
     method public void onSessionEvent(java.lang.String, android.os.Bundle);
+    method public void onShuffleModeChanged(boolean);
   }
 
   public static final class MediaController.PlaybackInfo {
@@ -24206,6 +24215,8 @@
     method public void sendCustomAction(android.media.session.PlaybackState.CustomAction, android.os.Bundle);
     method public void sendCustomAction(java.lang.String, android.os.Bundle);
     method public void setRating(android.media.Rating);
+    method public void setRepeatMode(int);
+    method public void setShuffleMode(boolean);
     method public void skipToNext();
     method public void skipToPrevious();
     method public void skipToQueueItem(long);
@@ -24232,7 +24243,9 @@
     method public void setQueue(java.util.List<android.media.session.MediaSession.QueueItem>);
     method public void setQueueTitle(java.lang.CharSequence);
     method public void setRatingType(int);
+    method public void setRepeatMode(int);
     method public void setSessionActivity(android.app.PendingIntent);
+    method public void setShuffleMode(boolean);
     field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
     field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
   }
@@ -24255,6 +24268,8 @@
     method public void onRewind();
     method public void onSeekTo(long);
     method public void onSetRating(android.media.Rating);
+    method public void onSetRepeatMode(int);
+    method public void onSetShuffleMode(boolean);
     method public void onSkipToNext();
     method public void onSkipToPrevious();
     method public void onSkipToQueueItem(long);
@@ -24315,12 +24330,17 @@
     field public static final long ACTION_REWIND = 8L; // 0x8L
     field public static final long ACTION_SEEK_TO = 256L; // 0x100L
     field public static final long ACTION_SET_RATING = 128L; // 0x80L
+    field public static final long ACTION_SET_REPEAT_MODE = 262144L; // 0x40000L
+    field public static final long ACTION_SET_SHUFFLE_MODE = 524288L; // 0x80000L
     field public static final long ACTION_SKIP_TO_NEXT = 32L; // 0x20L
     field public static final long ACTION_SKIP_TO_PREVIOUS = 16L; // 0x10L
     field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
     field public static final long ACTION_STOP = 1L; // 0x1L
     field public static final android.os.Parcelable.Creator<android.media.session.PlaybackState> CREATOR;
     field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
+    field public static final int REPEAT_MODE_ALL = 2; // 0x2
+    field public static final int REPEAT_MODE_NONE = 0; // 0x0
+    field public static final int REPEAT_MODE_ONE = 1; // 0x1
     field public static final int STATE_BUFFERING = 6; // 0x6
     field public static final int STATE_CONNECTING = 8; // 0x8
     field public static final int STATE_ERROR = 7; // 0x7
diff --git a/api/test-current.txt b/api/test-current.txt
index 881d290..ce7c674 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -2844,6 +2844,7 @@
   public class AccountManager {
     method public android.accounts.AccountManagerFuture<android.os.Bundle> addAccount(java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle);
+    method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle, int[]);
     method public void addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean);
     method public java.lang.String blockingGetAuthToken(android.accounts.Account, java.lang.String, boolean) throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
     method public void clearPassword(android.accounts.Account);
@@ -2862,10 +2863,13 @@
     method public android.accounts.AuthenticatorDescription[] getAuthenticatorTypes();
     method public java.lang.String getPassword(android.accounts.Account);
     method public java.lang.String getPreviousName(android.accounts.Account);
+    method public int[] getRequestingUidsForType(java.lang.String);
     method public java.lang.String getUserData(android.accounts.Account, java.lang.String);
     method public android.accounts.AccountManagerFuture<java.lang.Boolean> hasFeatures(android.accounts.Account, java.lang.String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
     method public void invalidateAuthToken(java.lang.String, java.lang.String);
+    method public boolean isAccountVisible(android.accounts.Account, int);
     method public android.accounts.AccountManagerFuture<java.lang.Boolean> isCredentialsUpdateSuggested(android.accounts.Account, java.lang.String, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
+    method public boolean makeAccountVisible(android.accounts.Account, int);
     method public static deprecated 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 static android.content.Intent newChooseAccountIntent(android.accounts.Account, java.util.List<android.accounts.Account>, java.lang.String[], java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle);
     method public boolean notifyAccountAuthenticated(android.accounts.Account);
@@ -2873,6 +2877,7 @@
     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 boolean removeAccountVisibility(android.accounts.Account, int);
     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);
@@ -22642,8 +22647,10 @@
     method public java.util.List<android.media.session.MediaSession.QueueItem> getQueue();
     method public java.lang.CharSequence getQueueTitle();
     method public int getRatingType();
+    method public int getRepeatMode();
     method public android.app.PendingIntent getSessionActivity();
     method public android.media.session.MediaSession.Token getSessionToken();
+    method public boolean getShuffleMode();
     method public android.media.session.MediaController.TransportControls getTransportControls();
     method public void registerCallback(android.media.session.MediaController.Callback);
     method public void registerCallback(android.media.session.MediaController.Callback, android.os.Handler);
@@ -22660,8 +22667,10 @@
     method public void onPlaybackStateChanged(android.media.session.PlaybackState);
     method public void onQueueChanged(java.util.List<android.media.session.MediaSession.QueueItem>);
     method public void onQueueTitleChanged(java.lang.CharSequence);
+    method public void onRepeatModeChanged(int);
     method public void onSessionDestroyed();
     method public void onSessionEvent(java.lang.String, android.os.Bundle);
+    method public void onShuffleModeChanged(boolean);
   }
 
   public static final class MediaController.PlaybackInfo {
@@ -22690,6 +22699,8 @@
     method public void sendCustomAction(android.media.session.PlaybackState.CustomAction, android.os.Bundle);
     method public void sendCustomAction(java.lang.String, android.os.Bundle);
     method public void setRating(android.media.Rating);
+    method public void setRepeatMode(int);
+    method public void setShuffleMode(boolean);
     method public void skipToNext();
     method public void skipToPrevious();
     method public void skipToQueueItem(long);
@@ -22716,7 +22727,9 @@
     method public void setQueue(java.util.List<android.media.session.MediaSession.QueueItem>);
     method public void setQueueTitle(java.lang.CharSequence);
     method public void setRatingType(int);
+    method public void setRepeatMode(int);
     method public void setSessionActivity(android.app.PendingIntent);
+    method public void setShuffleMode(boolean);
     field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
     field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
   }
@@ -22739,6 +22752,8 @@
     method public void onRewind();
     method public void onSeekTo(long);
     method public void onSetRating(android.media.Rating);
+    method public void onSetRepeatMode(int);
+    method public void onSetShuffleMode(boolean);
     method public void onSkipToNext();
     method public void onSkipToPrevious();
     method public void onSkipToQueueItem(long);
@@ -22799,12 +22814,17 @@
     field public static final long ACTION_REWIND = 8L; // 0x8L
     field public static final long ACTION_SEEK_TO = 256L; // 0x100L
     field public static final long ACTION_SET_RATING = 128L; // 0x80L
+    field public static final long ACTION_SET_REPEAT_MODE = 262144L; // 0x40000L
+    field public static final long ACTION_SET_SHUFFLE_MODE = 524288L; // 0x80000L
     field public static final long ACTION_SKIP_TO_NEXT = 32L; // 0x20L
     field public static final long ACTION_SKIP_TO_PREVIOUS = 16L; // 0x10L
     field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
     field public static final long ACTION_STOP = 1L; // 0x1L
     field public static final android.os.Parcelable.Creator<android.media.session.PlaybackState> CREATOR;
     field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
+    field public static final int REPEAT_MODE_ALL = 2; // 0x2
+    field public static final int REPEAT_MODE_NONE = 0; // 0x0
+    field public static final int REPEAT_MODE_ONE = 1; // 0x1
     field public static final int STATE_BUFFERING = 6; // 0x6
     field public static final int STATE_CONNECTING = 8; // 0x8
     field public static final int STATE_ERROR = 7; // 0x7
diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java
index d7f23cb..2e9d0d6 100644
--- a/cmds/media/src/com/android/commands/media/Media.java
+++ b/cmds/media/src/com/android/commands/media/Media.java
@@ -57,6 +57,7 @@
         (new Media()).run(args);
     }
 
+    @Override
     public void onShowUsage(PrintStream out) {
         out.println(
                 "usage: media [subcommand] [options]\n" +
@@ -73,6 +74,7 @@
         );
     }
 
+    @Override
     public void onRun() throws Exception {
         mSessionService = ISessionManager.Stub.asInterface(ServiceManager.checkService(
                 Context.MEDIA_SESSION_SERVICE));
@@ -222,6 +224,16 @@
             System.out.println("onVolumeInfoChanged " + info);
         }
 
+        @Override
+        public void onRepeatModeChanged(int repeatMode) throws RemoteException {
+            System.out.println("onRepeatModeChanged " + repeatMode);
+        }
+
+        @Override
+        public void onShuffleModeChanged(boolean shuffleMode) throws RemoteException {
+            System.out.println("onShuffleModeChanged " + shuffleMode);
+        }
+
         void printUsageMessage() {
             try {
                 System.out.println("V2Monitoring session " + mController.getTag()
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 88b1297..59d2f18 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -733,6 +733,115 @@
     }
 
     /**
+     * Adds an account directly to the AccountManager. Additionally this
+     * makes the Account visible to desired UIDs of applications on the device,
+     * and sends directed broadcasts to these individual applications.
+     * <p>Normally used by sign-up wizards associated with authenticators, not
+     *  directly by applications.
+     * <p>Calling this method does not update the last authenticated timestamp,
+     * referred by {@link #KEY_LAST_AUTHENTICATED_TIME}. To update it, call
+     * {@link #notifyAccountAuthenticated(Account)} after getting success.
+     * <p>It is safe to call this method from the main thread.
+     * <p>This method requires the caller to have a signature match with the
+     * authenticator that owns the specified account.
+     *
+     * @param account The {@link Account} to add
+     * @param password The password to associate with the account, null for none
+     * @param extras String values to use for the account's userdata, null for
+     *            none
+     * @param selectedUids Array of uids whose associated applications can access
+     * this account without any additional user approval.
+     *
+     * @return True if the account was successfully added, false if the account
+     *         already exists, the account is null, or another error occurs.
+     */
+    public boolean addAccountExplicitly(Account account, String password, Bundle extras,
+                int[] selectedUids) {
+        if (account == null) throw new IllegalArgumentException("account is null");
+        try {
+            return mService.addAccountExplicitlyWithUid(account, password, extras, selectedUids);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns all UIDs for applications that requested the account type.
+     * <p>This method requires the caller to have a signature match with the authenticator
+     * that owns the specified account.
+     *
+     * @param accountType The account type to be authenticated.
+     *
+     * @return array of all UIDs that support accounts of this
+     * account type that seek approval (to be used to know which accounts for
+     * the authenticator to include in addAccountExplicitly). Null if none.
+     */
+    public int[] getRequestingUidsForType(String accountType) {
+        try {
+            return mService.getRequestingUidsForType(accountType);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Gives a certain UID, represented a application, access to an account
+     * <p>This method requires the caller to have a signature match with the authenticator
+     * that owns the specified account.
+     *
+     * @param account Account to make visible.
+     * @param uid The UID of the application to add account access.
+     *
+     * @return True if account made visible to application and was not previously visible.
+     */
+    public boolean makeAccountVisible(Account account, int uid) {
+        try {
+            return mService.makeAccountVisible(account, uid);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Removes visibility of certain account of a process identified
+     * by a given UID to an application.
+     * This is called by the Authenticator.
+     * <p>This method requires the caller to have a signature match with the authenticator
+     * that owns the specified account.
+     *
+     * @param account Remove visibility of this account..
+     * @param uid The UID of the application to remove account access.
+     *
+     * @return True if application access to account removed and was previously visible.
+     */
+    public boolean removeAccountVisibility(Account account, int uid) {
+        try {
+            return mService.removeAccountVisibility(account, uid);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Checks visibility of certain account of a process identified
+     * by a given UID. This is called by the Authenticator.
+     * <p>This method requires the caller to have a signature match with the authenticator
+     * that owns the specified account.
+     *
+     * @param account Account to check visibility.
+     * @param uid The UID of the application to check account access.
+     *
+     * @return True if application has access to the account
+     */
+    public boolean isAccountVisible(Account account, int uid) {
+        try {
+            return mService.isAccountVisible(account, uid);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Notifies the system that the account has just been authenticated. This
      * information may be used by other applications to verify the account. This
      * should be called only when the user has entered correct credentials for
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index 7199288..c52faeb 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -21,7 +21,6 @@
 import android.accounts.AuthenticatorDescription;
 import android.os.Bundle;
 
-
 /**
  * Central application service that provides account management.
  * @hide
@@ -92,7 +91,8 @@
     void startUpdateCredentialsSession(in IAccountManagerResponse response, in Account account,
         String authTokenType, boolean expectActivityLaunch, in Bundle options);
 
-    /* Finish session started by startAddAccountSession(...) or startUpdateCredentialsSession(...) for user */
+    /* Finish session started by startAddAccountSession(...) or startUpdateCredentialsSession(...)
+    for user */
     void finishSessionAsUser(in IAccountManagerResponse response, in Bundle sessionBundle,
         boolean expectActivityLaunch, in Bundle appInfo, int userId);
 
@@ -102,4 +102,17 @@
     /* Check if credentials update is suggested */
     void isCredentialsUpdateSuggested(in IAccountManagerResponse response, in Account account,
         String statusToken);
+
+    /* Allows Authenticator to view what packages or UIDs on phone have requested it. */
+    int[] getRequestingUidsForType(String accountType);
+
+    /* Allows authenticator to add an account explicitly that is only visible to
+     certain uids; the authenticator learns of these UIDs */
+    boolean addAccountExplicitlyWithUid(in Account account, String password, in Bundle extras,
+            in int[] selectedUids);
+
+    /* Controls visibility of UIDs of applications to Accounts */
+    boolean removeAccountVisibility(in Account a, in int uid);
+    boolean makeAccountVisible(in Account a, in int uid);
+    boolean isAccountVisible(in Account a, in int uid);
 }
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 5d87528..8cc1bc4 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -2080,14 +2080,8 @@
     @Override
     public void setComponentEnabledSetting(ComponentName componentName,
                                            int newState, int flags) {
-        setComponentEnabledSettingAsUser(componentName, newState, flags, mContext.getUserId());
-    }
-
-    @Override
-    public void setComponentEnabledSettingAsUser(ComponentName componentName,
-            int newState, int flags, int userId) {
         try {
-            mPM.setComponentEnabledSetting(componentName, newState, flags, userId);
+            mPM.setComponentEnabledSetting(componentName, newState, flags, mContext.getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2105,16 +2099,9 @@
     @Override
     public void setApplicationEnabledSetting(String packageName,
                                              int newState, int flags) {
-        setApplicationEnabledSettingAsUser(packageName, newState, flags,
-                mContext.getUserId());
-    }
-
-    @Override
-    public void setApplicationEnabledSettingAsUser(String packageName,
-            int newState, int flags, int userId) {
         try {
             mPM.setApplicationEnabledSetting(packageName, newState, flags,
-                    userId, mContext.getOpPackageName());
+                    mContext.getUserId(), mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index b9b609b..6b23da9 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -492,7 +492,7 @@
      * If the calling launcher application contains pinned shortcuts, they will still work,
      * even though the caller no longer has the shortcut host permission.
      *
-     * <p>Returns {@code false} when the user is locked.
+     * @throws IllegalStateException when the user is locked.
      *
      * @see ShortcutManager
      */
@@ -510,13 +510,12 @@
      * <p>Callers must be allowed to access the shortcut information, as defined in {@link
      * #hasShortcutHostPermission()}.
      *
-     * <p>Returns am empty list when the user is locked, or when the {@code user} user
-     * is locked or not running.
-     *
      * @param query result includes shortcuts matching this query.
      * @param user The UserHandle of the profile.
      *
      * @return the IDs of {@link ShortcutInfo}s that match the query.
+     * @throws IllegalStateException when the user is locked, or when the {@code user} user
+     * is locked or not running.
      *
      * @see ShortcutManager
      */
@@ -556,12 +555,11 @@
      * <p>The calling launcher application must be allowed to access the shortcut information,
      * as defined in {@link #hasShortcutHostPermission()}.
      *
-     * <p>Call will be ignored when the user is locked, or when the {@code user} user
-     * is locked or not running.
-     *
      * @param packageName The target package name.
      * @param shortcutIds The IDs of the shortcut to be pinned.
      * @param user The UserHandle of the profile.
+     * @throws IllegalStateException when the user is locked, or when the {@code user} user
+     * is locked or not running.
      *
      * @see ShortcutManager
      */
@@ -630,13 +628,12 @@
      * <p>The calling launcher application must be allowed to access the shortcut information,
      * as defined in {@link #hasShortcutHostPermission()}.
      *
-     * <p>Returns {@code null} when the user is locked, or when the user owning the shortcut
-     * is locked or not running.
-     *
      * @param density The preferred density of the icon, zero for default density. Use
      * density DPI values from {@link DisplayMetrics}.
      *
      * @return The drawable associated with the shortcut.
+     * @throws IllegalStateException when the user is locked, or when the {@code user} user
+     * is locked or not running.
      *
      * @see ShortcutManager
      * @see #getShortcutBadgedIconDrawable(ShortcutInfo, int)
@@ -681,11 +678,10 @@
      * <p>The calling launcher application must be allowed to access the shortcut information,
      * as defined in {@link #hasShortcutHostPermission()}.
      *
-     * <p>Returns {@code 0} when the user is locked, or when the user owning the shortcut
-     * is locked or not running.
-     *
      * @param density Optional density for the icon, or 0 to use the default density. Use
      * @return A badged icon for the shortcut.
+     * @throws IllegalStateException when the user is locked, or when the {@code user} user
+     * is locked or not running.
      *
      * @see ShortcutManager
      * @see #getShortcutIconDrawable(ShortcutInfo, int)
@@ -704,15 +700,13 @@
      * <p>The calling launcher application must be allowed to access the shortcut information,
      * as defined in {@link #hasShortcutHostPermission()}.
      *
-     * <p>Throws {@link android.content.ActivityNotFoundException}
-     * when the user is locked, or when the {@code user} user
-     * is locked or not running.
-     *
      * @param packageName The target shortcut package name.
      * @param shortcutId The target shortcut ID.
      * @param sourceBounds The Rect containing the source bounds of the clicked icon.
      * @param startActivityOptions Options to pass to startActivity.
      * @param user The UserHandle of the profile.
+     * @throws IllegalStateException when the user is locked, or when the {@code user} user
+     * is locked or not running.
      *
      * @throws android.content.ActivityNotFoundException failed to start shortcut. (e.g.
      * the shortcut no longer exists, is disabled, the intent receiver activity doesn't exist, etc)
@@ -730,13 +724,11 @@
      * <p>The calling launcher application must be allowed to access the shortcut information,
      * as defined in {@link #hasShortcutHostPermission()}.
      *
-     * <p>Throws {@link android.content.ActivityNotFoundException}
-     * when the user is locked, or when the user owning the shortcut
-     * is locked or not running.
-     *
      * @param shortcut The target shortcut.
      * @param sourceBounds The Rect containing the source bounds of the clicked icon.
      * @param startActivityOptions Options to pass to startActivity.
+     * @throws IllegalStateException when the user is locked, or when the {@code user} user
+     * is locked or not running.
      *
      * @throws android.content.ActivityNotFoundException failed to start shortcut. (e.g.
      * the shortcut no longer exists, is disabled, the intent receiver activity doesn't exist, etc)
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 7ba067b..e8f0845 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -5379,14 +5379,6 @@
             int newState, int flags);
 
     /**
-     * Per-user version of {@link #setComponentEnabledSetting(ComponentName, int, int)}
-     *
-     * @hide
-     */
-    public abstract void setComponentEnabledSettingAsUser(ComponentName componentName,
-            int newState, int flags, int userId);
-
-    /**
      * Return the enabled setting for a package component (activity,
      * receiver, service, provider).  This returns the last value set by
      * {@link #setComponentEnabledSetting(ComponentName, int, int)}; in most
@@ -5425,14 +5417,6 @@
             int newState, int flags);
 
     /**
-     * Per-user version of {@link #setApplicationEnabledSetting(String, int, int)}
-     *
-     * @hide
-     */
-    public abstract void setApplicationEnabledSettingAsUser(String packageName,
-            int newState, int flags, int userId);
-
-    /**
      * Return the enabled setting for an application. This returns
      * the last value set by
      * {@link #setApplicationEnabledSetting(String, int, int)}; in most
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 370f7f9..95dd148 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -30,6 +30,7 @@
 import android.telephony.SignalStrength;
 import android.text.format.DateFormat;
 import android.util.ArrayMap;
+import android.util.Log;
 import android.util.LongSparseArray;
 import android.util.MutableBoolean;
 import android.util.Pair;
@@ -48,6 +49,7 @@
  * @hide
  */
 public abstract class BatteryStats implements Parcelable {
+    private static final String TAG = "BatteryStats";
 
     private static final boolean LOCAL_LOGV = false;
 
@@ -176,8 +178,11 @@
 
     /**
      * Current version of checkin data format.
+     *
+     * New in version 19:
+     *   - Wakelock data (wl) gets current and max times.
      */
-    static final String CHECKIN_VERSION = "18";
+    static final String CHECKIN_VERSION = "19";
 
     /**
      * Old version, we hit 9 and ran out of room, need to remove.
@@ -353,6 +358,32 @@
         public abstract long getTimeSinceMarkLocked(long elapsedRealtimeUs);
 
         /**
+         * Returns the max duration if it is being tracked.
+         * Not all Timer subclasses track the max duration and the current duration.
+
+         */
+        public long getMaxDurationMsLocked(long elapsedRealtimeMs) {
+            return -1;
+        }
+
+        /**
+         * Returns the current time the timer has been active, if it is being tracked.
+         * Not all Timer subclasses track the max duration and the current duration.
+         */
+        public long getCurrentDurationMsLocked(long elapsedRealtimeMs) {
+            return -1;
+        }
+
+        /**
+         * Returns whether the timer is currently running.  Some types of timers
+         * (e.g. BatchTimers) don't know whether the event is currently active,
+         * and report false.
+         */
+        public boolean isRunningLocked() {
+            return false;
+        }
+
+        /**
          * Temporary for debugging.
          */
         public abstract void logState(Printer pw, String prefix);
@@ -2561,6 +2592,22 @@
                 sb.append('(');
                 sb.append(count);
                 sb.append(" times)");
+                final long maxDurationMs = timer.getMaxDurationMsLocked(elapsedRealtimeUs/1000);
+                if (maxDurationMs >= 0) {
+                    sb.append(" max=");
+                    sb.append(maxDurationMs);
+                }
+                if (timer.isRunningLocked()) {
+                    final long currentMs = timer.getCurrentDurationMsLocked(elapsedRealtimeUs/1000);
+                    if (currentMs >= 0) {
+                        sb.append(" (running for ");
+                        sb.append(currentMs);
+                        sb.append("ms)");
+                    } else {
+                        sb.append(" (running)");
+                    }
+                }
+
                 return ", ";
             }
         }
@@ -2568,6 +2615,7 @@
     }
 
     /**
+     * Prints details about a timer, if its total time was greater than 0.
      *
      * @param pw a PrintWriter object to print to.
      * @param sb a StringBuilder object.
@@ -2576,24 +2624,40 @@
      * @param which which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
      * @param prefix a String to be prepended to each line of output.
      * @param type the name of the timer.
+     * @return true if anything was printed.
      */
     private static final boolean printTimer(PrintWriter pw, StringBuilder sb, Timer timer,
-            long rawRealtime, int which, String prefix, String type) {
+            long rawRealtimeUs, int which, String prefix, String type) {
         if (timer != null) {
             // Convert from microseconds to milliseconds with rounding
-            final long totalTime = (timer.getTotalTimeLocked(
-                    rawRealtime, which) + 500) / 1000;
+            final long totalTimeMs = (timer.getTotalTimeLocked(
+                    rawRealtimeUs, which) + 500) / 1000;
             final int count = timer.getCountLocked(which);
-            if (totalTime != 0) {
+            if (totalTimeMs != 0) {
                 sb.setLength(0);
                 sb.append(prefix);
                 sb.append("    ");
                 sb.append(type);
                 sb.append(": ");
-                formatTimeMs(sb, totalTime);
+                formatTimeMs(sb, totalTimeMs);
                 sb.append("realtime (");
                 sb.append(count);
                 sb.append(" times)");
+                final long maxDurationMs = timer.getMaxDurationMsLocked(rawRealtimeUs/1000);
+                if (maxDurationMs >= 0) {
+                    sb.append(" max=");
+                    sb.append(maxDurationMs);
+                }
+                if (timer.isRunningLocked()) {
+                    final long currentMs = timer.getCurrentDurationMsLocked(rawRealtimeUs/1000);
+                    if (currentMs >= 0) {
+                        sb.append(" (running for ");
+                        sb.append(currentMs);
+                        sb.append("ms)");
+                    } else {
+                        sb.append(" (running)");
+                    }
+                }
                 pw.println(sb.toString());
                 return true;
             }
@@ -2616,15 +2680,23 @@
             long elapsedRealtimeUs, String name, int which, String linePrefix) {
         long totalTimeMicros = 0;
         int count = 0;
+        long max = -1;
+        long current = -1;
         if (timer != null) {
             totalTimeMicros = timer.getTotalTimeLocked(elapsedRealtimeUs, which);
             count = timer.getCountLocked(which); 
+            current = timer.getCurrentDurationMsLocked(elapsedRealtimeUs/1000);
+            max = timer.getMaxDurationMsLocked(elapsedRealtimeUs/1000);
         }
         sb.append(linePrefix);
         sb.append((totalTimeMicros + 500) / 1000); // microseconds to milliseconds with rounding
         sb.append(',');
         sb.append(name != null ? name + "," : "");
         sb.append(count);
+        sb.append(',');
+        sb.append(current);
+        sb.append(',');
+        sb.append(max);
         return ",";
     }
     
diff --git a/core/java/android/view/FrameMetrics.java b/core/java/android/view/FrameMetrics.java
index 5c4450a..2b938d0 100644
--- a/core/java/android/view/FrameMetrics.java
+++ b/core/java/android/view/FrameMetrics.java
@@ -198,7 +198,7 @@
         int SWAP_BUFFERS = 12;
         int FRAME_COMPLETED = 13;
 
-        int FRAME_STATS_COUNT = 14; // must always be last
+        int FRAME_STATS_COUNT = 16; // must always be last
     }
 
     /*
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3186073..cdd7098 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -12363,6 +12363,10 @@
     public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {
         ensureTransformationInfo();
         if (mTransformationInfo.mAlpha != alpha) {
+            // Report visibility changes, which can affect children, to accessibility
+            if ((alpha == 0) ^ (mTransformationInfo.mAlpha == 0)) {
+                notifySubtreeAccessibilityStateChangedIfNeeded();
+            }
             mTransformationInfo.mAlpha = alpha;
             if (onSetAlpha((int) (alpha * 255))) {
                 mPrivateFlags |= PFLAG_ALPHA_SET;
@@ -12373,8 +12377,6 @@
                 mPrivateFlags &= ~PFLAG_ALPHA_SET;
                 invalidateViewProperty(true, false);
                 mRenderNode.setAlpha(getFinalAlpha());
-                notifyViewAccessibilityStateChangedIfNeeded(
-                        AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
             }
         }
     }
diff --git a/core/java/android/widget/TabHost.java b/core/java/android/widget/TabHost.java
index 28d187c..583f037 100644
--- a/core/java/android/widget/TabHost.java
+++ b/core/java/android/widget/TabHost.java
@@ -113,6 +113,7 @@
      * Creates a new {@link TabSpec} associated with this tab host.
      *
      * @param tag tag for the tab specification, must be non-null
+     * @throws IllegalArgumentException If the passed tag is null
      */
     @NonNull
     public TabSpec newTabSpec(@NonNull String tag) {
@@ -203,6 +204,8 @@
     /**
      * Add a tab.
      * @param tabSpec Specifies how to create the indicator and content.
+     * @throws IllegalArgumentException If the passed tab spec has null indicator strategy and / or
+     *      null content strategy.
      */
     public void addTab(TabSpec tabSpec) {
 
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 91dcc16..fef4a53 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -111,7 +111,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 148 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 149 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -1576,6 +1576,186 @@
         }
     }
 
+
+    /**
+     * A StopwatchTimer that also tracks the total and max individual
+     * time spent active according to the given timebase.  Whereas
+     * StopwatchTimer apportions the time amongst all in the pool,
+     * the total and max durations are not apportioned.
+     */
+    public static class DurationTimer extends StopwatchTimer {
+        /**
+         * The time (in ms) that the timer was last acquired or the time base
+         * last (re-)started. Increasing the nesting depth does not reset this time.
+         *
+         * -1 if the timer is currently not running or the time base is not running.
+         *
+         * If written to a parcel, the start time is reset, as is mNesting in the base class
+         * StopwatchTimer.
+         */
+        long mStartTimeMs = -1;
+
+        /**
+         * The longest time period (in ms) that the timer has been active.
+         */
+        long mMaxDurationMs;
+
+        /**
+         * The total time (in ms) that that the timer has been active since reset().
+         */
+        long mCurrentDurationMs;
+
+        public DurationTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
+                TimeBase timeBase, Parcel in) {
+            super(clocks, uid, type, timerPool, timeBase, in);
+            mMaxDurationMs = in.readLong();
+        }
+
+        public DurationTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
+                TimeBase timeBase) {
+            super(clocks, uid, type, timerPool, timeBase);
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, long elapsedRealtimeUs) {
+            super.writeToParcel(out, elapsedRealtimeUs);
+            out.writeLong(mMaxDurationMs);
+        }
+
+        /**
+         * Write the summary to the parcel.
+         *
+         * Since the time base is probably meaningless after we come back, reading
+         * from this will have the effect of stopping the timer. So here all we write
+         * is the max duration.
+         */
+        @Override
+        public void writeSummaryFromParcelLocked(Parcel out, long elapsedRealtimeUs) {
+            super.writeSummaryFromParcelLocked(out, elapsedRealtimeUs);
+            out.writeLong(mMaxDurationMs);
+        }
+
+        /**
+         * Read the summary parcel.
+         *
+         * Has the side effect of stopping the timer.
+         */
+        @Override
+        public void readSummaryFromParcelLocked(Parcel in) {
+            super.readSummaryFromParcelLocked(in);
+            mMaxDurationMs = in.readLong();
+            mStartTimeMs = -1;
+            mCurrentDurationMs = 0;
+        }
+
+        /**
+         * The TimeBase time started (again).
+         *
+         * If the timer is also running, store the start time.
+         */
+        public void onTimeStarted(long elapsedRealtimeUs, long baseUptime, long baseRealtime) {
+            super.onTimeStarted(elapsedRealtimeUs, baseUptime, baseRealtime);
+            if (mNesting > 0) {
+                mStartTimeMs = mTimeBase.getRealtime(mClocks.elapsedRealtime()*1000) / 1000;
+            }
+        }
+
+        /**
+         * The TimeBase stopped running.
+         *
+         * If the timer is running, add the duration into mCurrentDurationMs.
+         */
+        @Override
+        public void onTimeStopped(long elapsedRealtimeUs, long baseUptime, long baseRealtime) {
+            super.onTimeStopped(elapsedRealtimeUs, baseUptime, baseRealtime);
+            if (mNesting > 0) {
+                mCurrentDurationMs += (elapsedRealtimeUs / 1000) - mStartTimeMs;
+            }
+            mStartTimeMs = -1;
+        }
+
+        @Override
+        public void logState(Printer pw, String prefix) {
+            super.logState(pw, prefix);
+        }
+
+        @Override
+        public void startRunningLocked(long elapsedRealtimeMs) {
+            super.startRunningLocked(elapsedRealtimeMs);
+            if (mNesting == 1 && mTimeBase.isRunning()) {
+                // Just started
+                mStartTimeMs = mTimeBase.getRealtime(mClocks.elapsedRealtime()*1000) / 1000;
+            }
+        }
+
+        /**
+         * Decrements the mNesting ref-count on this timer.
+         *
+         * If it actually stopped (mNesting went to 0), then possibly update
+         * mMaxDuration if the current duration was the longest ever.
+         */
+        @Override
+        public void stopRunningLocked(long elapsedRealtimeMs) {
+            super.stopRunningLocked(elapsedRealtimeMs);
+            if (mNesting == 0) {
+                final long durationMs = getCurrentDurationMsLocked(elapsedRealtimeMs);
+                if (durationMs > mMaxDurationMs) {
+                    mMaxDurationMs = durationMs;
+                }
+                mStartTimeMs = -1;
+                mCurrentDurationMs = 0;
+            }
+        }
+
+        @Override
+        public boolean reset(boolean detachIfReset) {
+            boolean result = super.reset(detachIfReset);
+            mMaxDurationMs = 0;
+            mCurrentDurationMs = 0;
+            if (mNesting > 0) {
+                mStartTimeMs = mTimeBase.getRealtime(mClocks.elapsedRealtime()*1000) / 1000;
+            } else {
+                mStartTimeMs = -1;
+            }
+            return result;
+        }
+
+        /**
+         * Returns the max duration that this timer has ever seen.
+         *
+         * Note that this time is NOT split between the timers in the timer group that
+         * this timer is attached to.  It is the TOTAL time.
+         */
+        @Override
+        public long getMaxDurationMsLocked(long elapsedRealtimeMs) {
+            if (mNesting > 0) {
+                final long durationMs = getCurrentDurationMsLocked(elapsedRealtimeMs);
+                if (durationMs > mMaxDurationMs) {
+                    return durationMs;
+                }
+            }
+            return mMaxDurationMs;
+        }
+
+        /**
+         * Returns the time since the timer was started.
+         *
+         * Note that this time is NOT split between the timers in the timer group that
+         * this timer is attached to.  It is the TOTAL time.
+         */
+        @Override
+        public long getCurrentDurationMsLocked(long elapsedRealtimeMs) {
+            long durationMs = mCurrentDurationMs;
+            if (mNesting > 0) {
+                if (mTimeBase.isRunning()) {
+                    durationMs += (mTimeBase.getRealtime(elapsedRealtimeMs*1000)/1000)
+                            - mStartTimeMs;
+                }
+            }
+            return durationMs;
+        }
+    }
+
     /**
      * State for keeping track of timing information.
      */
@@ -6554,7 +6734,7 @@
             /**
              * How long (in ms) this uid has been keeping the device partially awake.
              */
-            StopwatchTimer mTimerPartial;
+            DurationTimer mTimerPartial;
 
             /**
              * How long (in ms) this uid has been keeping the device fully awake.
@@ -6583,8 +6763,8 @@
              * @param in the Parcel to be read from.
              * return a new Timer, or null.
              */
-            private StopwatchTimer readTimerFromParcel(int type, ArrayList<StopwatchTimer> pool,
-                    TimeBase timeBase, Parcel in) {
+            private StopwatchTimer readStopwatchTimerFromParcel(int type,
+                    ArrayList<StopwatchTimer> pool, TimeBase timeBase, Parcel in) {
                 if (in.readInt() == 0) {
                     return null;
                 }
@@ -6592,6 +6772,22 @@
                 return new StopwatchTimer(mBsi.mClocks, mUid, type, pool, timeBase, in);
             }
 
+            /**
+             * Reads a possibly null Timer from a Parcel.  The timer is associated with the
+             * proper timer pool from the given BatteryStatsImpl object.
+             *
+             * @param in the Parcel to be read from.
+             * return a new Timer, or null.
+             */
+            private DurationTimer readDurationTimerFromParcel(int type,
+                    ArrayList<StopwatchTimer> pool, TimeBase timeBase, Parcel in) {
+                if (in.readInt() == 0) {
+                    return null;
+                }
+
+                return new DurationTimer(mBsi.mClocks, mUid, type, pool, timeBase, in);
+            }
+
             boolean reset() {
                 boolean wlactive = false;
                 if (mTimerFull != null) {
@@ -6628,11 +6824,14 @@
             }
 
             void readFromParcelLocked(TimeBase timeBase, TimeBase screenOffTimeBase, Parcel in) {
-                mTimerPartial = readTimerFromParcel(WAKE_TYPE_PARTIAL,
+                mTimerPartial = readDurationTimerFromParcel(WAKE_TYPE_PARTIAL,
                         mBsi.mPartialTimers, screenOffTimeBase, in);
-                mTimerFull = readTimerFromParcel(WAKE_TYPE_FULL, mBsi.mFullTimers, timeBase, in);
-                mTimerWindow = readTimerFromParcel(WAKE_TYPE_WINDOW, mBsi.mWindowTimers, timeBase, in);
-                mTimerDraw = readTimerFromParcel(WAKE_TYPE_DRAW, mBsi.mDrawTimers, timeBase, in);
+                mTimerFull = readStopwatchTimerFromParcel(WAKE_TYPE_FULL,
+                        mBsi.mFullTimers, timeBase, in);
+                mTimerWindow = readStopwatchTimerFromParcel(WAKE_TYPE_WINDOW,
+                        mBsi.mWindowTimers, timeBase, in);
+                mTimerDraw = readStopwatchTimerFromParcel(WAKE_TYPE_DRAW,
+                        mBsi.mDrawTimers, timeBase, in);
             }
 
             void writeToParcelLocked(Parcel out, long elapsedRealtimeUs) {
@@ -6654,40 +6853,43 @@
             }
 
             public StopwatchTimer getStopwatchTimer(int type) {
-                StopwatchTimer t;
                 switch (type) {
-                    case WAKE_TYPE_PARTIAL:
-                        t = mTimerPartial;
+                    case WAKE_TYPE_PARTIAL: {
+                        DurationTimer t = mTimerPartial;
                         if (t == null) {
-                            t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_PARTIAL,
+                            t = new DurationTimer(mBsi.mClocks, mUid, WAKE_TYPE_PARTIAL,
                                     mBsi.mPartialTimers, mBsi.mOnBatteryScreenOffTimeBase);
                             mTimerPartial = t;
                         }
                         return t;
-                    case WAKE_TYPE_FULL:
-                        t = mTimerFull;
+                    }
+                    case WAKE_TYPE_FULL: {
+                        StopwatchTimer t = mTimerFull;
                         if (t == null) {
                             t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_FULL,
                                     mBsi.mFullTimers, mBsi.mOnBatteryTimeBase);
                             mTimerFull = t;
                         }
                         return t;
-                    case WAKE_TYPE_WINDOW:
-                        t = mTimerWindow;
+                    }
+                    case WAKE_TYPE_WINDOW: {
+                        StopwatchTimer t = mTimerWindow;
                         if (t == null) {
                             t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_WINDOW,
                                     mBsi.mWindowTimers, mBsi.mOnBatteryTimeBase);
                             mTimerWindow = t;
                         }
                         return t;
-                    case WAKE_TYPE_DRAW:
-                        t = mTimerDraw;
+                    }
+                    case WAKE_TYPE_DRAW: {
+                        StopwatchTimer t = mTimerDraw;
                         if (t == null) {
                             t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_DRAW,
                                     mBsi.mDrawTimers, mBsi.mOnBatteryTimeBase);
                             mTimerDraw = t;
                         }
                         return t;
+                    }
                     default:
                         throw new IllegalArgumentException("type=" + type);
                 }
diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp
index bb09d00..7213414 100644
--- a/core/jni/android_database_CursorWindow.cpp
+++ b/core/jni/android_database_CursorWindow.cpp
@@ -280,7 +280,7 @@
         if (size) {
             jchar* data = static_cast<jchar*>(env->GetPrimitiveArrayCritical(dataObj, NULL));
             utf8_to_utf16_no_null_terminator(reinterpret_cast<const uint8_t*>(str), len,
-                    reinterpret_cast<char16_t*>(data));
+                    reinterpret_cast<char16_t*>(data), (size_t) size);
             env->ReleasePrimitiveArrayCritical(dataObj, data, 0);
         }
         env->SetIntField(bufferObj, gCharArrayBufferClassInfo.sizeCopied, size);
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index a5c9d54..87a8ef8 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -242,6 +242,16 @@
         mPausedVDAnimators.clear();
     }
 
+    // Move all the animators to the paused list, and send a delayed message to notify the finished
+    // listener.
+    void pauseAnimators() {
+        mPausedVDAnimators.insert(mRunningVDAnimators.begin(), mRunningVDAnimators.end());
+        for (auto& anim : mRunningVDAnimators) {
+            detachVectorDrawableAnimator(anim.get());
+        }
+        mRunningVDAnimators.clear();
+    }
+
     void doAttachAnimatingNodes(AnimationContext* context) {
         for (size_t i = 0; i < mPendingAnimatingRenderNodes.size(); i++) {
             RenderNode* node = mPendingAnimatingRenderNodes[i].get();
@@ -415,8 +425,8 @@
         postOnFinishedEvents();
     }
 
-    virtual void detachAnimators() override {
-        mRootNode->detachAnimators();
+    virtual void pauseAnimators() override {
+        mRootNode->pauseAnimators();
     }
 
     virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener) {
@@ -426,7 +436,7 @@
 
     virtual void destroy() {
         AnimationContext::destroy();
-        detachAnimators();
+        mRootNode->detachAnimators();
         postOnFinishedEvents();
     }
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 61b4c8d..3296371 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2119,7 +2119,7 @@
     </string-array>
 
     <!-- This string array can be overriden to add an additional DRM support for WebView EME. -->
-    <!-- Array of "[keySystemName],[UuidOfMediaDrm]" @hide @SystemApi -->
+    <!-- Array of "[keySystemName],[UuidOfMediaDrm]" -->
     <string-array name="config_keySystemUuidMapping" translatable="false">
         <!-- Example:
         <item>"x-com.microsoft.playready,9A04F079-9840-4286-AB92-E65BE0885F95"</item>
@@ -2532,4 +2532,6 @@
          is installed. -->
     <bool name="config_permissionReviewRequired">false</bool>
 
+    <string name="config_networkOverLimitComponent" translatable="false">com.android.systemui/com.android.systemui.net.NetworkOverLimitActivity</string>
+    <string name="config_dataUsageSummaryComponent" translatable="false">com.android.settings/com.android.settings.Settings$DataUsageSummaryActivity</string>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index a37db7e..7bce379 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2547,6 +2547,7 @@
     <!-- @hide This really shouldn't be public; clients using it should use @* to ref it.  -->
     <public type="style" name="Theme.Leanback.FormWizard" id="0x010302d0" />
 
+    <!-- @hide @SystemApi This shouldn't be public. -->
     <public type="array" name="config_keySystemUuidMapping" id="0x01070005" />
 
     <!-- An interpolator which accelerates fast but decelerates slowly. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 54cb9cef2..b7087ec 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2648,6 +2648,10 @@
   <!-- Colon separated list of package names that should be granted DND access -->
   <java-symbol type="string" name="config_defaultDndAccessPackages" />
 
+  <!-- For NetworkPolicyManagerService -->
+  <java-symbol type="string" name="config_networkOverLimitComponent" />
+  <java-symbol type="string" name="config_dataUsageSummaryComponent" />
+
   <java-symbol type="string" name="lockscreen_storage_locked" />
 
   <!-- Used for MimeIconUtils. -->
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java
new file mode 100644
index 0000000..a15e367
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2016 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.internal.os;
+
+import android.os.BatteryStats;
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.util.Log;
+
+import junit.framework.TestCase;
+
+import org.mockito.Mockito;
+
+/**
+ * Test BatteryStatsImpl.DurationTimer.
+ *
+ * In these tests, unless otherwise commented, the time increments by
+ * 2x + 100, to make the subtraction unlikely to alias to another time.
+ */
+public class BatteryStatsDurationTimerTest extends TestCase {
+
+    @SmallTest
+    public void testStartStop() throws Exception {
+        final MockClocks clocks = new MockClocks();
+
+        final BatteryStatsImpl.TimeBase timeBase = new BatteryStatsImpl.TimeBase();
+        timeBase.init(clocks.uptimeMillis(), clocks.elapsedRealtime());
+
+        final BatteryStatsImpl.DurationTimer timer = new BatteryStatsImpl.DurationTimer(clocks, 
+                null, BatteryStats.WAKE_TYPE_PARTIAL, null, timeBase);
+
+        // TimeBase running, timer not running: current and max are 0
+        timeBase.setRunning(true, /* uptimeUs */ 0, /* realtimeUs */ 100*1000);
+        assertFalse(timer.isRunningLocked());
+        assertEquals(0, timer.getCurrentDurationMsLocked(300));
+        assertEquals(0, timer.getMaxDurationMsLocked(301));
+
+        // Start timer: current and max advance
+        timer.startRunningLocked(700);
+        assertTrue(timer.isRunningLocked());
+        assertEquals(800, timer.getCurrentDurationMsLocked(1500));
+        assertEquals(801, timer.getMaxDurationMsLocked(1501));
+
+        // Stop timer: current resets to 0, max remains
+        timer.stopRunningLocked(3100);
+        assertFalse(timer.isRunningLocked());
+        assertEquals(0, timer.getCurrentDurationMsLocked(6300));
+        assertEquals(2400, timer.getMaxDurationMsLocked(6301));
+
+        // Start time again, but check with a short time, and make sure max doesn't
+        // increment.
+        timer.startRunningLocked(12700);
+        assertTrue(timer.isRunningLocked());
+        assertEquals(100, timer.getCurrentDurationMsLocked(12800));
+        assertEquals(2400, timer.getMaxDurationMsLocked(12801));
+
+        // And stop it again, but with a short time, and make sure it doesn't increment.
+        timer.stopRunningLocked(12900);
+        assertFalse(timer.isRunningLocked());
+        assertEquals(0, timer.getCurrentDurationMsLocked(13000));
+        assertEquals(2400, timer.getMaxDurationMsLocked(13001));
+
+        // Now start and check that the time doesn't increase if the two times are the same.
+        timer.startRunningLocked(27000);
+        assertTrue(timer.isRunningLocked());
+        assertEquals(0, timer.getCurrentDurationMsLocked(27000));
+        assertEquals(2400, timer.getMaxDurationMsLocked(27000));
+
+        // Stop the TimeBase. The values should be frozen.
+        timeBase.setRunning(false, /* uptimeUs */ 10, /* realtimeUs */ 55000*1000);
+        assertTrue(timer.isRunningLocked());
+        assertEquals(28100, timer.getCurrentDurationMsLocked(110100)); // Why 28100 and not 28000?
+        assertEquals(28100, timer.getMaxDurationMsLocked(110101));
+
+        // Start the TimeBase. The values should be the old value plus the delta
+        // between when the timer restarted and the current time
+        timeBase.setRunning(true, /* uptimeUs */ 10, /* realtimeUs */ 220100*1000);
+        assertTrue(timer.isRunningLocked());
+        assertEquals(28300, timer.getCurrentDurationMsLocked(220300)); // extra 100 from above??
+        assertEquals(28301, timer.getMaxDurationMsLocked(220301));
+    }
+
+    @SmallTest
+    public void testReset() throws Exception {
+    }
+
+    @SmallTest
+    public void testParceling() throws Exception {
+        final MockClocks clocks = new MockClocks();
+
+        final BatteryStatsImpl.TimeBase timeBase = new BatteryStatsImpl.TimeBase();
+        timeBase.init(clocks.uptimeMillis(), clocks.elapsedRealtime());
+
+        final BatteryStatsImpl.DurationTimer timer = new BatteryStatsImpl.DurationTimer(clocks, 
+                null, BatteryStats.WAKE_TYPE_PARTIAL, null, timeBase);
+
+        // Start running on battery.
+        clocks.realtime = 100;
+        clocks.uptime = 10;
+        timeBase.setRunning(true, clocks.uptimeMillis()*1000, clocks.elapsedRealtime()*1000);
+
+        timer.startRunningLocked(300);
+
+        // Check that it did start running
+        assertEquals(400, timer.getMaxDurationMsLocked(700));
+        assertEquals(401, timer.getCurrentDurationMsLocked(701));
+
+        // Write summary
+        final Parcel summaryParcel = Parcel.obtain();
+        timer.writeSummaryFromParcelLocked(summaryParcel, 1500*1000);
+        summaryParcel.setDataPosition(0);
+
+        // Read summary
+        final BatteryStatsImpl.DurationTimer summary = new BatteryStatsImpl.DurationTimer(clocks, 
+                null, BatteryStats.WAKE_TYPE_PARTIAL, null, timeBase);
+        summary.startRunningLocked(3100);
+        summary.readSummaryFromParcelLocked(summaryParcel);
+        // The new one shouldn't be running, and therefore 0 for current time
+        assertFalse(summary.isRunningLocked());
+        assertEquals(0, summary.getCurrentDurationMsLocked(6300));
+        // The new one should have the max duration that we had when we wrote it
+        assertEquals(1200, summary.getMaxDurationMsLocked(6301));
+
+        // Write full
+        final Parcel fullParcel = Parcel.obtain();
+        timer.writeToParcel(fullParcel, 1500*1000);
+        fullParcel.setDataPosition(0);
+ 
+        // Read full - Should be the same as the summary as far as DurationTimer is concerned.
+        final BatteryStatsImpl.DurationTimer full = new BatteryStatsImpl.DurationTimer(clocks, 
+                null, BatteryStats.WAKE_TYPE_PARTIAL, null, timeBase, fullParcel);
+        // The new one shouldn't be running, and therefore 0 for current time
+        assertFalse(full.isRunningLocked());
+        assertEquals(0, full.getCurrentDurationMsLocked(6300));
+        // The new one should have the max duration that we had when we wrote it
+        assertEquals(1200, full.getMaxDurationMsLocked(6301));
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
index 78bcbbc..9518219 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -5,6 +5,7 @@
 
 @RunWith(Suite.class)
 @Suite.SuiteClasses({
+        BatteryStatsDurationTimerTest.class,
         BatteryStatsSamplingTimerTest.class,
         BatteryStatsServTest.class,
         BatteryStatsTimeBaseTest.class,
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index bf2648a..b423f6c 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -776,7 +776,7 @@
                     if (kDebugStringPoolNoisy) {
                         ALOGI("Caching UTF8 string: %s", u8str);
                     }
-                    utf8_to_utf16(u8str, u8len, u16str);
+                    utf8_to_utf16(u8str, u8len, u16str, *u16len + 1);
                     mCache[idx] = u16str;
                     return u16str;
                 } else {
@@ -883,7 +883,8 @@
             // the ordering, we need to convert strings in the pool to UTF-16.
             // But we don't want to hit the cache, so instead we will have a
             // local temporary allocation for the conversions.
-            char16_t* convBuffer = (char16_t*)malloc(strLen+4);
+            size_t convBufferLen = strLen + 4;
+            char16_t* convBuffer = (char16_t*)calloc(convBufferLen, sizeof(char16_t));
             ssize_t l = 0;
             ssize_t h = mHeader->stringCount-1;
 
@@ -893,8 +894,7 @@
                 const uint8_t* s = (const uint8_t*)string8At(mid, &len);
                 int c;
                 if (s != NULL) {
-                    char16_t* end = utf8_to_utf16_n(s, len, convBuffer, strLen+3);
-                    *end = 0;
+                    char16_t* end = utf8_to_utf16(s, len, convBuffer, convBufferLen);
                     c = strzcmp16(convBuffer, end-convBuffer, str, strLen);
                 } else {
                     c = -1;
diff --git a/libs/hwui/AnimationContext.h b/libs/hwui/AnimationContext.h
index 97b53b0..71ee860 100644
--- a/libs/hwui/AnimationContext.h
+++ b/libs/hwui/AnimationContext.h
@@ -100,7 +100,7 @@
 
     ANDROID_API virtual void destroy();
 
-    ANDROID_API virtual void detachAnimators() {}
+    ANDROID_API virtual void pauseAnimators() {}
 
 private:
     friend class AnimationHandle;
diff --git a/libs/hwui/FrameInfo.cpp b/libs/hwui/FrameInfo.cpp
index 09b3945..826f0bb 100644
--- a/libs/hwui/FrameInfo.cpp
+++ b/libs/hwui/FrameInfo.cpp
@@ -43,6 +43,9 @@
         == static_cast<int>(FrameInfoIndex::NumIndexes),
         "size mismatch: FrameInfoNames doesn't match the enum!");
 
+static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 16,
+        "Must update value in FrameMetrics.java#FRAME_STATS_COUNT (and here)");
+
 void FrameInfo::importUiThreadInfo(int64_t* info) {
     memcpy(mFrameInfo, info, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t));
 }
diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h
index 993b158..bac9d12d 100644
--- a/libs/hwui/FrameInfo.h
+++ b/libs/hwui/FrameInfo.h
@@ -52,6 +52,7 @@
     QueueBufferDuration,
 
     // Must be the last value!
+    // Also must be kept in sync with FrameMetrics.java#FRAME_STATS_COUNT
     NumIndexes
 };
 
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 5f8c798..073643d 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -323,7 +323,7 @@
 
 void CanvasContext::stopDrawing() {
     mRenderThread.removeFrameCallback(this);
-    mAnimationContext->detachAnimators();
+    mAnimationContext->pauseAnimators();
 }
 
 void CanvasContext::notifyFramePending() {
diff --git a/libs/hwui/utils/NinePatchImpl.cpp b/libs/hwui/utils/NinePatchImpl.cpp
index 2b59ca9..d37126c 100644
--- a/libs/hwui/utils/NinePatchImpl.cpp
+++ b/libs/hwui/utils/NinePatchImpl.cpp
@@ -20,7 +20,6 @@
 #include "SkBitmap.h"
 #include "SkCanvas.h"
 #include "SkColorPriv.h"
-#include "SkNinePatch.h"
 #include "SkPaint.h"
 #include "SkUnPreMultiply.h"
 
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index a56b1b8..4f2d9fbc 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -827,7 +827,8 @@
         }
 
         /**
-         * Returns the media id for this item.
+         * Returns the media id in the {@link MediaDescription} for this item.
+         * @see android.media.MediaMetadata#METADATA_KEY_MEDIA_ID
          */
         public @NonNull String getMediaId() {
             return mDescription.getMediaId();
diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
index 3affee5c0..a215493 100644
--- a/media/java/android/media/session/ISession.aidl
+++ b/media/java/android/media/session/ISession.aidl
@@ -45,6 +45,8 @@
     void setQueueTitle(CharSequence title);
     void setExtras(in Bundle extras);
     void setRatingType(int type);
+    void setRepeatMode(int repeatMode);
+    void setShuffleMode(boolean shuffleMode);
 
     // These commands relate to volume handling
     void setPlaybackToLocal(in AudioAttributes attributes);
diff --git a/media/java/android/media/session/ISessionCallback.aidl b/media/java/android/media/session/ISessionCallback.aidl
index 893bd3c..b3c6d59 100644
--- a/media/java/android/media/session/ISessionCallback.aidl
+++ b/media/java/android/media/session/ISessionCallback.aidl
@@ -46,6 +46,8 @@
     void onRewind();
     void onSeekTo(long pos);
     void onRate(in Rating rating);
+    void onRepeatMode(int repeatMode);
+    void onShuffleMode(boolean shuffleMode);
     void onCustomAction(String action, in Bundle args);
 
     // These callbacks are for volume handling
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index 249bcdc..b73f167 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -48,6 +48,14 @@
     ParcelableVolumeInfo getVolumeAttributes();
     void adjustVolume(int direction, int flags, String packageName);
     void setVolumeTo(int value, int flags, String packageName);
+    MediaMetadata getMetadata();
+    PlaybackState getPlaybackState();
+    ParceledListSlice getQueue();
+    CharSequence getQueueTitle();
+    Bundle getExtras();
+    int getRatingType();
+    int getRepeatMode();
+    boolean getShuffleMode();
 
     // These commands are for the TransportControls
     void prepare();
@@ -67,11 +75,7 @@
     void rewind();
     void seekTo(long pos);
     void rate(in Rating rating);
+    void repeatMode(int repeatMode);
+    void shuffleMode(boolean shuffleMode);
     void sendCustomAction(String action, in Bundle args);
-    MediaMetadata getMetadata();
-    PlaybackState getPlaybackState();
-    ParceledListSlice getQueue();
-    CharSequence getQueueTitle();
-    Bundle getExtras();
-    int getRatingType();
 }
diff --git a/media/java/android/media/session/ISessionControllerCallback.aidl b/media/java/android/media/session/ISessionControllerCallback.aidl
index cf31767..9517c08 100644
--- a/media/java/android/media/session/ISessionControllerCallback.aidl
+++ b/media/java/android/media/session/ISessionControllerCallback.aidl
@@ -36,4 +36,6 @@
     void onQueueTitleChanged(CharSequence title);
     void onExtrasChanged(in Bundle extras);
     void onVolumeInfoChanged(in ParcelableVolumeInfo info);
+    void onRepeatModeChanged(int repeatMode);
+    void onShuffleModeChanged(boolean shuffleMode);
 }
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 622900f..ddff1b7 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -63,7 +63,9 @@
     private static final int MSG_UPDATE_QUEUE = 5;
     private static final int MSG_UPDATE_QUEUE_TITLE = 6;
     private static final int MSG_UPDATE_EXTRAS = 7;
-    private static final int MSG_DESTROYED = 8;
+    private static final int MSG_UPDATE_REPEAT_MODE = 8;
+    private static final int MSG_UPDATE_SHUFFLE_MODE = 9;
+    private static final int MSG_DESTROYED = 10;
 
     private final ISessionController mSessionBinder;
 
@@ -234,6 +236,35 @@
     }
 
     /**
+     * Get the repeat mode for this session.
+     *
+     * @return The latest repeat mode set to the session, or
+     *         {@link PlaybackState#REPEAT_MODE_NONE} if not set.
+     */
+    public int getRepeatMode() {
+        try {
+            return mSessionBinder.getRepeatMode();
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Error calling getRepeatMode.", e);
+            return PlaybackState.REPEAT_MODE_NONE;
+        }
+    }
+
+    /**
+     * Get the shuffle mode for this session.
+     *
+     * @return The latest shuffle mode set to the session, or false if not set.
+     */
+    public boolean getShuffleMode() {
+        try {
+            return mSessionBinder.getShuffleMode();
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "Error calling getShuffleMode.", e);
+            return false;
+        }
+    }
+
+    /**
      * Get the flags for this session. Flags are defined in {@link MediaSession}.
      *
      * @return The current set of flags for the session.
@@ -579,6 +610,26 @@
          */
         public void onAudioInfoChanged(PlaybackInfo info) {
         }
+
+        /**
+         * Override to handle changes to the repeat mode.
+         *
+         * @param repeatMode The repeat mode. It should be one of followings:
+         *                   {@link PlaybackState#REPEAT_MODE_NONE},
+         *                   {@link PlaybackState#REPEAT_MODE_ONE},
+         *                   {@link PlaybackState#REPEAT_MODE_ALL}
+         */
+        public void onRepeatModeChanged(@PlaybackState.RepeatMode int repeatMode) {
+        }
+
+        /**
+         * Override to handle changes to the shuffle mode.
+         *
+         * @param shuffleMode The shuffle mode. {@code true} if _the_ shuffle mode is on,
+         *                    {@code false} otherwise.
+         */
+        public void onShuffleModeChanged(boolean shuffleMode) {
+        }
     }
 
     /**
@@ -862,6 +913,35 @@
         }
 
         /**
+         * Set the repeat mode for this session.
+         *
+         * @param repeatMode The repeat mode. Must be one of the followings:
+         *                   {@link PlaybackState#REPEAT_MODE_NONE},
+         *                   {@link PlaybackState#REPEAT_MODE_ONE},
+         *                   {@link PlaybackState#REPEAT_MODE_ALL}
+         */
+        public void setRepeatMode(@PlaybackState.RepeatMode int repeatMode) {
+            try {
+                mSessionBinder.repeatMode(repeatMode);
+            } catch (RemoteException e) {
+                Log.wtf(TAG, "Error calling setRepeatMode.", e);
+            }
+        }
+
+        /**
+         * Set the shuffle mode for this session.
+         *
+         * @param shuffleMode {@code true} if the shuffle mode is on, {@code false} otherwise.
+         */
+        public void setShuffleMode(boolean shuffleMode) {
+            try {
+                mSessionBinder.shuffleMode(shuffleMode);
+            } catch (RemoteException e) {
+                Log.wtf(TAG, "Error calling shuffleQueue.", e);
+            }
+        }
+
+        /**
          * Send a custom action back for the {@link MediaSession} to perform.
          *
          * @param customAction The action to perform.
@@ -1062,6 +1142,21 @@
             }
         }
 
+        @Override
+        public void onRepeatModeChanged(int repeatMode) {
+            MediaController controller = mController.get();
+            if (controller != null) {
+                controller.postMessage(MSG_UPDATE_REPEAT_MODE, repeatMode, null);
+            }
+        }
+
+        @Override
+        public void onShuffleModeChanged(boolean shuffleMode) {
+            MediaController controller = mController.get();
+            if (controller != null) {
+                controller.postMessage(MSG_UPDATE_SHUFFLE_MODE, shuffleMode, null);
+            }
+        }
     }
 
     private final static class MessageHandler extends Handler {
@@ -1100,6 +1195,12 @@
                 case MSG_UPDATE_VOLUME:
                     mCallback.onAudioInfoChanged((PlaybackInfo) msg.obj);
                     break;
+                case MSG_UPDATE_REPEAT_MODE:
+                    mCallback.onRepeatModeChanged((int) msg.obj);
+                    break;
+                case MSG_UPDATE_SHUFFLE_MODE:
+                    mCallback.onShuffleModeChanged((boolean) msg.obj);
+                    break;
                 case MSG_DESTROYED:
                     mCallback.onSessionDestroyed();
                     break;
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 0959961..cab5d93 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -480,6 +480,41 @@
     }
 
     /**
+     * Set the repeat mode for this session.
+     * <p>
+     * Note that if this method is not called before, {@link MediaController#getRepeatMode}
+     * will return {@link PlaybackState#REPEAT_MODE_NONE}.
+     *
+     * @param repeatMode The repeat mode. Must be one of the followings:
+     *                   {@link PlaybackState#REPEAT_MODE_NONE},
+     *                   {@link PlaybackState#REPEAT_MODE_ONE},
+     *                   {@link PlaybackState#REPEAT_MODE_ALL}
+     */
+    public void setRepeatMode(@PlaybackState.RepeatMode int repeatMode) {
+        try {
+            mBinder.setRepeatMode(repeatMode);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error in setRepeatMode.", e);
+        }
+    }
+
+    /**
+     * Set the shuffle mode for this session.
+     * <p>
+     * Note that if this method is not called before, {@link MediaController#getShuffleMode}
+     * will return {@code false}.
+     *
+     * @param shuffleMode {@code true} if the shuffle mode is on, {@code false} otherwise.
+     */
+    public void setShuffleMode(boolean shuffleMode) {
+        try {
+            mBinder.setShuffleMode(shuffleMode);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error in setShuffleMode.", e);
+        }
+    }
+
+    /**
      * Set some extras that can be associated with the {@link MediaSession}. No assumptions should
      * be made as to how a {@link MediaController} will handle these extras.
      * Keys should be fully qualified (e.g. com.example.MY_EXTRA) to avoid conflicts.
@@ -598,6 +633,14 @@
         postToCallback(CallbackMessageHandler.MSG_RATE, rating);
     }
 
+    private void dispatchRepeatMode(int repeatMode) {
+        postToCallback(CallbackMessageHandler.MSG_REPEAT_MODE, repeatMode);
+    }
+
+    private void dispatchShuffleMode(boolean shuffleMode) {
+        postToCallback(CallbackMessageHandler.MSG_SHUFFLE_MODE, shuffleMode);
+    }
+
     private void dispatchCustomAction(String action, Bundle args) {
         postToCallback(CallbackMessageHandler.MSG_CUSTOM_ACTION, action, args);
     }
@@ -964,6 +1007,33 @@
         }
 
         /**
+         * Override to handle the setting of the repeat mode.
+         * <p>
+         * You should call {@link #setRepeatMode} before end of this method in order to notify
+         * the change to the {@link MediaController}, or {@link MediaController#getRepeatMode}
+         * could return an invalid value.
+         *
+         * @param repeatMode The repeat mode which is one of followings:
+         *                   {@link PlaybackState#REPEAT_MODE_NONE},
+         *                   {@link PlaybackState#REPEAT_MODE_ONE},
+         *                   {@link PlaybackState#REPEAT_MODE_ALL}
+         */
+        public void onSetRepeatMode(@PlaybackState.RepeatMode int repeatMode) {
+        }
+
+        /**
+         * Override to handle the setting of the shuffle mode.
+         * <p>
+         * You should call {@link #setShuffleMode} before end of this method in order to notify
+         * the change to the {@link MediaController}, or {@link MediaController#getShuffleMode}
+         * could return an invalid value.
+         *
+         * @param shuffleMode true if the shuffle mode is on, false otherwise.
+         */
+        public void onSetShuffleMode(boolean shuffleMode) {
+        }
+
+        /**
          * Called when a {@link MediaController} wants a {@link PlaybackState.CustomAction} to be
          * performed.
          *
@@ -1145,6 +1215,22 @@
         }
 
         @Override
+        public void onRepeatMode(int repeatMode) {
+            MediaSession session = mMediaSession.get();
+            if (session != null) {
+                session.dispatchRepeatMode(repeatMode);
+            }
+        }
+
+        @Override
+        public void onShuffleMode(boolean shuffleMode) {
+            MediaSession session = mMediaSession.get();
+            if (session != null) {
+                session.dispatchShuffleMode(shuffleMode);
+            }
+        }
+
+        @Override
         public void onCustomAction(String action, Bundle args) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
@@ -1285,9 +1371,11 @@
         private static final int MSG_REWIND = 17;
         private static final int MSG_SEEK_TO = 18;
         private static final int MSG_RATE = 19;
-        private static final int MSG_CUSTOM_ACTION = 20;
-        private static final int MSG_ADJUST_VOLUME = 21;
-        private static final int MSG_SET_VOLUME = 22;
+        private static final int MSG_REPEAT_MODE = 20;
+        private static final int MSG_SHUFFLE_MODE = 21;
+        private static final int MSG_CUSTOM_ACTION = 22;
+        private static final int MSG_ADJUST_VOLUME = 23;
+        private static final int MSG_SET_VOLUME = 24;
 
         private MediaSession.Callback mCallback;
 
@@ -1376,6 +1464,12 @@
                 case MSG_RATE:
                     mCallback.onSetRating((Rating) msg.obj);
                     break;
+                case MSG_REPEAT_MODE:
+                    mCallback.onSetRepeatMode((int) msg.obj);
+                    break;
+                case MSG_SHUFFLE_MODE:
+                    mCallback.onSetShuffleMode((boolean) msg.obj);
+                    break;
                 case MSG_CUSTOM_ACTION:
                     mCallback.onCustomAction((String) msg.obj, msg.getData());
                     break;
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index 8283c8b..5cdd201 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -45,7 +45,8 @@
             ACTION_SKIP_TO_PREVIOUS, ACTION_SKIP_TO_NEXT, ACTION_FAST_FORWARD, ACTION_SET_RATING,
             ACTION_SEEK_TO, ACTION_PLAY_PAUSE, ACTION_PLAY_FROM_MEDIA_ID, ACTION_PLAY_FROM_SEARCH,
             ACTION_SKIP_TO_QUEUE_ITEM, ACTION_PLAY_FROM_URI, ACTION_PREPARE,
-            ACTION_PREPARE_FROM_MEDIA_ID, ACTION_PREPARE_FROM_SEARCH, ACTION_PREPARE_FROM_URI})
+            ACTION_PREPARE_FROM_MEDIA_ID, ACTION_PREPARE_FROM_SEARCH, ACTION_PREPARE_FROM_URI,
+            ACTION_SET_REPEAT_MODE, ACTION_SET_SHUFFLE_MODE})
     @Retention(RetentionPolicy.SOURCE)
     public @interface Actions {}
 
@@ -176,6 +177,20 @@
     public static final long ACTION_PREPARE_FROM_URI = 1 << 17;
 
     /**
+     * Indicates this session supports the set repeat mode command.
+     *
+     * @see Builder#setActions(long)
+     */
+    public static final long ACTION_SET_REPEAT_MODE = 1 << 18;
+
+    /**
+     * Indicates this session supports the set shuffle mode command.
+     *
+     * @see Builder#setActions(long)
+     */
+    public static final long ACTION_SET_SHUFFLE_MODE = 1 << 19;
+
+    /**
      * @hide
      */
     @IntDef({STATE_NONE, STATE_STOPPED, STATE_PAUSED, STATE_PLAYING, STATE_FAST_FORWARDING,
@@ -281,6 +296,30 @@
      */
     public final static long PLAYBACK_POSITION_UNKNOWN = -1;
 
+    /**
+     * @hide
+     */
+    @IntDef({REPEAT_MODE_NONE, REPEAT_MODE_ONE, REPEAT_MODE_ALL})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface RepeatMode {}
+    /**
+     * Use this value with {@link MediaController.TransportControls#setRepeatMode}
+     * to indicate that the playback will be stopped at the end of the playing media list.
+     */
+    public final static int REPEAT_MODE_NONE = 0;
+
+    /**
+     * Use this value with {@link MediaController.TransportControls#setRepeatMode}
+     * to indicate that the playback of the current playing media item will be repeated.
+     */
+    public final static int REPEAT_MODE_ONE = 1;
+
+    /**
+     * Use this value with {@link MediaController.TransportControls#setRepeatMode}
+     * to indicate that the playback of the playing media list will be repeated.
+     */
+    public final static int REPEAT_MODE_ALL = 2;
+
     private final int mState;
     private final long mPosition;
     private final long mBufferedPosition;
@@ -427,6 +466,8 @@
      * <li> {@link PlaybackState#ACTION_PREPARE_FROM_MEDIA_ID}</li>
      * <li> {@link PlaybackState#ACTION_PREPARE_FROM_SEARCH}</li>
      * <li> {@link PlaybackState#ACTION_PREPARE_FROM_URI}</li>
+     * <li> {@link PlaybackState#ACTION_SET_REPEAT_MODE}</li>
+     * <li> {@link PlaybackState#ACTION_SET_SHUFFLE_MODE}</li>
      * </ul>
      */
     @Actions
@@ -961,6 +1002,8 @@
          * <li> {@link PlaybackState#ACTION_PREPARE_FROM_MEDIA_ID}</li>
          * <li> {@link PlaybackState#ACTION_PREPARE_FROM_SEARCH}</li>
          * <li> {@link PlaybackState#ACTION_PREPARE_FROM_URI}</li>
+         * <li> {@link PlaybackState#ACTION_SET_REPEAT_MODE}</li>
+         * <li> {@link PlaybackState#ACTION_SET_SHUFFLE_MODE}</li>
          * </ul>
          *
          * @param actions The set of actions allowed.
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 4211369..6d4461e 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -62,6 +62,7 @@
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.res.Configuration;
+import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Bundle;
@@ -80,7 +81,6 @@
 import android.util.Log;
 import android.util.Patterns;
 import android.util.SparseArray;
-import android.view.KeyEvent;
 import android.view.View;
 import android.view.WindowManager;
 import android.view.View.OnFocusChangeListener;
@@ -775,7 +775,6 @@
             }
             msg = mContext.getString(R.string.bugreport_screenshot_taken);
         } else {
-            // TODO: try again using Framework APIs instead of relying on screencap.
             msg = mContext.getString(R.string.bugreport_screenshot_failed);
             Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
         }
@@ -1359,22 +1358,24 @@
     /**
      * Takes a screenshot and save it to the given location.
      */
-    private static boolean takeScreenshot(Context context, String screenshotFile) {
-        final ProcessBuilder screencap = new ProcessBuilder()
-                .command("/system/bin/screencap", "-p", screenshotFile);
-        Log.d(TAG, "Taking screenshot using " + screencap.command());
-        try {
-            final int exitValue = screencap.start().waitFor();
-            if (exitValue == 0) {
+    private static boolean takeScreenshot(Context context, String path) {
+        final Bitmap bitmap = Screenshooter.takeScreenshot();
+        if (bitmap == null) {
+            return false;
+        }
+        boolean status;
+        try (final FileOutputStream fos = new FileOutputStream(path)) {
+            if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos)) {
                 ((Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE)).vibrate(150);
                 return true;
+            } else {
+                Log.e(TAG, "Failed to save screenshot on " + path);
             }
-            Log.e(TAG, "screencap (" + screencap.command() + ") failed: " + exitValue);
-        } catch (IOException e) {
-            Log.e(TAG, "screencap (" + screencap.command() + ") failed", e);
-        } catch (InterruptedException e) {
-            Log.w(TAG, "Thread interrupted while screencap still running");
-            Thread.currentThread().interrupt();
+        } catch (IOException e ) {
+            Log.e(TAG, "Failed to save screenshot on " + path, e);
+            return false;
+        } finally {
+            bitmap.recycle();
         }
         return false;
     }
diff --git a/packages/Shell/src/com/android/shell/Screenshooter.java b/packages/Shell/src/com/android/shell/Screenshooter.java
new file mode 100644
index 0000000..3f4895b
--- /dev/null
+++ b/packages/Shell/src/com/android/shell/Screenshooter.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2015 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.shell;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.hardware.display.DisplayManagerGlobal;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.Display;
+import android.view.Surface;
+import android.view.SurfaceControl;
+
+/**
+ * Helper class used to take screenshots.
+ *
+ * TODO: logic below was copied and pasted from UiAutomation; it should be refactored into a common
+ * component that could be used by both (Shell and UiAutomation).
+ */
+final class Screenshooter {
+
+    private static final String TAG = "Screenshooter";
+
+    /** Rotation constant: Freeze rotation to 0 degrees (natural orientation) */
+    public static final int ROTATION_FREEZE_0 = Surface.ROTATION_0;
+
+    /** Rotation constant: Freeze rotation to 90 degrees . */
+    public static final int ROTATION_FREEZE_90 = Surface.ROTATION_90;
+
+    /** Rotation constant: Freeze rotation to 180 degrees . */
+    public static final int ROTATION_FREEZE_180 = Surface.ROTATION_180;
+
+    /** Rotation constant: Freeze rotation to 270 degrees . */
+    public static final int ROTATION_FREEZE_270 = Surface.ROTATION_270;
+
+    /**
+     * Takes a screenshot.
+     *
+     * @return The screenshot bitmap on success, null otherwise.
+     */
+    static Bitmap takeScreenshot() {
+        Display display = DisplayManagerGlobal.getInstance()
+                .getRealDisplay(Display.DEFAULT_DISPLAY);
+        Point displaySize = new Point();
+        display.getRealSize(displaySize);
+        final int displayWidth = displaySize.x;
+        final int displayHeight = displaySize.y;
+
+        final float screenshotWidth;
+        final float screenshotHeight;
+
+        final int rotation = display.getRotation();
+        switch (rotation) {
+            case ROTATION_FREEZE_0: {
+                screenshotWidth = displayWidth;
+                screenshotHeight = displayHeight;
+            } break;
+            case ROTATION_FREEZE_90: {
+                screenshotWidth = displayHeight;
+                screenshotHeight = displayWidth;
+            } break;
+            case ROTATION_FREEZE_180: {
+                screenshotWidth = displayWidth;
+                screenshotHeight = displayHeight;
+            } break;
+            case ROTATION_FREEZE_270: {
+                screenshotWidth = displayHeight;
+                screenshotHeight = displayWidth;
+            } break;
+            default: {
+                throw new IllegalArgumentException("Invalid rotation: "
+                        + rotation);
+            }
+        }
+
+        Log.d(TAG, "Taking screenshot of dimensions " + displayWidth + " x " + displayHeight);
+        // Take the screenshot
+        Bitmap screenShot =
+                SurfaceControl.screenshot((int) screenshotWidth, (int) screenshotHeight);
+        if (screenShot == null) {
+            Log.e(TAG, "Failed to take screenshot of dimensions " + screenshotWidth + " x "
+                    + screenshotHeight);
+            return null;
+        }
+
+        // Rotate the screenshot to the current orientation
+        if (rotation != ROTATION_FREEZE_0) {
+            Bitmap unrotatedScreenShot = Bitmap.createBitmap(displayWidth, displayHeight,
+                    Bitmap.Config.ARGB_8888);
+            Canvas canvas = new Canvas(unrotatedScreenShot);
+            canvas.translate(unrotatedScreenShot.getWidth() / 2,
+                    unrotatedScreenShot.getHeight() / 2);
+            canvas.rotate(getDegreesForRotation(rotation));
+            canvas.translate(- screenshotWidth / 2, - screenshotHeight / 2);
+            canvas.drawBitmap(screenShot, 0, 0, null);
+            canvas.setBitmap(null);
+            screenShot.recycle();
+            screenShot = unrotatedScreenShot;
+        }
+
+        // Optimization
+        screenShot.setHasAlpha(false);
+
+        return screenShot;
+    }
+
+    private static float getDegreesForRotation(int value) {
+        switch (value) {
+            case Surface.ROTATION_90: {
+                return 360f - 90f;
+            }
+            case Surface.ROTATION_180: {
+                return 360f - 180f;
+            }
+            case Surface.ROTATION_270: {
+                return 360f - 270f;
+            } default: {
+                return 0;
+            }
+        }
+    }
+
+}
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index f48039e..c2897cd 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -250,7 +250,7 @@
     <integer name="doze_pulse_duration_in">900</integer>
 
     <!-- Doze: pulse parameter - how long does it take to fade in after a pickup? -->
-    <integer name="doze_pulse_duration_in_pickup">300</integer>
+    <integer name="doze_pulse_duration_in_pickup">130</integer>
 
     <!-- Doze: pulse parameter - once faded in, how long does it stay visible? -->
     <integer name="doze_pulse_duration_visible">3000</integer>
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 843b109..228c4fd 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -116,6 +116,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
 
@@ -263,6 +264,8 @@
     private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
     private final AtomicInteger mNotificationIds = new AtomicInteger(1);
 
+    private static final String NEW_ACCOUNT_VISIBLE = "android.accounts.NEW_ACCOUNT_VISIBLE";
+
     static class UserAccounts {
         private final int userId;
         private final DeDatabaseHelper openHelper;
@@ -285,6 +288,21 @@
         /** protected by the {@link #cacheLock} */
         private final TokenCache accountTokenCaches = new TokenCache();
 
+        /** protected by the {@link #cacheLock} */
+        private final Map<String, ArrayList<Integer>> mApplicationAccountRequestMappings =
+                new HashMap<>();
+
+        /* Together the below two Sparse Arrays serve as visible list. One maps UID to account
+        number. Another maps Account number to Account.*/
+
+        /** protected by the {@link #cacheLock} */
+        private final SparseArray<ArrayList<Integer>> mVisibleListUidToMockAccountNumbers =
+                new SparseArray<>();
+
+        //TODO: Instead of using Mock Account IDs, use the actual account IDs.
+        /** protected by the {@link #cacheLock} */
+        private final SparseArray<Account> mMockAccountIdToAccount = new SparseArray<>();
+
         /**
          * protected by the {@link #cacheLock}
          *
@@ -344,6 +362,8 @@
 
         sThis.set(this);
 
+        addRequestsForPreInstalledApplications();
+
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
         intentFilter.addDataScheme("package");
@@ -366,13 +386,51 @@
                         @Override
                         public void run() {
                             purgeOldGrantsAll();
+
+                            /* clears application request's for account types supported */
+                            int uidOfUninstalledApplication =
+                                    intent.getIntExtra(Intent.EXTRA_UID, -1);
+                            if(uidOfUninstalledApplication != -1) {
+                                clearRequestedAccountVisibility(uidOfUninstalledApplication,
+                                        getUserAccounts(UserHandle.getUserId(
+                                        uidOfUninstalledApplication)));
+                            }
+
+                            /* removes visibility of previous UID of this uninstalled application*/
+                            removeAccountVisibilityAllAccounts(uidOfUninstalledApplication,
+                                        getUserAccounts(UserHandle.getUserId(
+                                        uidOfUninstalledApplication)));
                         }
                     };
                     new Thread(r).start();
                 }
+
             }
         }, intentFilter);
 
+        IntentFilter packageAddedOrChangedFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        packageAddedOrChangedFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+        packageAddedOrChangedFilter.addDataScheme("package");
+        mContext.registerReceiverAsUser(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context1, Intent intent) {
+                mMessageHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        int uidOfInstalledApplication =
+                                intent.getIntExtra(Intent.EXTRA_UID, -1);
+                        if(uidOfInstalledApplication != -1) {
+                            registerAccountTypesSupported(
+                                    uidOfInstalledApplication,
+                                    getUserAccounts(
+                                    UserHandle.getUserId(uidOfInstalledApplication)));
+                        }
+                    }
+                });
+            }
+        }, UserHandle.ALL, packageAddedOrChangedFilter, null, null);
+
         IntentFilter userFilter = new IntentFilter();
         userFilter.addAction(Intent.ACTION_USER_REMOVED);
         mContext.registerReceiverAsUser(new BroadcastReceiver() {
@@ -387,6 +445,475 @@
     }
 
     @Override
+    public boolean addAccountExplicitlyWithUid(Account account, String password, Bundle extras,
+            int[] selectedUids) {
+        if(addAccountExplicitly(account,password,extras)) {
+            for(int thisUid : selectedUids) {
+                makeAccountVisible(account, thisUid);
+            }
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public int[] getRequestingUidsForType(String accountType) {
+        int callingUid = Binder.getCallingUid();
+        if (!isAccountManagedByCaller(accountType, callingUid, UserHandle.getUserId(callingUid))) {
+            String msg = String.format(
+                    "uid %s cannot get secrets for accounts of type: %s",
+                    callingUid,
+                    accountType);
+            throw new SecurityException(msg);
+        }
+        return getRequestingUidsForType(accountType, getUserAccounts(
+                UserHandle.getUserId(callingUid)));
+    }
+
+    /**
+     * Returns all UIDs for applications that requested the account type. This method
+     * is called indirectly by the Authenticator and AccountManager
+     *
+     * @param accountType authenticator would like to know the requesting apps of
+     * @param ua UserAccount that currently hosts the account and application
+     *
+     * @return ArrayList of all UIDs that support accounts of this
+     * account type that seek approval (to be used to know which accounts for
+     * the authenticator to include in addAccountExplicitly). Null if none.
+     */
+    private int[] getRequestingUidsForType(String accountType, UserAccounts ua) {
+        synchronized(ua.cacheLock) {
+            Map<String, ArrayList<Integer>> userApplicationAccountRequestMappings =
+                    ua.mApplicationAccountRequestMappings;
+            ArrayList<Integer> allUidsForAccountType = userApplicationAccountRequestMappings.get(
+                    accountType);
+            if(allUidsForAccountType == null) {
+                return null;
+            }
+            int[] toReturn = new int[allUidsForAccountType.size()];
+            for(int i = 0 ; i < toReturn.length ; i++) {
+                toReturn[i] = allUidsForAccountType.get(i);
+            }
+            return toReturn;
+        }
+    }
+
+    @Override
+    public boolean isAccountVisible(Account a, int uid) {
+        int callingUid = Binder.getCallingUid();
+        if (!isAccountManagedByCaller(a.type, callingUid, UserHandle.getUserId(callingUid))) {
+            String msg = String.format(
+                    "uid %s cannot get secrets for accounts of type: %s",
+                    callingUid,
+                    a.type);
+            throw new SecurityException(msg);
+        }
+        return isAccountVisible(a, uid, getUserAccounts(UserHandle.getUserId(callingUid)));
+    }
+
+    /**
+     * Checks visibility of certain account of a process identified
+     * by a given UID. This is called by the Authenticator indirectly.
+     *
+     * @param a The account to check visibility of
+     * @param uid UID to check visibility of
+     * @param ua UserAccount that currently hosts the account and application
+     *
+     * @return True if application has access to the account
+     *
+     */
+    private boolean isAccountVisible(Account a, int uid, UserAccounts ua) {
+        int accountMapping = getMockAccountNumber(a, ua);
+        if(accountMapping < 0) {
+            return true;
+        }
+        synchronized(ua.cacheLock) {
+            SparseArray<ArrayList<Integer>> userWlUidToMockAccountNums =
+                    ua.mVisibleListUidToMockAccountNumbers;
+            ArrayList<Integer> linkedAccountsToUid = userWlUidToMockAccountNums.get(uid);
+            return linkedAccountsToUid != null && linkedAccountsToUid.contains(accountMapping);
+        }
+    }
+
+    @Override
+    public boolean makeAccountVisible(Account a, int uid) {
+        int callingUid = Binder.getCallingUid();
+        if (!isAccountManagedByCaller(a.type, callingUid, UserHandle.getUserId(callingUid))) {
+            String msg = String.format(
+                    "uid %s cannot get secrets for accounts of type: %s",
+                    callingUid,
+                    a.type);
+            throw new SecurityException(msg);
+        }
+        return makeAccountVisible(a, uid, getUserAccounts(UserHandle.getUserId(callingUid)));
+    }
+
+    /**
+     * Gives a certain UID, represented a application, access to an account. This method
+     * is called indirectly by the Authenticator.
+     *
+     * @param a Account to make visible
+     * @param uid to add visibility of the Account from
+     * @param ua UserAccount that currently hosts the account and application
+     *
+     * @return True if account made visible to application and was not previously visible.
+     */
+    private boolean makeAccountVisible(Account a, int uid, UserAccounts ua) {
+        int accountMapping = getMockAccountNumber(a, ua);
+        if(accountMapping < 0) {
+            accountMapping = makeAccountNumber(a, ua);
+        }
+
+        synchronized(ua.cacheLock) {
+            SparseArray<ArrayList<Integer>> userWlUidToMockAccountNums =
+                    ua.mVisibleListUidToMockAccountNumbers;
+            ArrayList<Integer> linkedAccountsToUid = userWlUidToMockAccountNums.get(uid);
+            if(linkedAccountsToUid == null) {
+                linkedAccountsToUid = new ArrayList<>();
+                linkedAccountsToUid.add(accountMapping);
+                userWlUidToMockAccountNums.put(uid, linkedAccountsToUid);
+            } else if(!linkedAccountsToUid.contains(accountMapping)) {
+                linkedAccountsToUid.add(accountMapping);
+            } else {
+                return false;
+            }
+        }
+
+        String[] subPackages = mPackageManager.getPackagesForUid(uid);
+        if(subPackages != null) {
+            for(String subPackage : subPackages) {
+                sendNotification(subPackage, a);
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public boolean removeAccountVisibility(Account a, int uid) {
+        int callingUid = Binder.getCallingUid();
+        if (!isAccountManagedByCaller(a.type, callingUid, UserHandle.getUserId(callingUid))) {
+            String msg = String.format(
+                    "uid %s cannot get secrets for accounts of type: %s",
+                    callingUid,
+                    a.type);
+            throw new SecurityException(msg);
+        }
+        return removeAccountVisibility(a, uid, getUserAccounts(UserHandle.getUserId(callingUid)));
+    }
+
+    /**
+     * Removes visibility of certain account of a process identified
+     * by a given UID to an application. This is called directly by the
+     * AccountManager and indirectly by the Authenticator.
+     *
+     * @param a Account to remove visibility from
+     * @param uid UID to remove visibility of the Account from
+     * @param ua UserAccount that hosts the account and application
+     *
+     * @return True if application access to account removed and was previously visible.
+     */
+    private boolean removeAccountVisibility(Account a, int uid, UserAccounts ua) {
+        int accountMapping = getMockAccountNumber(a, ua);
+        if(accountMapping < 0) {
+            return false;
+        }
+        synchronized(ua.cacheLock) {
+            SparseArray<ArrayList<Integer>> userWlUidToMockAccountNums =
+                    ua.mVisibleListUidToMockAccountNumbers;
+            ArrayList<Integer> linkedAccountsToUid = userWlUidToMockAccountNums.get(uid);
+            if(linkedAccountsToUid != null) {
+                boolean toReturn = linkedAccountsToUid.remove((Integer) accountMapping);
+                if(linkedAccountsToUid.size() == 0) {
+                    userWlUidToMockAccountNums.remove(uid);
+                }
+                return toReturn;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Registers an application's preferences for supported account types for login. This is
+     * a helper method of requestAccountVisibility and indirectly called by AccountManager.
+     *
+     * @param accountTypes account types third party app is willing to support
+     * @param uid of application requesting account visibility
+     * @param ua UserAccount that hosts the account and application
+     */
+    private void addRequestedAccountsVisibility(String[] accountTypes, int uid, UserAccounts ua) {
+        synchronized(ua.cacheLock) {
+            Map<String, ArrayList<Integer>> userApplicationAccountRequestMappings =
+                    ua.mApplicationAccountRequestMappings;
+            for(String accountType : accountTypes) {
+                ArrayList<Integer> accountUidAppList = userApplicationAccountRequestMappings
+                        .get(accountType);
+                if(accountUidAppList == null) {
+                    accountUidAppList = new ArrayList<>();
+                    accountUidAppList.add(uid);
+                    userApplicationAccountRequestMappings.put(accountType, accountUidAppList);
+                } else if (!accountUidAppList.contains(uid)) {
+                    accountUidAppList.add(uid);
+                }
+            }
+        }
+    }
+
+    /**
+     * Registers the requested login account types requested by all the applications already
+     * installed on the device.
+     */
+    private void addRequestsForPreInstalledApplications() {
+        List<PackageInfo> allInstalledPackages = mContext.getPackageManager().
+                getInstalledPackages(0);
+        for(PackageInfo pi : allInstalledPackages) {
+            int currentUid = pi.applicationInfo.uid;
+            if(currentUid != -1) {
+                registerAccountTypesSupported(currentUid,
+                        getUserAccounts(UserHandle.getUserId(currentUid)));
+            }
+        }
+    }
+
+    /**
+     * Clears all preferences an application had for login account types it offered
+     * support for. This method is used by AccountManager after application is
+     * uninstalled.
+     *
+     * @param uid Uid of the application to clear account type preferences
+     * @param ua UserAccount that hosted the account and application
+     *
+     * @return true if any previous settings were overridden.
+     */
+    private boolean clearRequestedAccountVisibility(int uid, UserAccounts ua) {
+        boolean accountsDeleted = false;
+        ArrayList<String> accountTypesToRemove = new ArrayList<>();
+        synchronized(ua.cacheLock) {
+            Map<String, ArrayList<Integer>> userApplicationAccountRequestMappings =
+                    ua.mApplicationAccountRequestMappings;
+            Set<Entry<String, ArrayList<Integer>>> accountTypeAppListEntries =
+                    userApplicationAccountRequestMappings.entrySet();
+
+            for(Entry<String, ArrayList<Integer>> entry : accountTypeAppListEntries) {
+                ArrayList<Integer> supportedApps = entry.getValue();
+                if(supportedApps.remove((Integer) uid)) {
+                    accountsDeleted = true;
+                }
+
+                if(supportedApps.isEmpty()) {
+                    accountTypesToRemove.add(entry.getKey());
+                }
+            }
+
+            for(String s : accountTypesToRemove) {
+                userApplicationAccountRequestMappings.remove(s);
+            }
+        }
+
+        return accountsDeleted;
+    }
+
+    /**
+     * Retrieves the mock account number associated with an Account in order to later retrieve
+     * the account from the Integer-Account Mapping. An account number is not the same as
+     * accountId in the database. This method can be indirectly called by AccountManager and
+     * indirectly by the Authenticator.
+     *
+     * @param a account to retrieve account number mapping
+     * @param ua UserAccount that currently hosts the account and application
+     *
+     * @return account number affiliated with the Account in question. Negative number if none.
+     */
+    private int getMockAccountNumber(Account a, UserAccounts ua) {
+    //TODO: Each account is linked to AccountId rather than generated mock account numbers
+        SparseArray<Account> userAcctIdToAcctMap =
+                ua.mMockAccountIdToAccount;
+            synchronized(ua.cacheLock) {
+                int indexOfAccount = userAcctIdToAcctMap.indexOfValueByValue(a);
+                if(indexOfAccount < 0) {
+                    return -1;
+                }
+                return userAcctIdToAcctMap.keyAt(indexOfAccount);
+            }
+    }
+
+    /**
+     * Returns a full list of accounts that a certain UID is allowed access
+     * based on the visible list entries.
+     *
+     * @param uid of application to retrieve visible listed accounts for
+     * @param ua UserAccount that currently hosts the account and application
+     *
+     * @return array of Account values that are accessible by the given uids
+     */
+    private Account[] getVisibleListedAccounts(int uid, UserAccounts ua) {
+        ArrayList<Account> visibleListedAccounts = new ArrayList<>();
+        synchronized(ua.cacheLock) {
+            SparseArray<Account> userAcctIdToAcctMap = ua.mMockAccountIdToAccount;
+            SparseArray<ArrayList<Integer>> userWlUidToMockAccountNums =
+                    ua.mVisibleListUidToMockAccountNumbers;
+            ArrayList<Integer> visibleListedUidAccountNumbers =
+                    userWlUidToMockAccountNums.get(uid);
+            if(visibleListedUidAccountNumbers != null) {
+                for(Integer accountNumber : visibleListedUidAccountNumbers) {
+                    Account currentAccount = userAcctIdToAcctMap.get(accountNumber);
+                    visibleListedAccounts.add(currentAccount);
+                }
+            }
+        }
+        Account[] arrVisibleListedAccounts = new Account[visibleListedAccounts.size()];
+        return visibleListedAccounts.toArray(arrVisibleListedAccounts);
+    }
+
+    /**
+     * Makes an account number for a given Account to be mapped to.
+     * This method is called by makeVisible if an Account does not have
+     * a mapping for the visible list. This method is thus indirectly
+     * called by the Authenticator.
+     *
+     * @param a account to make an account number mapping of
+     * @param ua UserAccount that currently hosts the account and application
+     *
+     * @return account number created to map to the given account
+     */
+    // TODO: Remove this method and use accountId from DB.
+    private int makeAccountNumber(Account a, UserAccounts ua) {
+        synchronized(ua.cacheLock) {
+            SparseArray<Account> userAcctIdToAcctMap = ua.mMockAccountIdToAccount;
+            int newAccountMapping = 0;
+            while(userAcctIdToAcctMap.get(newAccountMapping) != null) {
+                newAccountMapping++;
+            }
+            userAcctIdToAcctMap.put(newAccountMapping, a);
+            return newAccountMapping;
+        }
+    }
+
+
+
+    /**
+     * Registers an application, represented by a UID, to support account types detailed in
+     * the applications manifest as well as allowing it to opt for notifications.
+     *
+     * @param uid UID of application
+     * @param ua UserAccount that currently hosts the account and application
+     */
+    private void registerAccountTypesSupported(int uid, UserAccounts ua) {
+        /* Account types supported are drawn from the Android Manifest of the Application */
+        String interestedPackages = null;
+        try {
+            String[] allPackages = mPackageManager.getPackagesForUid(uid);
+            for(String aPackage : allPackages) {
+                ApplicationInfo ai = mPackageManager.getApplicationInfo(aPackage,
+                        PackageManager.GET_META_DATA);
+                Bundle b = ai.metaData;
+                if(b == null) {
+                    return;
+                }
+                interestedPackages = b.getString("android.accounts.SupportedLoginTypes");
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.d("NameNotFoundException", e.getMessage());
+        }
+        if(interestedPackages != null) {
+            /* request remote account types directly from here. Reads from Android Manifest */
+            requestAccountVisibility(interestedPackages.split(";"), uid, ua);
+        }
+    }
+
+    /**
+     * Allows AccountManager to register account types that an application has login
+     * support for. This method over-writes all of the application's previous settings
+     * for accounts it supported.
+     *
+     * @param accountTypes array of account types application wishes to support
+     * @param uid of application registering requested account types
+     * @param ua UserAccount that hosts the account and application
+     */
+    private void requestAccountVisibility(String[] accountTypes, int uid, UserAccounts ua) {
+        if(accountTypes.length > 0) {
+            clearRequestedAccountVisibility(uid, ua);
+            addRequestedAccountsVisibility(accountTypes, uid, ua);
+        }
+    }
+
+    /**
+     * Removes visibility of all Accounts to this particular UID. This is called when an
+     * application is uninstalled so another application that is installed with the same
+     * UID cannot access Accounts. This is called by AccountManager.
+     *
+     * @param uid of application to remove all Account visibility to
+     * @param ua UserAccount that hosts the current Account
+     */
+    private void removeAccountVisibilityAllAccounts(int uid, UserAccounts ua) {
+        synchronized(ua.cacheLock) {
+            SparseArray<ArrayList<Integer>> userWlUidToMockAccountNums =
+                    ua.mVisibleListUidToMockAccountNumbers;
+            SparseArray<Account> userAcctIdToAcctMap = ua.mMockAccountIdToAccount;
+            ArrayList<Integer> allAccountNumbersList = userWlUidToMockAccountNums.get(uid);
+            if(allAccountNumbersList != null) {
+                Integer[] allAccountNumbers = allAccountNumbersList.toArray(
+                        new Integer[allAccountNumbersList.size()]);
+                for(int accountNum : allAccountNumbers) {
+                    removeAccountVisibility(userAcctIdToAcctMap.get(accountNum), uid, ua);
+                }
+            }
+        }
+    }
+
+    /**
+     * Removes visible list functionality of a certain Account.
+     * This method is currently called by (1) addAccountExplicitly (as opposed to
+     * addAccountExplicitlyWithUid) and (2) removeAccountExplicitly.
+     *
+     * @param a the account to clear the visible list functionality for
+     * @param ua currently UserAccounts profile containing Account
+     *
+     * @return true if account previously had visible list functionality
+     */
+    private boolean removeVisibleListFunctionality(Account a, UserAccounts ua) {
+        int mockAccountNum = getMockAccountNumber(a, ua);
+        if(mockAccountNum < 0) {
+            return false;
+        }
+        synchronized(ua.cacheLock) {
+            SparseArray<ArrayList<Integer>> userWlUidToMockAccountNums =
+                    ua.mVisibleListUidToMockAccountNumbers;
+            SparseArray<Account> userAcctIdToAcctMap = ua.mMockAccountIdToAccount;
+
+            /* Removing mapping from account number to account removes visible list functionality*/
+            userAcctIdToAcctMap.remove(mockAccountNum);
+
+            for(int i = userWlUidToMockAccountNums.size() - 1 ; i >= 0  ; i--) {
+                int uidKey = userWlUidToMockAccountNums.keyAt(i);
+                ArrayList<Integer> allAccountNumbers = userWlUidToMockAccountNums.get(uidKey);
+                if(allAccountNumbers != null) {
+                    allAccountNumbers.remove(mockAccountNum);
+                    if(allAccountNumbers.isEmpty()) {
+                        userWlUidToMockAccountNums.remove(uidKey);
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Sends a direct intent to a package, notifying it of a visible account. This
+     * method is a helper method of makeAccountVisible.
+     *
+     * @param desiredPackage to send Account to
+     * @param visibleAccount to send to package
+     */
+    private void sendNotification(String desiredPackage, Account visibleAccount) {
+        Intent intent = new Intent();
+        intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
+        intent.setAction(NEW_ACCOUNT_VISIBLE);
+        intent.setPackage(desiredPackage);
+        intent.putExtra("android.accounts.KEY_ACCOUNT", (Account) visibleAccount);
+        mContext.sendBroadcast(intent);
+    }
+
+    @Override
     public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
             throws RemoteException {
         try {
@@ -563,7 +1090,7 @@
                     } else {
                         ArrayList<String> accountNames = accountNamesByType.get(accountType);
                         if (accountNames == null) {
-                            accountNames = new ArrayList<String>();
+                            accountNames = new ArrayList<>();
                             accountNamesByType.put(accountType, accountNames);
                         }
                         accountNames.add(accountName);
@@ -968,6 +1495,9 @@
     @Override
     public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
         Bundle.setDefusable(extras, true);
+        // clears the visible list functionality for this account because this method allows
+        // default account access to all applications for account.
+
         final int callingUid = Binder.getCallingUid();
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "addAccountExplicitly: " + account
@@ -983,6 +1513,7 @@
                     account.type);
             throw new SecurityException(msg);
         }
+        removeVisibleListFunctionality(account, getUserAccounts(UserHandle.getUserId(callingUid)));
         /*
          * Child users are not allowed to add accounts. Only the accounts that are
          * shared by the parent profile can be added to child profile.
@@ -1600,6 +2131,7 @@
                     account.type);
             throw new SecurityException(msg);
         }
+        removeVisibleListFunctionality(account, getUserAccounts(UserHandle.getUserId(callingUid)));
         UserAccounts accounts = getUserAccountsForCaller();
         SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
         final long accountId = getAccountIdLocked(db, account);
@@ -3330,7 +3862,7 @@
                         null);
             }
             // check whether each account matches the requested features
-            mAccountsWithFeatures = new ArrayList<Account>(mAccountsOfType.length);
+            mAccountsWithFeatures = new ArrayList<>(mAccountsOfType.length);
             mCurrentAccount = 0;
 
             checkAccount();
@@ -3515,7 +4047,6 @@
             callingUid = packageUid;
             opPackageName = callingPackage;
         }
-
         List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
                 opPackageName);
         if (visibleAccountTypes.isEmpty()
@@ -3666,7 +4197,23 @@
     @Override
     @NonNull
     public Account[] getAccounts(String type, String opPackageName) {
-        return getAccountsAsUser(type, UserHandle.getCallingUserId(), opPackageName);
+        Account[] accessibleAccounts =
+                getAccountsAsUser(type, UserHandle.getCallingUserId(), opPackageName);
+        /* Up until now, access to accounts is User Specific. With Push API, these accounts
+        can be filtered by application as well. Therefore, in this method specifically,
+        we will additionally add the visible listed accounts tied to the Application
+        specifically through visible listing, as approved by the AccountAuthenticator
+        for a specific application on a device. */
+        ArrayList<Account> allAccounts = new ArrayList<>(Arrays.asList(accessibleAccounts));
+        Account[] visibleListedAccounts = getVisibleListedAccounts(Binder.getCallingUid(),
+                getUserAccounts(UserHandle.getCallingUserId()));
+        for(Account visibleAccount : visibleListedAccounts) {
+            if(!allAccounts.contains(visibleAccount)) {
+                allAccounts.add(visibleAccount);
+            }
+        }
+        Account[] allAccountsArr = new Account[allAccounts.size()];
+        return allAccounts.toArray(allAccountsArr);
     }
 
     @Override
@@ -5374,7 +5921,7 @@
     private void removeAccountFromCacheLocked(UserAccounts accounts, Account account) {
         final Account[] oldAccountsForType = accounts.accountCache.get(account.type);
         if (oldAccountsForType != null) {
-            ArrayList<Account> newAccountsList = new ArrayList<Account>();
+            ArrayList<Account> newAccountsList = new ArrayList<>();
             for (Account curAccount : oldAccountsForType) {
                 if (!curAccount.equals(account)) {
                     newAccountsList.add(curAccount);
@@ -5416,17 +5963,17 @@
         UserInfo user = getUserManager().getUserInfo(userAccounts.userId);
         if (user != null && user.isRestricted()) {
             String[] packages = mPackageManager.getPackagesForUid(callingUid);
-            // If any of the packages is a white listed package, return the full set,
+            // If any of the packages is a visible listed package, return the full set,
             // otherwise return non-shared accounts only.
-            // This might be a temporary way to specify a whitelist
-            String whiteList = mContext.getResources().getString(
+            // This might be a temporary way to specify a visible list
+            String visibleList = mContext.getResources().getString(
                     com.android.internal.R.string.config_appsAuthorizedForSharedAccounts);
             for (String packageName : packages) {
-                if (whiteList.contains(";" + packageName + ";")) {
+                if (visibleList.contains(";" + packageName + ";")) {
                     return unfiltered;
                 }
             }
-            ArrayList<Account> allowed = new ArrayList<Account>();
+            ArrayList<Account> allowed = new ArrayList<>();
             Account[] sharedAccounts = getSharedAccountsAsUser(userAccounts.userId);
             if (sharedAccounts == null || sharedAccounts.length == 0) return unfiltered;
             String requiredAccountType = "";
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index d496e7a..35b17d7 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -699,7 +699,7 @@
                         throw new IllegalArgumentException("null notification");
                     }
                     if (r.foregroundId != id) {
-                        r.cancelNotification();
+                        cancelForegroudNotificationLocked(r);
                         r.foregroundId = id;
                     }
                     notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
@@ -721,7 +721,7 @@
                         }
                     }
                     if ((flags & Service.STOP_FOREGROUND_REMOVE) != 0) {
-                        r.cancelNotification();
+                        cancelForegroudNotificationLocked(r);
                         r.foregroundId = 0;
                         r.foregroundNoti = null;
                     } else if (r.appInfo.targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
@@ -738,6 +738,27 @@
         }
     }
 
+    private void cancelForegroudNotificationLocked(ServiceRecord r) {
+        if (r.foregroundId != 0) {
+            // First check to see if this app has any other active foreground services
+            // with the same notification ID.  If so, we shouldn't actually cancel it,
+            // because that would wipe away the notification that still needs to be shown
+            // due the other service.
+            ServiceMap sm = getServiceMap(r.userId);
+            if (sm != null) {
+                for (int i = sm.mServicesByName.size()-1; i >= 0; i--) {
+                    ServiceRecord other = sm.mServicesByName.valueAt(i);
+                    if (other.foregroundId == r.foregroundId
+                            && other.packageName.equals(r.packageName)) {
+                        // Found one!  Abort the cancel.
+                        return;
+                    }
+                }
+            }
+            r.cancelNotification();
+        }
+    }
+
     private void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
         boolean anyForeground = false;
         for (int i=proc.services.size()-1; i>=0; i--) {
@@ -1556,7 +1577,7 @@
             r.makeRestarting(mAm.mProcessStats.getMemFactorLocked(), now);
         }
 
-        r.cancelNotification();
+        cancelForegroudNotificationLocked(r);
 
         mAm.mHandler.removeCallbacks(r.restarter);
         mAm.mHandler.postAtTime(r.restarter, r.nextRestartTime);
@@ -2018,7 +2039,7 @@
             }
         }
 
-        r.cancelNotification();
+        cancelForegroudNotificationLocked(r);
         r.isForeground = false;
         r.foregroundId = 0;
         r.foregroundNoti = null;
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 2bfc402..71c7fd3 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -543,27 +543,25 @@
     }
     
     public void cancelNotification() {
-        if (foregroundId != 0) {
-            // Do asynchronous communication with notification manager to
-            // avoid deadlocks.
-            final String localPackageName = packageName;
-            final int localForegroundId = foregroundId;
-            ams.mHandler.post(new Runnable() {
-                public void run() {
-                    INotificationManager inm = NotificationManager.getService();
-                    if (inm == null) {
-                        return;
-                    }
-                    try {
-                        inm.cancelNotificationWithTag(localPackageName, null,
-                                localForegroundId, userId);
-                    } catch (RuntimeException e) {
-                        Slog.w(TAG, "Error canceling notification for service", e);
-                    } catch (RemoteException e) {
-                    }
+        // Do asynchronous communication with notification manager to
+        // avoid deadlocks.
+        final String localPackageName = packageName;
+        final int localForegroundId = foregroundId;
+        ams.mHandler.post(new Runnable() {
+            public void run() {
+                INotificationManager inm = NotificationManager.getService();
+                if (inm == null) {
+                    return;
                 }
-            });
-        }
+                try {
+                    inm.cancelNotificationWithTag(localPackageName, null,
+                            localForegroundId, userId);
+                } catch (RuntimeException e) {
+                    Slog.w(TAG, "Error canceling notification for service", e);
+                } catch (RemoteException e) {
+                }
+            }
+        });
     }
 
     public void stripForegroundServiceFlagFromNotification() {
diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
index a58d243..b47e079 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
@@ -176,9 +176,21 @@
 
     private void updateRaParams(RaParams params) {
         if (mRaDaemon != null) {
+            HashSet<IpPrefix> deprecated = null;
+
+            if (mLastRaParams != null) {
+                deprecated = new HashSet<>();
+
+                for (IpPrefix ipp : mLastRaParams.prefixes) {
+                    if (params == null || !params.prefixes.contains(ipp)) {
+                        deprecated.add(ipp);
+                    }
+                }
+            }
+
             // Currently, we send spurious RAs (5) whenever there's any update.
             // TODO: Compare params with mLastParams to avoid spurious updates.
-            mRaDaemon.buildNewRa(params);
+            mRaDaemon.buildNewRa(params, deprecated);
         }
 
         mLastRaParams = params;
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 88d6c14..2d71ce9 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -107,6 +107,8 @@
     private ParceledListSlice mQueue;
     private CharSequence mQueueTitle;
     private int mRatingType;
+    private int mRepeatMode;
+    private boolean mShuffleMode;
     private long mLastActiveTime;
     // End TransportPerformer fields
 
@@ -620,6 +622,44 @@
         }
     }
 
+    private void pushRepeatModeUpdate() {
+        synchronized (mLock) {
+            if (mDestroyed) {
+                return;
+            }
+            for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
+                ISessionControllerCallback cb = mControllerCallbacks.get(i);
+                try {
+                    cb.onRepeatModeChanged(mRepeatMode);
+                } catch (DeadObjectException e) {
+                    mControllerCallbacks.remove(i);
+                    Log.w(TAG, "Removed dead callback in pushRepeatModeUpdate.", e);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "unexpected exception in pushRepeatModeUpdate.", e);
+                }
+            }
+        }
+    }
+
+    private void pushShuffleModeUpdate() {
+        synchronized (mLock) {
+            if (mDestroyed) {
+                return;
+            }
+            for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
+                ISessionControllerCallback cb = mControllerCallbacks.get(i);
+                try {
+                    cb.onShuffleModeChanged(mShuffleMode);
+                } catch (DeadObjectException e) {
+                    mControllerCallbacks.remove(i);
+                    Log.w(TAG, "Removed dead callback in pushShuffleModeUpdate.", e);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "unexpected exception in pushShuffleModeUpdate.", e);
+                }
+            }
+        }
+    }
+
     private void pushSessionDestroyed() {
         synchronized (mLock) {
             // This is the only method that may be (and can only be) called
@@ -828,6 +868,30 @@
         }
 
         @Override
+        public void setRepeatMode(int repeatMode) {
+            boolean changed;
+            synchronized (mLock) {
+                changed = mRepeatMode != repeatMode;
+                mRepeatMode = repeatMode;
+            }
+            if (changed) {
+                mHandler.post(MessageHandler.MSG_UPDATE_REPEAT_MODE);
+            }
+        }
+
+        @Override
+        public void setShuffleMode(boolean shuffleMode) {
+            boolean changed;
+            synchronized (mLock) {
+                changed = mShuffleMode != shuffleMode;
+                mShuffleMode = shuffleMode;
+            }
+            if (changed) {
+                mHandler.post(MessageHandler.MSG_UPDATE_SHUFFLE_MODE);
+            }
+        }
+
+        @Override
         public void setCurrentVolume(int volume) {
             mCurrentVolume = volume;
             mHandler.post(MessageHandler.MSG_UPDATE_VOLUME);
@@ -1043,6 +1107,22 @@
             }
         }
 
+        public void repeatMode(int repeatMode) {
+            try {
+                mCb.onRepeatMode(repeatMode);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Remote failure in repeatMode.", e);
+            }
+        }
+
+        public void shuffleMode(boolean shuffleMode) {
+            try {
+                mCb.onShuffleMode(shuffleMode);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Remote failure in shuffleMode.", e);
+            }
+        }
+
         public void adjustVolume(int direction) {
             try {
                 mCb.onAdjustVolume(direction);
@@ -1278,13 +1358,25 @@
         }
 
         @Override
+        public void repeatMode(int repeatMode) {
+            updateCallingPackage();
+            mSessionCb.repeatMode(repeatMode);
+        }
+
+        @Override
+        public void shuffleMode(boolean shuffleMode) throws RemoteException {
+            updateCallingPackage();
+            mSessionCb.shuffleMode(shuffleMode);
+        }
+
+
+        @Override
         public void sendCustomAction(String action, Bundle args)
                 throws RemoteException {
             updateCallingPackage();
             mSessionCb.sendCustomAction(action, args);
         }
 
-
         @Override
         public MediaMetadata getMetadata() {
             synchronized (mLock) {
@@ -1322,6 +1414,16 @@
         }
 
         @Override
+        public int getRepeatMode() {
+            return mRepeatMode;
+        }
+
+        @Override
+        public boolean getShuffleMode() {
+            return mShuffleMode;
+        }
+
+        @Override
         public boolean isTransportControlEnabled() {
             return MediaSessionRecord.this.isTransportControlEnabled();
         }
@@ -1336,7 +1438,9 @@
         private static final int MSG_SEND_EVENT = 6;
         private static final int MSG_UPDATE_SESSION_STATE = 7;
         private static final int MSG_UPDATE_VOLUME = 8;
-        private static final int MSG_DESTROYED = 9;
+        private static final int MSG_UPDATE_REPEAT_MODE = 9;
+        private static final int MSG_UPDATE_SHUFFLE_MODE = 10;
+        private static final int MSG_DESTROYED = 11;
 
         public MessageHandler(Looper looper) {
             super(looper);
@@ -1368,6 +1472,12 @@
                 case MSG_UPDATE_VOLUME:
                     pushVolumeUpdate();
                     break;
+                case MSG_UPDATE_REPEAT_MODE:
+                    pushRepeatModeUpdate();
+                    break;
+                case MSG_UPDATE_SHUFFLE_MODE:
+                    pushShuffleModeUpdate();
+                    break;
                 case MSG_DESTROYED:
                     pushSessionDestroyed();
             }
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index b382a3b..f433af8 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -1036,7 +1036,7 @@
      */
     private void notifyOverLimitNL(NetworkTemplate template) {
         if (!mOverLimitNotified.contains(template)) {
-            mContext.startActivity(buildNetworkOverLimitIntent(template));
+            mContext.startActivity(buildNetworkOverLimitIntent(mContext.getResources(), template));
             mOverLimitNotified.add(template);
         }
     }
@@ -1081,7 +1081,7 @@
                 builder.setDeleteIntent(PendingIntent.getBroadcast(
                         mContext, 0, snoozeIntent, PendingIntent.FLAG_UPDATE_CURRENT));
 
-                final Intent viewIntent = buildViewDataUsageIntent(policy.template);
+                final Intent viewIntent = buildViewDataUsageIntent(res, policy.template);
                 builder.setContentIntent(PendingIntent.getActivity(
                         mContext, 0, viewIntent, PendingIntent.FLAG_UPDATE_CURRENT));
 
@@ -1117,7 +1117,7 @@
                 builder.setContentTitle(title);
                 builder.setContentText(body);
 
-                final Intent intent = buildNetworkOverLimitIntent(policy.template);
+                final Intent intent = buildNetworkOverLimitIntent(res, policy.template);
                 builder.setContentIntent(PendingIntent.getActivity(
                         mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
                 break;
@@ -1152,7 +1152,7 @@
                 builder.setContentTitle(title);
                 builder.setContentText(body);
 
-                final Intent intent = buildViewDataUsageIntent(policy.template);
+                final Intent intent = buildViewDataUsageIntent(res, policy.template);
                 builder.setContentIntent(PendingIntent.getActivity(
                         mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
                 break;
@@ -3525,19 +3525,19 @@
         return intent;
     }
 
-    private static Intent buildNetworkOverLimitIntent(NetworkTemplate template) {
+    private static Intent buildNetworkOverLimitIntent(Resources res, NetworkTemplate template) {
         final Intent intent = new Intent();
-        intent.setComponent(new ComponentName(
-                "com.android.systemui", "com.android.systemui.net.NetworkOverLimitActivity"));
+        intent.setComponent(ComponentName.unflattenFromString(
+                res.getString(R.string.config_networkOverLimitComponent)));
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         intent.putExtra(EXTRA_NETWORK_TEMPLATE, template);
         return intent;
     }
 
-    private static Intent buildViewDataUsageIntent(NetworkTemplate template) {
+    private static Intent buildViewDataUsageIntent(Resources res, NetworkTemplate template) {
         final Intent intent = new Intent();
-        intent.setComponent(new ComponentName(
-                "com.android.settings", "com.android.settings.Settings$DataUsageSummaryActivity"));
+        intent.setComponent(ComponentName.unflattenFromString(
+                res.getString(R.string.config_dataUsageSummaryComponent)));
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         intent.putExtra(EXTRA_NETWORK_TEMPLATE, template);
         return intent;
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index cd5bcd4..53e328c 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -768,41 +768,46 @@
 
             private void onShortcutChangedInner(@NonNull String packageName,
                     @UserIdInt int userId) {
-                final UserHandle user = UserHandle.of(userId);
+                try {
+                    final UserHandle user = UserHandle.of(userId);
 
-                final int n = mListeners.beginBroadcast();
-                for (int i = 0; i < n; i++) {
-                    IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
-                    BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
-                    if (!isEnabledProfileOf(user, cookie.user, "onShortcutChanged")) continue;
+                    final int n = mListeners.beginBroadcast();
+                    for (int i = 0; i < n; i++) {
+                        IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
+                        BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
+                        if (!isEnabledProfileOf(user, cookie.user, "onShortcutChanged")) continue;
 
-                    final int launcherUserId = cookie.user.getIdentifier();
+                        final int launcherUserId = cookie.user.getIdentifier();
 
-                    // Make sure the caller has the permission.
-                    if (!mShortcutServiceInternal.hasShortcutHostPermission(
-                            launcherUserId, cookie.packageName)) {
-                        continue;
+                        // Make sure the caller has the permission.
+                        if (!mShortcutServiceInternal.hasShortcutHostPermission(
+                                launcherUserId, cookie.packageName)) {
+                            continue;
+                        }
+                        // Each launcher has a different set of pinned shortcuts, so we need to do a
+                        // query in here.
+                        // (As of now, only one launcher has the permission at a time, so it's bit
+                        // moot, but we may change the permission model eventually.)
+                        final List<ShortcutInfo> list =
+                                mShortcutServiceInternal.getShortcuts(launcherUserId,
+                                        cookie.packageName,
+                                        /* changedSince= */ 0, packageName, /* shortcutIds=*/ null,
+                                        /* component= */ null,
+                                        ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY
+                                        | ShortcutQuery.FLAG_GET_ALL_KINDS
+                                        , userId);
+                        try {
+                            listener.onShortcutChanged(user, packageName,
+                                    new ParceledListSlice<>(list));
+                        } catch (RemoteException re) {
+                            Slog.d(TAG, "Callback failed ", re);
+                        }
                     }
-                    // Each launcher has a different set of pinned shortcuts, so we need to do a
-                    // query in here.
-                    // (As of now, only one launcher has the permission at a time, so it's bit
-                    // moot, but we may change the permission model eventually.)
-                    final List<ShortcutInfo> list =
-                            mShortcutServiceInternal.getShortcuts(launcherUserId,
-                                    cookie.packageName,
-                                    /* changedSince= */ 0, packageName, /* shortcutIds=*/ null,
-                                    /* component= */ null,
-                                    ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY
-                                    | ShortcutQuery.FLAG_GET_ALL_KINDS
-                                    , userId);
-                    try {
-                        listener.onShortcutChanged(user, packageName,
-                                new ParceledListSlice<>(list));
-                    } catch (RemoteException re) {
-                        Slog.d(TAG, "Callback failed ", re);
-                    }
+                    mListeners.finishBroadcast();
+                } catch (RuntimeException e) {
+                    // When the user is locked we get IllegalState, so just catch all.
+                    Log.w(TAG, e.getMessage(), e);
                 }
-                mListeners.finishBroadcast();
             }
         }
 
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index d875f1e9..8d400b5 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -77,6 +77,7 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 import android.util.SparseLongArray;
 import android.util.TypedValue;
@@ -85,7 +86,6 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.Preconditions;
@@ -301,6 +301,9 @@
                     | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
                     | PackageManager.MATCH_UNINSTALLED_PACKAGES;
 
+    @GuardedBy("mLock")
+    final SparseBooleanArray mUnlockedUsers = new SparseBooleanArray();
+
     // Stats
     @VisibleForTesting
     interface Stats {
@@ -522,6 +525,8 @@
             Slog.d(TAG, "handleUnlockUser: user=" + userId);
         }
         synchronized (mLock) {
+            mUnlockedUsers.put(userId, true);
+
             // Preload the user's shortcuts.
             // Also see if the locale has changed.
             // Note as of nyc, the locale is per-user, so the locale shouldn't change
@@ -534,8 +539,13 @@
 
     /** lifecycle event */
     void handleCleanupUser(int userId) {
+        if (DEBUG) {
+            Slog.d(TAG, "handleCleanupUser: user=" + userId);
+        }
         synchronized (mLock) {
             unloadUserLocked(userId);
+
+            mUnlockedUsers.put(userId, false);
         }
     }
 
@@ -978,16 +988,20 @@
         if (DEBUG) {
             Slog.d(TAG, "saveDirtyInfo");
         }
-        synchronized (mLock) {
-            for (int i = mDirtyUserIds.size() - 1; i >= 0; i--) {
-                final int userId = mDirtyUserIds.get(i);
-                if (userId == UserHandle.USER_NULL) { // USER_NULL for base state.
-                    saveBaseStateLocked();
-                } else {
-                    saveUserLocked(userId);
+        try {
+            synchronized (mLock) {
+                for (int i = mDirtyUserIds.size() - 1; i >= 0; i--) {
+                    final int userId = mDirtyUserIds.get(i);
+                    if (userId == UserHandle.USER_NULL) { // USER_NULL for base state.
+                        saveBaseStateLocked();
+                    } else {
+                        saveUserLocked(userId);
+                    }
                 }
+                mDirtyUserIds.clear();
             }
-            mDirtyUserIds.clear();
+        } catch (Exception e) {
+            wtf("Exception in saveDirtyInfo", e);
         }
     }
 
@@ -1037,20 +1051,14 @@
         }
     }
 
-    private boolean isUserUnlocked(@UserIdInt int userId) {
-        final long token = injectClearCallingIdentity();
-        try {
-            // Weird: when SystemService.onUnlockUser() is called, the user state is still
-            // unlocking, as opposed to unlocked.  So we need to accept the "unlocking" state too.
-            // We know when the user is unlocking, the CE storage is already unlocked.
-            return mUserManager.isUserUnlockingOrUnlocked(userId);
-        } finally {
-            injectRestoreCallingIdentity(token);
-        }
+    // Requires mLock held, but "Locked" prefix would look weired so we jsut say "L".
+    protected boolean isUserUnlockedL(@UserIdInt int userId) {
+        return mUnlockedUsers.get(userId);
     }
 
-    void throwIfUserLocked(@UserIdInt int userId) {
-        if (!isUserUnlocked(userId)) {
+    // Requires mLock held, but "Locked" prefix would look weired so we jsut say "L".
+    void throwIfUserLockedL(@UserIdInt int userId) {
+        if (!isUserUnlockedL(userId)) {
             throw new IllegalStateException("User " + userId + " is locked or not running");
         }
     }
@@ -1065,9 +1073,8 @@
     @GuardedBy("mLock")
     @NonNull
     ShortcutUser getUserShortcutsLocked(@UserIdInt int userId) {
-        if (!isUserUnlocked(userId)) {
+        if (!isUserUnlockedL(userId)) {
             wtf("User still locked");
-            return new ShortcutUser(this, userId);
         }
 
         ShortcutUser userPackages = mUsers.get(userId);
@@ -1471,22 +1478,21 @@
     }
 
     private void notifyListeners(@NonNull String packageName, @UserIdInt int userId) {
-        final long token = injectClearCallingIdentity();
-        try {
-            if (!mUserManager.isUserRunning(userId)) {
-                return;
-            }
-        } finally {
-            injectRestoreCallingIdentity(token);
-        }
         injectPostToHandler(() -> {
-            final ArrayList<ShortcutChangeListener> copy;
-            synchronized (mLock) {
-                copy = new ArrayList<>(mListeners);
-            }
-            // Note onShortcutChanged() needs to be called with the system service permissions.
-            for (int i = copy.size() - 1; i >= 0; i--) {
-                copy.get(i).onShortcutChanged(packageName, userId);
+            try {
+                final ArrayList<ShortcutChangeListener> copy;
+                synchronized (mLock) {
+                    if (!isUserUnlockedL(userId)) {
+                        return;
+                    }
+
+                    copy = new ArrayList<>(mListeners);
+                }
+                // Note onShortcutChanged() needs to be called with the system service permissions.
+                for (int i = copy.size() - 1; i >= 0; i--) {
+                    copy.get(i).onShortcutChanged(packageName, userId);
+                }
+            } catch (Exception ignore) {
             }
         });
     }
@@ -1558,12 +1564,13 @@
     public boolean setDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList,
             @UserIdInt int userId) {
         verifyCaller(packageName, userId);
-        throwIfUserLocked(userId);
 
         final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
         final int size = newShortcuts.size();
 
         synchronized (mLock) {
+            throwIfUserLockedL(userId);
+
             final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
             ps.getUser().onCalledByPublisher(packageName);
 
@@ -1609,12 +1616,13 @@
     public boolean updateShortcuts(String packageName, ParceledListSlice shortcutInfoList,
             @UserIdInt int userId) {
         verifyCaller(packageName, userId);
-        throwIfUserLocked(userId);
 
         final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
         final int size = newShortcuts.size();
 
         synchronized (mLock) {
+            throwIfUserLockedL(userId);
+
             final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
             ps.getUser().onCalledByPublisher(packageName);
 
@@ -1689,12 +1697,13 @@
     public boolean addDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList,
             @UserIdInt int userId) {
         verifyCaller(packageName, userId);
-        throwIfUserLocked(userId);
 
         final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
         final int size = newShortcuts.size();
 
         synchronized (mLock) {
+            throwIfUserLockedL(userId);
+
             final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
             ps.getUser().onCalledByPublisher(packageName);
 
@@ -1741,9 +1750,10 @@
             CharSequence disabledMessage, int disabledMessageResId, @UserIdInt int userId) {
         verifyCaller(packageName, userId);
         Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided");
-        throwIfUserLocked(userId);
 
         synchronized (mLock) {
+            throwIfUserLockedL(userId);
+
             final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
             ps.getUser().onCalledByPublisher(packageName);
 
@@ -1770,9 +1780,10 @@
     public void enableShortcuts(String packageName, List shortcutIds, @UserIdInt int userId) {
         verifyCaller(packageName, userId);
         Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided");
-        throwIfUserLocked(userId);
 
         synchronized (mLock) {
+            throwIfUserLockedL(userId);
+
             final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
             ps.getUser().onCalledByPublisher(packageName);
 
@@ -1792,9 +1803,10 @@
             @UserIdInt int userId) {
         verifyCaller(packageName, userId);
         Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided");
-        throwIfUserLocked(userId);
 
         synchronized (mLock) {
+            throwIfUserLockedL(userId);
+
             final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
             ps.getUser().onCalledByPublisher(packageName);
 
@@ -1816,9 +1828,10 @@
     @Override
     public void removeAllDynamicShortcuts(String packageName, @UserIdInt int userId) {
         verifyCaller(packageName, userId);
-        throwIfUserLocked(userId);
 
         synchronized (mLock) {
+            throwIfUserLockedL(userId);
+
             final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
             ps.getUser().onCalledByPublisher(packageName);
             ps.deleteAllDynamicShortcuts();
@@ -1832,9 +1845,10 @@
     public ParceledListSlice<ShortcutInfo> getDynamicShortcuts(String packageName,
             @UserIdInt int userId) {
         verifyCaller(packageName, userId);
-        throwIfUserLocked(userId);
 
         synchronized (mLock) {
+            throwIfUserLockedL(userId);
+
             return getShortcutsWithQueryLocked(
                     packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR,
                     ShortcutInfo::isDynamic);
@@ -1845,9 +1859,10 @@
     public ParceledListSlice<ShortcutInfo> getManifestShortcuts(String packageName,
             @UserIdInt int userId) {
         verifyCaller(packageName, userId);
-        throwIfUserLocked(userId);
 
         synchronized (mLock) {
+            throwIfUserLockedL(userId);
+
             return getShortcutsWithQueryLocked(
                     packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR,
                     ShortcutInfo::isManifestShortcut);
@@ -1858,9 +1873,10 @@
     public ParceledListSlice<ShortcutInfo> getPinnedShortcuts(String packageName,
             @UserIdInt int userId) {
         verifyCaller(packageName, userId);
-        throwIfUserLocked(userId);
 
         synchronized (mLock) {
+            throwIfUserLockedL(userId);
+
             return getShortcutsWithQueryLocked(
                     packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR,
                     ShortcutInfo::isPinned);
@@ -1890,9 +1906,10 @@
     @Override
     public int getRemainingCallCount(String packageName, @UserIdInt int userId) {
         verifyCaller(packageName, userId);
-        throwIfUserLocked(userId);
 
         synchronized (mLock) {
+            throwIfUserLockedL(userId);
+
             final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
             ps.getUser().onCalledByPublisher(packageName);
             return mMaxUpdatesPerInterval - ps.getApiCallCount();
@@ -1902,9 +1919,10 @@
     @Override
     public long getRateLimitResetTime(String packageName, @UserIdInt int userId) {
         verifyCaller(packageName, userId);
-        throwIfUserLocked(userId);
 
         synchronized (mLock) {
+            throwIfUserLockedL(userId);
+
             return getNextResetTimeLocked();
         }
     }
@@ -1921,7 +1939,6 @@
     @Override
     public void reportShortcutUsed(String packageName, String shortcutId, int userId) {
         verifyCaller(packageName, userId);
-        throwIfUserLocked(userId);
 
         Preconditions.checkNotNull(shortcutId);
 
@@ -1931,6 +1948,8 @@
         }
 
         synchronized (mLock) {
+            throwIfUserLockedL(userId);
+
             final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
             ps.getUser().onCalledByPublisher(packageName);
 
@@ -1962,6 +1981,11 @@
 
     void resetThrottlingInner(@UserIdInt int userId) {
         synchronized (mLock) {
+            if (!isUserUnlockedL(userId)) {
+                Log.w(TAG, "User " + userId + " is locked or not running");
+                return;
+            }
+
             getUserShortcutsLocked(userId).resetThrottling();
         }
         scheduleSaveUser(userId);
@@ -1976,25 +2000,23 @@
         Slog.i(TAG, "ShortcutManager: throttling counter reset for all users");
     }
 
-    void resetPackageThrottling(String packageName, int userId) {
-        synchronized (mLock) {
-            getPackageShortcutsLocked(packageName, userId)
-                    .resetRateLimitingForCommandLineNoSaving();
-            saveUserLocked(userId);
-        }
-    }
-
     @Override
     public void onApplicationActive(String packageName, int userId) {
         if (DEBUG) {
             Slog.d(TAG, "onApplicationActive: package=" + packageName + "  userid=" + userId);
         }
         enforceResetThrottlingPermission();
-        if (!isUserUnlocked(userId)) {
-            // This is called by system UI, so no need to throw.  Just ignore.
-            return;
+
+        synchronized (mLock) {
+            if (!isUserUnlockedL(userId)) {
+                // This is called by system UI, so no need to throw.  Just ignore.
+                return;
+            }
+
+            getPackageShortcutsLocked(packageName, userId)
+                    .resetRateLimitingForCommandLineNoSaving();
+            saveUserLocked(userId);
         }
-        resetPackageThrottling(packageName, userId);
     }
 
     // We override this method in unit tests to do a simpler check.
@@ -2011,9 +2033,9 @@
     // even when hasShortcutPermission() is overridden.
     @VisibleForTesting
     boolean hasShortcutHostPermissionInner(@NonNull String callingPackage, int userId) {
-        throwIfUserLocked(userId);
-
         synchronized (mLock) {
+            throwIfUserLockedL(userId);
+
             final ShortcutUser user = getUserShortcutsLocked(userId);
 
             // Always trust the in-memory cache.
@@ -2170,9 +2192,6 @@
                 @Nullable ComponentName componentName,
                 int queryFlags, int userId) {
             final ArrayList<ShortcutInfo> ret = new ArrayList<>();
-            if (!isUserUnlocked(userId) || !isUserUnlocked(launcherUserId)) {
-                return ret;
-            }
 
             final boolean cloneKeyFieldOnly =
                     ((queryFlags & ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY) != 0);
@@ -2183,6 +2202,9 @@
             }
 
             synchronized (mLock) {
+                throwIfUserLockedL(userId);
+                throwIfUserLockedL(launcherUserId);
+
                 getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
                         .attemptToRestoreIfNeededAndSave();
 
@@ -2251,11 +2273,10 @@
             Preconditions.checkStringNotEmpty(packageName, "packageName");
             Preconditions.checkStringNotEmpty(shortcutId, "shortcutId");
 
-            if (!isUserUnlocked(userId) || !isUserUnlocked(launcherUserId)) {
-                return false;
-            }
-
             synchronized (mLock) {
+                throwIfUserLockedL(userId);
+                throwIfUserLockedL(launcherUserId);
+
                 getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
                         .attemptToRestoreIfNeededAndSave();
 
@@ -2271,9 +2292,8 @@
             Preconditions.checkStringNotEmpty(packageName, "packageName");
             Preconditions.checkStringNotEmpty(shortcutId, "shortcutId");
 
-            if (!isUserUnlocked(userId) || !isUserUnlocked(launcherUserId)) {
-                return null;
-            }
+            throwIfUserLockedL(userId);
+            throwIfUserLockedL(launcherUserId);
 
             final ShortcutPackage p = getUserShortcutsLocked(userId)
                     .getPackageShortcutsIfExists(packageName);
@@ -2296,11 +2316,10 @@
             Preconditions.checkStringNotEmpty(packageName, "packageName");
             Preconditions.checkNotNull(shortcutIds, "shortcutIds");
 
-            if (!isUserUnlocked(userId) || !isUserUnlocked(launcherUserId)) {
-                return;
-            }
-
             synchronized (mLock) {
+                throwIfUserLockedL(userId);
+                throwIfUserLockedL(launcherUserId);
+
                 final ShortcutLauncher launcher =
                         getLauncherShortcutsLocked(callingPackage, userId, launcherUserId);
                 launcher.attemptToRestoreIfNeededAndSave();
@@ -2320,11 +2339,10 @@
             Preconditions.checkStringNotEmpty(packageName, "packageName can't be empty");
             Preconditions.checkStringNotEmpty(shortcutId, "shortcutId can't be empty");
 
-            if (!isUserUnlocked(userId) || !isUserUnlocked(launcherUserId)) {
-                return null;
-            }
-
             synchronized (mLock) {
+                throwIfUserLockedL(userId);
+                throwIfUserLockedL(launcherUserId);
+
                 getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
                         .attemptToRestoreIfNeededAndSave();
 
@@ -2354,11 +2372,10 @@
             Preconditions.checkNotNull(packageName, "packageName");
             Preconditions.checkNotNull(shortcutId, "shortcutId");
 
-            if (!isUserUnlocked(userId) || !isUserUnlocked(launcherUserId)) {
-                return 0;
-            }
-
             synchronized (mLock) {
+                throwIfUserLockedL(userId);
+                throwIfUserLockedL(launcherUserId);
+
                 getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
                         .attemptToRestoreIfNeededAndSave();
 
@@ -2382,11 +2399,10 @@
             Preconditions.checkNotNull(packageName, "packageName");
             Preconditions.checkNotNull(shortcutId, "shortcutId");
 
-            if (!isUserUnlocked(userId) || !isUserUnlocked(launcherUserId)) {
-                return null;
-            }
-
             synchronized (mLock) {
+                throwIfUserLockedL(userId);
+                throwIfUserLockedL(launcherUserId);
+
                 getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
                         .attemptToRestoreIfNeededAndSave();
 
@@ -2418,9 +2434,6 @@
         @Override
         public boolean hasShortcutHostPermission(int launcherUserId,
                 @NonNull String callingPackage) {
-            if (!isUserUnlocked(launcherUserId)) {
-                return false;
-            }
             return ShortcutService.this.hasShortcutHostPermission(callingPackage, launcherUserId);
         }
     }
@@ -2431,8 +2444,12 @@
             if (!mBootCompleted.get()) {
                 return; // Boot not completed, ignore the broadcast.
             }
-            if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
-                handleLocaleChanged();
+            try {
+                if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
+                    handleLocaleChanged();
+                }
+            } catch (Exception e) {
+                wtf("Exception in mReceiver.onReceive", e);
             }
         }
     };
@@ -2443,11 +2460,13 @@
         }
         scheduleSaveBaseState();
 
-        final long token = injectClearCallingIdentity();
-        try {
-            forEachLoadedUserLocked(user -> user.detectLocaleChange());
-        } finally {
-            injectRestoreCallingIdentity(token);
+        synchronized (mLock) {
+            final long token = injectClearCallingIdentity();
+            try {
+                forEachLoadedUserLocked(user -> user.detectLocaleChange());
+            } finally {
+                injectRestoreCallingIdentity(token);
+            }
         }
     }
 
@@ -2470,18 +2489,17 @@
             // but we still check it in unit tests.
             final long token = injectClearCallingIdentity();
             try {
-
-                if (!isUserUnlocked(userId)) {
-                    if (DEBUG) {
-                        Slog.d(TAG, "Ignoring package broadcast " + action
-                                + " for locked/stopped user " + userId);
-                    }
-                    return;
-                }
-
-                // Whenever we get one of those package broadcasts, or get
-                // ACTION_PREFERRED_ACTIVITY_CHANGED, we purge the default launcher cache.
                 synchronized (mLock) {
+                    if (!isUserUnlockedL(userId)) {
+                        if (DEBUG) {
+                            Slog.d(TAG, "Ignoring package broadcast " + action
+                                    + " for locked/stopped user " + userId);
+                        }
+                        return;
+                    }
+
+                    // Whenever we get one of those package broadcasts, or get
+                    // ACTION_PREFERRED_ACTIVITY_CHANGED, we purge the default launcher cache.
                     final ShortcutUser user = getUserShortcutsLocked(userId);
                     user.clearLauncher();
                 }
@@ -2521,6 +2539,8 @@
                         handlePackageDataCleared(packageName, userId);
                         break;
                 }
+            } catch (Exception e) {
+                wtf("Exception in mPackageMonitor.onReceive", e);
             } finally {
                 injectRestoreCallingIdentity(token);
             }
@@ -3031,9 +3051,14 @@
             Slog.d(TAG, "Backing up user " + userId);
         }
         synchronized (mLock) {
+            if (!isUserUnlockedL(userId)) {
+                wtf("Can't backup: user " + userId + " is locked or not running");
+                return null;
+            }
+
             final ShortcutUser user = getUserShortcutsLocked(userId);
             if (user == null) {
-                Slog.w(TAG, "Can't backup: user not found: id=" + userId);
+                wtf("Can't backup: user not found: id=" + userId);
                 return null;
             }
 
@@ -3058,15 +3083,19 @@
         if (DEBUG) {
             Slog.d(TAG, "Restoring user " + userId);
         }
-        final ShortcutUser user;
-        final ByteArrayInputStream is = new ByteArrayInputStream(payload);
-        try {
-            user = loadUserInternal(userId, is, /* fromBackup */ true);
-        } catch (XmlPullParserException | IOException e) {
-            Slog.w(TAG, "Restoration failed.", e);
-            return;
-        }
         synchronized (mLock) {
+            if (!isUserUnlockedL(userId)) {
+                wtf("Can't restore: user " + userId + " is locked or not running");
+                return;
+            }
+            final ShortcutUser user;
+            final ByteArrayInputStream is = new ByteArrayInputStream(payload);
+            try {
+                user = loadUserInternal(userId, is, /* fromBackup */ true);
+            } catch (XmlPullParserException | IOException e) {
+                Slog.w(TAG, "Restoration failed.", e);
+                return;
+            }
             mUsers.put(userId, user);
 
             // Then purge all the save images.
@@ -3276,7 +3305,7 @@
 
         private int mUserId = UserHandle.USER_SYSTEM;
 
-        private void parseOptions(boolean takeUser)
+        private void parseOptionsLocked(boolean takeUser)
                 throws CommandException {
             String opt;
             while ((opt = getNextOption()) != null) {
@@ -3284,7 +3313,7 @@
                     case "--user":
                         if (takeUser) {
                             mUserId = UserHandle.parseUserArg(getNextArgRequired());
-                            if (!isUserUnlocked(mUserId)) {
+                            if (!isUserUnlockedL(mUserId)) {
                                 throw new CommandException(
                                         "User " + mUserId + " is not running or locked");
                             }
@@ -3376,11 +3405,13 @@
         }
 
         private void handleResetThrottling() throws CommandException {
-            parseOptions(/* takeUser =*/ true);
+            synchronized (mLock) {
+                parseOptionsLocked(/* takeUser =*/ true);
 
-            Slog.i(TAG, "cmd: handleResetThrottling: user=" + mUserId);
+                Slog.i(TAG, "cmd: handleResetThrottling: user=" + mUserId);
 
-            resetThrottlingInner(mUserId);
+                resetThrottlingInner(mUserId);
+            }
         }
 
         private void handleResetAllThrottling() {
@@ -3426,34 +3457,42 @@
         }
 
         private void handleClearDefaultLauncher() throws CommandException {
-            parseOptions(/* takeUser =*/ true);
+            synchronized (mLock) {
+                parseOptionsLocked(/* takeUser =*/ true);
 
-            clearLauncher();
+                clearLauncher();
+            }
         }
 
         private void handleGetDefaultLauncher() throws CommandException {
-            parseOptions(/* takeUser =*/ true);
+            synchronized (mLock) {
+                parseOptionsLocked(/* takeUser =*/ true);
 
-            clearLauncher();
-            showLauncher();
+                clearLauncher();
+                showLauncher();
+            }
         }
 
         private void handleUnloadUser() throws CommandException {
-            parseOptions(/* takeUser =*/ true);
+            synchronized (mLock) {
+                parseOptionsLocked(/* takeUser =*/ true);
 
-            Slog.i(TAG, "cmd: handleUnloadUser: user=" + mUserId);
+                Slog.i(TAG, "cmd: handleUnloadUser: user=" + mUserId);
 
-            ShortcutService.this.handleCleanupUser(mUserId);
+                ShortcutService.this.handleCleanupUser(mUserId);
+            }
         }
 
         private void handleClearShortcuts() throws CommandException {
-            parseOptions(/* takeUser =*/ true);
-            final String packageName = getNextArgRequired();
+            synchronized (mLock) {
+                parseOptionsLocked(/* takeUser =*/ true);
+                final String packageName = getNextArgRequired();
 
-            Slog.i(TAG, "cmd: handleClearShortcuts: user" + mUserId + ", " + packageName);
+                Slog.i(TAG, "cmd: handleClearShortcuts: user" + mUserId + ", " + packageName);
 
-            ShortcutService.this.cleanUpPackageForAllLoadedUsers(packageName, mUserId,
-                    /* appStillExists = */ true);
+                ShortcutService.this.cleanUpPackageForAllLoadedUsers(packageName, mUserId,
+                        /* appStillExists = */ true);
+            }
         }
 
         private void handleVerifyStates() throws CommandException {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index e17d243..e489d96 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -27,6 +27,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.ActivityManagerNative;
+import android.app.AppGlobals;
 import android.app.IActivityManager;
 import android.app.IStopUserCallback;
 import android.app.KeyguardManager;
@@ -37,6 +38,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.IntentSender;
+import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.UserInfo;
@@ -2940,13 +2942,17 @@
             if (!TextUtils.isEmpty(demoLauncher)) {
                 ComponentName componentToEnable = ComponentName.unflattenFromString(demoLauncher);
                 String demoLauncherPkg = componentToEnable.getPackageName();
-                final PackageManager pm = mContext.getPackageManager();
-                pm.setComponentEnabledSettingAsUser(componentToEnable,
-                        PackageManager.COMPONENT_ENABLED_STATE_ENABLED, /* flags= */ 0,
-                        /* userId= */ userId);
-                pm.setApplicationEnabledSettingAsUser(demoLauncherPkg,
-                        PackageManager.COMPONENT_ENABLED_STATE_ENABLED, /* flags= */ 0,
-                        /* userId= */ userId);
+                try {
+                    final IPackageManager iPm = AppGlobals.getPackageManager();
+                    iPm.setComponentEnabledSetting(componentToEnable,
+                            PackageManager.COMPONENT_ENABLED_STATE_ENABLED, /* flags= */ 0,
+                            /* userId= */ userId);
+                    iPm.setApplicationEnabledSetting(demoLauncherPkg,
+                            PackageManager.COMPONENT_ENABLED_STATE_ENABLED, /* flags= */ 0,
+                            /* userId= */ userId, null);
+                } catch (RemoteException re) {
+                    // Internal, shouldn't happen
+                }
             }
         }
     }
diff --git a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
index 407d315..1a9d2f2 100644
--- a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
+++ b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
@@ -45,7 +45,9 @@
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Random;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -109,6 +111,11 @@
     private final byte[] mRA = new byte[IPV6_MIN_MTU];
     @GuardedBy("mLock")
     private int mRaLength;
+    @GuardedBy("mLock")
+    private final HashMap<IpPrefix, Integer> mDeprecatedPrefixes;
+
+    @GuardedBy("mLock")
+    private RaParams mRaParams;
 
     private volatile FileDescriptor mSocket;
     private volatile MulticastTransmitter mMulticastTransmitter;
@@ -141,45 +148,29 @@
         mIfIndex = ifindex;
         mHwAddr = hwaddr;
         mAllNodes = new InetSocketAddress(getAllNodesForScopeId(mIfIndex), 0);
+        mDeprecatedPrefixes = new HashMap<>();
     }
 
-    public void buildNewRa(RaParams params) {
+    public void buildNewRa(RaParams params, HashSet<IpPrefix> newlyDeprecated) {
+        if (newlyDeprecated != null) {
+            synchronized (mLock) {
+                for (IpPrefix ipp : newlyDeprecated) {
+                    mDeprecatedPrefixes.put(ipp, MAX_URGENT_RTR_ADVERTISEMENTS);
+                }
+            }
+        }
+
+        // TODO: Send MAX_URGENT_RTR_ADVERTISEMENTS zero router lifetime RAs,
+        // iff. we have already sent an RA.
         if (params == null || params.prefixes.isEmpty()) {
             // No RA to be served at this time.
             clearRa();
             return;
         }
 
-        if (params.mtu < IPV6_MIN_MTU) {
-            params.mtu = IPV6_MIN_MTU;
-        }
-
-        final ByteBuffer ra = ByteBuffer.wrap(mRA);
-        ra.order(ByteOrder.BIG_ENDIAN);
-
         synchronized (mLock) {
-            try {
-                putHeader(ra, params.hasDefaultRoute);
-                putSlla(ra, mHwAddr);
-                // https://tools.ietf.org/html/rfc5175#section-4 says:
-                //
-                //     "MUST NOT be added to a Router Advertisement message
-                //      if no flags in the option are set."
-                //
-                // putExpandedFlagsOption(ra);
-                putMtu(ra, params.mtu);
-                for (IpPrefix ipp : params.prefixes) {
-                    putPio(ra, ipp);
-                }
-                if (params.dnses.size() > 0) {
-                    putRdnss(ra, params.dnses);
-                }
-                mRaLength = ra.position();
-            } catch (BufferOverflowException e) {
-                Log.e(TAG, "Could not construct new RA: " + e);
-                mRaLength = 0;
-                return;
-            }
+            mRaParams = params;
+            assembleRa();
         }
 
         maybeNotifyMulticastTransmitter();
@@ -216,6 +207,64 @@
         }
     }
 
+    private void assembleRa() {
+        final ByteBuffer ra = ByteBuffer.wrap(mRA);
+        ra.order(ByteOrder.BIG_ENDIAN);
+
+        synchronized (mLock) {
+            try {
+                putHeader(ra, mRaParams.hasDefaultRoute);
+
+                putSlla(ra, mHwAddr);
+
+                // https://tools.ietf.org/html/rfc5175#section-4 says:
+                //
+                //     "MUST NOT be added to a Router Advertisement message
+                //      if no flags in the option are set."
+                //
+                // putExpandedFlagsOption(ra);
+
+                putMtu(ra, mRaParams.mtu);
+
+                for (IpPrefix ipp : mRaParams.prefixes) {
+                    putPio(ra, ipp, DEFAULT_LIFETIME, DEFAULT_LIFETIME);
+                    mDeprecatedPrefixes.remove(ipp);
+                }
+
+                for (IpPrefix ipp : mDeprecatedPrefixes.keySet()) {
+                    putPio(ra, ipp, 0, 0);
+                }
+
+                if (mRaParams.dnses.size() > 0) {
+                    putRdnss(ra, mRaParams.dnses);
+                }
+
+                mRaLength = ra.position();
+            } catch (BufferOverflowException e) {
+                Log.e(TAG, "Could not construct new RA: " + e);
+                mRaLength = 0;
+                return;
+            }
+        }
+    }
+
+    private int decrementDeprecatedPrefixes() {
+        int removed = 0;
+
+        synchronized (mLock) {
+            for (Map.Entry<IpPrefix, Integer> kv : mDeprecatedPrefixes.entrySet()) {
+                if (kv.getValue() == 0) {
+                    mDeprecatedPrefixes.remove(kv.getKey());
+                    removed++;
+                } else {
+                    kv.setValue(kv.getValue() - 1);
+                }
+            }
+        }
+
+        return removed;
+    }
+
     private void maybeNotifyMulticastTransmitter() {
         final MulticastTransmitter m = mMulticastTransmitter;
         if (m != null) {
@@ -325,10 +374,11 @@
         ra.put(ND_OPTION_MTU)
           .put(MTU_NUM_8OCTETS)
           .putShort(asShort(0))
-          .putInt(mtu);
+          .putInt((mtu < IPV6_MIN_MTU) ? IPV6_MIN_MTU : mtu);
     }
 
-    private static void putPio(ByteBuffer ra, IpPrefix ipp) {
+    private static void putPio(ByteBuffer ra, IpPrefix ipp,
+                               int validTime, int preferredTime) {
         /**
             Prefix Information
 
@@ -359,13 +409,17 @@
         final byte ND_OPTION_PIO = 3;
         final byte PIO_NUM_8OCTETS = 4;
 
+        if (validTime < 0) validTime = 0;
+        if (preferredTime < 0) preferredTime = 0;
+        if (preferredTime > validTime) preferredTime = validTime;
+
         final byte[] addr = ipp.getAddress().getAddress();
         ra.put(ND_OPTION_PIO)
           .put(PIO_NUM_8OCTETS)
           .put(asByte(prefixLength))
-          .put(asByte(0xc0))  // L&A set
-          .putInt(DEFAULT_LIFETIME)
-          .putInt(DEFAULT_LIFETIME)
+          .put(asByte(0xc0)) /* L & A set */
+          .putInt(validTime)
+          .putInt(preferredTime)
           .putInt(0)
           .put(addr);
     }
@@ -547,6 +601,11 @@
                 }
 
                 maybeSendRA(mAllNodes);
+                if (decrementDeprecatedPrefixes() > 0) {
+                    // At least one deprecated PIO has been removed;
+                    // reassemble the RA.
+                    assembleRa();
+                }
             }
         }
 
@@ -560,15 +619,17 @@
         }
 
         private int getNextMulticastTransmitDelaySec() {
+            int countDeprecatedPrefixes = 0;
             synchronized (mLock) {
                 if (mRaLength < MIN_RA_HEADER_SIZE) {
                     // No actual RA to send; just sleep for 1 day.
                     return DAY_IN_SECONDS;
                 }
+                countDeprecatedPrefixes = mDeprecatedPrefixes.size();
             }
 
             final int urgentPending = mUrgentAnnouncements.getAndDecrement();
-            if (urgentPending > 0) {
+            if (urgentPending > 0 || countDeprecatedPrefixes > 0) {
                 return MIN_DELAY_BETWEEN_RAS_SEC;
             }
 
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index ef9739d..a247056 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -42,6 +42,7 @@
 import android.test.AndroidTestCase;
 import android.test.mock.MockContext;
 import android.test.mock.MockPackageManager;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 
 import java.io.File;
@@ -76,7 +77,7 @@
         super.tearDown();
     }
 
-    public class AccountSorter implements Comparator<Account> {
+    class AccountSorter implements Comparator<Account> {
         public int compare(Account object1, Account object2) {
             if (object1 == object2) return 0;
             if (object1 == null) return 1;
@@ -87,6 +88,7 @@
         }
     }
 
+    @SmallTest
     public void testCheckAddAccount() throws Exception {
         unlockSystemUser();
         Account a11 = new Account("account1", "type1");
@@ -128,6 +130,7 @@
         assertEquals(a31, accounts[1]);
     }
 
+    @SmallTest
     public void testPasswords() throws Exception {
         unlockSystemUser();
         Account a11 = new Account("account1", "type1");
@@ -144,6 +147,7 @@
         assertEquals("p12", mAms.getPassword(a12));
     }
 
+    @SmallTest
     public void testUserdata() throws Exception {
         unlockSystemUser();
         Account a11 = new Account("account1", "type1");
@@ -177,6 +181,7 @@
         assertNull(mAms.getUserData(a12, "c"));
     }
 
+    @SmallTest
     public void testAuthtokens() throws Exception {
         unlockSystemUser();
         Account a11 = new Account("account1", "type1");
@@ -211,6 +216,7 @@
         assertNull(mAms.peekAuthToken(a12, "att2"));
     }
 
+    @SmallTest
     public void testRemovedAccountSync() throws Exception {
         unlockSystemUser();
         Account a1 = new Account("account1", "type1");
@@ -242,6 +248,7 @@
         assertEquals("Only a2 should be returned", a2, accounts[0]);
     }
 
+    @SmallTest
     public void testPreNDatabaseMigration() throws Exception {
         String preNDatabaseName = mAms.getPreNDatabaseName(UserHandle.USER_SYSTEM);
         Context originalContext = ((MyMockContext) getContext()).mTestContext;
@@ -296,10 +303,10 @@
         return intent;
     }
 
-    static public class MockAccountAuthenticatorCache implements IAccountAuthenticatorCache {
+    static class MockAccountAuthenticatorCache implements IAccountAuthenticatorCache {
         private ArrayList<ServiceInfo<AuthenticatorDescription>> mServices;
 
-        public MockAccountAuthenticatorCache() {
+        MockAccountAuthenticatorCache() {
             mServices = new ArrayList<>();
             AuthenticatorDescription d1 = new AuthenticatorDescription("type1", "p1", 0, 0, 0, 0);
             AuthenticatorDescription d2 = new AuthenticatorDescription("type2", "p2", 0, 0, 0, 0);
@@ -339,13 +346,13 @@
         }
     }
 
-    static public class MyMockContext extends MockContext {
+    static class MyMockContext extends MockContext {
         private Context mTestContext;
         private AppOpsManager mAppOpsManager;
         private UserManager mUserManager;
         private PackageManager mPackageManager;
 
-        public MyMockContext(Context testContext) {
+        MyMockContext(Context testContext) {
             this.mTestContext = testContext;
             this.mAppOpsManager = mock(AppOpsManager.class);
             this.mUserManager = mock(UserManager.class);
@@ -411,16 +418,16 @@
         }
     }
 
-    static public class MyMockPackageManager extends MockPackageManager {
+    static class MyMockPackageManager extends MockPackageManager {
         @Override
         public int checkSignatures(final int uid1, final int uid2) {
             return PackageManager.SIGNATURE_MATCH;
         }
     }
 
-    static public class MyAccountManagerService extends AccountManagerService {
+    static class MyAccountManagerService extends AccountManagerService {
         private Context mRealTestContext;
-        public MyAccountManagerService(Context context, PackageManager packageManager,
+        MyAccountManagerService(Context context, PackageManager packageManager,
                 IAccountAuthenticatorCache authenticatorCache, Context realTestContext) {
             super(context, packageManager, authenticatorCache);
             this.mRealTestContext = realTestContext;
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 0515a9a..d003e56 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -246,6 +246,20 @@
         }
 
         @Override
+        protected boolean isUserUnlockedL(@UserIdInt int userId) {
+            // Note due to a late change, now ShortcutManager doesn't use
+            // UserManager.isUserUnlockingOrUnlocked().  But all unit tests are still using it,
+            // so we convert here.
+
+            final long token = injectClearCallingIdentity();
+            try {
+                return mMockUserManager.isUserUnlockingOrUnlocked(userId);
+            } finally {
+                injectRestoreCallingIdentity(token);
+            }
+        }
+
+        @Override
         int injectDipToPixel(int dip) {
             return dip;
         }
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 4eae4ab..330dbab 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -752,13 +752,6 @@
         throw new UnsupportedOperationException();
     }
 
-    /** @hide - hidden in superclass */
-    @Override
-    public void setComponentEnabledSettingAsUser(ComponentName componentName,
-            int newState, int flags, int userId) {
-        throw new UnsupportedOperationException();
-    }
-
     @Override
     public int getComponentEnabledSetting(ComponentName componentName) {
         throw new UnsupportedOperationException();
@@ -769,13 +762,6 @@
         throw new UnsupportedOperationException();
     }
 
-    /** @hide - hidden in superclass */
-    @Override
-    public void setApplicationEnabledSettingAsUser(String packageName, int newState, int flags,
-            int userId) {
-        throw new UnsupportedOperationException();
-    }
-
     @Override
     public int getApplicationEnabledSetting(String packageName) {
         throw new UnsupportedOperationException();
diff --git a/tools/aapt2/link/ReferenceLinker.cpp b/tools/aapt2/link/ReferenceLinker.cpp
index fe886de..6aa9c0e 100644
--- a/tools/aapt2/link/ReferenceLinker.cpp
+++ b/tools/aapt2/link/ReferenceLinker.cpp
@@ -231,6 +231,7 @@
                                                                std::string* outError) {
     const SymbolTable::Symbol* symbol = resolveSymbol(reference, nameMangler, symbols);
     if (!symbol) {
+        if (outError) *outError = "not found";
         return {};
     }
 
diff --git a/tools/aapt2/public_attr_map.py b/tools/aapt2/tools/public_attr_map.py
similarity index 100%
rename from tools/aapt2/public_attr_map.py
rename to tools/aapt2/tools/public_attr_map.py
diff --git a/tools/aapt2/remove-duplicates.py b/tools/aapt2/tools/remove-duplicates.py
similarity index 100%
rename from tools/aapt2/remove-duplicates.py
rename to tools/aapt2/tools/remove-duplicates.py
diff --git a/tools/aapt2/util/Util.cpp b/tools/aapt2/util/Util.cpp
index 3c0e9bde..e743247 100644
--- a/tools/aapt2/util/Util.cpp
+++ b/tools/aapt2/util/Util.cpp
@@ -434,7 +434,11 @@
 
     std::u16string utf16;
     utf16.resize(utf16Length);
-    utf8_to_utf16(reinterpret_cast<const uint8_t*>(utf8.data()), utf8.length(), &*utf16.begin());
+    utf8_to_utf16(
+            reinterpret_cast<const uint8_t*>(utf8.data()),
+            utf8.length(),
+            &*utf16.begin(),
+            (size_t) utf16Length + 1);
     return utf16;
 }
 
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
index 1d5ac0c..9da65a6 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
@@ -638,7 +638,15 @@
             }
         }
 
-        // not a direct id valid reference? resolve it
+        // not a direct id valid reference. First check if it's an enum (this is a corner case
+        // for attributes that have a reference|enum type), then fallback to resolve
+        // as an ID without prefix.
+        Integer enumValue = resolveEnumAttribute(index);
+        if (enumValue != null) {
+            return enumValue;
+        }
+
+        // Ok, not an enum, resolve as an ID
         Integer idValue;
 
         if (resValue.isFramework()) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
index cef622b..b3ed9e1 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
@@ -712,11 +712,6 @@
     }
 
     @Override
-    public void setComponentEnabledSettingAsUser(ComponentName componentName, int newState,
-            int flags, int userId) {
-    }
-
-    @Override
     public int getComponentEnabledSetting(ComponentName componentName) {
         return 0;
     }
@@ -726,11 +721,6 @@
     }
 
     @Override
-    public void setApplicationEnabledSettingAsUser(String packageName, int newState, int flags,
-            int userId) {
-    }
-
-    @Override
     public int getApplicationEnabledSetting(String packageName) {
         return 0;
     }