Merge "a step toward enforcing unique metrics log IDs"
diff --git a/api/current.txt b/api/current.txt
index ed04a6f..b989d34 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -34412,6 +34412,8 @@
 
   public abstract class UtteranceProgressListener {
     ctor public UtteranceProgressListener();
+    method public void onAudioAvailable(java.lang.String, byte[]);
+    method public void onBeginSynthesis(java.lang.String, int, int, int);
     method public abstract void onDone(java.lang.String);
     method public abstract deprecated void onError(java.lang.String);
     method public void onError(java.lang.String, int);
diff --git a/api/system-current.txt b/api/system-current.txt
index 825fe75..68009c6 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -36662,6 +36662,8 @@
 
   public abstract class UtteranceProgressListener {
     ctor public UtteranceProgressListener();
+    method public void onAudioAvailable(java.lang.String, byte[]);
+    method public void onBeginSynthesis(java.lang.String, int, int, int);
     method public abstract void onDone(java.lang.String);
     method public abstract deprecated void onError(java.lang.String);
     method public void onError(java.lang.String, int);
diff --git a/api/test-current.txt b/api/test-current.txt
index f096d56..3460f5a 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -34426,6 +34426,8 @@
 
   public abstract class UtteranceProgressListener {
     ctor public UtteranceProgressListener();
+    method public void onAudioAvailable(java.lang.String, byte[]);
+    method public void onBeginSynthesis(java.lang.String, int, int, int);
     method public abstract void onDone(java.lang.String);
     method public abstract deprecated void onError(java.lang.String);
     method public void onError(java.lang.String, int);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 53f7b29..25c54fa 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -89,22 +89,25 @@
 
     private final Context mContext;
     private final IDevicePolicyManager mService;
-    private boolean mParentInstance;
+    private final boolean mParentInstance;
 
     private static final String REMOTE_EXCEPTION_MESSAGE =
             "Failed to talk with device policy manager service";
 
     private DevicePolicyManager(Context context, boolean parentInstance) {
-        this(context, IDevicePolicyManager.Stub.asInterface(
-                        ServiceManager.getService(Context.DEVICE_POLICY_SERVICE)));
-        mParentInstance = parentInstance;
+        this(context,
+                IDevicePolicyManager.Stub.asInterface(
+                        ServiceManager.getService(Context.DEVICE_POLICY_SERVICE)),
+                parentInstance);
     }
 
     /** @hide */
     @VisibleForTesting
-    protected DevicePolicyManager(Context context, IDevicePolicyManager service) {
+    protected DevicePolicyManager(
+            Context context, IDevicePolicyManager service, boolean parentInstance) {
         mContext = context;
         mService = service;
+        mParentInstance = parentInstance;
     }
 
     /** @hide */
@@ -1146,7 +1149,7 @@
     public void setPasswordMinimumLength(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumLength(admin, length);
+                mService.setPasswordMinimumLength(admin, length, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1167,7 +1170,7 @@
     public int getPasswordMinimumLength(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getPasswordMinimumLength(admin, userHandle);
+                return mService.getPasswordMinimumLength(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1200,7 +1203,7 @@
     public void setPasswordMinimumUpperCase(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumUpperCase(admin, length);
+                mService.setPasswordMinimumUpperCase(admin, length, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1228,7 +1231,7 @@
     public int getPasswordMinimumUpperCase(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getPasswordMinimumUpperCase(admin, userHandle);
+                return mService.getPasswordMinimumUpperCase(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1261,7 +1264,7 @@
     public void setPasswordMinimumLowerCase(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumLowerCase(admin, length);
+                mService.setPasswordMinimumLowerCase(admin, length, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1289,7 +1292,7 @@
     public int getPasswordMinimumLowerCase(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getPasswordMinimumLowerCase(admin, userHandle);
+                return mService.getPasswordMinimumLowerCase(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1321,7 +1324,7 @@
     public void setPasswordMinimumLetters(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumLetters(admin, length);
+                mService.setPasswordMinimumLetters(admin, length, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1347,7 +1350,7 @@
     public int getPasswordMinimumLetters(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getPasswordMinimumLetters(admin, userHandle);
+                return mService.getPasswordMinimumLetters(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1379,7 +1382,7 @@
     public void setPasswordMinimumNumeric(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumNumeric(admin, length);
+                mService.setPasswordMinimumNumeric(admin, length, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1406,7 +1409,7 @@
     public int getPasswordMinimumNumeric(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getPasswordMinimumNumeric(admin, userHandle);
+                return mService.getPasswordMinimumNumeric(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1438,7 +1441,7 @@
     public void setPasswordMinimumSymbols(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumSymbols(admin, length);
+                mService.setPasswordMinimumSymbols(admin, length, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1464,7 +1467,7 @@
     public int getPasswordMinimumSymbols(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getPasswordMinimumSymbols(admin, userHandle);
+                return mService.getPasswordMinimumSymbols(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1496,7 +1499,7 @@
     public void setPasswordMinimumNonLetter(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordMinimumNonLetter(admin, length);
+                mService.setPasswordMinimumNonLetter(admin, length, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1523,7 +1526,7 @@
     public int getPasswordMinimumNonLetter(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getPasswordMinimumNonLetter(admin, userHandle);
+                return mService.getPasswordMinimumNonLetter(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1556,7 +1559,7 @@
     public void setPasswordHistoryLength(@NonNull ComponentName admin, int length) {
         if (mService != null) {
             try {
-                mService.setPasswordHistoryLength(admin, length);
+                mService.setPasswordHistoryLength(admin, length, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1588,7 +1591,7 @@
     public void setPasswordExpirationTimeout(@NonNull ComponentName admin, long timeout) {
         if (mService != null) {
             try {
-                mService.setPasswordExpirationTimeout(admin, timeout);
+                mService.setPasswordExpirationTimeout(admin, timeout, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1607,7 +1610,7 @@
     public long getPasswordExpirationTimeout(@Nullable ComponentName admin) {
         if (mService != null) {
             try {
-                return mService.getPasswordExpirationTimeout(admin, myUserId());
+                return mService.getPasswordExpirationTimeout(admin, myUserId(), mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1628,7 +1631,7 @@
     public long getPasswordExpiration(@Nullable ComponentName admin) {
         if (mService != null) {
             try {
-                return mService.getPasswordExpiration(admin, myUserId());
+                return mService.getPasswordExpiration(admin, myUserId(), mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1651,7 +1654,7 @@
     public int getPasswordHistoryLength(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getPasswordHistoryLength(admin, userHandle);
+                return mService.getPasswordHistoryLength(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1703,7 +1706,7 @@
     public int getCurrentFailedPasswordAttempts() {
         if (mService != null) {
             try {
-                return mService.getCurrentFailedPasswordAttempts(myUserId());
+                return mService.getCurrentFailedPasswordAttempts(myUserId(), mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1750,7 +1753,7 @@
     public void setMaximumFailedPasswordsForWipe(@NonNull ComponentName admin, int num) {
         if (mService != null) {
             try {
-                mService.setMaximumFailedPasswordsForWipe(admin, num);
+                mService.setMaximumFailedPasswordsForWipe(admin, num, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1772,7 +1775,8 @@
     public int getMaximumFailedPasswordsForWipe(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getMaximumFailedPasswordsForWipe(admin, userHandle);
+                return mService.getMaximumFailedPasswordsForWipe(
+                        admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1790,7 +1794,8 @@
     public int getProfileWithMinimumFailedPasswordsForWipe(int userHandle) {
         if (mService != null) {
             try {
-                return mService.getProfileWithMinimumFailedPasswordsForWipe(userHandle);
+                return mService.getProfileWithMinimumFailedPasswordsForWipe(
+                        userHandle, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1882,7 +1887,7 @@
     public void setMaximumTimeToLock(@NonNull ComponentName admin, long timeMs) {
         if (mService != null) {
             try {
-                mService.setMaximumTimeToLock(admin, timeMs);
+                mService.setMaximumTimeToLock(admin, timeMs, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1905,7 +1910,7 @@
     public long getMaximumTimeToLock(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getMaximumTimeToLock(admin, userHandle);
+                return mService.getMaximumTimeToLock(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -1924,7 +1929,7 @@
     public void lockNow() {
         if (mService != null) {
             try {
-                mService.lockNow();
+                mService.lockNow(mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -2721,7 +2726,7 @@
     public void setKeyguardDisabledFeatures(@NonNull ComponentName admin, int which) {
         if (mService != null) {
             try {
-                mService.setKeyguardDisabledFeatures(admin, which);
+                mService.setKeyguardDisabledFeatures(admin, which, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -2731,8 +2736,8 @@
     /**
      * Determine whether or not features have been disabled in keyguard either by the calling
      * admin, if specified, or all admins.
-     * @param admin The name of the admin component to check, or {@code null} to check whether any admins
-     * have disabled features in keyguard.
+     * @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.
      */
@@ -2744,7 +2749,7 @@
     public int getKeyguardDisabledFeatures(@Nullable ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
-                return mService.getKeyguardDisabledFeatures(admin, userHandle);
+                return mService.getKeyguardDisabledFeatures(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
                 Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
             }
@@ -4667,7 +4672,8 @@
      * @see #addCrossProfileWidgetProvider(android.content.ComponentName, String)
      * @see #getCrossProfileWidgetProviders(android.content.ComponentName)
      */
-    public boolean removeCrossProfileWidgetProvider(@NonNull ComponentName admin, String packageName) {
+    public boolean removeCrossProfileWidgetProvider(
+            @NonNull ComponentName admin, String packageName) {
         if (mService != null) {
             try {
                 return mService.removeCrossProfileWidgetProvider(admin, packageName);
@@ -5126,7 +5132,8 @@
     }
 
     /**
-     * Obtains a {@link DevicePolicyManager} whose calls act on the parent profile.
+     * Called by the profile owner of a managed profile to obtain a {@link DevicePolicyManager}
+     * whose calls act on the parent profile.
      *
      * <p> Note only some methods will work on the parent Manager.
      *
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 57865f4..2b378a4 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -38,48 +38,48 @@
     void setPasswordQuality(in ComponentName who, int quality, boolean parent);
     int getPasswordQuality(in ComponentName who, int userHandle, boolean parent);
 
-    void setPasswordMinimumLength(in ComponentName who, int length);
-    int getPasswordMinimumLength(in ComponentName who, int userHandle);
+    void setPasswordMinimumLength(in ComponentName who, int length, boolean parent);
+    int getPasswordMinimumLength(in ComponentName who, int userHandle, boolean parent);
 
-    void setPasswordMinimumUpperCase(in ComponentName who, int length);
-    int getPasswordMinimumUpperCase(in ComponentName who, int userHandle);
+    void setPasswordMinimumUpperCase(in ComponentName who, int length, boolean parent);
+    int getPasswordMinimumUpperCase(in ComponentName who, int userHandle, boolean parent);
 
-    void setPasswordMinimumLowerCase(in ComponentName who, int length);
-    int getPasswordMinimumLowerCase(in ComponentName who, int userHandle);
+    void setPasswordMinimumLowerCase(in ComponentName who, int length, boolean parent);
+    int getPasswordMinimumLowerCase(in ComponentName who, int userHandle, boolean parent);
 
-    void setPasswordMinimumLetters(in ComponentName who, int length);
-    int getPasswordMinimumLetters(in ComponentName who, int userHandle);
+    void setPasswordMinimumLetters(in ComponentName who, int length, boolean parent);
+    int getPasswordMinimumLetters(in ComponentName who, int userHandle, boolean parent);
 
-    void setPasswordMinimumNumeric(in ComponentName who, int length);
-    int getPasswordMinimumNumeric(in ComponentName who, int userHandle);
+    void setPasswordMinimumNumeric(in ComponentName who, int length, boolean parent);
+    int getPasswordMinimumNumeric(in ComponentName who, int userHandle, boolean parent);
 
-    void setPasswordMinimumSymbols(in ComponentName who, int length);
-    int getPasswordMinimumSymbols(in ComponentName who, int userHandle);
+    void setPasswordMinimumSymbols(in ComponentName who, int length, boolean parent);
+    int getPasswordMinimumSymbols(in ComponentName who, int userHandle, boolean parent);
 
-    void setPasswordMinimumNonLetter(in ComponentName who, int length);
-    int getPasswordMinimumNonLetter(in ComponentName who, int userHandle);
+    void setPasswordMinimumNonLetter(in ComponentName who, int length, boolean parent);
+    int getPasswordMinimumNonLetter(in ComponentName who, int userHandle, boolean parent);
 
-    void setPasswordHistoryLength(in ComponentName who, int length);
-    int getPasswordHistoryLength(in ComponentName who, int userHandle);
+    void setPasswordHistoryLength(in ComponentName who, int length, boolean parent);
+    int getPasswordHistoryLength(in ComponentName who, int userHandle, boolean parent);
 
-    void setPasswordExpirationTimeout(in ComponentName who, long expiration);
-    long getPasswordExpirationTimeout(in ComponentName who, int userHandle);
+    void setPasswordExpirationTimeout(in ComponentName who, long expiration, boolean parent);
+    long getPasswordExpirationTimeout(in ComponentName who, int userHandle, boolean parent);
 
-    long getPasswordExpiration(in ComponentName who, int userHandle);
+    long getPasswordExpiration(in ComponentName who, int userHandle, boolean parent);
 
     boolean isActivePasswordSufficient(int userHandle, boolean parent);
-    int getCurrentFailedPasswordAttempts(int userHandle);
-    int getProfileWithMinimumFailedPasswordsForWipe(int userHandle);
+    int getCurrentFailedPasswordAttempts(int userHandle, boolean parent);
+    int getProfileWithMinimumFailedPasswordsForWipe(int userHandle, boolean parent);
 
-    void setMaximumFailedPasswordsForWipe(in ComponentName admin, int num);
-    int getMaximumFailedPasswordsForWipe(in ComponentName admin, int userHandle);
+    void setMaximumFailedPasswordsForWipe(in ComponentName admin, int num, boolean parent);
+    int getMaximumFailedPasswordsForWipe(in ComponentName admin, int userHandle, boolean parent);
 
     boolean resetPassword(String password, int flags);
 
-    void setMaximumTimeToLock(in ComponentName who, long timeMs);
-    long getMaximumTimeToLock(in ComponentName who, int userHandle);
+    void setMaximumTimeToLock(in ComponentName who, long timeMs, boolean parent);
+    long getMaximumTimeToLock(in ComponentName who, int userHandle, boolean parent);
 
-    void lockNow();
+    void lockNow(boolean parent);
 
     void wipeData(int flags);
 
@@ -99,8 +99,8 @@
     void setScreenCaptureDisabled(in ComponentName who, boolean disabled);
     boolean getScreenCaptureDisabled(in ComponentName who, int userHandle);
 
-    void setKeyguardDisabledFeatures(in ComponentName who, int which);
-    int getKeyguardDisabledFeatures(in ComponentName who, int userHandle);
+    void setKeyguardDisabledFeatures(in ComponentName who, int which, boolean parent);
+    int getKeyguardDisabledFeatures(in ComponentName who, int userHandle, boolean parent);
 
     void setActiveAdmin(in ComponentName policyReceiver, boolean refreshing, int userHandle);
     boolean isAdminActive(in ComponentName policyReceiver, int userHandle);
diff --git a/core/java/android/speech/tts/FileSynthesisCallback.java b/core/java/android/speech/tts/FileSynthesisCallback.java
index dea766b..ca9931a 100644
--- a/core/java/android/speech/tts/FileSynthesisCallback.java
+++ b/core/java/android/speech/tts/FileSynthesisCallback.java
@@ -111,6 +111,7 @@
                        "of AudioFormat.ENCODING_PCM_8BIT, AudioFormat.ENCODING_PCM_16BIT or " +
                        "AudioFormat.ENCODING_PCM_FLOAT");
         }
+        mDispatcher.dispatchOnBeginSynthesis(sampleRateInHz, audioFormat, channelCount);
 
         FileChannel fileChannel = null;
         synchronized (mStateLock) {
@@ -176,6 +177,10 @@
             fileChannel = mFileChannel;
         }
 
+        final byte[] bufferCopy = new byte[length];
+        System.arraycopy(buffer, offset, bufferCopy, 0, length);
+        mDispatcher.dispatchOnAudioAvailable(bufferCopy);
+
         try {
             fileChannel.write(ByteBuffer.wrap(buffer,  offset,  length));
             return TextToSpeech.SUCCESS;
diff --git a/core/java/android/speech/tts/ITextToSpeechCallback.aidl b/core/java/android/speech/tts/ITextToSpeechCallback.aidl
index d785c3f..4e3acf6a 100644
--- a/core/java/android/speech/tts/ITextToSpeechCallback.aidl
+++ b/core/java/android/speech/tts/ITextToSpeechCallback.aidl
@@ -22,33 +22,65 @@
  */
 oneway interface ITextToSpeechCallback {
     /**
-     * Tells the client that the synthesis has started.
+     * Tells the client that the synthesis has started playing.
      *
-     * @param utteranceId Unique id identifying synthesis request.
+     * @param utteranceId Unique id identifying the synthesis request.
      */
     void onStart(String utteranceId);
 
     /**
-     * Tells the client that the synthesis has finished.
+     * Tells the client that the synthesis has finished playing.
      *
-     * @param utteranceId Unique id identifying synthesis request.
+     * @param utteranceId Unique id identifying the synthesis request.
      */
     void onSuccess(String utteranceId);
 
     /**
      * Tells the client that the synthesis was stopped.
      *
-     * @param utteranceId Unique id identifying synthesis request.
+     * @param utteranceId Unique id identifying the synthesis request.
      */
     void onStop(String utteranceId, boolean isStarted);
 
     /**
      * Tells the client that the synthesis has failed.
      *
-     * @param utteranceId Unique id identifying synthesis request.
+     * @param utteranceId Unique id identifying the synthesis request.
      * @param errorCode One of the values from
      *        {@link android.speech.tts.v2.TextToSpeech}.
      */
     void onError(String utteranceId, int errorCode);
 
+    /**
+     * Tells the client that the TTS engine has started synthesizing the audio for a request.
+     *
+     * <p>
+     * This doesn't mean the synthesis request has already started playing (for example when there
+     * are synthesis requests ahead of it in the queue), but after receiving this callback you can
+     * expect onAudioAvailable to be called.
+     * </p>
+     *
+     * @param utteranceId Unique id identifying the synthesis request.
+     * @param sampleRateInHz Sample rate in HZ of the generated audio.
+     * @param audioFormat The audio format of the generated audio in the {@link #onAudioAvailable}
+     *        call. Should be one of {@link android.media.AudioFormat.ENCODING_PCM_8BIT},
+     *        {@link android.media.AudioFormat.ENCODING_PCM_16BIT} or
+     *        {@link android.media.AudioFormat.ENCODING_PCM_FLOAT}.
+     * @param channelCount The number of channels.
+     */
+    void onBeginSynthesis(String utteranceId, int sampleRateInHz, int audioFormat, int channelCount);
+
+    /**
+     * Tells the client about a chunk of the synthesized audio.
+     *
+     * <p>
+     * Called when a chunk of the synthesized audio is ready. This may be called more than once for
+     * every synthesis request, thereby streaming the audio to the client.
+     * </p>
+     *
+     * @param utteranceId Unique id identifying the synthesis request.
+     * @param audio The raw audio bytes. Its format is specified by the {@link #onStartAudio}
+     * callback.
+     */
+    void onAudioAvailable(String utteranceId, in byte[] audio);
 }
diff --git a/core/java/android/speech/tts/PlaybackSynthesisCallback.java b/core/java/android/speech/tts/PlaybackSynthesisCallback.java
index dcc0095..778aa86 100644
--- a/core/java/android/speech/tts/PlaybackSynthesisCallback.java
+++ b/core/java/android/speech/tts/PlaybackSynthesisCallback.java
@@ -15,6 +15,7 @@
  */
 package android.speech.tts;
 
+import android.annotation.NonNull;
 import android.media.AudioFormat;
 import android.speech.tts.TextToSpeechService.AudioOutputParams;
 import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
@@ -51,9 +52,10 @@
     private final Object mCallerIdentity;
     private final AbstractEventLogger mLogger;
 
-    PlaybackSynthesisCallback(AudioOutputParams audioParams, AudioPlaybackHandler audioTrackHandler,
-            UtteranceProgressDispatcher dispatcher, Object callerIdentity,
-            AbstractEventLogger logger, boolean clientIsUsingV2) {
+    PlaybackSynthesisCallback(@NonNull AudioOutputParams audioParams,
+            @NonNull AudioPlaybackHandler audioTrackHandler,
+            @NonNull UtteranceProgressDispatcher dispatcher, @NonNull Object callerIdentity,
+            @NonNull AbstractEventLogger logger, boolean clientIsUsingV2) {
         super(clientIsUsingV2);
         mAudioParams = audioParams;
         mAudioTrackHandler = audioTrackHandler;
@@ -130,6 +132,7 @@
                        "of AudioFormat.ENCODING_PCM_8BIT, AudioFormat.ENCODING_PCM_16BIT or " +
                        "AudioFormat.ENCODING_PCM_FLOAT");
         }
+        mDispatcher.dispatchOnBeginSynthesis(sampleRateInHz, audioFormat, channelCount);
 
         int channelConfig = BlockingAudioTrack.getChannelConfig(channelCount);
 
@@ -190,6 +193,7 @@
         // Sigh, another copy.
         final byte[] bufferCopy = new byte[length];
         System.arraycopy(buffer, offset, bufferCopy, 0, length);
+        mDispatcher.dispatchOnAudioAvailable(bufferCopy);
 
         // Might block on mItem.this, if there are too many buffers waiting to
         // be consumed.
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 61c33ff..d55c7bd 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -16,6 +16,7 @@
 package android.speech.tts;
 
 import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.annotation.RawRes;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
@@ -665,7 +666,7 @@
     private OnInitListener mInitListener;
     // Written from an unspecified application thread, read from
     // a binder thread.
-    private volatile UtteranceProgressListener mUtteranceProgressListener;
+    @Nullable private volatile UtteranceProgressListener mUtteranceProgressListener;
     private final Object mStartLock = new Object();
 
     private String mRequestedEngine;
@@ -2133,6 +2134,23 @@
                     listener.onStart(utteranceId);
                 }
             }
+
+            @Override
+            public void onBeginSynthesis(String utteranceId, int sampleRateInHz, int audioFormat,
+                                     int channelCount) {
+                UtteranceProgressListener listener = mUtteranceProgressListener;
+                if (listener != null) {
+                    listener.onBeginSynthesis(utteranceId, sampleRateInHz, audioFormat, channelCount);
+                }
+            }
+
+            @Override
+            public void onAudioAvailable(String utteranceId, byte[] audio) {
+                UtteranceProgressListener listener = mUtteranceProgressListener;
+                if (listener != null) {
+                    listener.onAudioAvailable(utteranceId, audio);
+                }
+            }
         };
 
         private class SetupConnectionAsyncTask extends AsyncTask<Void, Void, Integer> {
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 8c355d8..fc075de 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -15,6 +15,7 @@
  */
 package android.speech.tts;
 
+import android.annotation.NonNull;
 import android.app.Service;
 import android.content.Intent;
 import android.media.AudioAttributes;
@@ -111,7 +112,7 @@
     // A thread and it's associated handler for playing back any audio
     // associated with this TTS engine. Will handle all requests except synthesis
     // to file requests, which occur on the synthesis thread.
-    private AudioPlaybackHandler mAudioPlaybackHandler;
+    @NonNull private AudioPlaybackHandler mAudioPlaybackHandler;
     private TtsEngines mEngineHelper;
 
     private CallbackMap mCallbacks;
@@ -649,6 +650,8 @@
         public void dispatchOnSuccess();
         public void dispatchOnStart();
         public void dispatchOnError(int errorCode);
+        public void dispatchOnBeginSynthesis(int sampleRateInHz, int audioFormat, int channelCount);
+        public void dispatchOnAudioAvailable(byte[] audio);
     }
 
     /** Set of parameters affecting audio output. */
@@ -853,6 +856,22 @@
             }
         }
 
+        @Override
+        public void dispatchOnBeginSynthesis(int sampleRateInHz, int audioFormat, int channelCount) {
+            final String utteranceId = getUtteranceId();
+            if (utteranceId != null) {
+                mCallbacks.dispatchOnBeginSynthesis(getCallerIdentity(), utteranceId, sampleRateInHz, audioFormat, channelCount);
+            }
+        }
+
+        @Override
+        public void dispatchOnAudioAvailable(byte[] audio) {
+            final String utteranceId = getUtteranceId();
+            if (utteranceId != null) {
+                mCallbacks.dispatchOnAudioAvailable(getCallerIdentity(), utteranceId, audio);
+            }
+        }
+
         abstract public String getUtteranceId();
 
         String getStringParam(Bundle params, String key, String defaultValue) {
@@ -1430,7 +1449,6 @@
             } catch (RemoteException e) {
                 Log.e(TAG, "Callback onStart failed: " + e);
             }
-
         }
 
         public void dispatchOnError(Object callerIdentity, String utteranceId,
@@ -1444,6 +1462,26 @@
             }
         }
 
+        public void dispatchOnBeginSynthesis(Object callerIdentity, String utteranceId, int sampleRateInHz, int audioFormat, int channelCount) {
+            ITextToSpeechCallback cb = getCallbackFor(callerIdentity);
+            if (cb == null) return;
+            try {
+                cb.onBeginSynthesis(utteranceId, sampleRateInHz, audioFormat, channelCount);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Callback dispatchOnBeginSynthesis(String, int, int, int) failed: " + e);
+            }
+        }
+
+        public void dispatchOnAudioAvailable(Object callerIdentity, String utteranceId, byte[] buffer) {
+            ITextToSpeechCallback cb = getCallbackFor(callerIdentity);
+            if (cb == null) return;
+            try {
+                cb.onAudioAvailable(utteranceId, buffer);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Callback dispatchOnAudioAvailable(String, byte[]) failed: " + e);
+            }
+        }
+
         @Override
         public void onCallbackDied(ITextToSpeechCallback callback, Object cookie) {
             IBinder caller = (IBinder) cookie;
diff --git a/core/java/android/speech/tts/UtteranceProgressListener.java b/core/java/android/speech/tts/UtteranceProgressListener.java
index 890ea3d..72a5228 100644
--- a/core/java/android/speech/tts/UtteranceProgressListener.java
+++ b/core/java/android/speech/tts/UtteranceProgressListener.java
@@ -2,6 +2,8 @@
 
 package android.speech.tts;
 
+import android.media.AudioFormat;
+
 /**
  * Listener for events relating to the progress of an utterance through
  * the synthesis queue. Each utterance is associated with a call to
@@ -14,10 +16,10 @@
     /**
      * Called when an utterance "starts" as perceived by the caller. This will
      * be soon before audio is played back in the case of a {@link TextToSpeech#speak}
-     * or before the first bytes of a file are written to storage in the case
+     * or before the first bytes of a file are written to the file system in the case
      * of {@link TextToSpeech#synthesizeToFile}.
      *
-     * @param utteranceId the utterance ID of the utterance.
+     * @param utteranceId The utterance ID of the utterance.
      */
     public abstract void onStart(String utteranceId);
 
@@ -28,7 +30,7 @@
      *
      * This request is guaranteed to be called after {@link #onStart(String)}.
      *
-     * @param utteranceId the utterance ID of the utterance.
+     * @param utteranceId The utterance ID of the utterance.
      */
     public abstract void onDone(String utteranceId);
 
@@ -39,7 +41,7 @@
      * be a call to both {@link #onDone(String)} and {@link #onError(String)} for
      * the same utterance.
      *
-     * @param utteranceId the utterance ID of the utterance.
+     * @param utteranceId The utterance ID of the utterance.
      * @deprecated Use {@link #onError(String,int)} instead
      */
     @Deprecated
@@ -52,7 +54,7 @@
      * be a call to both {@link #onDone(String)} and {@link #onError(String,int)} for
      * the same utterance. The default implementation calls {@link #onError(String)}.
      *
-     * @param utteranceId the utterance ID of the utterance.
+     * @param utteranceId The utterance ID of the utterance.
      * @param errorCode one of the ERROR_* codes from {@link TextToSpeech}
      */
     public void onError(String utteranceId, int errorCode) {
@@ -65,7 +67,7 @@
      * or uses {@link TextToSpeech#QUEUE_FLUSH} as an argument with the
      * {@link TextToSpeech#speak} or {@link TextToSpeech#synthesizeToFile} methods.
      *
-     * @param utteranceId the utterance ID of the utterance.
+     * @param utteranceId The utterance ID of the utterance.
      * @param interrupted If true, then the utterance was interrupted while being synthesized
      *        and its output is incomplete. If false, then the utterance was flushed
      *        before the synthesis started.
@@ -74,6 +76,52 @@
     }
 
     /**
+     * Called when the TTS engine begins to synthesize the audio for a request.
+     *
+     * <p>
+     * It provides information about the format of the byte array for subsequent
+     * {@link #onAudioAvailable} calls.
+     * </p>
+     *
+     * <p>
+     * This is called when the TTS engine starts synthesizing audio for the request. If an
+     * application wishes to know when the audio is about to start playing, {#onStart(String)}
+     * should be used instead.
+     * </p>
+     *
+     * @param utteranceId The utterance ID of the utterance.
+     * @param sampleRateInHz Sample rate in hertz of the generated audio.
+     * @param audioFormat Audio format of the generated audio. Should be one of
+     *        {@link AudioFormat#ENCODING_PCM_8BIT}, {@link AudioFormat#ENCODING_PCM_16BIT} or
+     *        {@link AudioFormat#ENCODING_PCM_FLOAT}.
+     * @param channelCount The number of channels.
+     */
+    public void onBeginSynthesis(String utteranceId, int sampleRateInHz, int audioFormat, int channelCount) {
+    }
+
+    /**
+     * This is called when a chunk of audio is ready for consumption.
+     *
+     * <p>
+     * The audio parameter is a copy of what will be synthesized to the speakers (when synthesis was
+     * initiated with a {@link TextToSpeech#speak} call) or written to the file system (for
+     * {@link TextToSpeech#synthesizeToFile}). The audio bytes are delivered in one or more chunks;
+     * if {@link #onDone} or {@link #onError} is called all chunks have been received.
+     * </p>
+     *
+     * <p>
+     * The audio received here may not be played for some time depending on buffer sizes and the
+     * amount of items on the synthesis queue.
+     * </p>
+     *
+     * @param utteranceId The utterance ID of the utterance.
+     * @param audio A chunk of audio; the format can be known by listening to
+     *        {@link #onBeginSynthesis(String, int, int, int)}.
+     */
+    public void onAudioAvailable(String utteranceId, byte[] audio) {
+    }
+
+    /**
      * Wraps an old deprecated OnUtteranceCompletedListener with a shiny new
      * progress listener.
      *
diff --git a/libs/hwui/utils/TestWindowContext.cpp b/libs/hwui/utils/TestWindowContext.cpp
index dcc4946..b0431ce 100644
--- a/libs/hwui/utils/TestWindowContext.cpp
+++ b/libs/hwui/utils/TestWindowContext.cpp
@@ -138,8 +138,8 @@
 
         // Move the pixels into the destination SkBitmap
 
-        SK_ALWAYSBREAK(nativeBuffer.format == android::PIXEL_FORMAT_RGBA_8888 &&
-                       "Native buffer not RGBA!");
+        LOG_ALWAYS_FATAL_IF(nativeBuffer.format != android::PIXEL_FORMAT_RGBA_8888,
+                            "Native buffer not RGBA!");
         SkImageInfo nativeConfig =
             SkImageInfo::Make(nativeBuffer.width, nativeBuffer.height,
                               kRGBA_8888_SkColorType, kPremul_SkAlphaType);
@@ -153,8 +153,8 @@
             return false;
         }
 
-        SK_ALWAYSBREAK(bmp->colorType() == kRGBA_8888_SkColorType &&
-                       "Destination buffer not RGBA!");
+        LOG_ALWAYS_FATAL_IF(bmp->colorType() != kRGBA_8888_SkColorType,
+                            "Destination buffer not RGBA!");
         success =
             nativeWrapper.readPixels(destinationConfig, bmp->getPixels(), bmp->rowBytes(), 0, 0);
         if (!success) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9c24271..1434e5e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -536,6 +536,7 @@
     // default actuion automatically.  Important for devices without direct input
     // devices.
     private boolean mShowDialogs = true;
+    private boolean mInVrMode = false;
 
     BroadcastQueue mFgBroadcastQueue;
     BroadcastQueue mBgBroadcastQueue;
@@ -2204,7 +2205,15 @@
             } break;
             case VR_MODE_CHANGE_MSG: {
                 VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
-                vrService.setVrMode(msg.arg1 != 0);
+                final boolean vrMode = msg.arg1 != 0;
+                vrService.setVrMode(vrMode);
+
+                if (mInVrMode != vrMode) {
+                    synchronized (ActivityManagerService.this) {
+                        mInVrMode = vrMode;
+                        mShowDialogs = shouldShowDialogs(mConfiguration, mInVrMode);
+                    }
+                }
             } break;
             }
         }
@@ -18439,7 +18448,7 @@
 
                 // TODO: If our config changes, should we auto dismiss any currently
                 // showing dialogs?
-                mShowDialogs = shouldShowDialogs(newConfig);
+                mShowDialogs = shouldShowDialogs(newConfig, mInVrMode);
 
                 AttributeCache ac = AttributeCache.instance();
                 if (ac != null) {
@@ -18528,13 +18537,13 @@
      * A thought: SystemUI might also want to get told about this, the Power
      * dialog / global actions also might want different behaviors.
      */
-    private static final boolean shouldShowDialogs(Configuration config) {
+    private static final boolean shouldShowDialogs(Configuration config, boolean inVrMode) {
         final boolean inputMethodExists = !(config.keyboard == Configuration.KEYBOARD_NOKEYS
                                    && config.touchscreen == Configuration.TOUCHSCREEN_NOTOUCH
                                    && config.navigation == Configuration.NAVIGATION_NONAV);
         final boolean uiIsNotCarType = !((config.uiMode & Configuration.UI_MODE_TYPE_MASK)
                                     == Configuration.UI_MODE_TYPE_CAR);
-        return inputMethodExists && uiIsNotCarType;
+        return inputMethodExists && uiIsNotCarType && !inVrMode;
     }
 
     @Override
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 7232562..74d4659 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -132,7 +132,6 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.devicepolicy.DevicePolicyManagerService.ActiveAdmin.TrustAgentInfo;
-import com.android.server.pm.UserManagerService;
 import com.android.server.pm.UserRestrictionsUtils;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -244,16 +243,20 @@
         GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.WIFI_ON);
     }
 
-    // Keyguard features that when set of a profile will affect the profiles
-    // parent user.
+    /** Keyguard features that when set on a profile will affect the profiles parent user. */
     private static final int PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER =
+            // STOPSHIP If the work challenge supports fingerprint, move DISABLE_FINGERPRINT
+            // to PROFILE_KEYGUARD_FEATURES_AFFECT_PROFILE?
             DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS
             | DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
 
-    // Keyguard features that are allowed to be set on a managed profile
+    /** Keyguard features that when set on a profile affect the profile content or challenge only */
+    private static final int PROFILE_KEYGUARD_FEATURES_AFFECT_PROFILE =
+            DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS;
+
+    /** Keyguard features that are allowed to be set on a managed profile */
     private static final int PROFILE_KEYGUARD_FEATURES =
-            PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER
-            | DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS;
+            PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER | PROFILE_KEYGUARD_FEATURES_AFFECT_PROFILE;
 
     final Context mContext;
     final Injector mInjector;
@@ -596,12 +599,18 @@
         }
 
         ActiveAdmin getParentActiveAdmin() {
-            if (parentAdmin == null && !isParent) {
+            Preconditions.checkState(!isParent);
+
+            if (parentAdmin == null) {
                 parentAdmin = new ActiveAdmin(info, /* parent */ true);
             }
             return parentAdmin;
         }
 
+        boolean hasParentActiveAdmin() {
+            return parentAdmin != null;
+        }
+
         int getUid() { return info.getActivityInfo().applicationInfo.uid; }
 
         public UserHandle getUserHandle() {
@@ -933,6 +942,8 @@
                         Log.w(LOG_TAG, "Missing text when loading long support message");
                     }
                 } else if (TAG_PARENT_ADMIN.equals(tag)) {
+                    Preconditions.checkState(!isParent);
+
                     parentAdmin = new ActiveAdmin(info, /* parent */ true);
                     parentAdmin.readFromXml(parser);
                 } else if (TAG_ORGANIZATION_COLOR.equals(tag)) {
@@ -1146,6 +1157,12 @@
             }
             pw.print(prefix); pw.println("userRestrictions:");
             UserRestrictionsUtils.dumpRestrictions(pw, prefix + "  ", userRestrictions);
+            pw.print(prefix); pw.print("isParent=");
+                    pw.println(isParent);
+            if (parentAdmin != null) {
+                pw.print(prefix);  pw.println("parentAdmin:");
+                parentAdmin.dump(prefix + "  ", pw);
+            }
         }
     }
 
@@ -1405,7 +1422,7 @@
         mIPackageManager = Preconditions.checkNotNull(injector.getIPackageManager());
 
         mLocalService = new LocalService();
-        mLockPatternUtils = new LockPatternUtils(mContext);
+        mLockPatternUtils = injector.newLockPatternUtils();
 
         mHasFeature = mContext.getPackageManager()
                 .hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN);
@@ -1662,8 +1679,8 @@
      * Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration
      * reminders.  Clears alarm if no expirations are configured.
      */
-    protected void setExpirationAlarmCheckLocked(Context context, DevicePolicyData policy) {
-        final long expiration = getPasswordExpirationLocked(null, policy.mUserHandle);
+    private void setExpirationAlarmCheckLocked(Context context, int userHandle) {
+        final long expiration = getPasswordExpirationLocked(null, userHandle, /* parent */ false);
         final long now = System.currentTimeMillis();
         final long timeToExpire = expiration - now;
         final long alarmTime;
@@ -1689,7 +1706,7 @@
             PendingIntent pi = PendingIntent.getBroadcastAsUser(context, REQUEST_EXPIRE_PASSWORD,
                     new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
                     PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT,
-                    new UserHandle(policy.mUserHandle));
+                    UserHandle.of(userHandle));
             am.cancel(pi);
             if (alarmTime != 0) {
                 am.set(AlarmManager.RTC, alarmTime, pi);
@@ -1709,6 +1726,17 @@
         return null;
     }
 
+    ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who, int userHandle, boolean parent) {
+        if (parent) {
+            enforceManagedProfile(userHandle, "call APIs on the parent profile");
+        }
+        ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+        if (admin != null && parent) {
+            admin = admin.getParentActiveAdmin();
+        }
+        return admin;
+    }
+
     ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
             throws SecurityException {
         final int callingUid = mInjector.binderGetCallingUid();
@@ -1739,6 +1767,15 @@
         }
     }
 
+    ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy, boolean parent)
+            throws SecurityException {
+        if (parent) {
+            enforceManagedProfile(mInjector.userHandleGetCallingUserId(),
+                    "call APIs on the parent profile");
+        }
+        ActiveAdmin admin = getActiveAdminForCallerLocked(who, reqPolicy);
+        return parent ? admin.getParentActiveAdmin() : admin;
+    }
     /**
      * Find the admin for the component and userId bit of the uid, then check
      * the admin's uid matches the uid.
@@ -1858,6 +1895,18 @@
         }
     }
 
+    /**
+     * Sends a broadcast to each profile that share the password unlock with the given user id.
+     */
+    private void sendAdminCommandForLockscreenPoliciesLocked(
+            String action, int reqPolicy, int userHandle) {
+        if (isSeparateProfileChallengeEnabled(userHandle)) {
+            sendAdminCommandLocked(action, reqPolicy, userHandle);
+        } else {
+            sendAdminCommandToSelfAndProfilesLocked(action, reqPolicy, userHandle);
+        }
+    }
+
     void removeActiveAdminLocked(final ComponentName adminReceiver, final int userHandle) {
         final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
         if (admin != null) {
@@ -1881,7 +1930,7 @@
                                     resetGlobalProxyLocked(getUserData(userHandle));
                                 }
                                 saveSettingsLocked(userHandle);
-                                updateMaximumTimeToLockLocked(policy);
+                                updateMaximumTimeToLockLocked(userHandle);
                                 policy.mRemovingAdmins.remove(adminReceiver);
                             }
                             // The removed admin might have disabled camera, so update user
@@ -2198,12 +2247,12 @@
         // never normally happen.
         final long identity = mInjector.binderClearCallingIdentity();
         try {
-            LockPatternUtils utils = mInjector.newLockPatternUtils();
-            if (utils.getActivePasswordQuality(userHandle) < policy.mActivePasswordQuality) {
+            int actualPasswordQuality = mLockPatternUtils.getActivePasswordQuality(userHandle);
+            if (actualPasswordQuality < policy.mActivePasswordQuality) {
                 Slog.w(LOG_TAG, "Active password quality 0x"
                         + Integer.toHexString(policy.mActivePasswordQuality)
                         + " does not match actual quality 0x"
-                        + Integer.toHexString(utils.getActivePasswordQuality(userHandle)));
+                        + Integer.toHexString(actualPasswordQuality));
                 policy.mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
                 policy.mActivePasswordLength = 0;
                 policy.mActivePasswordUpperCase = 0;
@@ -2218,7 +2267,7 @@
         }
 
         validatePasswordOwnerLocked(policy);
-        updateMaximumTimeToLockLocked(policy);
+        updateMaximumTimeToLockLocked(userHandle);
         updateLockTaskPackagesLocked(policy.mLockTaskPackages, userHandle);
         if (policy.mStatusBarDisabled) {
             setStatusBarDisabledInternal(policy.mStatusBarDisabled, userHandle);
@@ -2382,25 +2431,21 @@
         synchronized (this) {
             final long now = System.currentTimeMillis();
 
-            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
-            for (UserInfo ui : profiles) {
-                int profileUserHandle = ui.id;
-                final DevicePolicyData policy = getUserData(profileUserHandle);
-                final int count = policy.mAdminList.size();
-                if (count > 0) {
-                    for (int i = 0; i < count; i++) {
-                        final ActiveAdmin admin = policy.mAdminList.get(i);
-                        if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
-                                && admin.passwordExpirationTimeout > 0L
-                                && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS
-                                && admin.passwordExpirationDate > 0L) {
-                            sendAdminCommandLocked(admin,
-                                    DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
-                        }
-                    }
+            // Return the strictest policy across all participating admins.
+            List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(
+                    userHandle, /* parent */ false);
+            final int N = admins.size();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = admins.get(i);
+                if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
+                        && admin.passwordExpirationTimeout > 0L
+                        && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS
+                        && admin.passwordExpirationDate > 0L) {
+                    sendAdminCommandLocked(admin,
+                            DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
                 }
             }
-            setExpirationAlarmCheckLocked(mContext, getUserData(userHandle));
+            setExpirationAlarmCheckLocked(mContext, userHandle);
         }
     }
 
@@ -2669,7 +2714,7 @@
     @Override
     public boolean isSeparateProfileChallengeAllowed(int userHandle) {
         ComponentName profileOwner = getProfileOwner(userHandle);
-        return !isAdminApiLevelMOrBelow(profileOwner, userHandle);
+        return profileOwner != null && !isAdminApiLevelMOrBelow(profileOwner, userHandle);
     }
 
     @Override
@@ -2678,18 +2723,14 @@
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
-        final int userHandle = UserHandle.getCallingUserId();
         validateQualityConstant(quality);
 
         synchronized (this) {
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
-            if (parent) {
-                ap = ap.getParentActiveAdmin();
-            }
+            ActiveAdmin ap = getActiveAdminForCallerLocked(
+                    who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
             if (ap.passwordQuality != quality) {
                 ap.passwordQuality = quality;
-                saveSettingsLocked(userHandle);
+                saveSettingsLocked(mInjector.userHandleGetCallingUserId());
             }
         }
     }
@@ -2704,46 +2745,55 @@
             int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
-                if (parent && admin != null) {
-                    admin = admin.getParentActiveAdmin();
-                }
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
                 return admin != null ? admin.passwordQuality : mode;
             }
 
-            if (isSeparateProfileChallengeEnabled(userHandle) && !parent) {
-                // If a Work Challenge is in use, only return its restrictions.
-                DevicePolicyData policy = getUserDataUnchecked(userHandle);
-                final int N = policy.mAdminList.size();
-                for (int i = 0; i < N; i++) {
-                    ActiveAdmin admin = policy.mAdminList.get(i);
-                    if (mode < admin.passwordQuality) {
-                        mode = admin.passwordQuality;
-                    }
+            // Return the strictest policy across all participating admins.
+            List<ActiveAdmin> admins =
+                    getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+            final int N = admins.size();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = admins.get(i);
+                if (mode < admin.passwordQuality) {
+                    mode = admin.passwordQuality;
                 }
-            } else {
-                // Return strictest policy for this user and profiles that are visible from this
-                // user that do not use a separate work challenge.
-                // TODO: When there are separate parent restrictions the profile should just
-                // obey its own.
-                List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
-                for (UserInfo userInfo : profiles) {
-                    // Only aggregate data for the parent profile plus the non-work challenge
-                    // enabled profiles.
-                    if (!(userInfo.isManagedProfile()
-                            && isSeparateProfileChallengeEnabled(userInfo.id))) {
-                        DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
-                        final int N = policy.mAdminList.size();
-                        for (int i = 0; i < N; i++) {
-                            ActiveAdmin admin = policy.mAdminList.get(i);
-                            if (mode < admin.passwordQuality) {
-                                mode = admin.passwordQuality;
-                            }
+            }
+            return mode;
+        }
+    }
+
+    private List<ActiveAdmin> getActiveAdminsForLockscreenPoliciesLocked(
+            int userHandle, boolean parent) {
+        if (!parent && isSeparateProfileChallengeEnabled(userHandle)) {
+            // If this user has a separate challenge, only return its restrictions.
+            return getUserDataUnchecked(userHandle).mAdminList;
+        } else {
+            // Return all admins for this user and the profiles that are visible from this
+            // user that do not use a separate work challenge.
+            ArrayList<ActiveAdmin> admins = new ArrayList<ActiveAdmin>();
+            for (UserInfo userInfo : mUserManager.getProfiles(userHandle)) {
+                DevicePolicyData policy = getUserData(userInfo.id);
+                if (!isManagedProfile(userInfo.id)) {
+                    admins.addAll(policy.mAdminList);
+                } else {
+                    // For managed profiles, we always include the policies set on the parent
+                    // profile. Additionally, we include the ones set on the managed profile
+                    // if no separate challenge is in place.
+                    boolean hasSeparateChallenge = isSeparateProfileChallengeEnabled(userInfo.id);
+                    final int N = policy.mAdminList.size();
+                    for (int i = 0; i < N; i++) {
+                        ActiveAdmin admin = policy.mAdminList.get(i);
+                        if (admin.hasParentActiveAdmin()) {
+                            admins.add(admin.getParentActiveAdmin());
+                        }
+                        if (!hasSeparateChallenge) {
+                            admins.add(admin);
                         }
                     }
                 }
             }
-            return mode;
+            return admins;
         }
     }
 
@@ -2757,24 +2807,23 @@
     }
 
     @Override
-    public void setPasswordMinimumLength(ComponentName who, int length) {
+    public void setPasswordMinimumLength(ComponentName who, int length, boolean parent) {
         if (!mHasFeature) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
-        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+            ActiveAdmin ap = getActiveAdminForCallerLocked(
+                    who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
             if (ap.minimumPasswordLength != length) {
                 ap.minimumPasswordLength = length;
-                saveSettingsLocked(userHandle);
+                saveSettingsLocked(mInjector.userHandleGetCallingUserId());
             }
         }
     }
 
     @Override
-    public int getPasswordMinimumLength(ComponentName who, int userHandle) {
+    public int getPasswordMinimumLength(ComponentName who, int userHandle, boolean parent) {
         if (!mHasFeature) {
             return 0;
         }
@@ -2783,20 +2832,18 @@
             int length = 0;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
                 return admin != null ? admin.minimumPasswordLength : length;
             }
 
-            // Return strictest policy for this user and profiles that are visible from this user.
-            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
-            for (UserInfo userInfo : profiles) {
-                DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
-                final int N = policy.mAdminList.size();
-                for (int i=0; i<N; i++) {
-                    ActiveAdmin admin = policy.mAdminList.get(i);
-                    if (length < admin.minimumPasswordLength) {
-                        length = admin.minimumPasswordLength;
-                    }
+            // Return the strictest policy across all participating admins.
+            List<ActiveAdmin> admins =
+                    getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+            final int N = admins.size();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = admins.get(i);
+                if (length < admin.minimumPasswordLength) {
+                    length = admin.minimumPasswordLength;
                 }
             }
             return length;
@@ -2804,24 +2851,23 @@
     }
 
     @Override
-    public void setPasswordHistoryLength(ComponentName who, int length) {
+    public void setPasswordHistoryLength(ComponentName who, int length, boolean parent) {
         if (!mHasFeature) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
-        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+            ActiveAdmin ap = getActiveAdminForCallerLocked(
+                    who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
             if (ap.passwordHistoryLength != length) {
                 ap.passwordHistoryLength = length;
-                saveSettingsLocked(userHandle);
+                saveSettingsLocked(mInjector.userHandleGetCallingUserId());
             }
         }
     }
 
     @Override
-    public int getPasswordHistoryLength(ComponentName who, int userHandle) {
+    public int getPasswordHistoryLength(ComponentName who, int userHandle, boolean parent) {
         if (!mHasFeature) {
             return 0;
         }
@@ -2830,37 +2876,36 @@
             int length = 0;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
                 return admin != null ? admin.passwordHistoryLength : length;
             }
 
-            // Return strictest policy for this user and profiles that are visible from this user.
-            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
-            for (UserInfo userInfo : profiles) {
-                DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
-                final int N = policy.mAdminList.size();
-                for (int i = 0; i < N; i++) {
-                    ActiveAdmin admin = policy.mAdminList.get(i);
-                    if (length < admin.passwordHistoryLength) {
-                        length = admin.passwordHistoryLength;
-                    }
+            // Return the strictest policy across all participating admins.
+            List<ActiveAdmin> admins =
+                    getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+            final int N = admins.size();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = admins.get(i);
+                if (length < admin.passwordHistoryLength) {
+                    length = admin.passwordHistoryLength;
                 }
             }
+
             return length;
         }
     }
 
     @Override
-    public void setPasswordExpirationTimeout(ComponentName who, long timeout) {
+    public void setPasswordExpirationTimeout(ComponentName who, long timeout, boolean parent) {
         if (!mHasFeature) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
         Preconditions.checkArgumentNonnegative(timeout, "Timeout must be >= 0 ms");
-        final int userHandle = UserHandle.getCallingUserId();
+        final int userHandle = mInjector.userHandleGetCallingUserId();
         synchronized (this) {
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD);
+            ActiveAdmin ap = getActiveAdminForCallerLocked(
+                    who, DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD, parent);
             // Calling this API automatically bumps the expiration date
             final long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
             ap.passwordExpirationDate = expiration;
@@ -2871,8 +2916,10 @@
                         .format(new Date(expiration)));
             }
             saveSettingsLocked(userHandle);
-            // in case this is the first one
-            setExpirationAlarmCheckLocked(mContext, getUserData(userHandle));
+
+            // in case this is the first one, set the alarm on the appropriate user.
+            int affectedUserHandle = parent ? getProfileParentId(userHandle) : userHandle;
+            setExpirationAlarmCheckLocked(mContext, affectedUserHandle);
         }
     }
 
@@ -2881,7 +2928,7 @@
      * Returns 0 if not configured.
      */
     @Override
-    public long getPasswordExpirationTimeout(ComponentName who, int userHandle) {
+    public long getPasswordExpirationTimeout(ComponentName who, int userHandle, boolean parent) {
         if (!mHasFeature) {
             return 0L;
         }
@@ -2890,20 +2937,19 @@
             long timeout = 0L;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
                 return admin != null ? admin.passwordExpirationTimeout : timeout;
             }
 
-            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
-            for (UserInfo userInfo : profiles) {
-                DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
-                final int N = policy.mAdminList.size();
-                for (int i = 0; i < N; i++) {
-                    ActiveAdmin admin = policy.mAdminList.get(i);
-                    if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
-                            && timeout > admin.passwordExpirationTimeout)) {
-                        timeout = admin.passwordExpirationTimeout;
-                    }
+            // Return the strictest policy across all participating admins.
+            List<ActiveAdmin> admins =
+                    getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+            final int N = admins.size();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = admins.get(i);
+                if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
+                        && timeout > admin.passwordExpirationTimeout)) {
+                    timeout = admin.passwordExpirationTimeout;
                 }
             }
             return timeout;
@@ -2984,59 +3030,56 @@
      * Return a single admin's expiration date/time, or the min (soonest) for all admins.
      * Returns 0 if not configured.
      */
-    private long getPasswordExpirationLocked(ComponentName who, int userHandle) {
+    private long getPasswordExpirationLocked(ComponentName who, int userHandle, boolean parent) {
         long timeout = 0L;
 
         if (who != null) {
-            ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+            ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
             return admin != null ? admin.passwordExpirationDate : timeout;
         }
 
-        List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
-        for (UserInfo userInfo : profiles) {
-            DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
-            final int N = policy.mAdminList.size();
-            for (int i = 0; i < N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (timeout == 0L || (admin.passwordExpirationDate != 0
-                        && timeout > admin.passwordExpirationDate)) {
-                    timeout = admin.passwordExpirationDate;
-                }
+        // Return the strictest policy across all participating admins.
+        List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+        final int N = admins.size();
+        for (int i = 0; i < N; i++) {
+            ActiveAdmin admin = admins.get(i);
+            if (timeout == 0L || (admin.passwordExpirationDate != 0
+                    && timeout > admin.passwordExpirationDate)) {
+                timeout = admin.passwordExpirationDate;
             }
         }
         return timeout;
     }
 
     @Override
-    public long getPasswordExpiration(ComponentName who, int userHandle) {
+    public long getPasswordExpiration(ComponentName who, int userHandle, boolean parent) {
         if (!mHasFeature) {
             return 0L;
         }
         enforceFullCrossUsersPermission(userHandle);
         synchronized (this) {
-            return getPasswordExpirationLocked(who, userHandle);
+            return getPasswordExpirationLocked(who, userHandle, parent);
         }
     }
 
     @Override
-    public void setPasswordMinimumUpperCase(ComponentName who, int length) {
+    public void setPasswordMinimumUpperCase(ComponentName who, int length, boolean parent) {
         if (!mHasFeature) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
-        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+            ActiveAdmin ap = getActiveAdminForCallerLocked(
+                    who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
             if (ap.minimumPasswordUpperCase != length) {
                 ap.minimumPasswordUpperCase = length;
-                saveSettingsLocked(userHandle);
+                saveSettingsLocked(mInjector.userHandleGetCallingUserId());
             }
         }
     }
 
     @Override
-    public int getPasswordMinimumUpperCase(ComponentName who, int userHandle) {
+    public int getPasswordMinimumUpperCase(ComponentName who, int userHandle, boolean parent) {
         if (!mHasFeature) {
             return 0;
         }
@@ -3045,20 +3088,18 @@
             int length = 0;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
                 return admin != null ? admin.minimumPasswordUpperCase : length;
             }
 
-            // Return strictest policy for this user and profiles that are visible from this user.
-            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
-            for (UserInfo userInfo : profiles) {
-                DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
-                final int N = policy.mAdminList.size();
-                for (int i=0; i<N; i++) {
-                    ActiveAdmin admin = policy.mAdminList.get(i);
-                    if (length < admin.minimumPasswordUpperCase) {
-                        length = admin.minimumPasswordUpperCase;
-                    }
+            // Return the strictest policy across all participating admins.
+            List<ActiveAdmin> admins =
+                    getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+            final int N = admins.size();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = admins.get(i);
+                if (length < admin.minimumPasswordUpperCase) {
+                    length = admin.minimumPasswordUpperCase;
                 }
             }
             return length;
@@ -3066,21 +3107,20 @@
     }
 
     @Override
-    public void setPasswordMinimumLowerCase(ComponentName who, int length) {
+    public void setPasswordMinimumLowerCase(ComponentName who, int length, boolean parent) {
         Preconditions.checkNotNull(who, "ComponentName is null");
-        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+            ActiveAdmin ap = getActiveAdminForCallerLocked(
+                    who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
             if (ap.minimumPasswordLowerCase != length) {
                 ap.minimumPasswordLowerCase = length;
-                saveSettingsLocked(userHandle);
+                saveSettingsLocked(mInjector.userHandleGetCallingUserId());
             }
         }
     }
 
     @Override
-    public int getPasswordMinimumLowerCase(ComponentName who, int userHandle) {
+    public int getPasswordMinimumLowerCase(ComponentName who, int userHandle, boolean parent) {
         if (!mHasFeature) {
             return 0;
         }
@@ -3089,20 +3129,18 @@
             int length = 0;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
                 return admin != null ? admin.minimumPasswordLowerCase : length;
             }
 
-            // Return strictest policy for this user and profiles that are visible from this user.
-            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
-            for (UserInfo userInfo : profiles) {
-                DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
-                final int N = policy.mAdminList.size();
-                for (int i=0; i<N; i++) {
-                    ActiveAdmin admin = policy.mAdminList.get(i);
-                    if (length < admin.minimumPasswordLowerCase) {
-                        length = admin.minimumPasswordLowerCase;
-                    }
+            // Return the strictest policy across all participating admins.
+            List<ActiveAdmin> admins =
+                    getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+            final int N = admins.size();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = admins.get(i);
+                if (length < admin.minimumPasswordLowerCase) {
+                    length = admin.minimumPasswordLowerCase;
                 }
             }
             return length;
@@ -3110,24 +3148,23 @@
     }
 
     @Override
-    public void setPasswordMinimumLetters(ComponentName who, int length) {
+    public void setPasswordMinimumLetters(ComponentName who, int length, boolean parent) {
         if (!mHasFeature) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
-        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+            ActiveAdmin ap = getActiveAdminForCallerLocked(
+                    who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
             if (ap.minimumPasswordLetters != length) {
                 ap.minimumPasswordLetters = length;
-                saveSettingsLocked(userHandle);
+                saveSettingsLocked(mInjector.userHandleGetCallingUserId());
             }
         }
     }
 
     @Override
-    public int getPasswordMinimumLetters(ComponentName who, int userHandle) {
+    public int getPasswordMinimumLetters(ComponentName who, int userHandle, boolean parent) {
         if (!mHasFeature) {
             return 0;
         }
@@ -3136,23 +3173,21 @@
             int length = 0;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
                 return admin != null ? admin.minimumPasswordLetters : length;
             }
 
-            // Return strictest policy for this user and profiles that are visible from this user.
-            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
-            for (UserInfo userInfo : profiles) {
-                DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
-                final int N = policy.mAdminList.size();
-                for (int i=0; i<N; i++) {
-                    ActiveAdmin admin = policy.mAdminList.get(i);
-                    if (!isLimitPasswordAllowed(admin, PASSWORD_QUALITY_COMPLEX)) {
-                        continue;
-                    }
-                    if (length < admin.minimumPasswordLetters) {
-                        length = admin.minimumPasswordLetters;
-                    }
+            // Return the strictest policy across all participating admins.
+            List<ActiveAdmin> admins =
+                    getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+            final int N = admins.size();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = admins.get(i);
+                if (!isLimitPasswordAllowed(admin, PASSWORD_QUALITY_COMPLEX)) {
+                    continue;
+                }
+                if (length < admin.minimumPasswordLetters) {
+                    length = admin.minimumPasswordLetters;
                 }
             }
             return length;
@@ -3160,24 +3195,23 @@
     }
 
     @Override
-    public void setPasswordMinimumNumeric(ComponentName who, int length) {
+    public void setPasswordMinimumNumeric(ComponentName who, int length, boolean parent) {
         if (!mHasFeature) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
-        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+            ActiveAdmin ap = getActiveAdminForCallerLocked(
+                    who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
             if (ap.minimumPasswordNumeric != length) {
                 ap.minimumPasswordNumeric = length;
-                saveSettingsLocked(userHandle);
+                saveSettingsLocked(mInjector.userHandleGetCallingUserId());
             }
         }
     }
 
     @Override
-    public int getPasswordMinimumNumeric(ComponentName who, int userHandle) {
+    public int getPasswordMinimumNumeric(ComponentName who, int userHandle, boolean parent) {
         if (!mHasFeature) {
             return 0;
         }
@@ -3186,23 +3220,21 @@
             int length = 0;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
                 return admin != null ? admin.minimumPasswordNumeric : length;
             }
 
-            // Return strictest policy for this user and profiles that are visible from this user.
-            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
-            for (UserInfo userInfo : profiles) {
-                DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
-                final int N = policy.mAdminList.size();
-                for (int i = 0; i < N; i++) {
-                    ActiveAdmin admin = policy.mAdminList.get(i);
-                    if (!isLimitPasswordAllowed(admin, PASSWORD_QUALITY_COMPLEX)) {
-                        continue;
-                    }
-                    if (length < admin.minimumPasswordNumeric) {
-                        length = admin.minimumPasswordNumeric;
-                    }
+            // Return the strictest policy across all participating admins.
+            List<ActiveAdmin> admins =
+                    getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+            final int N = admins.size();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = admins.get(i);
+                if (!isLimitPasswordAllowed(admin, PASSWORD_QUALITY_COMPLEX)) {
+                    continue;
+                }
+                if (length < admin.minimumPasswordNumeric) {
+                    length = admin.minimumPasswordNumeric;
                 }
             }
             return length;
@@ -3210,24 +3242,23 @@
     }
 
     @Override
-    public void setPasswordMinimumSymbols(ComponentName who, int length) {
+    public void setPasswordMinimumSymbols(ComponentName who, int length, boolean parent) {
         if (!mHasFeature) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
-        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+            ActiveAdmin ap = getActiveAdminForCallerLocked(
+                    who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
             if (ap.minimumPasswordSymbols != length) {
                 ap.minimumPasswordSymbols = length;
-                saveSettingsLocked(userHandle);
+                saveSettingsLocked(mInjector.userHandleGetCallingUserId());
             }
         }
     }
 
     @Override
-    public int getPasswordMinimumSymbols(ComponentName who, int userHandle) {
+    public int getPasswordMinimumSymbols(ComponentName who, int userHandle, boolean parent) {
         if (!mHasFeature) {
             return 0;
         }
@@ -3236,23 +3267,21 @@
             int length = 0;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
                 return admin != null ? admin.minimumPasswordSymbols : length;
             }
 
-            // Return strictest policy for this user and profiles that are visible from this user.
-            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
-            for (UserInfo userInfo : profiles) {
-                DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
-                final int N = policy.mAdminList.size();
-                for (int i=0; i<N; i++) {
-                    ActiveAdmin admin = policy.mAdminList.get(i);
-                    if (!isLimitPasswordAllowed(admin, PASSWORD_QUALITY_COMPLEX)) {
-                        continue;
-                    }
-                    if (length < admin.minimumPasswordSymbols) {
-                        length = admin.minimumPasswordSymbols;
-                    }
+            // Return the strictest policy across all participating admins.
+            List<ActiveAdmin> admins =
+                    getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+            final int N = admins.size();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = admins.get(i);
+                if (!isLimitPasswordAllowed(admin, PASSWORD_QUALITY_COMPLEX)) {
+                    continue;
+                }
+                if (length < admin.minimumPasswordSymbols) {
+                    length = admin.minimumPasswordSymbols;
                 }
             }
             return length;
@@ -3260,24 +3289,23 @@
     }
 
     @Override
-    public void setPasswordMinimumNonLetter(ComponentName who, int length) {
+    public void setPasswordMinimumNonLetter(ComponentName who, int length, boolean parent) {
         if (!mHasFeature) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
-        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+            ActiveAdmin ap = getActiveAdminForCallerLocked(
+                    who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
             if (ap.minimumPasswordNonLetter != length) {
                 ap.minimumPasswordNonLetter = length;
-                saveSettingsLocked(userHandle);
+                saveSettingsLocked(mInjector.userHandleGetCallingUserId());
             }
         }
     }
 
     @Override
-    public int getPasswordMinimumNonLetter(ComponentName who, int userHandle) {
+    public int getPasswordMinimumNonLetter(ComponentName who, int userHandle, boolean parent) {
         if (!mHasFeature) {
             return 0;
         }
@@ -3286,23 +3314,21 @@
             int length = 0;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
                 return admin != null ? admin.minimumPasswordNonLetter : length;
             }
 
-            // Return strictest policy for this user and profiles that are visible from this user.
-            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
-            for (UserInfo userInfo : profiles) {
-                DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
-                final int N = policy.mAdminList.size();
-                for (int i=0; i<N; i++) {
-                    ActiveAdmin admin = policy.mAdminList.get(i);
-                    if (!isLimitPasswordAllowed(admin, PASSWORD_QUALITY_COMPLEX)) {
-                        continue;
-                    }
-                    if (length < admin.minimumPasswordNonLetter) {
-                        length = admin.minimumPasswordNonLetter;
-                    }
+            // Return the strictest policy across all participating admins.
+            List<ActiveAdmin> admins =
+                    getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+            final int N = admins.size();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = admins.get(i);
+                if (!isLimitPasswordAllowed(admin, PASSWORD_QUALITY_COMPLEX)) {
+                    continue;
+                }
+                if (length < admin.minimumPasswordNonLetter) {
+                    length = admin.minimumPasswordNonLetter;
                 }
             }
             return length;
@@ -3317,119 +3343,129 @@
         enforceFullCrossUsersPermission(userHandle);
 
         synchronized (this) {
-            int id = getCredentialOwner(userHandle);
-            DevicePolicyData policy = getUserDataUnchecked(id);
-
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
-            ActiveAdmin admin =
-                    getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
-            ComponentName adminComponentName = admin.info.getComponent();
-            // TODO: Include the Admin sdk level check in LockPatternUtils check.
-            ComponentName who = !isAdminApiLevelMOrBelow(adminComponentName, userHandle)
-                    && isSeparateProfileChallengeEnabled(userHandle)
-                        ? adminComponentName : null;
-            if (policy.mActivePasswordQuality < getPasswordQuality(who, userHandle, parent)
-                    || policy.mActivePasswordLength < getPasswordMinimumLength(null, userHandle)) {
+            getActiveAdminForCallerLocked(
+                    null, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
+
+            DevicePolicyData policy = getUserDataUnchecked(getCredentialOwner(userHandle, parent));
+            if (policy.mActivePasswordQuality < getPasswordQuality(null, userHandle, parent)
+                    || policy.mActivePasswordLength < getPasswordMinimumLength(
+                            null, userHandle, parent)) {
                 return false;
             }
             if (policy.mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
                 return true;
             }
-            return policy.mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null, userHandle)
-                && policy.mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null, userHandle)
-                && policy.mActivePasswordLetters >= getPasswordMinimumLetters(null, userHandle)
-                && policy.mActivePasswordNumeric >= getPasswordMinimumNumeric(null, userHandle)
-                && policy.mActivePasswordSymbols >= getPasswordMinimumSymbols(null, userHandle)
-                && policy.mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null, userHandle);
+            return policy.mActivePasswordUpperCase >= getPasswordMinimumUpperCase(
+                            null, userHandle, parent)
+                    && policy.mActivePasswordLowerCase >= getPasswordMinimumLowerCase(
+                            null, userHandle, parent)
+                    && policy.mActivePasswordLetters >= getPasswordMinimumLetters(
+                            null, userHandle, parent)
+                    && policy.mActivePasswordNumeric >= getPasswordMinimumNumeric(
+                            null, userHandle, parent)
+                    && policy.mActivePasswordSymbols >= getPasswordMinimumSymbols(
+                            null, userHandle, parent)
+                    && policy.mActivePasswordNonLetter >= getPasswordMinimumNonLetter(
+                            null, userHandle, parent);
         }
     }
 
     @Override
-    public int getCurrentFailedPasswordAttempts(int userHandle) {
+    public int getCurrentFailedPasswordAttempts(int userHandle, boolean parent) {
         synchronized (this) {
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
-            getActiveAdminForCallerLocked(null,
-                    DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
+            getActiveAdminForCallerLocked(
+                    null, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, parent);
 
-            int credentialOwnerId = getCredentialOwner(userHandle);
-            DevicePolicyData policy = getUserDataUnchecked(credentialOwnerId);
+            DevicePolicyData policy = getUserDataUnchecked(getCredentialOwner(userHandle, parent));
 
             return policy.mFailedPasswordAttempts;
         }
     }
 
     @Override
-    public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
+    public void setMaximumFailedPasswordsForWipe(ComponentName who, int num, boolean parent) {
         if (!mHasFeature) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
-        final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
-            getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_WIPE_DATA);
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
+            getActiveAdminForCallerLocked(
+                    who, DeviceAdminInfo.USES_POLICY_WIPE_DATA, parent);
+            ActiveAdmin ap = getActiveAdminForCallerLocked(
+                    who, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, parent);
             if (ap.maximumFailedPasswordsForWipe != num) {
                 ap.maximumFailedPasswordsForWipe = num;
-                saveSettingsLocked(userHandle);
+                saveSettingsLocked(mInjector.userHandleGetCallingUserId());
             }
         }
     }
 
     @Override
-    public int getMaximumFailedPasswordsForWipe(ComponentName who, int userHandle) {
+    public int getMaximumFailedPasswordsForWipe(ComponentName who, int userHandle, boolean parent) {
         if (!mHasFeature) {
             return 0;
         }
         enforceFullCrossUsersPermission(userHandle);
         synchronized (this) {
-            ActiveAdmin admin = (who != null) ? getActiveAdminUncheckedLocked(who, userHandle)
-                    : getAdminWithMinimumFailedPasswordsForWipeLocked(userHandle);
+            ActiveAdmin admin = (who != null)
+                    ? getActiveAdminUncheckedLocked(who, userHandle, parent)
+                    : getAdminWithMinimumFailedPasswordsForWipeLocked(userHandle, parent);
             return admin != null ? admin.maximumFailedPasswordsForWipe : 0;
         }
     }
 
     @Override
-    public int getProfileWithMinimumFailedPasswordsForWipe(int userHandle) {
+    public int getProfileWithMinimumFailedPasswordsForWipe(int userHandle, boolean parent) {
         if (!mHasFeature) {
             return UserHandle.USER_NULL;
         }
         enforceFullCrossUsersPermission(userHandle);
         synchronized (this) {
-            ActiveAdmin admin = getAdminWithMinimumFailedPasswordsForWipeLocked(userHandle);
+            ActiveAdmin admin = getAdminWithMinimumFailedPasswordsForWipeLocked(
+                    userHandle, parent);
             return admin != null ? admin.getUserHandle().getIdentifier() : UserHandle.USER_NULL;
         }
     }
 
     /**
-     * Returns the admin with the strictest policy on maximum failed passwords for this user and all
-     * profiles that are visible from this user. If the policy for the primary and any other profile
-     * are equal, it returns the admin for the primary profile.
-     * Returns {@code null} if none of them have that policy set.
+     * Returns the admin with the strictest policy on maximum failed passwords for:
+     * <ul>
+     *   <li>this user if it has a separate profile challenge, or
+     *   <li>this user and all profiles that don't have their own challenge otherwise.
+     * </ul>
+     * <p>If the policy for the primary and any other profile are equal, it returns the admin for
+     * the primary profile.
+     * Returns {@code null} if no participating admin has that policy set.
      */
-    private ActiveAdmin getAdminWithMinimumFailedPasswordsForWipeLocked(int userHandle) {
+    private ActiveAdmin getAdminWithMinimumFailedPasswordsForWipeLocked(
+            int userHandle, boolean parent) {
         int count = 0;
         ActiveAdmin strictestAdmin = null;
-        for (UserInfo userInfo : mUserManager.getProfiles(userHandle)) {
-            DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
-            for (ActiveAdmin admin : policy.mAdminList) {
-                if (admin.maximumFailedPasswordsForWipe ==
-                        ActiveAdmin.DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) {
-                    continue;  // No max number of failed passwords policy set for this profile.
-                }
 
-                // We always favor the primary profile if several profiles have the same value set.
-                if (count == 0 ||
-                        count > admin.maximumFailedPasswordsForWipe ||
-                        (userInfo.isPrimary() && count >= admin.maximumFailedPasswordsForWipe)) {
-                    count = admin.maximumFailedPasswordsForWipe;
-                    strictestAdmin = admin;
-                }
+        // Return the strictest policy across all participating admins.
+        List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+        final int N = admins.size();
+        for (int i = 0; i < N; i++) {
+            ActiveAdmin admin = admins.get(i);
+            if (admin.maximumFailedPasswordsForWipe ==
+                    ActiveAdmin.DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) {
+                continue;  // No max number of failed passwords policy set for this profile.
+            }
+
+            // We always favor the primary profile if several profiles have the same value set.
+            int userId = admin.getUserHandle().getIdentifier();
+            if (count == 0 ||
+                    count > admin.maximumFailedPasswordsForWipe ||
+                    (count == admin.maximumFailedPasswordsForWipe &&
+                            mUserManager.getUserInfo(userId).isPrimary())) {
+                count = admin.maximumFailedPasswordsForWipe;
+                strictestAdmin = admin;
             }
         }
         return strictestAdmin;
@@ -3443,14 +3479,9 @@
         final int callingUid = mInjector.binderGetCallingUid();
         final int userHandle = mInjector.userHandleGetCallingUserId();
 
-        long ident = mInjector.binderClearCallingIdentity();
-        try {
-            if (getCredentialOwner(userHandle) != userHandle) {
-                throw new SecurityException("You can not change password for this profile because"
+        if (getCredentialOwner(userHandle, /* parent */ false) != userHandle) {
+            throw new SecurityException("You can not change password for this profile because"
                     + " it shares the password with the owner profile");
-            }
-        } finally {
-            mInjector.binderRestoreCallingIdentity(ident);
         }
 
         String password = passwordOrNull != null ? passwordOrNull : "";
@@ -3494,7 +3525,7 @@
                     }
                 }
             }
-            quality = getPasswordQuality(null, userHandle, false);
+            quality = getPasswordQuality(null, userHandle, /* parent */ false);
             if (quality == DevicePolicyManager.PASSWORD_QUALITY_MANAGED) {
                 quality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
             }
@@ -3510,7 +3541,7 @@
                 }
                 quality = Math.max(realQuality, quality);
             }
-            int length = getPasswordMinimumLength(null, userHandle);
+            int length = getPasswordMinimumLength(null, userHandle, /* parent */ false);
             if (password.length() < length) {
                 Slog.w(LOG_TAG, "resetPassword: password length " + password.length()
                         + " does not meet required length " + length);
@@ -3539,40 +3570,43 @@
                         nonletter++;
                     }
                 }
-                int neededLetters = getPasswordMinimumLetters(null, userHandle);
+                int neededLetters = getPasswordMinimumLetters(null, userHandle, /* parent */ false);
                 if(letters < neededLetters) {
                     Slog.w(LOG_TAG, "resetPassword: number of letters " + letters
                             + " does not meet required number of letters " + neededLetters);
                     return false;
                 }
-                int neededNumbers = getPasswordMinimumNumeric(null, userHandle);
+                int neededNumbers = getPasswordMinimumNumeric(null, userHandle, /* parent */ false);
                 if (numbers < neededNumbers) {
                     Slog.w(LOG_TAG, "resetPassword: number of numerical digits " + numbers
                             + " does not meet required number of numerical digits "
                             + neededNumbers);
                     return false;
                 }
-                int neededLowerCase = getPasswordMinimumLowerCase(null, userHandle);
+                int neededLowerCase = getPasswordMinimumLowerCase(
+                        null, userHandle, /* parent */ false);
                 if (lowercase < neededLowerCase) {
                     Slog.w(LOG_TAG, "resetPassword: number of lowercase letters " + lowercase
                             + " does not meet required number of lowercase letters "
                             + neededLowerCase);
                     return false;
                 }
-                int neededUpperCase = getPasswordMinimumUpperCase(null, userHandle);
+                int neededUpperCase = getPasswordMinimumUpperCase(
+                        null, userHandle, /* parent */ false);
                 if (uppercase < neededUpperCase) {
                     Slog.w(LOG_TAG, "resetPassword: number of uppercase letters " + uppercase
                             + " does not meet required number of uppercase letters "
                             + neededUpperCase);
                     return false;
                 }
-                int neededSymbols = getPasswordMinimumSymbols(null, userHandle);
+                int neededSymbols = getPasswordMinimumSymbols(null, userHandle, /* parent */ false);
                 if (symbols < neededSymbols) {
                     Slog.w(LOG_TAG, "resetPassword: number of special symbols " + symbols
                             + " does not meet required number of special symbols " + neededSymbols);
                     return false;
                 }
-                int neededNonLetter = getPasswordMinimumNonLetter(null, userHandle);
+                int neededNonLetter = getPasswordMinimumNonLetter(
+                        null, userHandle, /* parent */ false);
                 if (nonletter < neededNonLetter) {
                     Slog.w(LOG_TAG, "resetPassword: number of non-letter characters " + nonletter
                             + " does not meet required number of non-letter characters "
@@ -3597,17 +3631,16 @@
 
         // Don't do this with the lock held, because it is going to call
         // back in to the service.
-        ident = mInjector.binderClearCallingIdentity();
+        final long ident = mInjector.binderClearCallingIdentity();
         try {
-            LockPatternUtils utils = mInjector.newLockPatternUtils();
             if (!TextUtils.isEmpty(password)) {
-                utils.saveLockPassword(password, null, quality, userHandle);
+                mLockPatternUtils.saveLockPassword(password, null, quality, userHandle);
             } else {
-                utils.clearLock(userHandle);
+                mLockPatternUtils.clearLock(userHandle);
             }
             boolean requireEntry = (flags & DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY) != 0;
             if (requireEntry) {
-                utils.requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
+                mLockPatternUtils.requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
                         UserHandle.USER_ALL);
             }
             synchronized (this) {
@@ -3627,7 +3660,7 @@
     private boolean isLockScreenSecureUnchecked(int userId) {
         long ident = mInjector.binderClearCallingIdentity();
         try {
-            return mInjector.newLockPatternUtils().isSecure(userId);
+            return mLockPatternUtils.isSecure(userId);
         } finally {
             mInjector.binderRestoreCallingIdentity(ident);
         }
@@ -3654,50 +3687,69 @@
     }
 
     @Override
-    public void setMaximumTimeToLock(ComponentName who, long timeMs) {
+    public void setMaximumTimeToLock(ComponentName who, long timeMs, boolean parent) {
         if (!mHasFeature) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
-        final int userHandle = UserHandle.getCallingUserId();
+        final int userHandle = mInjector.userHandleGetCallingUserId();
         synchronized (this) {
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
+            ActiveAdmin ap = getActiveAdminForCallerLocked(
+                    who, DeviceAdminInfo.USES_POLICY_FORCE_LOCK, parent);
             if (ap.maximumTimeToUnlock != timeMs) {
                 ap.maximumTimeToUnlock = timeMs;
                 saveSettingsLocked(userHandle);
-                updateMaximumTimeToLockLocked(getUserData(userHandle));
+                updateMaximumTimeToLockLocked(userHandle);
             }
         }
     }
 
-    void updateMaximumTimeToLockLocked(DevicePolicyData policy) {
-        long timeMs = getMaximumTimeToLock(null, policy.mUserHandle);
+    void updateMaximumTimeToLockLocked(int userHandle) {
+        // Calculate the min timeout for all profiles - including the ones with a separate
+        // challenge. Ideally if the timeout only affected the profile challenge we'd lock that
+        // challenge only and keep the screen on. However there is no easy way of doing that at the
+        // moment so we set the screen off timeout regardless of whether it affects the parent user
+        // or the profile challenge only.
+        long timeMs = Integer.MAX_VALUE;
+        List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+        for (UserInfo userInfo : profiles) {
+            DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
+            final int N = policy.mAdminList.size();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = policy.mAdminList.get(i);
+                if (admin.maximumTimeToUnlock > 0
+                        && timeMs > admin.maximumTimeToUnlock) {
+                    timeMs = admin.maximumTimeToUnlock;
+                }
+            }
+        }
+
+        // We only store the last maximum time to lock on the parent profile. So if calling from a
+        // managed profile, retrieve the policy for the parent.
+        DevicePolicyData policy = getUserDataUnchecked(getProfileParentId(userHandle));
         if (policy.mLastMaximumTimeToLock == timeMs) {
             return;
         }
+        policy.mLastMaximumTimeToLock = timeMs;
 
-        long ident = mInjector.binderClearCallingIdentity();
+        final long ident = mInjector.binderClearCallingIdentity();
         try {
-            if (timeMs <= 0) {
-                timeMs = Integer.MAX_VALUE;
-            } else {
+            if (policy.mLastMaximumTimeToLock != Integer.MAX_VALUE) {
                 // Make sure KEEP_SCREEN_ON is disabled, since that
                 // would allow bypassing of the maximum time to lock.
                 mInjector.settingsGlobalPutInt(Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
             }
 
-            policy.mLastMaximumTimeToLock = timeMs;
             // TODO It can overflow.  Cap it.
             mInjector.getPowerManagerInternal()
-                    .setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs);
+                    .setMaximumScreenOffTimeoutFromDeviceAdmin((int)policy.mLastMaximumTimeToLock);
         } finally {
             mInjector.binderRestoreCallingIdentity(ident);
         }
     }
 
     @Override
-    public long getMaximumTimeToLock(ComponentName who, int userHandle) {
+    public long getMaximumTimeToLock(ComponentName who, int userHandle, boolean parent) {
         if (!mHasFeature) {
             return 0;
         }
@@ -3706,23 +3758,21 @@
             long time = 0;
 
             if (who != null) {
-                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+                ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
                 return admin != null ? admin.maximumTimeToUnlock : time;
             }
 
-            // Return strictest policy for this user and profiles that are visible from this user.
-            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
-            for (UserInfo userInfo : profiles) {
-                DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
-                final int N = policy.mAdminList.size();
-                for (int i=0; i<N; i++) {
-                    ActiveAdmin admin = policy.mAdminList.get(i);
-                    if (time == 0) {
-                        time = admin.maximumTimeToUnlock;
-                    } else if (admin.maximumTimeToUnlock != 0
-                            && time > admin.maximumTimeToUnlock) {
-                        time = admin.maximumTimeToUnlock;
-                    }
+            // Return the strictest policy across all participating admins.
+            List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(
+                    userHandle, parent);
+            final int N = admins.size();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = admins.get(i);
+                if (time == 0) {
+                    time = admin.maximumTimeToUnlock;
+                } else if (admin.maximumTimeToUnlock != 0
+                        && time > admin.maximumTimeToUnlock) {
+                    time = admin.maximumTimeToUnlock;
                 }
             }
             return time;
@@ -3730,32 +3780,36 @@
     }
 
     @Override
-    public void lockNow() {
+    public void lockNow(boolean parent) {
         if (!mHasFeature) {
             return;
         }
         synchronized (this) {
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
-            getActiveAdminForCallerLocked(null,
-                    DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
-            lockNowUnchecked();
-        }
-    }
+            getActiveAdminForCallerLocked(
+                    null, DeviceAdminInfo.USES_POLICY_FORCE_LOCK, parent);
 
-    private void lockNowUnchecked() {
-        long ident = mInjector.binderClearCallingIdentity();
-        try {
-            // Power off the display
-            mInjector.powerManagerGoToSleep(SystemClock.uptimeMillis(),
-                    PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN, 0);
-            // Ensure the device is locked
-            new LockPatternUtils(mContext).requireStrongAuth(
-                    STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW, UserHandle.USER_ALL);
-            mInjector.getIWindowManager().lockNow(null);
-        } catch (RemoteException e) {
-        } finally {
-            mInjector.binderRestoreCallingIdentity(ident);
+            int userToLock = mInjector.userHandleGetCallingUserId();
+
+            // Unless this is a managed profile with work challenge enabled, lock all users.
+            if (parent || !isSeparateProfileChallengeEnabled(userToLock)) {
+                userToLock = UserHandle.USER_ALL;
+            }
+            final long ident = mInjector.binderClearCallingIdentity();
+            try {
+                mLockPatternUtils.requireStrongAuth(
+                        STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW, userToLock);
+                if (userToLock == UserHandle.USER_ALL) {
+                    // Power off the display
+                    mInjector.powerManagerGoToSleep(SystemClock.uptimeMillis(),
+                            PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN, 0);
+                    mInjector.getIWindowManager().lockNow(null);
+                }
+            } catch (RemoteException e) {
+            } finally {
+                mInjector.binderRestoreCallingIdentity(ident);
+            }
         }
     }
 
@@ -4168,7 +4222,8 @@
             return;
         }
         enforceFullCrossUsersPermission(userHandle);
-        // Managed Profile password can only be changed when per user encryption is present.
+
+        // Managed Profile password can only be changed when it has a separate challenge.
         if (!isSeparateProfileChallengeEnabled(userHandle)) {
             enforceNotManagedProfile(userHandle, "set the active password");
         }
@@ -4193,18 +4248,12 @@
                 policy.mFailedPasswordAttempts = 0;
                 saveSettingsLocked(userHandle);
                 updatePasswordExpirationsLocked(userHandle);
-                setExpirationAlarmCheckLocked(mContext, policy);
+                setExpirationAlarmCheckLocked(mContext, userHandle);
 
                 // Send a broadcast to each profile using this password as its primary unlock.
-                if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userHandle)) {
-                    sendAdminCommandLocked(
-                            DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
-                            DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle);
-                } else {
-                    sendAdminCommandToSelfAndProfilesLocked(
-                            DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
-                            DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle);
-                }
+                sendAdminCommandForLockscreenPoliciesLocked(
+                        DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
+                        DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle);
             }
         } finally {
             mInjector.binderRestoreCallingIdentity(ident);
@@ -4215,33 +4264,35 @@
      * Called any time the device password is updated. Resets all password expiration clocks.
      */
     private void updatePasswordExpirationsLocked(int userHandle) {
-            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
-            for (UserInfo userInfo : profiles) {
-                int profileId = userInfo.id;
-                DevicePolicyData policy = getUserDataUnchecked(profileId);
-                final int N = policy.mAdminList.size();
-                if (N > 0) {
-                    for (int i=0; i<N; i++) {
-                        ActiveAdmin admin = policy.mAdminList.get(i);
-                        if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
-                            long timeout = admin.passwordExpirationTimeout;
-                            long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
-                            admin.passwordExpirationDate = expiration;
-                        }
-                    }
-                }
-                saveSettingsLocked(profileId);
+        ArraySet<Integer> affectedUserIds = new ArraySet<Integer>();
+        List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(
+                userHandle, /* parent */ false);
+        final int N = admins.size();
+        for (int i = 0; i < N; i++) {
+            ActiveAdmin admin = admins.get(i);
+            if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
+                affectedUserIds.add(admin.getUserHandle().getIdentifier());
+                long timeout = admin.passwordExpirationTimeout;
+                long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
+                admin.passwordExpirationDate = expiration;
             }
+        }
+        for (int affectedUserId : affectedUserIds) {
+            saveSettingsLocked(affectedUserId);
+        }
     }
 
     @Override
     public void reportFailedPasswordAttempt(int userHandle) {
         enforceFullCrossUsersPermission(userHandle);
-        enforceNotManagedProfile(userHandle, "report failed password attempt");
+        if (!isSeparateProfileChallengeEnabled(userHandle)) {
+            enforceNotManagedProfile(userHandle,
+                    "report failed password attempt if separate profile challenge is not in place");
+        }
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
 
-        long ident = mInjector.binderClearCallingIdentity();
+        final long ident = mInjector.binderClearCallingIdentity();
         try {
             boolean wipeData = false;
             int identifier = 0;
@@ -4250,8 +4301,8 @@
                 policy.mFailedPasswordAttempts++;
                 saveSettingsLocked(userHandle);
                 if (mHasFeature) {
-                    ActiveAdmin strictestAdmin =
-                            getAdminWithMinimumFailedPasswordsForWipeLocked(userHandle);
+                    ActiveAdmin strictestAdmin = getAdminWithMinimumFailedPasswordsForWipeLocked(
+                            userHandle, /* parent */ false);
                     int max = strictestAdmin != null
                             ? strictestAdmin.maximumFailedPasswordsForWipe : 0;
                     if (max > 0 && policy.mFailedPasswordAttempts >= max) {
@@ -4261,7 +4312,8 @@
                         wipeData = true;
                         identifier = strictestAdmin.getUserHandle().getIdentifier();
                     }
-                    sendAdminCommandToSelfAndProfilesLocked(
+
+                    sendAdminCommandForLockscreenPoliciesLocked(
                             DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
                             DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
                 }
@@ -4291,7 +4343,7 @@
                     policy.mPasswordOwner = -1;
                     saveSettingsLocked(userHandle);
                     if (mHasFeature) {
-                        sendAdminCommandToSelfAndProfilesLocked(
+                        sendAdminCommandForLockscreenPoliciesLocked(
                                 DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
                                 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
                     }
@@ -4951,22 +5003,25 @@
         }
     }
 
-    /**
-     * Selectively disable keyguard features.
-     */
     @Override
-    public void setKeyguardDisabledFeatures(ComponentName who, int which) {
+    public void setKeyguardDisabledFeatures(ComponentName who, int which, boolean parent) {
         if (!mHasFeature) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
-        final int userHandle = UserHandle.getCallingUserId();
+        final int userHandle = mInjector.userHandleGetCallingUserId();
         if (isManagedProfile(userHandle)) {
-            which = which & PROFILE_KEYGUARD_FEATURES;
+            if (parent) {
+                which = which & PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
+            } else if (isSeparateProfileChallengeEnabled(userHandle)){
+                which = which & PROFILE_KEYGUARD_FEATURES_AFFECT_PROFILE;
+            } else {
+                which = which & PROFILE_KEYGUARD_FEATURES;
+            }
         }
         synchronized (this) {
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES);
+            ActiveAdmin ap = getActiveAdminForCallerLocked(
+                    who, DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES, parent);
             if (ap.disabledKeyguardFeatures != which) {
                 ap.disabledKeyguardFeatures = which;
                 saveSettingsLocked(userHandle);
@@ -4979,50 +5034,43 @@
      * or the aggregate of all active admins if who is null.
      */
     @Override
-    public int getKeyguardDisabledFeatures(ComponentName who, int userHandle) {
+    public int getKeyguardDisabledFeatures(ComponentName who, int userHandle, boolean parent) {
         if (!mHasFeature) {
             return 0;
         }
         enforceFullCrossUsersPermission(userHandle);
-        long ident = mInjector.binderClearCallingIdentity();
+        final long ident = mInjector.binderClearCallingIdentity();
         try {
             synchronized (this) {
                 if (who != null) {
-                    ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+                    ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle, parent);
                     return (admin != null) ? admin.disabledKeyguardFeatures : 0;
                 }
 
-                UserInfo user = mUserManager.getUserInfo(userHandle);
-                final List<UserInfo> profiles;
-                if (user.isManagedProfile()) {
+                final List<ActiveAdmin> admins;
+                if (!parent && isManagedProfile(userHandle)) {
                     // If we are being asked about a managed profile, just return keyguard features
                     // disabled by admins in the profile.
-                    profiles = Collections.singletonList(user);
+                    admins = getUserDataUnchecked(userHandle).mAdminList;
                 } else {
-                    // Otherwise return those set by admins in the user
-                    // and its profiles.
-                    profiles = mUserManager.getProfiles(userHandle);
+                    // Otherwise return those set by admins in the user and its profiles.
+                    admins = getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
                 }
 
-                // Determine which keyguard features are disabled by any active admin.
-                int which = 0;
-                for (UserInfo userInfo : profiles) {
-                    DevicePolicyData policy = getUserData(userInfo.id);
-                    final int N = policy.mAdminList.size();
-                    for (int i = 0; i < N; i++) {
-                        ActiveAdmin admin = policy.mAdminList.get(i);
-                        if (userInfo.id == userHandle || !userInfo.isManagedProfile()) {
-                            // If we are being asked explictly about this user
-                            // return all disabled features even if its a managed profile.
-                            which |= admin.disabledKeyguardFeatures;
-                        } else if (!isSeparateProfileChallengeEnabled(
-                                userInfo.id)) {
-                            // Otherwise a managed profile is only allowed to disable
-                            // some features on the parent user, and we only aggregate them if
-                            // it doesn't have its own challenge.
-                            which |= (admin.disabledKeyguardFeatures
-                                    & PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER);
-                        }
+                int which = DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
+                final int N = admins.size();
+                for (int i = 0; i < N; i++) {
+                    ActiveAdmin admin = admins.get(i);
+                    int userId = admin.getUserHandle().getIdentifier();
+                    if (userId == userHandle || !isManagedProfile(userHandle)) {
+                        // If we are being asked explicitly about this user
+                        // return all disabled features even if its a managed profile.
+                        which |= admin.disabledKeyguardFeatures;
+                    } else {
+                        // Otherwise a managed profile is only allowed to disable
+                        // some features on the parent user.
+                        which |= (admin.disabledKeyguardFeatures
+                                & PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER);
                     }
                 }
                 return which;
@@ -5283,7 +5331,7 @@
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
             long token = mInjector.binderClearCallingIdentity();
             try {
-                new LockPatternUtils(mContext).setDeviceOwnerInfo(info);
+                mLockPatternUtils.setDeviceOwnerInfo(info);
             } finally {
                 mInjector.binderRestoreCallingIdentity(token);
             }
@@ -5293,7 +5341,7 @@
 
     @Override
     public String getDeviceOwnerLockScreenInfo() {
-        return new LockPatternUtils(mContext).getDeviceOwnerInfo();
+        return mLockPatternUtils.getDeviceOwnerInfo();
     }
 
     private void clearUserPoliciesLocked(UserHandle userHandle) {
@@ -5570,15 +5618,37 @@
         }
     }
 
-    private void enforceNotManagedProfile(int userHandle, String message) {
-        if(isManagedProfile(userHandle)) {
-            throw new SecurityException("You can not " + message + " for a managed profile. ");
+    private void enforceManagedProfile(int userHandle, String message) {
+        if(!isManagedProfile(userHandle)) {
+            throw new SecurityException("You can not " + message + " outside a managed profile.");
         }
     }
 
-    private int getCredentialOwner(int userHandle) {
-        long ident = mInjector.binderClearCallingIdentity();
+    private void enforceNotManagedProfile(int userHandle, String message) {
+        if(isManagedProfile(userHandle)) {
+            throw new SecurityException("You can not " + message + " for a managed profile.");
+        }
+    }
+
+    private int getProfileParentId(int userHandle) {
+        final long ident = mInjector.binderClearCallingIdentity();
         try {
+            UserInfo parentUser = mUserManager.getProfileParent(userHandle);
+            return parentUser != null ? parentUser.id : userHandle;
+        } finally {
+            mInjector.binderRestoreCallingIdentity(ident);
+        }
+    }
+
+    private int getCredentialOwner(int userHandle, boolean parent) {
+        final long ident = mInjector.binderClearCallingIdentity();
+        try {
+            if (parent) {
+                UserInfo parentProfile = mUserManager.getProfileParent(userHandle);
+                if (parentProfile != null) {
+                    userHandle = parentProfile.id;
+                }
+            }
             return mUserManager.getCredentialOwnerProfile(userHandle);
         } finally {
             mInjector.binderRestoreCallingIdentity(ident);
@@ -6515,15 +6585,8 @@
                             + userId);
                 }
 
-                UserManager um = UserManager.get(mContext);
-                UserInfo primaryUser = um.getProfileParent(userId);
-
-                // Call did not come from a managed profile
-                if (primaryUser == null) {
-                    primaryUser = um.getUserInfo(userId);
-                }
-
-                if (!isSystemApp(mIPackageManager, packageName, primaryUser.id)) {
+                int parentUserId = getProfileParentId(userId);
+                if (!isSystemApp(mIPackageManager, packageName, parentUserId)) {
                     throw new IllegalArgumentException("Only system apps can be enabled this way.");
                 }
 
@@ -6551,19 +6614,12 @@
             long id = mInjector.binderClearCallingIdentity();
 
             try {
-                UserManager um = UserManager.get(mContext);
-                UserInfo primaryUser = um.getProfileParent(userId);
-
-                // Call did not come from a managed profile.
-                if (primaryUser == null) {
-                    primaryUser = um.getUserInfo(userId);
-                }
-
+                int parentUserId = getProfileParentId(userId);
                 List<ResolveInfo> activitiesToEnable = mIPackageManager.queryIntentActivities(
                         intent,
                         intent.resolveTypeIfNeeded(mContext.getContentResolver()),
                         0, // no flags
-                        primaryUser.id);
+                        parentUserId);
 
                 if (VERBOSE_LOG) {
                     Slog.d(LOG_TAG, "Enabling system activities: " + activitiesToEnable);
@@ -6573,7 +6629,7 @@
                     for (ResolveInfo info : activitiesToEnable) {
                         if (info.activityInfo != null) {
                             String packageName = info.activityInfo.packageName;
-                            if (isSystemApp(mIPackageManager, packageName, primaryUser.id)) {
+                            if (isSystemApp(mIPackageManager, packageName, parentUserId)) {
                                 numberOfAppsInstalled++;
                                 mIPackageManager.installExistingPackageAsUser(packageName, userId);
                             } else {
@@ -6977,7 +7033,8 @@
 
             if (Settings.Global.STAY_ON_WHILE_PLUGGED_IN.equals(setting)) {
                 // ignore if it contradicts an existing policy
-                long timeMs = getMaximumTimeToLock(who, UserHandle.getCallingUserId());
+                long timeMs = getMaximumTimeToLock(
+                        who, mInjector.userHandleGetCallingUserId(), /* parent */ false);
                 if (timeMs > 0 && timeMs < Integer.MAX_VALUE) {
                     return;
                 }
@@ -7000,7 +7057,7 @@
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
-            if (isDeviceOwner(who, mInjector.userHandleGetCallingUserId())) {
+            if (isDeviceOwner(who, callingUserId)) {
                 if (!SECURE_SETTINGS_DEVICEOWNER_WHITELIST.contains(setting)) {
                     throw new SecurityException(String.format(
                             "Permission denial: Device owners cannot update %1$s", setting));
@@ -7073,15 +7130,14 @@
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
         }
         final int userId = UserHandle.getCallingUserId();
-        LockPatternUtils utils = new LockPatternUtils(mContext);
 
         long ident = mInjector.binderClearCallingIdentity();
         try {
             // disallow disabling the keyguard if a password is currently set
-            if (disabled && utils.isSecure(userId)) {
+            if (disabled && mLockPatternUtils.isSecure(userId)) {
                 return false;
             }
-            utils.setLockScreenDisabled(disabled, userId);
+            mLockPatternUtils.setLockScreenDisabled(disabled, userId);
         } finally {
             mInjector.binderRestoreCallingIdentity(ident);
         }
@@ -7214,7 +7270,6 @@
 
         @Override
         public boolean isActiveAdminWithPolicy(int uid, int reqPolicy) {
-            final int userId = UserHandle.getUserId(uid);
             synchronized(DevicePolicyManagerService.this) {
                 return getActiveAdminWithPolicyForUidLocked(null, reqPolicy, uid) != null;
             }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java
index b80f3bf..3da61d6 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java
@@ -26,7 +26,7 @@
 
     public DevicePolicyManagerTestable(DpmMockContext context,
             DevicePolicyManagerServiceTestable dpms) {
-        super(context, dpms);
+        super(context, dpms, /* parentInstance = */ false);
         this.dpms = dpms;
     }