Merge "Add ability to get device by address" into mnc-dev
diff --git a/api/current.txt b/api/current.txt
index d38e75a..aa0f946 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2716,6 +2716,7 @@
     method public final android.os.IBinder getIBinder();
     method public abstract android.os.Bundle hasFeatures(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String[]) throws android.accounts.NetworkErrorException;
     method public abstract android.os.Bundle updateCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
+    field public static final java.lang.String KEY_CUSTOM_TOKEN_EXPIRY = "android.accounts.expiry";
   }
 
   public class Account implements android.os.Parcelable {
@@ -37390,7 +37391,6 @@
     field public static final int TITLE_CHANGED = 64; // 0x40
     field public static final int TYPE_ACCESSIBILITY_OVERLAY = 2032; // 0x7f0
     field public static final int TYPE_APPLICATION = 2; // 0x2
-    field public static final int TYPE_APPLICATION_ABOVE_SUB_PANEL = 1005; // 0x3ed
     field public static final int TYPE_APPLICATION_ATTACHED_DIALOG = 1003; // 0x3eb
     field public static final int TYPE_APPLICATION_MEDIA = 1001; // 0x3e9
     field public static final int TYPE_APPLICATION_PANEL = 1000; // 0x3e8
diff --git a/api/system-current.txt b/api/system-current.txt
index 44d8c8e..9b2f0a0 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -71,6 +71,7 @@
     field public static final java.lang.String CAPTURE_VIDEO_OUTPUT = "android.permission.CAPTURE_VIDEO_OUTPUT";
     field public static final java.lang.String CHANGE_COMPONENT_ENABLED_STATE = "android.permission.CHANGE_COMPONENT_ENABLED_STATE";
     field public static final java.lang.String CHANGE_CONFIGURATION = "android.permission.CHANGE_CONFIGURATION";
+    field public static final java.lang.String CHANGE_DEVICE_IDLE_TEMP_WHITELIST = "android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST";
     field public static final java.lang.String CHANGE_NETWORK_STATE = "android.permission.CHANGE_NETWORK_STATE";
     field public static final java.lang.String CHANGE_WIFI_MULTICAST_STATE = "android.permission.CHANGE_WIFI_MULTICAST_STATE";
     field public static final java.lang.String CHANGE_WIFI_STATE = "android.permission.CHANGE_WIFI_STATE";
@@ -2797,6 +2798,7 @@
     method public final android.os.IBinder getIBinder();
     method public abstract android.os.Bundle hasFeatures(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String[]) throws android.accounts.NetworkErrorException;
     method public abstract android.os.Bundle updateCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
+    field public static final java.lang.String KEY_CUSTOM_TOKEN_EXPIRY = "android.accounts.expiry";
   }
 
   public class Account implements android.os.Parcelable {
@@ -6331,6 +6333,7 @@
     method public java.util.List<android.app.usage.ConfigurationStats> queryConfigurations(int, long, long);
     method public android.app.usage.UsageEvents queryEvents(long, long);
     method public java.util.List<android.app.usage.UsageStats> queryUsageStats(int, long, long);
+    method public void whitelistAppTemporarily(java.lang.String, long, android.os.UserHandle);
     field public static final int INTERVAL_BEST = 4; // 0x4
     field public static final int INTERVAL_DAILY = 0; // 0x0
     field public static final int INTERVAL_MONTHLY = 2; // 0x2
@@ -6486,7 +6489,9 @@
     method public static boolean checkBluetoothAddress(java.lang.String);
     method public void closeProfileProxy(int, android.bluetooth.BluetoothProfile);
     method public boolean disable();
+    method public boolean disableBLE();
     method public boolean enable();
+    method public boolean enableBLE();
     method public java.lang.String getAddress();
     method public android.bluetooth.le.BluetoothLeAdvertiser getBluetoothLeAdvertiser();
     method public android.bluetooth.le.BluetoothLeScanner getBluetoothLeScanner();
@@ -6502,6 +6507,7 @@
     method public boolean isBleScanAlwaysAvailable();
     method public boolean isDiscovering();
     method public boolean isEnabled();
+    method public boolean isLeEnabled();
     method public boolean isMultipleAdvertisementSupported();
     method public boolean isOffloadedFilteringSupported();
     method public boolean isOffloadedScanBatchingSupported();
@@ -6512,6 +6518,7 @@
     method public deprecated boolean startLeScan(android.bluetooth.BluetoothAdapter.LeScanCallback);
     method public deprecated boolean startLeScan(java.util.UUID[], android.bluetooth.BluetoothAdapter.LeScanCallback);
     method public deprecated void stopLeScan(android.bluetooth.BluetoothAdapter.LeScanCallback);
+    field public static final java.lang.String ACTION_BLE_STATE_CHANGED = "android.bluetooth.adapter.action.BLE_STATE_CHANGED";
     field public static final java.lang.String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED";
     field public static final java.lang.String ACTION_DISCOVERY_FINISHED = "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
     field public static final java.lang.String ACTION_DISCOVERY_STARTED = "android.bluetooth.adapter.action.DISCOVERY_STARTED";
@@ -39651,7 +39658,6 @@
     field public static final int TITLE_CHANGED = 64; // 0x40
     field public static final int TYPE_ACCESSIBILITY_OVERLAY = 2032; // 0x7f0
     field public static final int TYPE_APPLICATION = 2; // 0x2
-    field public static final int TYPE_APPLICATION_ABOVE_SUB_PANEL = 1005; // 0x3ed
     field public static final int TYPE_APPLICATION_ATTACHED_DIALOG = 1003; // 0x3eb
     field public static final int TYPE_APPLICATION_MEDIA = 1001; // 0x3e9
     field public static final int TYPE_APPLICATION_PANEL = 1000; // 0x3e8
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java
index dbc9051..3e4a66d 100644
--- a/core/java/android/accounts/AbstractAccountAuthenticator.java
+++ b/core/java/android/accounts/AbstractAccountAuthenticator.java
@@ -108,6 +108,14 @@
 public abstract class AbstractAccountAuthenticator {
     private static final String TAG = "AccountAuthenticator";
 
+    /**
+     * Bundle key used for the {@code long} expiration time (in millis from the unix epoch) of the
+     * associated auth token.
+     *
+     * @see #getAuthToken
+     */
+    public static final String KEY_CUSTOM_TOKEN_EXPIRY = "android.accounts.expiry";
+
     private final Context mContext;
 
     public AbstractAccountAuthenticator(Context context) {
@@ -115,6 +123,7 @@
     }
 
     private class Transport extends IAccountAuthenticator.Stub {
+        @Override
         public void addAccount(IAccountAuthenticatorResponse response, String accountType,
                 String authTokenType, String[] features, Bundle options)
                 throws RemoteException {
@@ -140,6 +149,7 @@
             }
         }
 
+        @Override
         public void confirmCredentials(IAccountAuthenticatorResponse response,
                 Account account, Bundle options) throws RemoteException {
             if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -162,6 +172,7 @@
             }
         }
 
+        @Override
         public void getAuthTokenLabel(IAccountAuthenticatorResponse response,
                 String authTokenType)
                 throws RemoteException {
@@ -184,6 +195,7 @@
             }
         }
 
+        @Override
         public void getAuthToken(IAccountAuthenticatorResponse response,
                 Account account, String authTokenType, Bundle loginOptions)
                 throws RemoteException {
@@ -209,6 +221,7 @@
             }
         }
 
+        @Override
         public void updateCredentials(IAccountAuthenticatorResponse response, Account account,
                 String authTokenType, Bundle loginOptions) throws RemoteException {
             if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -234,6 +247,7 @@
             }
         }
 
+        @Override
         public void editProperties(IAccountAuthenticatorResponse response,
                 String accountType) throws RemoteException {
             checkBinderPermission();
@@ -248,6 +262,7 @@
             }
         }
 
+        @Override
         public void hasFeatures(IAccountAuthenticatorResponse response,
                 Account account, String[] features) throws RemoteException {
             checkBinderPermission();
@@ -262,6 +277,7 @@
             }
         }
 
+        @Override
         public void getAccountRemovalAllowed(IAccountAuthenticatorResponse response,
                 Account account) throws RemoteException {
             checkBinderPermission();
@@ -276,6 +292,7 @@
             }
         }
 
+        @Override
         public void getAccountCredentialsForCloning(IAccountAuthenticatorResponse response,
                 Account account) throws RemoteException {
             checkBinderPermission();
@@ -291,6 +308,7 @@
             }
         }
 
+        @Override
         public void addAccountFromCredentials(IAccountAuthenticatorResponse response,
                 Account account,
                 Bundle accountCredentials) throws RemoteException {
@@ -410,21 +428,42 @@
     public abstract Bundle confirmCredentials(AccountAuthenticatorResponse response,
             Account account, Bundle options)
             throws NetworkErrorException;
+
     /**
-     * Gets the authtoken for an account.
+     * Gets an authtoken for an account.
+     *
+     * If not {@code null}, the resultant {@link Bundle} will contain different sets of keys
+     * depending on whether a token was successfully issued and, if not, whether one
+     * could be issued via some {@link android.app.Activity}.
+     * <p>
+     * If a token cannot be provided without some additional activity, the Bundle should contain
+     * {@link AccountManager#KEY_INTENT} with an associated {@link Intent}. On the other hand, if
+     * there is no such activity, then a Bundle containing
+     * {@link AccountManager#KEY_ERROR_CODE} and {@link AccountManager#KEY_ERROR_MESSAGE} should be
+     * returned.
+     * <p>
+     * If a token can be successfully issued, the implementation should return the
+     * {@link AccountManager#KEY_ACCOUNT_NAME} and {@link AccountManager#KEY_ACCOUNT_TYPE} of the
+     * account associated with the token as well as the {@link AccountManager#KEY_AUTHTOKEN}. In
+     * addition {@link AbstractAccountAuthenticator} implementations that declare themselves
+     * {@code android:customTokens=true} may also provide a non-negative {@link
+     * #KEY_CUSTOM_TOKEN_EXPIRY} long value containing the expiration timestamp of the expiration
+     * time (in millis since the unix epoch).
+     * <p>
+     * Implementers should assume that tokens will be cached on the basis of account and
+     * authTokenType. The system may ignore the contents of the supplied options Bundle when
+     * determining to re-use a cached token. Furthermore, implementers should assume a supplied
+     * expiration time will be treated as non-binding advice.
+     * <p>
+     * Finally, note that for android:customTokens=false authenticators, tokens are cached
+     * indefinitely until some client calls {@link
+     * AccountManager#invalidateAuthToken(String,String)}.
+     *
      * @param response to send the result back to the AccountManager, will never be null
      * @param account the account whose credentials are to be retrieved, will never be null
      * @param authTokenType the type of auth token to retrieve, will never be null
      * @param options a Bundle of authenticator-specific options, may be null
-     * @return a Bundle result or null if the result is to be returned via the response. The result
-     * will contain either:
-     * <ul>
-     * <li> {@link AccountManager#KEY_INTENT}, or
-     * <li> {@link AccountManager#KEY_ACCOUNT_NAME}, {@link AccountManager#KEY_ACCOUNT_TYPE},
-     * and {@link AccountManager#KEY_AUTHTOKEN}, or
-     * <li> {@link AccountManager#KEY_ERROR_CODE} and {@link AccountManager#KEY_ERROR_MESSAGE} to
-     * indicate an error
-     * </ul>
+     * @return a Bundle result or null if the result is to be returned via the response.
      * @throws NetworkErrorException if the authenticator could not honor the request due to a
      * network error
      */
@@ -518,6 +557,7 @@
     public Bundle getAccountCredentialsForCloning(final AccountAuthenticatorResponse response,
             final Account account) throws NetworkErrorException {
         new Thread(new Runnable() {
+            @Override
             public void run() {
                 Bundle result = new Bundle();
                 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
@@ -543,6 +583,7 @@
             Account account,
             Bundle accountCredentials) throws NetworkErrorException {
         new Thread(new Runnable() {
+            @Override
             public void run() {
                 Bundle result = new Bundle();
                 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 978b4bc..a0b95b6 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -16,6 +16,8 @@
 
 package android.app.admin;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
@@ -76,7 +78,7 @@
  * <h3>Developer Guides</h3>
  * <p>For more information about managing policies for device administration, read the
  * <a href="{@docRoot}guide/topics/admin/device-admin.html">Device Administration</a>
- * developer guide.</p>
+ * developer guide.
  * </div>
  */
 public class DevicePolicyManager {
@@ -122,9 +124,6 @@
      *
      * <p> If provisioning fails, the managedProfile is removed so the device returns to its
      * previous state.
-     *
-     * <p>Input: Nothing.</p>
-     * <p>Output: Nothing</p>
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_PROVISION_MANAGED_PROFILE
@@ -155,7 +154,7 @@
      * message containing an NFC record with MIME type {@link #MIME_TYPE_PROVISIONING_NFC}.
      *
      * <p> When this extra is set, the application must have exactly one device admin receiver.
-     * This receiver will be set as the profile or device owner and active admin.</p>
+     * This receiver will be set as the profile or device owner and active admin.
 
      * @see DeviceAdminReceiver
      * @deprecated Use {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}. This extra is still
@@ -212,7 +211,7 @@
 
     /**
      * A Boolean extra that can be used by the mobile device management application to skip the
-     * disabling of system apps during provisioning when set to <code>true</code>.
+     * disabling of system apps during provisioning when set to {@code true}.
      *
      * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
      * provisioning via an NFC bump.
@@ -644,9 +643,6 @@
      *
      * <p>
      * If provisioning fails, the device is factory reset.
-     *
-     * <p>Input: Nothing.</p>
-     * <p>Output: Nothing</p>
      */
     public static final String MIME_TYPE_PROVISIONING_NFC_V2
             = "application/com.android.managedprovisioning.v2";
@@ -847,18 +843,18 @@
      * Return true if the given administrator component is currently
      * active (enabled) in the system.
      */
-    public boolean isAdminActive(ComponentName who) {
-        return isAdminActiveAsUser(who, UserHandle.myUserId());
+    public boolean isAdminActive(@NonNull ComponentName admin) {
+        return isAdminActiveAsUser(admin, UserHandle.myUserId());
     }
 
     /**
      * @see #isAdminActive(ComponentName)
      * @hide
      */
-    public boolean isAdminActiveAsUser(ComponentName who, int userId) {
+    public boolean isAdminActiveAsUser(@NonNull ComponentName admin, int userId) {
         if (mService != null) {
             try {
-                return mService.isAdminActive(who, userId);
+                return mService.isAdminActive(admin, userId);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -870,10 +866,10 @@
      * for the user.
      * @hide
      */
-    public boolean isRemovingAdmin(ComponentName who, int userId) {
+    public boolean isRemovingAdmin(@NonNull ComponentName admin, int userId) {
         if (mService != null) {
             try {
-                return mService.isRemovingAdmin(who, userId);
+                return mService.isRemovingAdmin(admin, userId);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -883,8 +879,8 @@
 
 
     /**
-     * Return a list of all currently active device administrator's component
-     * names.  Note that if there are no administrators than null may be
+     * Return a list of all currently active device administrators' component
+     * names.  If there are no administrators {@code null} may be
      * returned.
      */
     public List<ComponentName> getActiveAdmins() {
@@ -928,10 +924,10 @@
      * try to remove someone else's component, a security exception will be
      * thrown.
      */
-    public void removeActiveAdmin(ComponentName who) {
+    public void removeActiveAdmin(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
-                mService.removeActiveAdmin(who, UserHandle.myUserId());
+                mService.removeActiveAdmin(admin, UserHandle.myUserId());
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -940,14 +936,14 @@
 
     /**
      * Returns true if an administrator has been granted a particular device policy.  This can
-     * be used to check if the administrator was activated under an earlier set of policies,
+     * be used to check whether the administrator was activated under an earlier set of policies,
      * but requires additional policies after an upgrade.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.  Must be
      * an active administrator, or an exception will be thrown.
      * @param usesPolicy Which uses-policy to check, as defined in {@link DeviceAdminInfo}.
      */
-    public boolean hasGrantedPolicy(ComponentName admin, int usesPolicy) {
+    public boolean hasGrantedPolicy(@NonNull ComponentName admin, int usesPolicy) {
         if (mService != null) {
             try {
                 return mService.hasGrantedPolicy(admin, usesPolicy, UserHandle.myUserId());
@@ -1048,7 +1044,7 @@
      * {@link #PASSWORD_QUALITY_ALPHABETIC}, {@link #PASSWORD_QUALITY_ALPHANUMERIC}
      * or {@link #PASSWORD_QUALITY_COMPLEX}.
      */
-    public void setPasswordQuality(ComponentName admin, int quality) {
+    public void setPasswordQuality(@NonNull ComponentName admin, int quality) {
         if (mService != null) {
             try {
                 mService.setPasswordQuality(admin, quality);
@@ -1061,15 +1057,15 @@
     /**
      * Retrieve the current minimum password quality for all admins of this user
      * and its profiles or a particular one.
-     * @param admin The name of the admin component to check, or null to aggregate
+     * @param admin The name of the admin component to check, or {@code null} to aggregate
      * all admins.
      */
-    public int getPasswordQuality(ComponentName admin) {
+    public int getPasswordQuality(@Nullable ComponentName admin) {
         return getPasswordQuality(admin, UserHandle.myUserId());
     }
 
     /** @hide per-user version */
-    public int getPasswordQuality(ComponentName admin, int userHandle) {
+    public int getPasswordQuality(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
                 return mService.getPasswordQuality(admin, userHandle);
@@ -1101,7 +1097,7 @@
      * @param length The new desired minimum password length.  A value of 0
      * means there is no restriction.
      */
-    public void setPasswordMinimumLength(ComponentName admin, int length) {
+    public void setPasswordMinimumLength(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
                 mService.setPasswordMinimumLength(admin, length);
@@ -1114,15 +1110,15 @@
     /**
      * Retrieve the current minimum password length for all admins of this
      * user and its profiles or a particular one.
-     * @param admin The name of the admin component to check, or null to aggregate
+     * @param admin The name of the admin component to check, or {@code null} to aggregate
      * all admins.
      */
-    public int getPasswordMinimumLength(ComponentName admin) {
+    public int getPasswordMinimumLength(@Nullable ComponentName admin) {
         return getPasswordMinimumLength(admin, UserHandle.myUserId());
     }
 
     /** @hide per-user version */
-    public int getPasswordMinimumLength(ComponentName admin, int userHandle) {
+    public int getPasswordMinimumLength(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
                 return mService.getPasswordMinimumLength(admin, userHandle);
@@ -1155,7 +1151,7 @@
      *            required in the password. A value of 0 means there is no
      *            restriction.
      */
-    public void setPasswordMinimumUpperCase(ComponentName admin, int length) {
+    public void setPasswordMinimumUpperCase(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
                 mService.setPasswordMinimumUpperCase(admin, length);
@@ -1173,17 +1169,17 @@
      * and only applies when the password quality is
      * {@link #PASSWORD_QUALITY_COMPLEX}.
      *
-     * @param admin The name of the admin component to check, or null to
+     * @param admin The name of the admin component to check, or {@code null} to
      *            aggregate all admins.
      * @return The minimum number of upper case letters required in the
      *         password.
      */
-    public int getPasswordMinimumUpperCase(ComponentName admin) {
+    public int getPasswordMinimumUpperCase(@Nullable ComponentName admin) {
         return getPasswordMinimumUpperCase(admin, UserHandle.myUserId());
     }
 
     /** @hide per-user version */
-    public int getPasswordMinimumUpperCase(ComponentName admin, int userHandle) {
+    public int getPasswordMinimumUpperCase(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
                 return mService.getPasswordMinimumUpperCase(admin, userHandle);
@@ -1216,7 +1212,7 @@
      *            required in the password. A value of 0 means there is no
      *            restriction.
      */
-    public void setPasswordMinimumLowerCase(ComponentName admin, int length) {
+    public void setPasswordMinimumLowerCase(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
                 mService.setPasswordMinimumLowerCase(admin, length);
@@ -1234,17 +1230,17 @@
      * and only applies when the password quality is
      * {@link #PASSWORD_QUALITY_COMPLEX}.
      *
-     * @param admin The name of the admin component to check, or null to
+     * @param admin The name of the admin component to check, or {@code null} to
      *            aggregate all admins.
      * @return The minimum number of lower case letters required in the
      *         password.
      */
-    public int getPasswordMinimumLowerCase(ComponentName admin) {
+    public int getPasswordMinimumLowerCase(@Nullable ComponentName admin) {
         return getPasswordMinimumLowerCase(admin, UserHandle.myUserId());
     }
 
     /** @hide per-user version */
-    public int getPasswordMinimumLowerCase(ComponentName admin, int userHandle) {
+    public int getPasswordMinimumLowerCase(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
                 return mService.getPasswordMinimumLowerCase(admin, userHandle);
@@ -1276,7 +1272,7 @@
      * @param length The new desired minimum number of letters required in the
      *            password. A value of 0 means there is no restriction.
      */
-    public void setPasswordMinimumLetters(ComponentName admin, int length) {
+    public void setPasswordMinimumLetters(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
                 mService.setPasswordMinimumLetters(admin, length);
@@ -1293,16 +1289,16 @@
      * and only applies when the password quality is
      * {@link #PASSWORD_QUALITY_COMPLEX}.
      *
-     * @param admin The name of the admin component to check, or null to
+     * @param admin The name of the admin component to check, or {@code null} to
      *            aggregate all admins.
      * @return The minimum number of letters required in the password.
      */
-    public int getPasswordMinimumLetters(ComponentName admin) {
+    public int getPasswordMinimumLetters(@Nullable ComponentName admin) {
         return getPasswordMinimumLetters(admin, UserHandle.myUserId());
     }
 
     /** @hide per-user version */
-    public int getPasswordMinimumLetters(ComponentName admin, int userHandle) {
+    public int getPasswordMinimumLetters(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
                 return mService.getPasswordMinimumLetters(admin, userHandle);
@@ -1334,7 +1330,7 @@
      * @param length The new desired minimum number of numerical digits required
      *            in the password. A value of 0 means there is no restriction.
      */
-    public void setPasswordMinimumNumeric(ComponentName admin, int length) {
+    public void setPasswordMinimumNumeric(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
                 mService.setPasswordMinimumNumeric(admin, length);
@@ -1352,16 +1348,16 @@
      * and only applies when the password quality is
      * {@link #PASSWORD_QUALITY_COMPLEX}.
      *
-     * @param admin The name of the admin component to check, or null to
+     * @param admin The name of the admin component to check, or {@code null} to
      *            aggregate all admins.
      * @return The minimum number of numerical digits required in the password.
      */
-    public int getPasswordMinimumNumeric(ComponentName admin) {
+    public int getPasswordMinimumNumeric(@Nullable ComponentName admin) {
         return getPasswordMinimumNumeric(admin, UserHandle.myUserId());
     }
 
     /** @hide per-user version */
-    public int getPasswordMinimumNumeric(ComponentName admin, int userHandle) {
+    public int getPasswordMinimumNumeric(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
                 return mService.getPasswordMinimumNumeric(admin, userHandle);
@@ -1393,7 +1389,7 @@
      * @param length The new desired minimum number of symbols required in the
      *            password. A value of 0 means there is no restriction.
      */
-    public void setPasswordMinimumSymbols(ComponentName admin, int length) {
+    public void setPasswordMinimumSymbols(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
                 mService.setPasswordMinimumSymbols(admin, length);
@@ -1410,16 +1406,16 @@
      * and only applies when the password quality is
      * {@link #PASSWORD_QUALITY_COMPLEX}.
      *
-     * @param admin The name of the admin component to check, or null to
+     * @param admin The name of the admin component to check, or {@code null} to
      *            aggregate all admins.
      * @return The minimum number of symbols required in the password.
      */
-    public int getPasswordMinimumSymbols(ComponentName admin) {
+    public int getPasswordMinimumSymbols(@Nullable ComponentName admin) {
         return getPasswordMinimumSymbols(admin, UserHandle.myUserId());
     }
 
     /** @hide per-user version */
-    public int getPasswordMinimumSymbols(ComponentName admin, int userHandle) {
+    public int getPasswordMinimumSymbols(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
                 return mService.getPasswordMinimumSymbols(admin, userHandle);
@@ -1451,7 +1447,7 @@
      * @param length The new desired minimum number of letters required in the
      *            password. A value of 0 means there is no restriction.
      */
-    public void setPasswordMinimumNonLetter(ComponentName admin, int length) {
+    public void setPasswordMinimumNonLetter(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
                 mService.setPasswordMinimumNonLetter(admin, length);
@@ -1469,16 +1465,16 @@
      * and only applies when the password quality is
      * {@link #PASSWORD_QUALITY_COMPLEX}.
      *
-     * @param admin The name of the admin component to check, or null to
+     * @param admin The name of the admin component to check, or {@code null} to
      *            aggregate all admins.
      * @return The minimum number of letters required in the password.
      */
-    public int getPasswordMinimumNonLetter(ComponentName admin) {
+    public int getPasswordMinimumNonLetter(@Nullable ComponentName admin) {
         return getPasswordMinimumNonLetter(admin, UserHandle.myUserId());
     }
 
     /** @hide per-user version */
-    public int getPasswordMinimumNonLetter(ComponentName admin, int userHandle) {
+    public int getPasswordMinimumNonLetter(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
                 return mService.getPasswordMinimumNonLetter(admin, userHandle);
@@ -1511,7 +1507,7 @@
    * @param length The new desired length of password history. A value of 0
    *        means there is no restriction.
    */
-    public void setPasswordHistoryLength(ComponentName admin, int length) {
+    public void setPasswordHistoryLength(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
                 mService.setPasswordHistoryLength(admin, length);
@@ -1543,7 +1539,7 @@
      * @param timeout The limit (in ms) that a password can remain in effect. A value of 0
      *        means there is no restriction (unlimited).
      */
-    public void setPasswordExpirationTimeout(ComponentName admin, long timeout) {
+    public void setPasswordExpirationTimeout(@NonNull ComponentName admin, long timeout) {
         if (mService != null) {
             try {
                 mService.setPasswordExpirationTimeout(admin, timeout);
@@ -1557,12 +1553,12 @@
      * Get the password expiration timeout for the given admin. The expiration timeout is the
      * recurring expiration timeout provided in the call to
      * {@link #setPasswordExpirationTimeout(ComponentName, long)} for the given admin or the
-     * aggregate of all policy administrators if admin is null.
+     * aggregate of all policy administrators if {@code admin} is null.
      *
-     * @param admin The name of the admin component to check, or null to aggregate all admins.
+     * @param admin The name of the admin component to check, or {@code null} to aggregate all admins.
      * @return The timeout for the given admin or the minimum of all timeouts
      */
-    public long getPasswordExpirationTimeout(ComponentName admin) {
+    public long getPasswordExpirationTimeout(@Nullable ComponentName admin) {
         if (mService != null) {
             try {
                 return mService.getPasswordExpirationTimeout(admin, UserHandle.myUserId());
@@ -1580,10 +1576,10 @@
      * If admin is null, then a composite of all expiration timeouts is returned
      * - which will be the minimum of all timeouts.
      *
-     * @param admin The name of the admin component to check, or null to aggregate all admins.
+     * @param admin The name of the admin component to check, or {@code null} to aggregate all admins.
      * @return The password expiration time, in ms.
      */
-    public long getPasswordExpiration(ComponentName admin) {
+    public long getPasswordExpiration(@Nullable ComponentName admin) {
         if (mService != null) {
             try {
                 return mService.getPasswordExpiration(admin, UserHandle.myUserId());
@@ -1597,16 +1593,16 @@
     /**
      * Retrieve the current password history length for all admins of this
      * user and its profiles or a particular one.
-     * @param admin The name of the admin component to check, or null to aggregate
+     * @param admin The name of the admin component to check, or {@code null} to aggregate
      * all admins.
      * @return The length of the password history
      */
-    public int getPasswordHistoryLength(ComponentName admin) {
+    public int getPasswordHistoryLength(@Nullable ComponentName admin) {
         return getPasswordHistoryLength(admin, UserHandle.myUserId());
     }
 
     /** @hide per-user version */
-    public int getPasswordHistoryLength(ComponentName admin, int userHandle) {
+    public int getPasswordHistoryLength(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
                 return mService.getPasswordHistoryLength(admin, userHandle);
@@ -1705,7 +1701,7 @@
      * @param num The number of failed password attempts at which point the
      * device will wipe its data.
      */
-    public void setMaximumFailedPasswordsForWipe(ComponentName admin, int num) {
+    public void setMaximumFailedPasswordsForWipe(@NonNull ComponentName admin, int num) {
         if (mService != null) {
             try {
                 mService.setMaximumFailedPasswordsForWipe(admin, num);
@@ -1719,15 +1715,15 @@
      * Retrieve the current maximum number of login attempts that are allowed
      * before the device wipes itself, for all admins of this user and its profiles
      * or a particular one.
-     * @param admin The name of the admin component to check, or null to aggregate
+     * @param admin The name of the admin component to check, or {@code null} to aggregate
      * all admins.
      */
-    public int getMaximumFailedPasswordsForWipe(ComponentName admin) {
+    public int getMaximumFailedPasswordsForWipe(@Nullable ComponentName admin) {
         return getMaximumFailedPasswordsForWipe(admin, UserHandle.myUserId());
     }
 
     /** @hide per-user version */
-    public int getMaximumFailedPasswordsForWipe(ComponentName admin, int userHandle) {
+    public int getMaximumFailedPasswordsForWipe(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
                 return mService.getMaximumFailedPasswordsForWipe(admin, userHandle);
@@ -1824,7 +1820,7 @@
      * @param timeMs The new desired maximum time to lock in milliseconds.
      * A value of 0 means there is no restriction.
      */
-    public void setMaximumTimeToLock(ComponentName admin, long timeMs) {
+    public void setMaximumTimeToLock(@NonNull ComponentName admin, long timeMs) {
         if (mService != null) {
             try {
                 mService.setMaximumTimeToLock(admin, timeMs);
@@ -1837,17 +1833,17 @@
     /**
      * Retrieve the current maximum time to unlock for all admins of this user
      * and its profiles or a particular one.
-     * @param admin The name of the admin component to check, or null to aggregate
+     * @param admin The name of the admin component to check, or {@code null} to aggregate
      * all admins.
      * @return time in milliseconds for the given admin or the minimum value (strictest) of
      * all admins if admin is null. Returns 0 if there are no restrictions.
      */
-    public long getMaximumTimeToLock(ComponentName admin) {
+    public long getMaximumTimeToLock(@Nullable ComponentName admin) {
         return getMaximumTimeToLock(admin, UserHandle.myUserId());
     }
 
     /** @hide per-user version */
-    public long getMaximumTimeToLock(ComponentName admin, int userHandle) {
+    public long getMaximumTimeToLock(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
                 return mService.getMaximumTimeToLock(admin, userHandle);
@@ -1922,21 +1918,20 @@
      * this method; if it has not, a security exception will be thrown.
      * Only the first device admin can set the proxy. If a second admin attempts
      * to set the proxy, the {@link ComponentName} of the admin originally setting the
-     * proxy will be returned. If successful in setting the proxy, null will
+     * proxy will be returned. If successful in setting the proxy, {@code null} will
      * be returned.
      * The method can be called repeatedly by the device admin alrady setting the
      * proxy to update the proxy and exclusion list.
      *
-     * @param admin Which {@link DeviceAdminReceiver} this request is associated
-     *            with.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param proxySpec the global proxy desired. Must be an HTTP Proxy.
      *            Pass Proxy.NO_PROXY to reset the proxy.
      * @param exclusionList a list of domains to be excluded from the global proxy.
-     * @return returns null if the proxy was successfully set, or a {@link ComponentName}
-     *            of the device admin that sets thew proxy otherwise.
+     * @return {@code null} if the proxy was successfully set, or otherwise a {@link ComponentName}
+     *            of the device admin that sets the proxy.
      * @hide
      */
-    public ComponentName setGlobalProxy(ComponentName admin, Proxy proxySpec,
+    public ComponentName setGlobalProxy(@NonNull ComponentName admin, Proxy proxySpec,
             List<String> exclusionList ) {
         if (proxySpec == null) {
             throw new NullPointerException();
@@ -2001,7 +1996,8 @@
      * @param proxyInfo The a {@link ProxyInfo} object defining the new global
      *        HTTP proxy.  A {@code null} value will clear the global HTTP proxy.
      */
-    public void setRecommendedGlobalProxy(ComponentName admin, ProxyInfo proxyInfo) {
+    public void setRecommendedGlobalProxy(@NonNull ComponentName admin, @Nullable ProxyInfo
+            proxyInfo) {
         if (mService != null) {
             try {
                 mService.setRecommendedGlobalProxy(admin, proxyInfo);
@@ -2013,8 +2009,8 @@
 
     /**
      * Returns the component name setting the global proxy.
-     * @return ComponentName object of the device admin that set the global proxy, or
-     *            null if no admin has set the proxy.
+     * @return ComponentName object of the device admin that set the global proxy, or {@code null}
+     *         if no admin has set the proxy.
      * @hide
      */
     public ComponentName getGlobalProxyAdmin() {
@@ -2147,7 +2143,7 @@
      * {@link #ENCRYPTION_STATUS_ACTIVE}.  This is the value of the requests;  Use
      * {@link #getStorageEncryptionStatus()} to query the actual device state.
      */
-    public int setStorageEncryption(ComponentName admin, boolean encrypt) {
+    public int setStorageEncryption(@NonNull ComponentName admin, boolean encrypt) {
         if (mService != null) {
             try {
                 return mService.setStorageEncryption(admin, encrypt);
@@ -2167,7 +2163,7 @@
      * administrators.
      * @return true if the admin(s) are requesting encryption, false if not.
      */
-    public boolean getStorageEncryption(ComponentName admin) {
+    public boolean getStorageEncryption(@Nullable ComponentName admin) {
         if (mService != null) {
             try {
                 return mService.getStorageEncryption(admin, UserHandle.myUserId());
@@ -2216,14 +2212,14 @@
     /**
      * Installs the given certificate as a user CA.
      *
-     * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Use
-     * <code>null</code> if calling from a delegated certificate installer.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+     *              {@code null} if calling from a delegated certificate installer.
      * @param certBuffer encoded form of the certificate to install.
      *
      * @return false if the certBuffer cannot be parsed or installation is
      *         interrupted, true otherwise.
      */
-    public boolean installCaCert(ComponentName admin, byte[] certBuffer) {
+    public boolean installCaCert(@Nullable ComponentName admin, byte[] certBuffer) {
         if (mService != null) {
             try {
                 return mService.installCaCert(admin, certBuffer);
@@ -2237,11 +2233,11 @@
     /**
      * Uninstalls the given certificate from trusted user CAs, if present.
      *
-     * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Use
-     * <code>null</code> if calling from a delegated certificate installer.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+     *              {@code null} if calling from a delegated certificate installer.
      * @param certBuffer encoded form of the certificate to remove.
      */
-    public void uninstallCaCert(ComponentName admin, byte[] certBuffer) {
+    public void uninstallCaCert(@Nullable ComponentName admin, byte[] certBuffer) {
         if (mService != null) {
             try {
                 final String alias = getCaCertAlias(certBuffer);
@@ -2259,11 +2255,11 @@
      * If a user has installed any certificates by other means than device policy these will be
      * included too.
      *
-     * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Use
-     * <code>null</code> if calling from a delegated certificate installer.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+     *              {@code null} if calling from a delegated certificate installer.
      * @return a List of byte[] arrays, each encoding one user CA certificate.
      */
-    public List<byte[]> getInstalledCaCerts(ComponentName admin) {
+    public List<byte[]> getInstalledCaCerts(@Nullable ComponentName admin) {
         List<byte[]> certs = new ArrayList<byte[]>();
         if (mService != null) {
             try {
@@ -2287,10 +2283,10 @@
      * Uninstalls all custom trusted CA certificates from the profile. Certificates installed by
      * means other than device policy will also be removed, except for system CA certificates.
      *
-     * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Use
-     * <code>null</code> if calling from a delegated certificate installer.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+     *              {@code null} if calling from a delegated certificate installer.
      */
-    public void uninstallAllUserCaCerts(ComponentName admin) {
+    public void uninstallAllUserCaCerts(@Nullable ComponentName admin) {
         if (mService != null) {
             for (String alias : new TrustedCertificateStore().userAliases()) {
                 try {
@@ -2305,11 +2301,11 @@
     /**
      * Returns whether this certificate is installed as a trusted CA.
      *
-     * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Use
-     * <code>null</code> if calling from a delegated certificate installer.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+     *              {@code null} if calling from a delegated certificate installer.
      * @param certBuffer encoded form of the certificate to look up.
      */
-    public boolean hasCaCertInstalled(ComponentName admin, byte[] certBuffer) {
+    public boolean hasCaCertInstalled(@Nullable ComponentName admin, byte[] certBuffer) {
         if (mService != null) {
             try {
                 mService.enforceCanManageCaCerts(admin);
@@ -2327,21 +2323,21 @@
      * Called by a device or profile owner to install a certificate and private key pair. The
      * keypair will be visible to all apps within the profile.
      *
-     * @param who Which {@link DeviceAdminReceiver} this request is associated with. Use
-     * <code>null</code> if calling from a delegated certificate installer.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+     *            {@code null} if calling from a delegated certificate installer.
      * @param privKey The private key to install.
      * @param cert The certificate to install.
      * @param alias The private key alias under which to install the certificate. If a certificate
      * with that alias already exists, it will be overwritten.
      * @return {@code true} if the keys were installed, {@code false} otherwise.
      */
-    public boolean installKeyPair(ComponentName who, PrivateKey privKey, Certificate cert,
+    public boolean installKeyPair(@Nullable ComponentName admin, PrivateKey privKey, Certificate cert,
             String alias) {
         try {
             final byte[] pemCert = Credentials.convertToPem(cert);
             final byte[] pkcs8Key = KeyFactory.getInstance(privKey.getAlgorithm())
                     .getKeySpec(privKey, PKCS8EncodedKeySpec.class).getEncoded();
-            return mService.installKeyPair(who, pkcs8Key, pemCert, alias);
+            return mService.installKeyPair(admin, pkcs8Key, pemCert, alias);
         } catch (RemoteException e) {
             Log.w(TAG, "Failed talking with device policy service", e);
         } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
@@ -2353,7 +2349,7 @@
     }
 
     /**
-     * Returns the alias of a given CA certificate in the certificate store, or null if it
+     * @return the alias of a given CA certificate in the certificate store, or {@code null} if it
      * doesn't exist.
      */
     private static String getCaCertAlias(byte[] certBuffer) throws CertificateException {
@@ -2373,15 +2369,15 @@
      * it is later cleared by calling this method with a null value or uninstallling the certificate
      * installer.
      *
-     * @param who Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param installerPackage The package name of the certificate installer which will be given
-     * access. If <code>null</code> is given the current package will be cleared.
+     * access. If {@code null} is given the current package will be cleared.
      */
-    public void setCertInstallerPackage(ComponentName who, String installerPackage)
-            throws SecurityException {
+    public void setCertInstallerPackage(@NonNull ComponentName admin, @Nullable String
+            installerPackage) throws SecurityException {
         if (mService != null) {
             try {
-                mService.setCertInstallerPackage(who, installerPackage);
+                mService.setCertInstallerPackage(admin, installerPackage);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -2392,14 +2388,14 @@
      * Called by a profile owner or device owner to retrieve the certificate installer for the
      * current user. null if none is set.
      *
-     * @param who Which {@link DeviceAdminReceiver} this request is associated with.
-     * @return The package name of the current delegated certificate installer. <code>null</code>
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @return The package name of the current delegated certificate installer, or {@code null}
      * if none is set.
      */
-    public String getCertInstallerPackage(ComponentName who) throws SecurityException {
+    public String getCertInstallerPackage(@NonNull ComponentName admin) throws SecurityException {
         if (mService != null) {
             try {
-                return mService.getCertInstallerPackage(who);
+                return mService.getCertInstallerPackage(admin);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -2419,7 +2415,7 @@
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param disabled Whether or not the camera should be disabled.
      */
-    public void setCameraDisabled(ComponentName admin, boolean disabled) {
+    public void setCameraDisabled(@NonNull ComponentName admin, boolean disabled) {
         if (mService != null) {
             try {
                 mService.setCameraDisabled(admin, disabled);
@@ -2432,15 +2428,15 @@
     /**
      * Determine whether or not the device's cameras have been disabled for this user,
      * either by the current admin, if specified, or all admins.
-     * @param admin The name of the admin component to check, or null to check if any admins
+     * @param admin The name of the admin component to check, or {@code null} to check whether any admins
      * have disabled the camera
      */
-    public boolean getCameraDisabled(ComponentName admin) {
+    public boolean getCameraDisabled(@Nullable ComponentName admin) {
         return getCameraDisabled(admin, UserHandle.myUserId());
     }
 
     /** @hide per-user version */
-    public boolean getCameraDisabled(ComponentName admin, int userHandle) {
+    public boolean getCameraDisabled(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
                 return mService.getCameraDisabled(admin, userHandle);
@@ -2463,7 +2459,7 @@
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param disabled Whether screen capture is disabled or not.
      */
-    public void setScreenCaptureDisabled(ComponentName admin, boolean disabled) {
+    public void setScreenCaptureDisabled(@NonNull ComponentName admin, boolean disabled) {
         if (mService != null) {
             try {
                 mService.setScreenCaptureDisabled(admin, disabled);
@@ -2476,15 +2472,15 @@
     /**
      * Determine whether or not screen capture has been disabled by the current
      * admin, if specified, or all admins.
-     * @param admin The name of the admin component to check, or null to check if any admins
+     * @param admin The name of the admin component to check, or {@code null} to check whether any admins
      * have disabled screen capture.
      */
-    public boolean getScreenCaptureDisabled(ComponentName admin) {
+    public boolean getScreenCaptureDisabled(@Nullable ComponentName admin) {
         return getScreenCaptureDisabled(admin, UserHandle.myUserId());
     }
 
     /** @hide per-user version */
-    public boolean getScreenCaptureDisabled(ComponentName admin, int userHandle) {
+    public boolean getScreenCaptureDisabled(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
                 return mService.getScreenCaptureDisabled(admin, userHandle);
@@ -2507,7 +2503,7 @@
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param required Whether auto time is set required or not.
      */
-    public void setAutoTimeRequired(ComponentName admin, boolean required) {
+    public void setAutoTimeRequired(@NonNull ComponentName admin, boolean required) {
         if (mService != null) {
             try {
                 mService.setAutoTimeRequired(admin, required);
@@ -2561,7 +2557,7 @@
      * {@link #KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS}, {@link #KEYGUARD_DISABLE_FINGERPRINT},
      * {@link #KEYGUARD_DISABLE_FEATURES_ALL}
      */
-    public void setKeyguardDisabledFeatures(ComponentName admin, int which) {
+    public void setKeyguardDisabledFeatures(@NonNull ComponentName admin, int which) {
         if (mService != null) {
             try {
                 mService.setKeyguardDisabledFeatures(admin, which);
@@ -2574,17 +2570,17 @@
     /**
      * Determine whether or not features have been disabled in keyguard either by the current
      * admin, if specified, or all admins.
-     * @param admin The name of the admin component to check, or null to check if any admins
+     * @param admin The name of the admin component to check, or {@code null} to check whether any admins
      * have disabled features in keyguard.
      * @return bitfield of flags. See {@link #setKeyguardDisabledFeatures(ComponentName, int)}
      * for a list.
      */
-    public int getKeyguardDisabledFeatures(ComponentName admin) {
+    public int getKeyguardDisabledFeatures(@Nullable ComponentName admin) {
         return getKeyguardDisabledFeatures(admin, UserHandle.myUserId());
     }
 
     /** @hide per-user version */
-    public int getKeyguardDisabledFeatures(ComponentName admin, int userHandle) {
+    public int getKeyguardDisabledFeatures(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
                 return mService.getKeyguardDisabledFeatures(admin, userHandle);
@@ -2598,7 +2594,8 @@
     /**
      * @hide
      */
-    public void setActiveAdmin(ComponentName policyReceiver, boolean refreshing, int userHandle) {
+    public void setActiveAdmin(@NonNull ComponentName policyReceiver, boolean refreshing,
+            int userHandle) {
         if (mService != null) {
             try {
                 mService.setActiveAdmin(policyReceiver, refreshing, userHandle);
@@ -2611,15 +2608,15 @@
     /**
      * @hide
      */
-    public void setActiveAdmin(ComponentName policyReceiver, boolean refreshing) {
+    public void setActiveAdmin(@NonNull ComponentName policyReceiver, boolean refreshing) {
         setActiveAdmin(policyReceiver, refreshing, UserHandle.myUserId());
     }
 
     /**
-     * Returns the DeviceAdminInfo as defined by the administrator's package info & meta-data
+     * Returns the DeviceAdminInfo as defined by the administrator's package info &amp; meta-data
      * @hide
      */
-    public DeviceAdminInfo getAdminInfo(ComponentName cn) {
+    public DeviceAdminInfo getAdminInfo(@NonNull ComponentName cn) {
         ActivityInfo ai;
         try {
             ai = mContext.getPackageManager().getReceiverInfo(cn,
@@ -2646,7 +2643,7 @@
     /**
      * @hide
      */
-    public void getRemoveWarning(ComponentName admin, RemoteCallback result) {
+    public void getRemoveWarning(@Nullable ComponentName admin, RemoteCallback result) {
         if (mService != null) {
             try {
                 mService.getRemoveWarning(admin, result, UserHandle.myUserId());
@@ -2740,10 +2737,10 @@
     /**
      * Used to determine if a particular package has been registered as a Device Owner app.
      * A device owner app is a special device admin that cannot be deactivated by the user, once
-     * activated as a device admin. It also cannot be uninstalled. To check if a particular
+     * activated as a device admin. It also cannot be uninstalled. To check whether a particular
      * package is currently registered as the device owner app, pass in the package name from
      * {@link Context#getPackageName()} to this method.<p/>This is useful for device
-     * admin apps that want to check if they are also registered as the device owner app. The
+     * admin apps that want to check whether they are also registered as the device owner app. The
      * exact mechanism by which a device admin app is registered as a device owner app is defined by
      * the setup process.
      * @param packageName the package name of the app, to compare with the registered device owner
@@ -2820,19 +2817,20 @@
      * MANAGE_DEVICE_ADMINS permission before the device is provisioned or by a device owner app. A
      * device initializer app is granted device owner privileges during device initialization and
      * profile owner privileges during secondary user initialization.
-     * @param who Which {@link DeviceAdminReceiver} this request is associated with, or null if not
-     *        called by the device owner.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+     *              {@code null} if not called by the device owner.
      * @param initializer Which {@link DeviceAdminReceiver} to make device initializer.
      * @return whether the component was successfully registered as the device initializer.
      * @throws IllegalArgumentException if the componentname is null or invalid
      * @throws IllegalStateException if the caller is not device owner or the device has
      *         already been provisioned or a device initializer already exists.
      */
-    public boolean setDeviceInitializer(ComponentName who, ComponentName initializer)
+    public boolean setDeviceInitializer(@Nullable ComponentName admin,
+            @NonNull ComponentName initializer)
             throws IllegalArgumentException, IllegalStateException {
         if (mService != null) {
             try {
-                return mService.setDeviceInitializer(who, initializer);
+                return mService.setDeviceInitializer(admin, initializer);
             } catch (RemoteException re) {
                 Log.w(TAG, "Failed to set device initializer");
             }
@@ -2863,12 +2861,12 @@
      * subsequently created users. This method can be called by either the device owner or device
      * initializer itself. The caller must be an active administrator.
      *
-     * @param who Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      */
-    public void clearDeviceInitializerApp(ComponentName who) {
+    public void clearDeviceInitializerApp(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
-                mService.clearDeviceInitializer(who);
+                mService.clearDeviceInitializer(admin);
             } catch (RemoteException re) {
                 Log.w(TAG, "Failed to clear device initializer");
             }
@@ -2927,7 +2925,7 @@
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @return whether the user is now enabled.
      */
-    public boolean setUserEnabled(ComponentName admin) {
+    public boolean setUserEnabled(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
                 return mService.setUserEnabled(admin);
@@ -2955,7 +2953,7 @@
      *         the user has already been set up.
      */
     @SystemApi
-    public boolean setActiveProfileOwner(ComponentName admin, @Deprecated String ownerName)
+    public boolean setActiveProfileOwner(@NonNull ComponentName admin, @Deprecated String ownerName)
             throws IllegalArgumentException {
         if (mService != null) {
             try {
@@ -2980,7 +2978,7 @@
      * @return
      */
     @SystemApi
-    public void clearProfileOwner(ComponentName admin) {
+    public void clearProfileOwner(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
                 mService.clearProfileOwner(admin);
@@ -2992,14 +2990,14 @@
 
     /**
      * @hide
-     * Checks if the user was already setup.
+     * Checks whether the user was already setup.
      */
     public boolean hasUserSetupCompleted() {
         if (mService != null) {
             try {
                 return mService.hasUserSetupCompleted();
             } catch (RemoteException re) {
-                Log.w(TAG, "Failed to check if user setup has completed");
+                Log.w(TAG, "Failed to check whether user setup has completed");
             }
         }
         return true;
@@ -3021,7 +3019,7 @@
      * @throws IllegalArgumentException if admin is null, the package isn't installed, or the
      * preconditions mentioned are not met.
      */
-    public boolean setProfileOwner(ComponentName admin, @Deprecated String ownerName,
+    public boolean setProfileOwner(@NonNull ComponentName admin, @Deprecated String ownerName,
             int userHandle) throws IllegalArgumentException {
         if (admin == null) {
             throw new NullPointerException("admin cannot be null");
@@ -3048,7 +3046,7 @@
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      */
-    public void setProfileEnabled(ComponentName admin) {
+    public void setProfileEnabled(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
                 mService.setProfileEnabled(admin);
@@ -3066,12 +3064,13 @@
      * @see #isProfileOwnerApp
      * @see #isDeviceOwnerApp
      *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associate with.
      * @param profileName The name of the profile.
      */
-    public void setProfileName(ComponentName who, String profileName) {
+    public void setProfileName(@NonNull ComponentName admin, String profileName) {
         if (mService != null) {
             try {
-                mService.setProfileName(who, profileName);
+                mService.setProfileName(admin, profileName);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -3102,7 +3101,7 @@
 
     /**
      * @hide
-     * @return the packageName of the owner of the given user profile or null if no profile
+     * @return the packageName of the owner of the given user profile or {@code null} if no profile
      * owner has been set for that user.
      * @throws IllegalArgumentException if the userId is invalid.
      */
@@ -3130,8 +3129,8 @@
 
     /**
      * @hide
-     * @return the human readable name of the organisation associated with this DPM or null if
-     *         one is not set.
+     * @return the human readable name of the organisation associated with this DPM or {@code null}
+     *         if one is not set.
      * @throws IllegalArgumentException if the userId is invalid.
      */
     public String getProfileOwnerName() throws IllegalArgumentException {
@@ -3185,8 +3184,8 @@
      * @param filter The IntentFilter for which a default handler is added.
      * @param activity The Activity that is added as default intent handler.
      */
-    public void addPersistentPreferredActivity(ComponentName admin, IntentFilter filter,
-            ComponentName activity) {
+    public void addPersistentPreferredActivity(@NonNull ComponentName admin, IntentFilter filter,
+            @NonNull ComponentName activity) {
         if (mService != null) {
             try {
                 mService.addPersistentPreferredActivity(admin, filter, activity);
@@ -3206,7 +3205,7 @@
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param packageName The name of the package for which preferences are removed.
      */
-    public void clearPackagePersistentPreferredActivities(ComponentName admin,
+    public void clearPackagePersistentPreferredActivities(@NonNull ComponentName admin,
             String packageName) {
         if (mService != null) {
             try {
@@ -3241,7 +3240,7 @@
      *
      * @see UserManager#KEY_RESTRICTIONS_PENDING
      */
-    public void setApplicationRestrictions(ComponentName admin, String packageName,
+    public void setApplicationRestrictions(@NonNull ComponentName admin, String packageName,
             Bundle settings) {
         if (mService != null) {
             try {
@@ -3271,8 +3270,8 @@
      * then it's up to the TrustAgent itself to aggregate the values from all device admins.
      * <p>Consult documentation for the specific TrustAgent to determine legal options parameters.
      */
-    public void setTrustAgentConfiguration(ComponentName admin, ComponentName target,
-            PersistableBundle configuration) {
+    public void setTrustAgentConfiguration(@NonNull ComponentName admin,
+            @NonNull ComponentName target, PersistableBundle configuration) {
         if (mService != null) {
             try {
                 mService.setTrustAgentConfiguration(admin, target, configuration);
@@ -3296,14 +3295,14 @@
      * @param agent Which component to get enabled features for.
      * @return configuration for the given trust agent.
      */
-    public List<PersistableBundle> getTrustAgentConfiguration(ComponentName admin,
-            ComponentName agent) {
+    public List<PersistableBundle> getTrustAgentConfiguration(@Nullable ComponentName admin,
+            @NonNull ComponentName agent) {
         return getTrustAgentConfiguration(admin, agent, UserHandle.myUserId());
     }
 
     /** @hide per-user version */
-    public List<PersistableBundle> getTrustAgentConfiguration(ComponentName admin,
-            ComponentName agent, int userHandle) {
+    public List<PersistableBundle> getTrustAgentConfiguration(@Nullable ComponentName admin,
+            @NonNull ComponentName agent, int userHandle) {
         if (mService != null) {
             try {
                 return mService.getTrustAgentConfiguration(admin, agent, userHandle);
@@ -3321,13 +3320,13 @@
      * <p>The calling device admin must be a profile owner. If it is not, a
      * security exception will be thrown.
      *
-     * @param who Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param disabled If true caller-Id information in the managed profile is not displayed.
      */
-    public void setCrossProfileCallerIdDisabled(ComponentName who, boolean disabled) {
+    public void setCrossProfileCallerIdDisabled(@NonNull ComponentName admin, boolean disabled) {
         if (mService != null) {
             try {
-                mService.setCrossProfileCallerIdDisabled(who, disabled);
+                mService.setCrossProfileCallerIdDisabled(admin, disabled);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -3341,12 +3340,12 @@
      * <p>The calling device admin must be a profile owner. If it is not, a
      * security exception will be thrown.
      *
-     * @param who Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      */
-    public boolean getCrossProfileCallerIdDisabled(ComponentName who) {
+    public boolean getCrossProfileCallerIdDisabled(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
-                return mService.getCrossProfileCallerIdDisabled(who);
+                return mService.getCrossProfileCallerIdDisabled(admin);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -3396,15 +3395,15 @@
      * <p>
      * This API works on managed profile only.
      *
-     * @param who Which {@link DeviceAdminReceiver} this request is associated
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated
      *            with.
      * @param disabled If true, bluetooth devices cannot access enterprise
      *            contacts.
      */
-    public void setBluetoothContactSharingDisabled(ComponentName who, boolean disabled) {
+    public void setBluetoothContactSharingDisabled(@NonNull ComponentName admin, boolean disabled) {
         if (mService != null) {
             try {
-                mService.setBluetoothContactSharingDisabled(who, disabled);
+                mService.setBluetoothContactSharingDisabled(admin, disabled);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -3420,13 +3419,13 @@
      * <p>
      * This API works on managed profile only.
      *
-     * @param who Which {@link DeviceAdminReceiver} this request is associated
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated
      *            with.
      */
-    public boolean getBluetoothContactSharingDisabled(ComponentName who) {
+    public boolean getBluetoothContactSharingDisabled(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
-                return mService.getBluetoothContactSharingDisabled(who);
+                return mService.getBluetoothContactSharingDisabled(admin);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed talking with device policy service", e);
             }
@@ -3465,7 +3464,7 @@
      * @param flags {@link DevicePolicyManager#FLAG_MANAGED_CAN_ACCESS_PARENT} and
      * {@link DevicePolicyManager#FLAG_PARENT_CAN_ACCESS_MANAGED} are supported.
      */
-    public void addCrossProfileIntentFilter(ComponentName admin, IntentFilter filter, int flags) {
+    public void addCrossProfileIntentFilter(@NonNull ComponentName admin, IntentFilter filter, int flags) {
         if (mService != null) {
             try {
                 mService.addCrossProfileIntentFilter(admin, filter, flags);
@@ -3481,7 +3480,7 @@
      * Only removes those that have been set by the profile owner.
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      */
-    public void clearCrossProfileIntentFilters(ComponentName admin) {
+    public void clearCrossProfileIntentFilters(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
                 mService.clearCrossProfileIntentFilters(admin);
@@ -3512,7 +3511,7 @@
      * @return true if setting the restriction succeeded. It fail if there is
      * one or more non-system accessibility services enabled, that are not in the list.
      */
-    public boolean setPermittedAccessibilityServices(ComponentName admin,
+    public boolean setPermittedAccessibilityServices(@NonNull ComponentName admin,
             List<String> packageNames) {
         if (mService != null) {
             try {
@@ -3533,7 +3532,7 @@
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @return List of accessiblity service package names.
      */
-    public List<String> getPermittedAccessibilityServices(ComponentName admin) {
+    public List<String> getPermittedAccessibilityServices(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
                 return mService.getPermittedAccessibilityServices(admin);
@@ -3591,7 +3590,7 @@
      *     one or more non-system input methods currently enabled that are not in
      *     the packageNames list.
      */
-    public boolean setPermittedInputMethods(ComponentName admin, List<String> packageNames) {
+    public boolean setPermittedInputMethods(@NonNull ComponentName admin, List<String> packageNames) {
         if (mService != null) {
             try {
                 return mService.setPermittedInputMethods(admin, packageNames);
@@ -3612,7 +3611,7 @@
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @return List of input method package names.
      */
-    public List<String> getPermittedInputMethods(ComponentName admin) {
+    public List<String> getPermittedInputMethods(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
                 return mService.getPermittedInputMethods(admin);
@@ -3655,9 +3654,10 @@
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param name the user's name
      * @see UserHandle
-     * @return the UserHandle object for the created user, or null if the user could not be created.
+     * @return the {@link android.os.UserHandle} object for the created user, or {@code null} if the
+     *         user could not be created.
      */
-    public UserHandle createUser(ComponentName admin, String name) {
+    public UserHandle createUser(@NonNull ComponentName admin, String name) {
         try {
             return mService.createUser(admin, name);
         } catch (RemoteException re) {
@@ -3688,10 +3688,11 @@
      * @param adminExtras Extras that will be passed to onEnable of the admin receiver
      *      on the new user.
      * @see UserHandle
-     * @return the UserHandle object for the created user, or null if the user could not be created.
+     * @return the {@link android.os.UserHandle} object for the created user, or {@code null} if the
+     *         user could not be created.
      */
-    public UserHandle createAndInitializeUser(ComponentName admin, String name, String ownerName,
-            ComponentName profileOwnerComponent, Bundle adminExtras) {
+    public UserHandle createAndInitializeUser(@NonNull ComponentName admin, String name,
+            String ownerName, @NonNull ComponentName profileOwnerComponent, Bundle adminExtras) {
         try {
             return mService.createAndInitializeUser(admin, name, ownerName, profileOwnerComponent,
                     adminExtras);
@@ -3709,7 +3710,7 @@
      * @param userHandle the user to remove.
      * @return {@code true} if the user was removed, {@code false} otherwise.
      */
-    public boolean removeUser(ComponentName admin, UserHandle userHandle) {
+    public boolean removeUser(@NonNull ComponentName admin, UserHandle userHandle) {
         try {
             return mService.removeUser(admin, userHandle);
         } catch (RemoteException re) {
@@ -3727,7 +3728,7 @@
      *
      * @see Intent#ACTION_USER_FOREGROUND
      */
-    public boolean switchUser(ComponentName admin, UserHandle userHandle) {
+    public boolean switchUser(@NonNull ComponentName admin, @Nullable UserHandle userHandle) {
         try {
             return mService.switchUser(admin, userHandle);
         } catch (RemoteException re) {
@@ -3749,7 +3750,7 @@
      * {@link DevicePolicyManager#setApplicationRestrictions} was called, or an empty {@link Bundle}
      * if no restrictions have been set.
      */
-    public Bundle getApplicationRestrictions(ComponentName admin, String packageName) {
+    public Bundle getApplicationRestrictions(@NonNull ComponentName admin, String packageName) {
         if (mService != null) {
             try {
                 return mService.getApplicationRestrictions(admin, packageName);
@@ -3771,7 +3772,7 @@
      * @param key The key of the restriction. See the constants in
      *            {@link android.os.UserManager} for the list of keys.
      */
-    public void addUserRestriction(ComponentName admin, String key) {
+    public void addUserRestriction(@NonNull ComponentName admin, String key) {
         if (mService != null) {
             try {
                 mService.setUserRestriction(admin, key, true);
@@ -3792,7 +3793,7 @@
      * @param key The key of the restriction. See the constants in
      *            {@link android.os.UserManager} for the list of keys.
      */
-    public void clearUserRestriction(ComponentName admin, String key) {
+    public void clearUserRestriction(@NonNull ComponentName admin, String key) {
         if (mService != null) {
             try {
                 mService.setUserRestriction(admin, key, false);
@@ -3812,7 +3813,7 @@
      *                 unhidden.
      * @return boolean Whether the hidden setting of the package was successfully updated.
      */
-    public boolean setApplicationHidden(ComponentName admin, String packageName,
+    public boolean setApplicationHidden(@NonNull ComponentName admin, String packageName,
             boolean hidden) {
         if (mService != null) {
             try {
@@ -3831,7 +3832,7 @@
      * @param packageName The name of the package to retrieve the hidden status of.
      * @return boolean {@code true} if the package is hidden, {@code false} otherwise.
      */
-    public boolean isApplicationHidden(ComponentName admin, String packageName) {
+    public boolean isApplicationHidden(@NonNull ComponentName admin, String packageName) {
         if (mService != null) {
             try {
                 return mService.isApplicationHidden(admin, packageName);
@@ -3849,7 +3850,7 @@
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param packageName The package to be re-enabled in the current profile.
      */
-    public void enableSystemApp(ComponentName admin, String packageName) {
+    public void enableSystemApp(@NonNull ComponentName admin, String packageName) {
         if (mService != null) {
             try {
                 mService.enableSystemApp(admin, packageName);
@@ -3868,7 +3869,7 @@
      *               intent will be re-enabled in the current profile.
      * @return int The number of activities that matched the intent and were installed.
      */
-    public int enableSystemApp(ComponentName admin, Intent intent) {
+    public int enableSystemApp(@NonNull ComponentName admin, Intent intent) {
         if (mService != null) {
             try {
                 return mService.enableSystemAppWithIntent(admin, intent);
@@ -3894,7 +3895,7 @@
      * @param disabled The boolean indicating that account management will be disabled (true) or
      * enabled (false).
      */
-    public void setAccountManagementDisabled(ComponentName admin, String accountType,
+    public void setAccountManagementDisabled(@NonNull ComponentName admin, String accountType,
             boolean disabled) {
         if (mService != null) {
             try {
@@ -3950,7 +3951,7 @@
      * @see DeviceAdminReceiver#onLockTaskModeExiting(Context, Intent)
      * @see UserManager#DISALLOW_CREATE_WINDOWS
      */
-    public void setLockTaskPackages(ComponentName admin, String[] packages)
+    public void setLockTaskPackages(@NonNull ComponentName admin, String[] packages)
             throws SecurityException {
         if (mService != null) {
             try {
@@ -3967,7 +3968,7 @@
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @hide
      */
-    public String[] getLockTaskPackages(ComponentName admin) {
+    public String[] getLockTaskPackages(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
                 return mService.getLockTaskPackages(admin);
@@ -4024,7 +4025,7 @@
      * @param setting The name of the setting to update.
      * @param value The value to update the setting to.
      */
-    public void setGlobalSetting(ComponentName admin, String setting, String value) {
+    public void setGlobalSetting(@NonNull ComponentName admin, String setting, String value) {
         if (mService != null) {
             try {
                 mService.setGlobalSetting(admin, setting, value);
@@ -4052,7 +4053,7 @@
      * @param setting The name of the setting to update.
      * @param value The value to update the setting to.
      */
-    public void setSecureSetting(ComponentName admin, String setting, String value) {
+    public void setSecureSetting(@NonNull ComponentName admin, String setting, String value) {
         if (mService != null) {
             try {
                 mService.setSecureSetting(admin, setting, value);
@@ -4072,7 +4073,8 @@
      * {@link RestrictionsReceiver}. If this param is null,
      * it removes the restrictions provider previously assigned.
      */
-    public void setRestrictionsProvider(ComponentName admin, ComponentName provider) {
+    public void setRestrictionsProvider(@NonNull ComponentName admin,
+            @Nullable ComponentName provider) {
         if (mService != null) {
             try {
                 mService.setRestrictionsProvider(admin, provider);
@@ -4088,7 +4090,7 @@
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param on {@code true} to mute master volume, {@code false} to turn mute off.
      */
-    public void setMasterVolumeMuted(ComponentName admin, boolean on) {
+    public void setMasterVolumeMuted(@NonNull ComponentName admin, boolean on) {
         if (mService != null) {
             try {
                 mService.setMasterVolumeMuted(admin, on);
@@ -4104,7 +4106,7 @@
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @return {@code true} if master volume is muted, {@code false} if it's not.
      */
-    public boolean isMasterVolumeMuted(ComponentName admin) {
+    public boolean isMasterVolumeMuted(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
                 return mService.isMasterVolumeMuted(admin);
@@ -4123,7 +4125,7 @@
      * @param packageName package to change.
      * @param uninstallBlocked true if the user shouldn't be able to uninstall the package.
      */
-    public void setUninstallBlocked(ComponentName admin, String packageName,
+    public void setUninstallBlocked(@NonNull ComponentName admin, String packageName,
             boolean uninstallBlocked) {
         if (mService != null) {
             try {
@@ -4139,16 +4141,16 @@
      * Requires the caller to be the profile owner if checking a specific admin's policy.
      * <p>
      * <strong>Note:</strong> Starting from {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}, the
-     * behavior of this API is changed such that passing <code>null</code> as the <code>admin</code>
+     * behavior of this API is changed such that passing {@code null} as the {@code admin}
      * parameter will return if any admin has blocked the uninstallation. Before L MR1, passing
-     * <code>null</code> will cause a NullPointerException to be raised.
+     * {@code null} will cause a NullPointerException to be raised.
      *
-     * @param admin The name of the admin component whose blocking policy will be checked, or null
-     *            to check if any admin has blocked the uninstallation.
+     * @param admin The name of the admin component whose blocking policy will be checked, or
+     *              {@code null} to check whether any admin has blocked the uninstallation.
      * @param packageName package to check.
      * @return true if uninstallation is blocked.
      */
-    public boolean isUninstallBlocked(ComponentName admin, String packageName) {
+    public boolean isUninstallBlocked(@Nullable ComponentName admin, String packageName) {
         if (mService != null) {
             try {
                 return mService.isUninstallBlocked(admin, packageName);
@@ -4168,7 +4170,6 @@
      * provides a different widget type.
      * <p>
      * <strong>Note:</strong> By default no widget provider package is white-listed.
-     * </p>
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param packageName The package from which widget providers are white-listed.
@@ -4177,7 +4178,7 @@
      * @see #removeCrossProfileWidgetProvider(android.content.ComponentName, String)
      * @see #getCrossProfileWidgetProviders(android.content.ComponentName)
      */
-    public boolean addCrossProfileWidgetProvider(ComponentName admin, String packageName) {
+    public boolean addCrossProfileWidgetProvider(@NonNull ComponentName admin, String packageName) {
         if (mService != null) {
             try {
                 return mService.addCrossProfileWidgetProvider(admin, packageName);
@@ -4195,7 +4196,6 @@
      * android.content.ComponentName, String)}.
      * <p>
      * <strong>Note:</strong> By default no widget provider package is white-listed.
-     * </p>
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param packageName The package from which widget providers are no longer
@@ -4205,7 +4205,7 @@
      * @see #addCrossProfileWidgetProvider(android.content.ComponentName, String)
      * @see #getCrossProfileWidgetProviders(android.content.ComponentName)
      */
-    public boolean removeCrossProfileWidgetProvider(ComponentName admin, String packageName) {
+    public boolean removeCrossProfileWidgetProvider(@NonNull ComponentName admin, String packageName) {
         if (mService != null) {
             try {
                 return mService.removeCrossProfileWidgetProvider(admin, packageName);
@@ -4226,7 +4226,7 @@
      * @see #addCrossProfileWidgetProvider(android.content.ComponentName, String)
      * @see #removeCrossProfileWidgetProvider(android.content.ComponentName, String)
      */
-    public List<String> getCrossProfileWidgetProviders(ComponentName admin) {
+    public List<String> getCrossProfileWidgetProviders(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
                 List<String> providers = mService.getCrossProfileWidgetProviders(admin);
@@ -4246,7 +4246,7 @@
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param icon the bitmap to set as the photo.
      */
-    public void setUserIcon(ComponentName admin, Bitmap icon) {
+    public void setUserIcon(@NonNull ComponentName admin, Bitmap icon) {
         try {
             mService.setUserIcon(admin, icon);
         } catch (RemoteException re) {
@@ -4273,16 +4273,17 @@
      * Called by device owners to set a local system update policy. When a new policy is set,
      * {@link #ACTION_SYSTEM_UPDATE_POLICY_CHANGED} is broadcasted.
      *
-     * @param who Which {@link DeviceAdminReceiver} this request is associated with. All components
-     * in the device owner package can set system update policies and the most recent policy takes
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with. All
+     *              components in the device owner package can set system update policies and the
+     *              most recent policy takes
      * effect.
-     * @param policy the new policy, or null to clear the current policy.
+     * @param policy the new policy, or {@code null} to clear the current policy.
      * @see SystemUpdatePolicy
      */
-    public void setSystemUpdatePolicy(ComponentName who, SystemUpdatePolicy policy) {
+    public void setSystemUpdatePolicy(@NonNull ComponentName admin, SystemUpdatePolicy policy) {
         if (mService != null) {
             try {
-                mService.setSystemUpdatePolicy(who, policy);
+                mService.setSystemUpdatePolicy(admin, policy);
             } catch (RemoteException re) {
                 Log.w(TAG, "Error calling setSystemUpdatePolicy", re);
             }
@@ -4292,7 +4293,7 @@
     /**
      * Retrieve a local system update policy set previously by {@link #setSystemUpdatePolicy}.
      *
-     * @return The current policy object, or null if no policy is set.
+     * @return The current policy object, or {@code null} if no policy is set.
      */
     public SystemUpdatePolicy getSystemUpdatePolicy() {
         if (mService != null) {
@@ -4319,7 +4320,7 @@
      * @return {@code false} if attempting to disable the keyguard while a lock password was in
      * place. {@code true} otherwise.
      */
-    public boolean setKeyguardDisabled(ComponentName admin, boolean disabled) {
+    public boolean setKeyguardDisabled(@NonNull ComponentName admin, boolean disabled) {
         try {
             return mService.setKeyguardDisabled(admin, disabled);
         } catch (RemoteException re) {
@@ -4339,7 +4340,7 @@
      * @return {@code false} if attempting to disable the status bar failed.
      * {@code true} otherwise.
      */
-    public boolean setStatusBarDisabled(ComponentName admin, boolean disabled) {
+    public boolean setStatusBarDisabled(@NonNull ComponentName admin, boolean disabled) {
         try {
             return mService.setStatusBarDisabled(admin, disabled);
         } catch (RemoteException re) {
@@ -4377,7 +4378,8 @@
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param activity The Activity to be started by default during user setup.
      */
-    public void setPreferredSetupActivity(ComponentName admin, ComponentName activity) {
+    public void setPreferredSetupActivity(@NonNull ComponentName admin,
+            @NonNull ComponentName activity) {
         try {
             mService.setPreferredSetupActivity(admin, activity);
         } catch (RemoteException re) {
@@ -4395,7 +4397,7 @@
      * @param policy One of the policy constants {@link #PERMISSION_POLICY_PROMPT},
      * {@link #PERMISSION_POLICY_AUTO_GRANT} and {@link #PERMISSION_POLICY_AUTO_DENY}.
      */
-    public void setPermissionPolicy(ComponentName admin, int policy) {
+    public void setPermissionPolicy(@NonNull ComponentName admin, int policy) {
         try {
             mService.setPermissionPolicy(admin, policy);
         } catch (RemoteException re) {
@@ -4409,7 +4411,7 @@
      * @param admin Which profile or device owner this request is associated with.
      * @return the current policy for future permission requests.
      */
-    public int getPermissionPolicy(ComponentName admin) {
+    public int getPermissionPolicy(@NonNull ComponentName admin) {
         try {
             return mService.getPermissionPolicy(admin);
         } catch (RemoteException re) {
@@ -4439,7 +4441,7 @@
      * @see #PERMISSION_GRANT_STATE_DEFAULT
      * @see #PERMISSION_GRANT_STATE_GRANTED
      */
-    public boolean setPermissionGrantState(ComponentName admin, String packageName,
+    public boolean setPermissionGrantState(@NonNull ComponentName admin, String packageName,
             String permission, int grantState) {
         try {
             return mService.setPermissionGrantState(admin, packageName, permission, grantState);
@@ -4466,7 +4468,7 @@
      * @see #setPermissionGrantState(ComponentName, String, String, int)
      * @see PackageManager#checkPermission(String, String)
      */
-    public int getPermissionGrantState(ComponentName admin, String packageName,
+    public int getPermissionGrantState(@NonNull ComponentName admin, String packageName,
             String permission) {
         try {
             return mService.getPermissionGrantState(admin, packageName, permission);
diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl
index 254408a..a9328bc 100644
--- a/core/java/android/app/usage/IUsageStatsManager.aidl
+++ b/core/java/android/app/usage/IUsageStatsManager.aidl
@@ -32,4 +32,5 @@
     UsageEvents queryEvents(long beginTime, long endTime, String callingPackage);
     void setAppInactive(String packageName, boolean inactive, int userId);
     boolean isAppInactive(String packageName, int userId);
+    void whitelistAppTemporarily(String packageName, long duration, int userId);
 }
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 34699d8..c74b0f2 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -16,6 +16,7 @@
 
 package android.app.usage;
 
+import android.annotation.SystemApi;
 import android.content.Context;
 import android.content.pm.ParceledListSlice;
 import android.os.RemoteException;
@@ -245,4 +246,25 @@
             // fall through
         }
     }
+
+    /**
+     * {@hide}
+     * Temporarily whitelist the specified app for a short duration. This is to allow an app
+     * receiving a high priority message to be able to access the network and acquire wakelocks
+     * even if the device is in power-save mode or the app is currently considered inactive.
+     * The caller must hold the CHANGE_DEVICE_IDLE_TEMP_WHITELIST permission.
+     * @param packageName The package name of the app to whitelist.
+     * @param duration Duration to whitelist the app for, in milliseconds. It is recommended that
+     * this be limited to 10s of seconds. Requested duration will be clamped to a few minutes.
+     * @param user The user for whom the package should be whitelisted. Passing in a user that is
+     * not the same as the caller's process will require the INTERACT_ACROSS_USERS permission.
+     * @see #isAppInactive(String)
+     */
+    @SystemApi
+    public void whitelistAppTemporarily(String packageName, long duration, UserHandle user) {
+        try {
+            mService.whitelistAppTemporarily(packageName, duration, user.getIdentifier());
+        } catch (RemoteException re) {
+        }
+    }
 }
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index b22b914..8107a97 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -410,6 +410,7 @@
      * Broadcast Action: The Bluetooth adapter state has changed in LE only mode.
      * @hide
      */
+    @SystemApi
     public static final String ACTION_BLE_STATE_CHANGED =
         "android.bluetooth.adapter.action.BLE_STATE_CHANGED";
 
@@ -620,17 +621,18 @@
      * @return true if the local Bluetooth LE adapter is turned on
      * @hide
      */
-     public boolean isLeEnabled() {
-        final int state = getLeState();
-        if (state == BluetoothAdapter.STATE_ON) {
-            if (DBG) Log.d (TAG, "STATE_ON");
-        } else if (state == BluetoothAdapter.STATE_BLE_ON) {
-            if (DBG) Log.d (TAG, "STATE_BLE_ON");
-        } else {
-            if (DBG) Log.d (TAG, "STATE_OFF");
-            return false;
-        }
-        return true;
+    @SystemApi
+    public boolean isLeEnabled() {
+       final int state = getLeState();
+       if (state == BluetoothAdapter.STATE_ON) {
+           if (DBG) Log.d (TAG, "STATE_ON");
+       } else if (state == BluetoothAdapter.STATE_BLE_ON) {
+           if (DBG) Log.d (TAG, "STATE_BLE_ON");
+       } else {
+           if (DBG) Log.d (TAG, "STATE_OFF");
+           return false;
+       }
+       return true;
     }
 
     /**
@@ -680,6 +682,7 @@
      *         immediate error
      * @hide
      */
+    @SystemApi
     public boolean disableBLE() {
         if (!isBleScanAlwaysAvailable()) return false;
 
@@ -742,6 +745,7 @@
      *         immediate error
      * @hide
      */
+    @SystemApi
     public boolean enableBLE() {
         if (!isBleScanAlwaysAvailable()) return false;
 
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index f0c3f2d..8bcd5d1 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -160,7 +160,6 @@
 
         final TypedValue v = mValue;
         if (getValueAt(index, v)) {
-            StrictMode.noteResourceMismatch(v);
             return v.coerceToString();
         }
 
@@ -183,24 +182,6 @@
      */
     @Nullable
     public String getString(int index) {
-        return getString(index, true);
-    }
-
-    /**
-     * Returns a string representation of the value at the given index,
-     * optionally throwing a resource mismatch strict mode violation if the
-     * value must be coerced to a string.
-     *
-     * @param index the index of the attribute to retrieve
-     * @param strict {@code true} to throw a strict mode violation for string
-     *               coercion, {@code false} otherwise
-     * @return a string representation of the value at the given index, or
-     *         {@code null} if the resource could not be coerced to a string
-     * @see StrictMode#noteResourceMismatch(Object)
-     * @hide Used internally for view attribute inspection.
-     */
-    @Nullable
-    public String getString(int index, boolean strict) {
         if (mRecycled) {
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
@@ -216,9 +197,6 @@
 
         final TypedValue v = mValue;
         if (getValueAt(index, v)) {
-            if (strict) {
-                StrictMode.noteResourceMismatch(v);
-            }
             final CharSequence cs = v.coerceToString();
             return cs != null ? cs.toString() : null;
         }
@@ -292,7 +270,6 @@
 
         final TypedValue v = mValue;
         if (getValueAt(index, v)) {
-            StrictMode.noteResourceMismatch(v);
             final CharSequence cs = v.coerceToString();
             return cs != null ? cs.toString() : null;
         }
diff --git a/core/java/android/os/IDeviceIdleController.aidl b/core/java/android/os/IDeviceIdleController.aidl
index 602bfea..268295d 100644
--- a/core/java/android/os/IDeviceIdleController.aidl
+++ b/core/java/android/os/IDeviceIdleController.aidl
@@ -16,6 +16,8 @@
 
 package android.os;
 
+import android.os.UserHandle;
+
 /** @hide */
 interface IDeviceIdleController {
     void addPowerSaveWhitelistApp(String name);
@@ -23,5 +25,7 @@
     String[] getSystemPowerWhitelist();
     String[] getFullPowerWhitelist();
     int[] getAppIdWhitelist();
+    int[] getAppIdTempWhitelist();
     boolean isPowerSaveWhitelistApp(String name);
+    void addPowerSaveTempWhitelistApp(String name, long duration, int userId);
 }
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 1d9d7d2..8b18f32 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -928,6 +928,14 @@
             = "android.os.action.POWER_SAVE_WHITELIST_CHANGED";
 
     /**
+     * @hide Intent that is broadcast when the set of temporarily whitelisted apps has changed.
+     * This broadcast is only sent to registered receivers.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_POWER_SAVE_TEMP_WHITELIST_CHANGED
+            = "android.os.action.POWER_SAVE_TEMP_WHITELIST_CHANGED";
+
+    /**
      * Intent that is broadcast when the state of {@link #isPowerSaveMode()} is about to change.
      * This broadcast is only sent to registered receivers.
      *
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index e523285..e742f98 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -137,6 +137,8 @@
 
     public abstract void setDeviceIdleWhitelist(int[] appids);
 
+    public abstract void setDeviceIdleTempWhitelist(int[] appids);
+
     public abstract void updateUidProcState(int uid, int procState);
 
     public abstract void uidGone(int uid);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3e621b1..cfd504d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4510,7 +4510,7 @@
             }
 
             attributes[i] = resourceName;
-            attributes[i + 1] = t.getString(index, false);
+            attributes[i + 1] = t.getString(index);
             i += 2;
         }
 
@@ -6351,7 +6351,7 @@
             }
             View next = rootView.findViewInsideOutShouldExist(this,
                     mAccessibilityTraversalBeforeId);
-            if (next != null) {
+            if (next != null && next.includeForAccessibility()) {
                 info.setTraversalBefore(next);
             }
         }
@@ -6363,7 +6363,7 @@
             }
             View next = rootView.findViewInsideOutShouldExist(this,
                     mAccessibilityTraversalAfterId);
-            if (next != null) {
+            if (next != null && next.includeForAccessibility()) {
                 info.setTraversalAfter(next);
             }
         }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index f0c86e5..45bc1df 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -309,6 +309,7 @@
          * Window type: a above sub-panel on top of an application window and it's
          * sub-panel windows. These windows are displayed on top of their attached window
          * and any {@link #TYPE_APPLICATION_SUB_PANEL} panels.
+         * @hide
          */
         public static final int TYPE_APPLICATION_ABOVE_SUB_PANEL = FIRST_SUB_WINDOW + 5;
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c775365..439affe 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -81,6 +81,7 @@
     <protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGING" />
     <protected-broadcast android:name="android.os.action.DEVICE_IDLE_MODE_CHANGED" />
     <protected-broadcast android:name="android.os.action.POWER_SAVE_WHITELIST_CHANGED" />
+    <protected-broadcast android:name="android.os.action.POWER_SAVE_TEMP_WHITELIST_CHANGED" />
 
     <protected-broadcast android:name="android.os.action.SCREEN_BRIGHTNESS_BOOST_CHANGED" />
 
@@ -2136,6 +2137,12 @@
     <permission android:name="android.permission.CHANGE_APP_IDLE_STATE"
         android:protectionLevel="signature" />
 
+    <!-- @hide @SystemApi Allows an application to temporarily whitelist an inactive app to
+         access the network and acquire wakelocks.
+         <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST"
+        android:protectionLevel="system|signature" />
+
     <!-- @SystemApi Allows an application to collect battery statistics -->
     <permission android:name="android.permission.BATTERY_STATS"
         android:protectionLevel="signature|system|development" />
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 93fcb2f..45dad8d 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1785,16 +1785,11 @@
   <java-symbol type="string" name="smv_process" />
   <java-symbol type="string" name="tethered_notification_message" />
   <java-symbol type="string" name="tethered_notification_title" />
-  <java-symbol type="string" name="throttle_warning_notification_message" />
-  <java-symbol type="string" name="throttle_warning_notification_title" />
-  <java-symbol type="string" name="throttled_notification_message" />
-  <java-symbol type="string" name="throttled_notification_title" />
   <java-symbol type="string" name="usb_accessory_notification_title" />
   <java-symbol type="string" name="usb_cd_installer_notification_title" />
   <java-symbol type="string" name="usb_mtp_notification_title" />
   <java-symbol type="string" name="usb_charging_notification_title" />
   <java-symbol type="string" name="usb_notification_message" />
-  <java-symbol type="string" name="use_physical_keyboard" />
   <java-symbol type="string" name="usb_ptp_notification_title" />
   <java-symbol type="string" name="usb_midi_notification_title" />
   <java-symbol type="string" name="vpn_text" />
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index f324933..cf3b7c8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -357,17 +357,19 @@
     }
 
     private void updateNetworkInfo(NetworkInfo networkInfo) {
-        /* sticky broadcasts can call this when wifi is disabled */
-        if (!mWifiManager.isWifiEnabled()) {
-            mScanner.pause();
-            return;
-        }
+        if (mScanner != null) {
+            /* sticky broadcasts can call this when wifi is disabled */
+            if (!mWifiManager.isWifiEnabled()) {
+                mScanner.pause();
+                return;
+            }
 
-        if (networkInfo != null &&
-                networkInfo.getDetailedState() == DetailedState.OBTAINING_IPADDR) {
-            mScanner.pause();
-        } else {
-            mScanner.resume();
+            if (networkInfo != null &&
+                    networkInfo.getDetailedState() == DetailedState.OBTAINING_IPADDR) {
+                mScanner.pause();
+            } else {
+                mScanner.resume();
+            }
         }
 
         mLastInfo = mWifiManager.getConnectionInfo();
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 6d02365..9e3cf37 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -180,7 +180,7 @@
             .setColor(r.getColor(com.android.internal.R.color.system_notification_accent_color));
 
         mNotificationStyle = new Notification.BigPictureStyle()
-            .bigPicture(picture);
+            .bigPicture(picture.createAshmemBitmap());
         mNotificationBuilder.setStyle(mNotificationStyle);
 
         // For "public" situations we want to show all the same info but
@@ -203,7 +203,7 @@
         // On the tablet, the large icon makes the notification appear as if it is clickable (and
         // on small devices, the large icon is not shown) so defer showing the large icon until
         // we compose the final post-save notification below.
-        mNotificationBuilder.setLargeIcon(icon);
+        mNotificationBuilder.setLargeIcon(icon.createAshmemBitmap());
         // But we still don't set it for the expanded view, allowing the smallIcon to show here.
         mNotificationStyle.bigLargeIcon((Bitmap) null);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index cfc95bf..686e24c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -272,7 +272,7 @@
     }
 
     private boolean isCarrierNetworkChangeActive() {
-        return !hasService() && mCurrentState.carrierNetworkChangeMode;
+        return mCurrentState.carrierNetworkChangeMode;
     }
 
     public void handleBroadcast(Intent intent) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
index dd6f272..2df1980 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
@@ -391,35 +391,7 @@
 
     }
 
-    public void testCarrierNetworkChange_carrierNetworkChangeWhileConnected() {
-      int strength = SignalStrength.SIGNAL_STRENGTH_GREAT;
-
-      setupDefaultSignal();
-      setLevel(strength);
-
-      // API call is made
-      setCarrierNetworkChange(true /* enabled */);
-
-      // Boolean value is set, but we still have a signal, should be showing normal
-      verifyLastMobileDataIndicators(true /* visible */,
-              TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[1][strength] /* strengthIcon */,
-              DEFAULT_ICON /* typeIcon */);
-
-      // Lose voice but still have data
-      setVoiceRegState(ServiceState.STATE_OUT_OF_SERVICE);
-      verifyLastMobileDataIndicators(true /* visible */,
-              TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[1][strength] /* strengthIcon */,
-              DEFAULT_ICON /* typeIcon */);
-
-      // Voice but no data
-      setVoiceRegState(ServiceState.STATE_IN_SERVICE);
-      setDataRegState(ServiceState.STATE_OUT_OF_SERVICE);
-      verifyLastMobileDataIndicators(true /* visible */,
-              TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[1][strength] /* strengthIcon */,
-              DEFAULT_ICON /* typeIcon */);
-    }
-
-    public void testCarrierNetworkChange_carrierNetworkChangeWhileDisconnected() {
+    public void testCarrierNetworkChange_carrierNetworkChange() {
       int strength = SignalStrength.SIGNAL_STRENGTH_GREAT;
 
       setupDefaultSignal();
@@ -430,20 +402,16 @@
               TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH[1][strength] /* strengthIcon */,
               DEFAULT_ICON /* typeIcon */);
 
-      // API call is made and all connectivity lost
+      // API call is made
       setCarrierNetworkChange(true /* enabled */);
-      setVoiceRegState(ServiceState.STATE_OUT_OF_SERVICE);
-      setDataRegState(ServiceState.STATE_OUT_OF_SERVICE);
 
-      // Out of service and carrier network change is true, show special indicator
+      // Carrier network change is true, show special indicator
       verifyLastMobileDataIndicators(true /* visible */,
               TelephonyIcons.TELEPHONY_CARRIER_NETWORK_CHANGE[0][0] /* strengthIcon */,
               0 /* typeIcon */);
 
       // Revert back
       setCarrierNetworkChange(false /* enabled */);
-      setVoiceRegState(ServiceState.STATE_IN_SERVICE);
-      setDataRegState(ServiceState.STATE_IN_SERVICE);
 
       // Verify back in previous state
       verifyLastMobileDataIndicators(true /* visible */,
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 9b7b2d3..e9759c3 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -16,14 +16,19 @@
 
 package com.android.server;
 
+import android.Manifest;
+import android.app.ActivityManagerNative;
 import android.app.AlarmManager;
+import android.app.AppGlobals;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.hardware.Sensor;
 import android.hardware.SensorManager;
 import android.hardware.TriggerEvent;
@@ -47,7 +52,9 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.SparseBooleanArray;
+import android.util.SparseLongArray;
 import android.util.TimeUtils;
 import android.util.Xml;
 import android.view.Display;
@@ -55,6 +62,7 @@
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.os.AtomicFile;
 import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
 import com.android.server.am.BatteryStatsService;
@@ -72,6 +80,7 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
 
 /**
  * Keeps track of device idleness and drives low power mode based on that.
@@ -79,7 +88,8 @@
 public class DeviceIdleController extends SystemService {
     private static final String TAG = "DeviceIdleController";
 
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    private static final boolean DEBUG = false;
+    private static final boolean COMPRESS_TIME = false;
 
     public static final String SERVICE_NAME = "deviceidle";
 
@@ -94,29 +104,31 @@
      * immediately after going inactive just because we don't want to be continually running
      * the significant motion sensor whenever the screen is off.
      */
-    private static final long DEFAULT_INACTIVE_TIMEOUT = !DEBUG ? 30*60*1000L
-            : 2 * 60 * 1000L;
+    private static final long DEFAULT_INACTIVE_TIMEOUT = !COMPRESS_TIME ? 30*60*1000L
+            : 3 * 60 * 1000L;
     /**
      * This is the time, after seeing motion, that we wait after becoming inactive from
      * that until we start looking for motion again.
      */
-    private static final long DEFAULT_MOTION_INACTIVE_TIMEOUT = !DEBUG ? 10*60*1000L
+    private static final long DEFAULT_MOTION_INACTIVE_TIMEOUT = !COMPRESS_TIME ? 10*60*1000L
             : 60 * 1000L;
     /**
      * This is the time, after the inactive timeout elapses, that we will wait looking
      * for significant motion until we truly consider the device to be idle.
      */
-    private static final long DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT = !DEBUG ? 30*60*1000L
-            : 2 * 60 * 1000L;
+    private static final long DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT = !COMPRESS_TIME ? 30*60*1000L
+            : 3 * 60 * 1000L;
     /**
      * This is the initial time, after being idle, that we will allow ourself to be back
      * in the IDLE_PENDING state allowing the system to run normally until we return to idle.
      */
-    private static final long DEFAULT_IDLE_PENDING_TIMEOUT = 5*60*1000L;
+    private static final long DEFAULT_IDLE_PENDING_TIMEOUT = !COMPRESS_TIME ? 5*60*1000L
+            : 30 * 1000L;
     /**
      * Maximum pending idle timeout (time spent running) we will be allowed to use.
      */
-    private static final long DEFAULT_MAX_IDLE_PENDING_TIMEOUT = 10*60*1000L;
+    private static final long DEFAULT_MAX_IDLE_PENDING_TIMEOUT = !COMPRESS_TIME ? 10*60*1000L
+            : 60 * 1000L;
     /**
      * Scaling factor to apply to current pending idle timeout each time we cycle through
      * that state.
@@ -126,13 +138,13 @@
      * This is the initial time that we want to sit in the idle state before waking up
      * again to return to pending idle and allowing normal work to run.
      */
-    private static final long DEFAULT_IDLE_TIMEOUT = !DEBUG ? 60*60*1000L
-            : 5 * 60 * 1000L;
+    private static final long DEFAULT_IDLE_TIMEOUT = !COMPRESS_TIME ? 60*60*1000L
+            : 6 * 60 * 1000L;
     /**
      * Maximum idle duration we will be allowed to use.
      */
-    private static final long DEFAULT_MAX_IDLE_TIMEOUT = !DEBUG ? 6*60*60*1000L
-            : 10 * 60 * 1000L;
+    private static final long DEFAULT_MAX_IDLE_TIMEOUT = !COMPRESS_TIME ? 6*60*60*1000L
+            : 30 * 60 * 1000L;
     /**
      * Scaling factor to apply to current idle timeout each time we cycle through that state.
      */
@@ -141,8 +153,13 @@
      * This is the minimum time we will allow until the next upcoming alarm for us to
      * actually go in to idle mode.
      */
-    private static final long DEFAULT_MIN_TIME_TO_ALARM = !DEBUG ? 60*60*1000L
-            : 5 * 60 * 1000L;
+    private static final long DEFAULT_MIN_TIME_TO_ALARM = !COMPRESS_TIME ? 60*60*1000L
+            : 6 * 60 * 1000L;
+
+    /**
+     * Max amount of time to temporarily whitelist an app when it receives a high priority tickle.
+     */
+    private static final long MAX_TEMP_APP_WHITELIST_DURATION = 5 * 60 * 1000L;
 
     private AlarmManager mAlarmManager;
     private IBatteryStats mBatteryStats;
@@ -210,6 +227,17 @@
      */
     private int[] mPowerSaveWhitelistAppIdArray = new int[0];
 
+    /**
+     * List of end times for UIDs that are temporarily marked as being allowed to access
+     * the network and acquire wakelocks. Times are in milliseconds.
+     */
+    private SparseLongArray mTempWhitelistAppIdEndTimes = new SparseLongArray();
+
+    /**
+     * Current app IDs of temporarily whitelist apps for high-priority messages.
+     */
+    private int[] mTempWhitelistAppIdArray = new int[0];
+
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override public void onReceive(Context context, Intent intent) {
             if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
@@ -252,6 +280,7 @@
     static final int MSG_REPORT_IDLE_ON = 2;
     static final int MSG_REPORT_IDLE_OFF = 3;
     static final int MSG_REPORT_ACTIVE = 4;
+    static final int MSG_TEMP_APP_WHITELIST_TIMEOUT = 5;
 
     final class MyHandler extends Handler {
         MyHandler(Looper looper) {
@@ -294,6 +323,10 @@
                         getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
                     }
                 } break;
+                case MSG_TEMP_APP_WHITELIST_TIMEOUT: {
+                    int uid = msg.arg1;
+                    checkTempAppWhitelistTimeout(uid);
+                } break;
             }
         }
     }
@@ -325,10 +358,39 @@
             return getAppIdWhitelistInternal();
         }
 
+        @Override public int[] getAppIdTempWhitelist() {
+            return getAppIdTempWhitelistInternal();
+        }
+
         @Override public boolean isPowerSaveWhitelistApp(String name) {
             return isPowerSaveWhitelistAppInternal(name);
         }
 
+        @Override public void addPowerSaveTempWhitelistApp(String packageName, long duration,
+                int userId) throws RemoteException {
+            getContext().enforceCallingPermission(
+                    Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
+                    "No permission to change device idle whitelist");
+            userId = ActivityManagerNative.getDefault().handleIncomingUser(
+                    Binder.getCallingPid(),
+                    Binder.getCallingUid(),
+                    userId,
+                    /*allowAll=*/ false,
+                    /*requireFull=*/ false,
+                    "addAppBrieflyToWhitelist", null);
+            final long token = Binder.clearCallingIdentity();
+            try {
+                PackageInfo pi = AppGlobals.getPackageManager()
+                        .getPackageInfo(packageName, 0, userId);
+                if (pi == null) return;
+                DeviceIdleController.this.addPowerSaveTempWhitelistAppInternal(packageName,
+                        duration, userId);
+            } catch (RemoteException re) {
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
         @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             DeviceIdleController.this.dump(fd, pw, args);
         }
@@ -481,6 +543,70 @@
         }
     }
 
+    public int[] getAppIdTempWhitelistInternal() {
+        synchronized (this) {
+            return mTempWhitelistAppIdArray;
+        }
+    }
+
+    /**
+     * Adds an app to the temporary whitelist and resets the endTime for granting the
+     * app an exemption to access network and acquire wakelocks.
+     */
+    public void addPowerSaveTempWhitelistAppInternal(String packageName, long duration,
+            int userId) {
+        if (duration > MAX_TEMP_APP_WHITELIST_DURATION) {
+            duration = MAX_TEMP_APP_WHITELIST_DURATION;
+        }
+        try {
+            int uid = getContext().getPackageManager().getPackageUid(packageName, userId);
+            int appId = UserHandle.getAppId(uid);
+            final long timeNow = System.currentTimeMillis();
+            synchronized (this) {
+                long currentEndTime = mTempWhitelistAppIdEndTimes.get(appId);
+                // Set the new end time
+                mTempWhitelistAppIdEndTimes.put(appId, timeNow + duration);
+                if (DEBUG) {
+                    Slog.d(TAG, "Adding AppId " + appId + " to temp whitelist");
+                }
+                if (currentEndTime == 0) {
+                    // No pending timeout for the app id, post a delayed message
+                    postTempActiveTimeoutMessage(appId, duration);
+                    updateTempWhitelistAppIdsLocked();
+                    reportTempWhitelistChangedLocked();
+                }
+            }
+        } catch (NameNotFoundException e) {
+        }
+    }
+
+    private void postTempActiveTimeoutMessage(int uid, long delay) {
+        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_TEMP_APP_WHITELIST_TIMEOUT, uid, 0),
+                delay);
+    }
+
+    void checkTempAppWhitelistTimeout(int uid) {
+        final long timeNow = System.currentTimeMillis();
+        synchronized (this) {
+            long endTime = mTempWhitelistAppIdEndTimes.get(uid);
+            if (endTime == 0) {
+                // Nothing to do
+                return;
+            }
+            if (timeNow >= endTime) {
+                mTempWhitelistAppIdEndTimes.delete(uid);
+                if (DEBUG) {
+                    Slog.d(TAG, "Removing UID " + uid + " from temp whitelist");
+                }
+                updateTempWhitelistAppIdsLocked();
+                reportTempWhitelistChangedLocked();
+            } else {
+                // Need more time
+                postTempActiveTimeoutMessage(uid, endTime - timeNow);
+            }
+        }
+    }
+
     void updateDisplayLocked() {
         mCurDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
         // We consider any situation where the display is showing something to be it on,
@@ -659,14 +785,41 @@
         }
         mPowerSaveWhitelistAppIdArray = appids;
         if (mLocalPowerManager != null) {
+            if (DEBUG) {
+                Slog.d(TAG, "Setting wakelock whitelist to "
+                        + Arrays.toString(mPowerSaveWhitelistAppIdArray));
+            }
             mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAppIdArray);
         }
     }
 
+    private void updateTempWhitelistAppIdsLocked() {
+        final int size = mTempWhitelistAppIdEndTimes.size();
+        if (mTempWhitelistAppIdArray.length != size) {
+            mTempWhitelistAppIdArray = new int[size];
+        }
+        for (int i = 0; i < size; i++) {
+            mTempWhitelistAppIdArray[i] = mTempWhitelistAppIdEndTimes.keyAt(i);
+        }
+        if (mLocalPowerManager != null) {
+            if (DEBUG) {
+                Slog.d(TAG, "Setting wakelock temp whitelist to "
+                        + Arrays.toString(mTempWhitelistAppIdArray));
+            }
+            mLocalPowerManager.setDeviceIdleTempWhitelist(mTempWhitelistAppIdArray);
+        }
+    }
+
     private void reportPowerSaveWhitelistChangedLocked() {
         Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-        getContext().sendBroadcast(intent);
+        getContext().sendBroadcastAsUser(intent, UserHandle.OWNER);
+    }
+
+    private void reportTempWhitelistChangedLocked() {
+        Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_TEMP_WHITELIST_CHANGED);
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+        getContext().sendBroadcastAsUser(intent, UserHandle.OWNER);
     }
 
     void readConfigFileLocked() {
@@ -817,11 +970,18 @@
         }
 
         if (args != null) {
+            int userId = UserHandle.USER_OWNER;
             for (int i=0; i<args.length; i++) {
                 String arg = args[i];
                 if ("-h".equals(arg)) {
                     dumpHelp(pw);
                     return;
+                } else if ("-u".equals(arg)) {
+                    i++;
+                    if (i < args.length) {
+                        arg = args[i];
+                        userId = Integer.parseInt(arg);
+                    }
                 } else if ("-a".equals(arg)) {
                     // Ignore, we always dump all.
                 } else if ("step".equals(arg)) {
@@ -873,6 +1033,17 @@
                         }
                     }
                     return;
+                } else if ("tempwhitelist".equals(arg)) {
+                    i++;
+                    if (i >= args.length) {
+                        pw.println("At least one package name must be specified");
+                        return;
+                    }
+                    while (i < args.length) {
+                        arg = args[i];
+                        i++;
+                        addPowerSaveTempWhitelistAppInternal(arg, 10000L, userId);
+                    }
                 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
                     pw.println("Unknown option: " + arg);
                     return;
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index d214a20..3315c89 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server.accounts;
 
 import android.Manifest;
+import android.accounts.AbstractAccountAuthenticator;
 import android.accounts.Account;
 import android.accounts.AccountAndUser;
 import android.accounts.AccountAuthenticatorResponse;
@@ -49,6 +50,7 @@
 import android.content.pm.RegisteredServicesCache;
 import android.content.pm.RegisteredServicesCacheListener;
 import android.content.pm.ResolveInfo;
+import android.content.pm.Signature;
 import android.content.pm.UserInfo;
 import android.database.Cursor;
 import android.database.DatabaseUtils;
@@ -84,6 +86,11 @@
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 import java.sql.Timestamp;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
@@ -93,6 +100,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -166,6 +174,10 @@
     private static final String[] ACCOUNT_TYPE_COUNT_PROJECTION =
             new String[] { ACCOUNTS_TYPE, ACCOUNTS_TYPE_COUNT};
     private static final Intent ACCOUNTS_CHANGED_INTENT;
+    static {
+        ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
+        ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+    }
 
     private static final String COUNT_OF_MATCHING_GRANTS = ""
             + "SELECT COUNT(*) FROM " + TABLE_GRANTS + ", " + TABLE_ACCOUNTS
@@ -177,6 +189,7 @@
 
     private static final String SELECTION_AUTHTOKENS_BY_ACCOUNT =
             AUTHTOKENS_ACCOUNTS_ID + "=(select _id FROM accounts WHERE name=? AND type=?)";
+
     private static final String[] COLUMNS_AUTHTOKENS_TYPE_AND_AUTHTOKEN = {AUTHTOKENS_TYPE,
             AUTHTOKENS_AUTHTOKEN};
 
@@ -205,6 +218,10 @@
         /** protected by the {@link #cacheLock} */
         private final HashMap<Account, HashMap<String, String>> authTokenCache =
                 new HashMap<Account, HashMap<String, String>>();
+
+        /** protected by the {@link #cacheLock} */
+        private final HashMap<Account, WeakReference<TokenCache>> accountTokenCaches = new HashMap<>();
+
         /**
          * protected by the {@link #cacheLock}
          *
@@ -237,12 +254,6 @@
             new AtomicReference<AccountManagerService>();
     private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
 
-    static {
-        ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
-        ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-    }
-
-
     /**
      * This should only be called by system code. One should only call this after the service
      * has started.
@@ -425,6 +436,7 @@
                         final Account account = new Account(accountName, accountType);
                         accounts.userDataCache.remove(account);
                         accounts.authTokenCache.remove(account);
+                        accounts.accountTokenCaches.remove(account);
                     } else {
                         ArrayList<String> accountNames = accountNamesByType.get(accountType);
                         if (accountNames == null) {
@@ -1337,9 +1349,10 @@
 
     @Override
     public void invalidateAuthToken(String accountType, String authToken) {
+        int callerUid = Binder.getCallingUid();
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "invalidateAuthToken: accountType " + accountType
-                    + ", caller's uid " + Binder.getCallingUid()
+                    + ", caller's uid " + callerUid
                     + ", pid " + Binder.getCallingPid());
         }
         if (accountType == null) throw new IllegalArgumentException("accountType is null");
@@ -1353,6 +1366,7 @@
                 db.beginTransaction();
                 try {
                     invalidateAuthTokenLocked(accounts, db, accountType, authToken);
+                    invalidateCustomTokenLocked(accounts, accountType, authToken);
                     db.setTransactionSuccessful();
                 } finally {
                     db.endTransaction();
@@ -1363,6 +1377,26 @@
         }
     }
 
+    private void invalidateCustomTokenLocked(
+            UserAccounts accounts,
+            String accountType,
+            String authToken) {
+        if (authToken == null || accountType == null) {
+            return;
+        }
+        // Also wipe out cached token in memory.
+        for (Account a : accounts.accountTokenCaches.keySet()) {
+            if (a.type.equals(accountType)) {
+                WeakReference<TokenCache> tokenCacheRef =
+                        accounts.accountTokenCaches.get(a);
+                TokenCache cache = null;
+                if (tokenCacheRef != null && (cache = tokenCacheRef.get()) != null) {
+                    cache.remove(authToken);
+                }
+            }
+        }
+    }
+
     private void invalidateAuthTokenLocked(UserAccounts accounts, SQLiteDatabase db,
             String accountType, String authToken) {
         if (authToken == null || accountType == null) {
@@ -1385,14 +1419,41 @@
                 String accountName = cursor.getString(1);
                 String authTokenType = cursor.getString(2);
                 db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ID + "=" + authTokenId, null);
-                writeAuthTokenIntoCacheLocked(accounts, db, new Account(accountName, accountType),
-                        authTokenType, null);
+                writeAuthTokenIntoCacheLocked(
+                        accounts,
+                        db,
+                        new Account(accountName, accountType),
+                        authTokenType,
+                        null);
             }
         } finally {
             cursor.close();
         }
     }
 
+    private void saveCachedToken(
+            UserAccounts accounts,
+            Account account,
+            String callerPkg,
+            byte[] callerSigDigest,
+            String tokenType,
+            String token,
+            long expiryMillis) {
+
+        if (account == null || tokenType == null || callerPkg == null || callerSigDigest == null) {
+            return;
+        }
+        cancelNotification(getSigninRequiredNotificationId(accounts, account),
+                new UserHandle(accounts.userId));
+        synchronized (accounts.cacheLock) {
+            TokenCache cache = getTokenCacheForAccountLocked(accounts, account);
+            if (cache != null) {
+                cache.put(token, tokenType, callerPkg, callerSigDigest, expiryMillis);
+            }
+            return;
+        }
+    }
+
     private boolean saveAuthTokenToDatabase(UserAccounts accounts, Account account, String type,
             String authToken) {
         if (account == null || type == null) {
@@ -1510,6 +1571,7 @@
                     db.update(TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
                     db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?", argsAccountId);
                     accounts.authTokenCache.remove(account);
+                    accounts.accountTokenCaches.remove(account);
                     db.setTransactionSuccessful();
 
                     String action = (password == null || password.length() == 0) ?
@@ -1673,9 +1735,14 @@
     }
 
     @Override
-    public void getAuthToken(IAccountManagerResponse response, final Account account,
-            final String authTokenType, final boolean notifyOnAuthFailure,
-            final boolean expectActivityLaunch, Bundle loginOptionsIn) {
+    public void getAuthToken(
+            IAccountManagerResponse response,
+            final Account account,
+            final String authTokenType,
+            final boolean notifyOnAuthFailure,
+            final boolean expectActivityLaunch,
+            final Bundle loginOptions) {
+
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "getAuthToken: " + account
                     + ", response " + response
@@ -1707,19 +1774,33 @@
         final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
         authenticatorInfo = mAuthenticatorCache.getServiceInfo(
                 AuthenticatorDescription.newKey(account.type), accounts.userId);
+
         final boolean customTokens =
-            authenticatorInfo != null && authenticatorInfo.type.customTokens;
+                authenticatorInfo != null && authenticatorInfo.type.customTokens;
 
         // skip the check if customTokens
         final int callerUid = Binder.getCallingUid();
         final boolean permissionGranted = customTokens ||
             permissionIsGranted(account, authTokenType, callerUid);
 
-        final Bundle loginOptions = (loginOptionsIn == null) ? new Bundle() :
-            loginOptionsIn;
+        // Get the calling package. We will use it for the purpose of caching.
+        final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
+        List<String> callerOwnedPackageNames = Arrays.asList(mPackageManager.getPackagesForUid(callerUid));
+        if (callerPkg == null || !callerOwnedPackageNames.contains(callerPkg)) {
+            String msg = String.format(
+                    "Uid %s is attempting to illegally masquerade as package %s!",
+                    callerUid,
+                    callerPkg);
+            throw new SecurityException(msg);
+        }
+
         // let authenticator know the identity of the caller
         loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
         loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
+
+        // Distill the caller's package signatures into a single digest.
+        final byte[] callerPkgSigDigest = calculatePackageSignatureDigest(callerPkg);
+
         if (notifyOnAuthFailure) {
             loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
         }
@@ -1740,6 +1821,28 @@
                 }
             }
 
+            if (customTokens) {
+                /*
+                 * Look up tokens in the new cache only if the loginOptions don't have parameters
+                 * outside of those expected to be injected by the AccountManager, e.g.
+                 * ANDORID_PACKAGE_NAME.
+                 */
+                String token = readCachedTokenInternal(
+                        accounts,
+                        account,
+                        authTokenType,
+                        callerPkg,
+                        callerPkgSigDigest);
+                if (token != null) {
+                    Bundle result = new Bundle();
+                    result.putString(AccountManager.KEY_AUTHTOKEN, token);
+                    result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
+                    result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
+                    onResult(response, result);
+                    return;
+                }
+            }
+
             new Session(accounts, response, account.type, expectActivityLaunch,
                     false /* stripAuthTokenFromResult */, account.name,
                     false /* authDetailsRequired */) {
@@ -1786,9 +1889,26 @@
                                         "the type and name should not be empty");
                                 return;
                             }
+                            Account resultAccount = new Account(name, type);
                             if (!customTokens) {
-                                saveAuthTokenToDatabase(mAccounts, new Account(name, type),
-                                        authTokenType, authToken);
+                                saveAuthTokenToDatabase(
+                                        mAccounts,
+                                        resultAccount,
+                                        authTokenType,
+                                        authToken);
+                            }
+                            long expiryMillis = result.getLong(
+                                    AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 0L);
+                            if (customTokens
+                                    && expiryMillis > System.currentTimeMillis()) {
+                                saveCachedToken(
+                                        mAccounts,
+                                        account,
+                                        callerPkg,
+                                        callerPkgSigDigest,
+                                        authTokenType,
+                                        authToken,
+                                        expiryMillis);
                             }
                         }
 
@@ -1807,6 +1927,25 @@
         }
     }
 
+    private byte[] calculatePackageSignatureDigest(String callerPkg) {
+        MessageDigest digester;
+        try {
+            digester = MessageDigest.getInstance("SHA-256");
+            PackageInfo pkgInfo = mPackageManager.getPackageInfo(
+                    callerPkg, PackageManager.GET_SIGNATURES);
+            for (Signature sig : pkgInfo.signatures) {
+                digester.update(sig.toByteArray());
+            }
+        } catch (NoSuchAlgorithmException x) {
+            Log.wtf(TAG, "SHA-256 should be available", x);
+            digester = null;
+        } catch (NameNotFoundException e) {
+            Log.w(TAG, "Could not find packageinfo for: " + callerPkg);
+            digester = null;
+        }
+        return (digester == null) ? null : digester.digest();
+    }
+
     private void createNoCredentialsPermissionNotification(Account account, Intent intent,
             int userId) {
         int uid = intent.getIntExtra(
@@ -2745,13 +2884,13 @@
             if (result != null) {
                 boolean isSuccessfulConfirmCreds = result.getBoolean(
                         AccountManager.KEY_BOOLEAN_RESULT, false);
-                boolean isSuccessfulUpdateCreds = 
+                boolean isSuccessfulUpdateCreds =
                         result.containsKey(AccountManager.KEY_ACCOUNT_NAME)
                         && result.containsKey(AccountManager.KEY_ACCOUNT_TYPE);
-                // We should only update lastAuthenticated time, if 
+                // We should only update lastAuthenticated time, if
                 // mUpdateLastAuthenticatedTime is true and the confirmRequest
                 // or updateRequest was successful
-                boolean needUpdate = mUpdateLastAuthenticatedTime 
+                boolean needUpdate = mUpdateLastAuthenticatedTime
                         && (isSuccessfulConfirmCreds || isSuccessfulUpdateCreds);
                 if (needUpdate || mAuthDetailsRequired) {
                     boolean accountPresent = isAccountPresentForCaller(mAccountName, mAccountType);
@@ -3398,7 +3537,6 @@
                 return;
             }
         }
-
         String msg = "caller uid " + uid + " lacks any of " + TextUtils.join(",", permissions);
         Log.w(TAG, "  " + msg);
         throw new SecurityException(msg);
@@ -3796,6 +3934,18 @@
         }
     }
 
+    protected String readCachedTokenInternal(
+            UserAccounts accounts,
+            Account account,
+            String tokenType,
+            String callingPackage,
+            byte[] pkgSigDigest) {
+        synchronized (accounts.cacheLock) {
+            TokenCache cache = getTokenCacheForAccountLocked(accounts, account);
+            return cache.get(tokenType, callingPackage, pkgSigDigest);
+        }
+    }
+
     protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts, final SQLiteDatabase db,
             Account account, String key, String value) {
         HashMap<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
@@ -3877,6 +4027,17 @@
         return authTokensForAccount;
     }
 
+    protected TokenCache getTokenCacheForAccountLocked(UserAccounts accounts, Account account) {
+        WeakReference<TokenCache> cacheRef = accounts.accountTokenCaches.get(account);
+        TokenCache cache;
+        if (cacheRef == null || (cache = cacheRef.get()) == null) {
+            cache = new TokenCache();
+            cacheRef = new WeakReference<>(cache);
+            accounts.accountTokenCaches.put(account, cacheRef);
+        }
+        return cache;
+    }
+
     private Context getContextForUser(UserHandle user) {
         try {
             return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
diff --git a/services/core/java/com/android/server/accounts/TokenCache.java b/services/core/java/com/android/server/accounts/TokenCache.java
new file mode 100644
index 0000000..70a7010
--- /dev/null
+++ b/services/core/java/com/android/server/accounts/TokenCache.java
@@ -0,0 +1,163 @@
+/*
+ * 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.server.accounts;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * TokenCaches manage tokens associated with an account in memory.
+ */
+/* default */ class TokenCache {
+
+    private static class Value {
+        public final String token;
+        public final long expiryEpochMillis;
+
+        public Value(String token, long expiryEpochMillis) {
+            this.token = token;
+            this.expiryEpochMillis = expiryEpochMillis;
+        }
+    }
+
+    private static class Key {
+        public final String packageName;
+        public final String tokenType;
+        public final byte[] sigDigest;
+
+        public Key(String tokenType, String packageName, byte[] sigDigest) {
+            this.tokenType = tokenType;
+            this.packageName = packageName;
+            this.sigDigest = sigDigest;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (o != null && o instanceof Key) {
+                Key cacheKey = (Key) o;
+                return Objects.equals(packageName, cacheKey.packageName)
+                        && Objects.equals(tokenType, cacheKey.tokenType)
+                        && Arrays.equals(sigDigest, cacheKey.sigDigest);
+            } else {
+                return false;
+            }
+        }
+
+        @Override
+        public int hashCode() {
+            return packageName.hashCode() ^ tokenType.hashCode() ^ Arrays.hashCode(sigDigest);
+        }
+    }
+
+    /**
+     * Map associating basic token lookup information with with actual tokens (and optionally their
+     * expiration times). 
+     */
+    private HashMap<Key, Value> mCachedTokens = new HashMap<>();
+
+    /**
+     * Map associated tokens with an Evictor that will manage evicting the token from the cache.
+     * This reverse lookup is needed because very little information is given at token invalidation
+     * time.
+     */
+    private HashMap<String, Evictor> mTokenEvictors = new HashMap<>();
+
+    private class Evictor {
+        private final String mToken;
+        private final List<Key> mKeys;
+
+        public Evictor(String token) {
+            mKeys = new ArrayList<>();
+            mToken = token;
+        }
+
+        public void add(Key k) {
+            mKeys.add(k);
+        }
+
+        public void evict() {
+            for (Key k : mKeys) {
+                mCachedTokens.remove(k);
+            }
+            // Clear out the evictor reference.
+            mTokenEvictors.remove(mToken);
+        }
+    }
+
+    /**
+     * Caches the specified token until the specified expiryMillis. The token will be associated
+     * with the given token type, package name, and digest of signatures.
+     *
+     * @param token
+     * @param tokenType
+     * @param packageName
+     * @param sigDigest
+     * @param expiryMillis
+     */
+    public void put(
+            String token,
+            String tokenType,
+            String packageName,
+            byte[] sigDigest,
+            long expiryMillis) {
+        if (token == null || System.currentTimeMillis() > expiryMillis) {
+            return;
+        }
+        Key k = new Key(tokenType, packageName, sigDigest);
+        // Prep evictor. No token should be cached without a corresponding evictor.
+        Evictor evictor = mTokenEvictors.get(token);
+        if (evictor == null) {
+            evictor = new Evictor(token);
+        }
+        evictor.add(k);
+        mTokenEvictors.put(token, evictor);
+        // Then cache values.
+        Value v = new Value(token, expiryMillis);
+        mCachedTokens.put(k, v);
+    }
+
+    /**
+     * Evicts the specified token from the cache. This should be called as part of a token
+     * invalidation workflow.
+     */
+    public void remove(String token) {
+        Evictor evictor = mTokenEvictors.get(token);
+        if (evictor == null) {
+            // This condition is expected if the token isn't cached.
+            return;
+        }
+        evictor.evict();
+    }
+
+    /**
+     * Gets a token from the cache if possible.
+     */
+    public String get(String tokenType, String packageName, byte[] sigDigest) {
+        Key k = new Key(tokenType, packageName, sigDigest);
+        Value v = mCachedTokens.get(k);
+        long currentTime = System.currentTimeMillis();
+        if (v != null && currentTime < v.expiryEpochMillis) {
+            return v.token;
+        } else if (v != null) {
+            remove(v.token);
+        }
+        return null;
+    }
+}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index fa4d204..333db5d 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -518,7 +518,7 @@
             // r.record is null if findServiceLocked() failed the caller permission check
             if (r.record == null) {
                 throw new SecurityException(
-                        "Permission Denial: Accessing service " + r.record.name
+                        "Permission Denial: Accessing service"
                         + " from pid=" + Binder.getCallingPid()
                         + ", uid=" + Binder.getCallingUid()
                         + " requires " + r.permission);
diff --git a/services/core/java/com/android/server/camera/CameraService.java b/services/core/java/com/android/server/camera/CameraService.java
index 777a9dd..9347c24 100644
--- a/services/core/java/com/android/server/camera/CameraService.java
+++ b/services/core/java/com/android/server/camera/CameraService.java
@@ -20,10 +20,15 @@
 import android.content.pm.UserInfo;
 import android.hardware.ICameraService;
 import android.hardware.ICameraServiceProxy;
+import android.os.Handler;
 import android.os.IBinder;
+import android.os.Message;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserManager;
+import android.util.Slog;
 
+import com.android.server.ServiceThread;
 import com.android.server.SystemService;
 
 import java.util.Collection;
@@ -36,7 +41,8 @@
  *
  * @hide
  */
-public class CameraService extends SystemService {
+public class CameraService extends SystemService implements Handler.Callback {
+    private static final String TAG = "CameraService_proxy";
 
     /**
      * This must match the ICameraService.aidl definition
@@ -49,7 +55,14 @@
     public static final int NO_EVENT = 0; // NOOP
     public static final int USER_SWITCHED = 1; // User changed, argument is the new user handle
 
+    // Handler message codes
+    private static final int MSG_SWITCH_USER = 1;
+
+    private static final int RETRY_DELAY_TIME = 20; //ms
+
     private final Context mContext;
+    private final ServiceThread mHandlerThread;
+    private final Handler mHandler;
     private UserManager mUserManager;
 
     private final Object mLock = new Object();
@@ -58,18 +71,29 @@
     private final ICameraServiceProxy.Stub mCameraServiceProxy = new ICameraServiceProxy.Stub() {
         @Override
         public void pingForUserUpdate() {
-            // Binder call
-            synchronized(mLock) {
-                if (mEnabledCameraUsers != null) {
-                    notifyMediaserver(USER_SWITCHED, mEnabledCameraUsers);
-                }
-            }
+            notifySwitchWithRetries(30);
         }
     };
 
     public CameraService(Context context) {
         super(context);
         mContext = context;
+        mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_DISPLAY, /*allowTo*/false);
+        mHandlerThread.start();
+        mHandler = new Handler(mHandlerThread.getLooper(), this);
+    }
+
+    @Override
+    public boolean handleMessage(Message msg) {
+        switch(msg.what) {
+            case MSG_SWITCH_USER: {
+                notifySwitchWithRetries(msg.arg1);
+            } break;
+            default: {
+                Slog.e(TAG, "CameraService error, invalid message: " + msg.what);
+            } break;
+        }
+        return true;
     }
 
     @Override
@@ -119,12 +143,30 @@
         return handles;
     }
 
-    private void notifyMediaserver(int eventType, Set<Integer> updatedUserHandles) {
+    private void notifySwitchWithRetries(int retries) {
+        synchronized(mLock) {
+            if (mEnabledCameraUsers == null) {
+                return;
+            }
+            if (notifyMediaserver(USER_SWITCHED, mEnabledCameraUsers)) {
+                retries = 0;
+            }
+        }
+        if (retries <= 0) {
+            return;
+        }
+        Slog.i(TAG, "Could not notify camera service of user switch, retrying...");
+        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SWITCH_USER, retries - 1, 0, null),
+                RETRY_DELAY_TIME);
+    }
+
+    private boolean notifyMediaserver(int eventType, Set<Integer> updatedUserHandles) {
         // Forward the user switch event to the native camera service running in the mediaserver
         // process.
         IBinder cameraServiceBinder = getBinderService(CAMERA_SERVICE_BINDER_NAME);
         if (cameraServiceBinder == null) {
-            return; // Camera service not active, cannot evict user clients.
+            Slog.w(TAG, "Could not notify mediaserver, camera service not available.");
+            return false; // Camera service not active, cannot evict user clients.
         }
 
         ICameraService cameraServiceRaw = ICameraService.Stub.asInterface(cameraServiceBinder);
@@ -132,8 +174,11 @@
         try {
             cameraServiceRaw.notifySystemEvent(eventType, toArray(updatedUserHandles));
         } catch (RemoteException e) {
+            Slog.w(TAG, "Could not notify mediaserver, remote exception: " + e);
             // Not much we can do if camera service is dead.
+            return false;
         }
+        return true;
     }
 
     private static int[] toArray(Collection<Integer> c) {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 792d4ba..7673af4 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -283,9 +283,12 @@
     /**
      * UIDs that have been white-listed to always be able to have network access
      * in power save mode.
+     * TODO: An int array might be sufficient
      */
     private final SparseBooleanArray mPowerSaveWhitelistAppIds = new SparseBooleanArray();
 
+    private final SparseBooleanArray mPowerSaveTempWhitelistAppIds = new SparseBooleanArray();
+
     /** Set of ifaces that are metered. */
     private ArraySet<String> mMeteredIfaces = new ArraySet<>();
     /** Set of over-limit templates that have been notified. */
@@ -371,6 +374,19 @@
         }
     }
 
+    void updatePowerSaveTempWhitelistLocked() {
+        try {
+            final int[] whitelist = mDeviceIdleController.getAppIdTempWhitelist();
+            mPowerSaveTempWhitelistAppIds.clear();
+            if (whitelist != null) {
+                for (int uid : whitelist) {
+                    mPowerSaveTempWhitelistAppIds.put(uid, true);
+                }
+            }
+        } catch (RemoteException e) {
+        }
+    }
+
     public void systemReady() {
         if (!isBandwidthControlEnabled()) {
             Slog.w(TAG, "bandwidth controls disabled, unable to enforce policy");
@@ -392,6 +408,7 @@
                         if (mRestrictPower != enabled) {
                             mRestrictPower = enabled;
                             updateRulesForGlobalChangeLocked(true);
+                            updateRulesForTempWhitelistChangeLocked();
                         }
                     }
                 }
@@ -404,6 +421,7 @@
 
             if (mRestrictBackground || mRestrictPower || mDeviceIdleMode) {
                 updateRulesForGlobalChangeLocked(true);
+                updateRulesForTempWhitelistChangeLocked();
                 updateNotificationsLocked();
             }
         }
@@ -428,6 +446,7 @@
         // listen for changes to power save whitelist
         final IntentFilter whitelistFilter = new IntentFilter(
                 PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
+        whitelistFilter.addAction(PowerManager.ACTION_POWER_SAVE_TEMP_WHITELIST_CHANGED);
         mContext.registerReceiver(mPowerSaveWhitelistReceiver, whitelistFilter, null, mHandler);
 
         // watch for network interfaces to be claimed
@@ -496,8 +515,13 @@
         public void onReceive(Context context, Intent intent) {
             // on background handler thread, and POWER_SAVE_WHITELIST_CHANGED is protected
             synchronized (mRulesLock) {
-                updatePowerSaveWhitelistLocked();
-                updateRulesForGlobalChangeLocked(false);
+                if (PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED.equals(intent.getAction())) {
+                    updatePowerSaveWhitelistLocked();
+                    updateRulesForGlobalChangeLocked(false);
+                } else {
+                    updatePowerSaveTempWhitelistLocked();
+                    updateRulesForTempWhitelistChangeLocked();
+                }
             }
         }
     };
@@ -2019,6 +2043,17 @@
         }
     }
 
+    void updateRulesForTempWhitelistChangeLocked() {
+        final List<UserInfo> users = mUserManager.getUsers();
+        for (UserInfo user : users) {
+            for (int i = mPowerSaveTempWhitelistAppIds.size() - 1; i >= 0; i--) {
+                int appId = mPowerSaveTempWhitelistAppIds.keyAt(i);
+                int uid = UserHandle.getUid(user.id, appId);
+                updateRulesForUidLocked(uid);
+            }
+        }
+    }
+
     private static boolean isUidValidForRules(int uid) {
         // allow rules on specific system services, and any apps
         if (uid == android.os.Process.MEDIA_UID || uid == android.os.Process.DRM_UID
@@ -2065,8 +2100,10 @@
 
         // derive active rules based on policy and active state
 
+        int appId = UserHandle.getAppId(uid);
         int uidRules = RULE_ALLOW_ALL;
-        if (uidIdle && !mPowerSaveWhitelistAppIds.get(UserHandle.getAppId(uid))) {
+        if (uidIdle && !mPowerSaveWhitelistAppIds.get(appId)
+                && !mPowerSaveTempWhitelistAppIds.get(appId)) {
             uidRules = RULE_REJECT_ALL;
         } else if (!uidForeground && (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
             // uid in background, and policy says to block metered data
@@ -2077,7 +2114,8 @@
                 uidRules = RULE_REJECT_METERED;
             }
         } else if (mRestrictPower || mDeviceIdleMode) {
-            final boolean whitelisted = mPowerSaveWhitelistAppIds.get(UserHandle.getAppId(uid));
+            final boolean whitelisted = mPowerSaveWhitelistAppIds.get(appId)
+                    || mPowerSaveTempWhitelistAppIds.get(appId);
             if (!whitelisted && !uidForeground
                     && (uidPolicy & POLICY_ALLOW_BACKGROUND_BATTERY_SAVE) == 0) {
                 // uid is in background, restrict power use mode is on (so we want to
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f9bfe72..9b619c7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4991,7 +4991,7 @@
                 scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
                         scanFlags, currentTime, null);
             } catch (PackageManagerException e) {
-                Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage());
+                Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage(), e);
 
                 // Delete invalid userdata apps
                 if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 7bd5b78..c8397e2 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -497,6 +497,12 @@
      * be done once per window. */
     private WindowState mWinDismissingKeyguard;
 
+    /** When window is currently dismissing the keyguard, dismissing the keyguard must handle
+     * the keygaurd secure state change instantly case, e.g. the use case of inserting a PIN
+     * lock SIM card. This variable is used to record the previous keyguard secure state for
+     * monitoring secure state change on window dismissing keyguard. */
+    private boolean mSecureDismissingKeyguard;
+
     /** The window that is currently showing "over" the keyguard. If there is an app window
      * belonging to another app on top of this the keyguard shows. If there is a fullscreen
      * app window under this, still dismiss the keyguard but don't show the app underneath. Show
@@ -4272,9 +4278,11 @@
                             mDismissKeyguard == DISMISS_KEYGUARD_NONE) {
                         if (DEBUG_LAYOUT) Slog.v(TAG,
                                 "Setting mDismissKeyguard true by win " + win);
-                        mDismissKeyguard = mWinDismissingKeyguard == win ?
-                                DISMISS_KEYGUARD_CONTINUE : DISMISS_KEYGUARD_START;
+                        mDismissKeyguard = (mWinDismissingKeyguard == win
+                                && mSecureDismissingKeyguard == mKeyguardSecure)
+                                ? DISMISS_KEYGUARD_CONTINUE : DISMISS_KEYGUARD_START;
                         mWinDismissingKeyguard = win;
+                        mSecureDismissingKeyguard = mKeyguardSecure;
                         mForceStatusBarFromKeyguard = mShowingLockscreen && mKeyguardSecure;
                     } else if (mAppsToBeHidden.isEmpty() && showWhenLocked) {
                         if (DEBUG_LAYOUT) Slog.v(TAG,
@@ -4460,6 +4468,7 @@
                 }
             } else {
                 mWinDismissingKeyguard = null;
+                mSecureDismissingKeyguard = false;
                 mKeyguardHidden = false;
                 if (setKeyguardOccludedLw(false)) {
                     changes |= FINISH_LAYOUT_REDO_LAYOUT
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index c1fe984..3af97db 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -438,6 +438,9 @@
     // Set of app ids that we will always respect the wake locks for.
     int[] mDeviceIdleWhitelist = new int[0];
 
+    // Set of app ids that are temporarily allowed to acquire wakelocks due to high-pri message
+    int[] mDeviceIdleTempWhitelist = new int[0];
+
     private final SparseIntArray mUidState = new SparseIntArray();
 
     // True if theater mode is enabled
@@ -2320,6 +2323,15 @@
         }
     }
 
+    void setDeviceIdleTempWhitelistInternal(int[] appids) {
+        synchronized (mLock) {
+            mDeviceIdleTempWhitelist = appids;
+            if (mDeviceIdleMode) {
+                updateWakeLockDisabledStatesLocked();
+            }
+        }
+    }
+
     void updateUidProcStateInternal(int uid, int procState) {
         synchronized (mLock) {
             mUidState.put(uid, procState);
@@ -2372,6 +2384,7 @@
                 // for application uids that are not whitelisted.
                 if (appid >= Process.FIRST_APPLICATION_UID &&
                         Arrays.binarySearch(mDeviceIdleWhitelist, appid) < 0 &&
+                        Arrays.binarySearch(mDeviceIdleTempWhitelist, appid) < 0 &&
                         mUidState.get(wakeLock.mOwnerUid,
                                 ActivityManager.PROCESS_STATE_CACHED_EMPTY)
                                 > ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
@@ -2579,6 +2592,7 @@
             pw.println("  mBatteryLevelLow=" + mBatteryLevelLow);
             pw.println("  mDeviceIdleMode=" + mDeviceIdleMode);
             pw.println("  mDeviceIdleWhitelist=" + Arrays.toString(mDeviceIdleWhitelist));
+            pw.println("  mDeviceIdleTempWhitelist=" + Arrays.toString(mDeviceIdleTempWhitelist));
             pw.println("  mLastWakeTime=" + TimeUtils.formatUptime(mLastWakeTime));
             pw.println("  mLastSleepTime=" + TimeUtils.formatUptime(mLastSleepTime));
             pw.println("  mLastUserActivityTime=" + TimeUtils.formatUptime(mLastUserActivityTime));
@@ -3478,6 +3492,11 @@
         }
 
         @Override
+        public void setDeviceIdleTempWhitelist(int[] appids) {
+            setDeviceIdleTempWhitelistInternal(appids);
+        }
+
+        @Override
         public void updateUidProcState(int uid, int procState) {
             updateUidProcStateInternal(uid, procState);
         }
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index e5981fb..4b62c40 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -408,7 +408,7 @@
         }
 
         // If it's to reboot into recovery, invoke uncrypt via init service.
-        if (mRebootReason.equals(PowerManager.REBOOT_RECOVERY)) {
+        if (PowerManager.REBOOT_RECOVERY.equals(mRebootReason)) {
             uncrypt();
         }
 
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index f914369..5d6df26 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -238,6 +238,7 @@
             final TaskStack stack = win.getStack();
             if (win.isVisibleLw() && stack != null && stack != focusedStack) {
                 mTmpRect.set(win.mVisibleFrame);
+                // If no intersection, we need mTmpRect to be unmodified.
                 mTmpRect.intersect(win.mVisibleInsets);
                 mTouchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE);
             }
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 7cdf8b2..4545032 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -144,7 +144,11 @@
                 bounds = mTmpRect;
                 mFullscreen = true;
             } else {
-                bounds.intersect(mTmpRect); // ensure bounds are entirely within the display rect
+                // ensure bounds are entirely within the display rect
+                if (!bounds.intersect(mTmpRect)) {
+                    // Can't set bounds outside the containing display.. Sorry!
+                    return false;
+                }
                 mFullscreen = mTmpRect.equals(bounds);
             }
         }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 5c9f87e..7019453 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -208,7 +208,7 @@
     static final boolean DEBUG_APP_ORIENTATION = false;
     static final boolean DEBUG_CONFIGURATION = false;
     static final boolean DEBUG_APP_TRANSITIONS = false;
-    static final boolean DEBUG_STARTING_WINDOW = false;
+    static final boolean DEBUG_STARTING_WINDOW = true;
     static final boolean DEBUG_WALLPAPER = false;
     static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER;
     static final boolean DEBUG_DRAG = false;
@@ -2272,6 +2272,16 @@
             } else if (changingTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
                 mLastWallpaperDisplayOffsetY = changingTarget.mWallpaperDisplayOffsetY;
             }
+            if (target.mWallpaperXStep >= 0) {
+                mLastWallpaperXStep = target.mWallpaperXStep;
+            } else if (changingTarget.mWallpaperXStep >= 0) {
+                mLastWallpaperXStep = changingTarget.mWallpaperXStep;
+            }
+            if (target.mWallpaperYStep >= 0) {
+                mLastWallpaperYStep = target.mWallpaperYStep;
+            } else if (changingTarget.mWallpaperYStep >= 0) {
+                mLastWallpaperYStep = changingTarget.mWallpaperYStep;
+            }
         }
 
         for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
@@ -6223,7 +6233,10 @@
                         int bottom = wf.bottom - cr.bottom;
                         frame.union(left, top, right, bottom);
                         ws.getStackBounds(stackBounds);
-                        frame.intersect(stackBounds);
+                        if (!frame.intersect(stackBounds)) {
+                            // Set frame empty if there's no intersection.
+                            frame.setEmpty();
+                        }
                     }
 
                     if (ws.mAppToken != null && ws.mAppToken.token == appToken &&
@@ -6270,12 +6283,16 @@
 
                 if (!includeFullDisplay) {
                     // Constrain frame to the screen size.
-                    frame.intersect(0, 0, dw, dh);
+                    if (!frame.intersect(0, 0, dw, dh)) {
+                        frame.setEmpty();
+                    }
                 } else {
                     // Caller just wants entire display.
                     frame.set(0, 0, dw, dh);
                 }
-
+                if (frame.isEmpty()) {
+                    return null;
+                }
 
                 if (width < 0) {
                     width = frame.width();
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index b8b243c..eda7f79 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -547,7 +547,9 @@
             }
             // Make sure the containing frame is within the content frame so we don't layout
             // resized window under screen decorations.
-            mContainingFrame.intersect(cf);
+            if (!mContainingFrame.intersect(cf)) {
+                mContainingFrame.set(cf);
+            }
             mDisplayFrame.set(mContainingFrame);
         } else {
             mContainingFrame.set(pf);
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index ff3bb28..23057c4 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -90,23 +90,24 @@
 
     static final String TAG = "UsageStatsService";
 
-    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    static final boolean DEBUG = false;
+    private static final boolean COMPRESS_TIME = false;
 
     private static final long TEN_SECONDS = 10 * 1000;
     private static final long ONE_MINUTE = 60 * 1000;
     private static final long TWENTY_MINUTES = 20 * 60 * 1000;
-    private static final long FLUSH_INTERVAL = DEBUG ? TEN_SECONDS : TWENTY_MINUTES;
+    private static final long FLUSH_INTERVAL = COMPRESS_TIME ? TEN_SECONDS : TWENTY_MINUTES;
     private static final long TIME_CHANGE_THRESHOLD_MILLIS = 2 * 1000; // Two seconds.
 
-    static final long DEFAULT_APP_IDLE_THRESHOLD_MILLIS = DEBUG ? ONE_MINUTE * 4
+    static final long DEFAULT_APP_IDLE_THRESHOLD_MILLIS = COMPRESS_TIME ? ONE_MINUTE * 4
             : 12 * 60 * ONE_MINUTE; // 12 hours of screen-on time sans dream-time
-    static final long DEFAULT_WALLCLOCK_APP_IDLE_THRESHOLD_MILLIS = DEBUG ? ONE_MINUTE * 8
+    static final long DEFAULT_WALLCLOCK_APP_IDLE_THRESHOLD_MILLIS = COMPRESS_TIME ? ONE_MINUTE * 8
             : 2L * 24 * 60 * ONE_MINUTE; // 2 days
-    static final long DEFAULT_CHECK_IDLE_INTERVAL = DEBUG ? ONE_MINUTE
+    static final long DEFAULT_CHECK_IDLE_INTERVAL = COMPRESS_TIME ? ONE_MINUTE
             : 8 * 60 * ONE_MINUTE; // 8 hours
-    static final long DEFAULT_PAROLE_INTERVAL = DEBUG ? ONE_MINUTE * 10
+    static final long DEFAULT_PAROLE_INTERVAL = COMPRESS_TIME ? ONE_MINUTE * 10
             : 24 * 60 * ONE_MINUTE; // 24 hours between paroles
-    static final long DEFAULT_PAROLE_DURATION = DEBUG ? ONE_MINUTE
+    static final long DEFAULT_PAROLE_DURATION = COMPRESS_TIME ? ONE_MINUTE
             : 10 * ONE_MINUTE; // 10 minutes
 
     // Handler message types.
@@ -338,7 +339,6 @@
 
     /** Check all running users' apps to see if they enter an idle state. */
     void checkIdleStates() {
-        if (DEBUG) Slog.d(TAG, "Checking idle state");
         final int[] runningUsers;
         try {
             runningUsers = ActivityManagerNative.getDefault().getRunningUserIds();
@@ -994,6 +994,12 @@
         }
 
         @Override
+        public void whitelistAppTemporarily(String packageName, long duration, int userId)
+                throws RemoteException {
+            mDeviceIdleController.addPowerSaveTempWhitelistApp(packageName, duration, userId);
+        }
+
+        @Override
         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
                     != PackageManager.PERMISSION_GRANTED) {
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index 3dae917..cbe7c5d 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -61,6 +61,7 @@
           mMinSdkVersion(NULL), mTargetSdkVersion(NULL), mMaxSdkVersion(NULL),
           mVersionCode(NULL), mVersionName(NULL), mReplaceVersion(false), mCustomPackage(NULL),
           mExtraPackages(NULL), mMaxResVersion(NULL), mDebugMode(false), mNonConstantId(false),
+          mSkipSymbolsWithoutDefaultLocalization(false),
           mProduct(NULL), mUseCrunchCache(false), mErrorOnFailedInsert(false),
           mErrorOnMissingConfigEntry(false), mOutputTextSymbols(NULL),
           mSingleCrunchInputFile(NULL), mSingleCrunchOutputFile(NULL),
@@ -191,6 +192,8 @@
     void setDebugMode(bool val) { mDebugMode = val; }
     bool getNonConstantId() const { return mNonConstantId; }
     void setNonConstantId(bool val) { mNonConstantId = val; }
+    bool getSkipSymbolsWithoutDefaultLocalization() const { return mSkipSymbolsWithoutDefaultLocalization; }
+    void setSkipSymbolsWithoutDefaultLocalization(bool val) { mSkipSymbolsWithoutDefaultLocalization = val; }
     const char* getProduct() const { return mProduct; }
     void setProduct(const char * val) { mProduct = val; }
     void setUseCrunchCache(bool val) { mUseCrunchCache = val; }
@@ -315,6 +318,7 @@
     const char* mMaxResVersion;
     bool        mDebugMode;
     bool        mNonConstantId;
+    bool        mSkipSymbolsWithoutDefaultLocalization;
     const char* mProduct;
     bool        mUseCrunchCache;
     bool        mErrorOnFailedInsert;
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index 7dee585..f832c60 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -212,6 +212,9 @@
         "   --ignore-assets\n"
         "       Assets to be ignored. Default pattern is:\n"
         "       %s\n"
+        "   --skip-symbols-without-default-localization\n"
+        "       Prevents symbols from being generated for strings that do not have a default\n"
+        "       localization\n"
         "   --no-version-vectors\n"
         "       Do not automatically generate versioned copies of vector XML resources.\n",
         gDefaultIgnoreAssets);
@@ -659,6 +662,8 @@
                     bundle.setProduct(argv[0]);
                 } else if (strcmp(cp, "-non-constant-id") == 0) {
                     bundle.setNonConstantId(true);
+                } else if (strcmp(cp, "-skip-symbols-without-default-localization") == 0) {
+                    bundle.setSkipSymbolsWithoutDefaultLocalization(true);
                 } else if (strcmp(cp, "-shared-lib") == 0) {
                     bundle.setNonConstantId(true);
                     bundle.setBuildSharedLibrary(true);
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index beb94fd..5d20815 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -1604,7 +1604,7 @@
     
     if (table.hasResources()) {
         sp<AaptSymbols> symbols = assets->getSymbolsFor(String8("R"));
-        err = table.addSymbols(symbols);
+        err = table.addSymbols(symbols, bundle->getSkipSymbolsWithoutDefaultLocalization());
         if (err < NO_ERROR) {
             return err;
         }
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 3b146da..e64fdf7 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -913,6 +913,7 @@
         if (code == ResXMLTree::START_TAG) {
             const String16* curTag = NULL;
             String16 curType;
+            String16 curName;
             int32_t curFormat = ResTable_map::TYPE_ANY;
             bool curIsBag = false;
             bool curIsBagReplaceOnOverwrite = false;
@@ -1321,6 +1322,10 @@
                 ssize_t attri = block.indexOfAttribute(NULL, "type");
                 if (attri >= 0) {
                     curType = String16(block.getAttributeStringValue(attri, &len));
+                    ssize_t nameIdx = block.indexOfAttribute(NULL, "name");
+                    if (nameIdx >= 0) {
+                        curName = String16(block.getAttributeStringValue(nameIdx, &len));
+                    }
                     ssize_t formatIdx = block.indexOfAttribute(NULL, "format");
                     if (formatIdx >= 0) {
                         String16 formatStr = String16(block.getAttributeStringValue(
@@ -1363,6 +1368,9 @@
                 }
                 
                 if (name.size() > 0) {
+                    if (locale.size() == 0) {
+                        outTable->addDefaultLocalization(name);
+                    }
                     if (translatable == false16) {
                         curIsFormatted = false;
                         // Untranslatable strings must only exist in the default [empty] locale
@@ -1658,6 +1666,9 @@
                     hasErrors = localHasErrors = true;
                 }
                 else if (err == NO_ERROR) {
+                    if (curType == string16 && !curParams.language[0] && !curParams.country[0]) {
+                        outTable->addDefaultLocalization(curName);
+                    }
                     if (curIsPseudolocalizable && localeIsDefined(curParams)
                             && bundle->getPseudolocalize() > 0) {
                         // pseudolocalize here
@@ -2622,8 +2633,11 @@
     return firstError;
 }
 
-status_t ResourceTable::addSymbols(const sp<AaptSymbols>& outSymbols) {
+status_t ResourceTable::addSymbols(const sp<AaptSymbols>& outSymbols,
+        bool skipSymbolsWithoutDefaultLocalization) {
     const size_t N = mOrderedPackages.size();
+    const String8 defaultLocale;
+    const String16 stringType("string");
     size_t pi;
 
     for (pi=0; pi<N; pi++) {
@@ -2664,6 +2678,19 @@
                     return UNKNOWN_ERROR;
                 }
                 if (Res_GETPACKAGE(rid) + 1 == p->getAssignedId()) {
+
+                    if (skipSymbolsWithoutDefaultLocalization &&
+                            t->getName() == stringType) {
+
+                        // Don't generate symbols for strings without a default localization.
+                        if (mHasDefaultLocalization.find(c->getName())
+                                == mHasDefaultLocalization.end()) {
+                            // printf("Skip symbol [%08x] %s\n", rid,
+                            //          String8(c->getName()).string());
+                            continue;
+                        }
+                    }
+
                     typeSymbols->addSymbol(String8(c->getName()), rid, c->getPos());
                     
                     String16 comment(c->getComment());
@@ -2686,6 +2713,12 @@
     mLocalizations[name][locale] = src;
 }
 
+void
+ResourceTable::addDefaultLocalization(const String16& name)
+{
+    mHasDefaultLocalization.insert(name);
+}
+
 
 /*!
  * Flag various sorts of localization problems.  '+' indicates checks already implemented;
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index 9644224..2c1bec1 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -235,8 +235,10 @@
                        const ConfigDescription* config = NULL);
 
     status_t assignResourceIds();
-    status_t addSymbols(const sp<AaptSymbols>& outSymbols = NULL);
+    status_t addSymbols(const sp<AaptSymbols>& outSymbols = NULL,
+                        bool skipSymbolsWithoutDefaultLocalization = false);
     void addLocalization(const String16& name, const String8& locale, const SourcePos& src);
+    void addDefaultLocalization(const String16& name);
     status_t validateLocalizations(void);
 
     status_t flatten(Bundle* bundle, const sp<const ResourceFilter>& filter,
@@ -588,6 +590,8 @@
 
     // key = string resource name, value = set of locales in which that name is defined
     std::map<String16, std::map<String8, SourcePos>> mLocalizations;
+    // set of string resources names that have a default localization
+    std::set<String16> mHasDefaultLocalization;
     std::queue<CompileResourceWorkItem> mWorkQueue;
 };