Merge "RESTRICT AUTOMERGE Use consistent calling uid and package in navigateUpTo" into qt-qpr1-dev
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index cd0b340..c2a7c79 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -665,6 +665,8 @@
     char dex2oatImageCompilerFilterBuf[sizeof("--compiler-filter=")-1 + PROPERTY_VALUE_MAX];
     char dex2oatThreadsBuf[sizeof("-j")-1 + PROPERTY_VALUE_MAX];
     char dex2oatThreadsImageBuf[sizeof("-j")-1 + PROPERTY_VALUE_MAX];
+    char dex2oatCpuSetBuf[sizeof("--cpu-set=")-1 + PROPERTY_VALUE_MAX];
+    char dex2oatCpuSetImageBuf[sizeof("--cpu-set=")-1 + PROPERTY_VALUE_MAX];
     char dex2oat_isa_variant_key[PROPERTY_KEY_MAX];
     char dex2oat_isa_variant[sizeof("--instruction-set-variant=") -1 + PROPERTY_VALUE_MAX];
     char dex2oat_isa_features_key[PROPERTY_KEY_MAX];
@@ -937,6 +939,10 @@
     parseCompilerOption("dalvik.vm.dex2oat-threads", dex2oatThreadsBuf, "-j", "-Xcompiler-option");
     parseCompilerOption("dalvik.vm.image-dex2oat-threads", dex2oatThreadsImageBuf, "-j",
                         "-Ximage-compiler-option");
+    parseCompilerOption("dalvik.vm.dex2oat-cpu-set", dex2oatCpuSetBuf, "--cpu-set=",
+                        "-Xcompiler-option");
+    parseCompilerOption("dalvik.vm.image-dex2oat-cpu-set", dex2oatCpuSetImageBuf, "--cpu-set=",
+                        "-Ximage-compiler-option");
 
     // The runtime will compile a boot image, when necessary, not using installd. Thus, we need to
     // pass the instruction-set-features/variant as an image-compiler-option.
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a0d2d84..5d5729b 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1212,12 +1212,16 @@
     <string name="permdesc_readPhoneNumbers">Allows the app to access the phone numbers of the device.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_wakeLock" product="automotive">keep car screen turned on</string>
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_wakeLock" product="tablet">prevent tablet from sleeping</string>
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_wakeLock" product="tv">prevent TV from sleeping</string>
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_wakeLock" product="default">prevent phone from sleeping</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_wakeLock" product="automotive">Allows the app to keep the car screen turned on.</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_wakeLock" product="tablet">Allows the app to prevent the tablet from going to sleep.</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_wakeLock" product="tv">Allows the app to prevent the TV from going to sleep.</string>
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 646aa13..9866c30 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -1067,6 +1067,17 @@
         return onUserPasswordChanged(UserHandle.getUserId(Process.myUid()), newPassword);
     }
 
+    /**
+     * Notify keystore about the latest user locked state. This is to support keyguard-bound key.
+     */
+    public void onUserLockedStateChanged(int userHandle, boolean locked) {
+        try {
+            mBinder.onKeyguardVisibilityChanged(locked, userHandle);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to update user locked state " + userHandle, e);
+        }
+    }
+
     private class KeyAttestationCallbackResult {
         private KeystoreResponse keystoreResponse;
         private KeymasterCertificateChain certificateChain;
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 820d82d..d2ae7c1 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -1251,7 +1251,10 @@
         }
     }
 
-    static int capturePolicyToFlags(@CapturePolicy int capturePolicy, int flags) {
+    /**
+     * @hide
+     */
+    public static int capturePolicyToFlags(@CapturePolicy int capturePolicy, int flags) {
         switch (capturePolicy) {
             case ALLOW_CAPTURE_BY_NONE:
                 flags |= FLAG_NO_MEDIA_PROJECTION | FLAG_NO_SYSTEM_CAPTURE;
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 6890270..142bc12 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1507,23 +1507,22 @@
      *     {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL},
      *     {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM},
      *     {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}.
-     * @throws IllegalArgumentException if the argument is not a valid value.
+     * @throws RuntimeException if the argument is not a valid value.
      */
     public void setAllowedCapturePolicy(@AudioAttributes.CapturePolicy int capturePolicy) {
-        int flags = AudioAttributes.capturePolicyToFlags(capturePolicy, 0x0);
-        // TODO: got trough AudioService and save a cache to restore in case of AP crash
         // TODO: also pass the package in case multiple packages have the same UID
-        int result = AudioSystem.setAllowedCapturePolicy(Process.myUid(), flags);
-        if (result != AudioSystem.AUDIO_STATUS_OK) {
-            Log.e(TAG, "Could not setAllowedCapturePolicy: " + result);
-            return;
+        final IAudioService service = getService();
+        try {
+            int result = service.setAllowedCapturePolicy(capturePolicy);
+            if (result != AudioSystem.AUDIO_STATUS_OK) {
+                Log.e(TAG, "Could not setAllowedCapturePolicy: " + result);
+                return;
+            }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        mCapturePolicy = capturePolicy;
     }
 
-    @AudioAttributes.CapturePolicy
-    private int mCapturePolicy = AudioAttributes.ALLOW_CAPTURE_BY_ALL;
-
     /**
      * Return the capture policy.
      * @return the capture policy set by {@link #setAllowedCapturePolicy(int)} or
@@ -1531,7 +1530,13 @@
      */
     @AudioAttributes.CapturePolicy
     public int getAllowedCapturePolicy() {
-        return mCapturePolicy;
+        int result = AudioAttributes.ALLOW_CAPTURE_BY_ALL;
+        try {
+            result = getService().getAllowedCapturePolicy();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to query allowed capture policy: " + e);
+        }
+        return result;
     }
 
     //====================================================================
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 71f52a1..7052e5a 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -259,6 +259,10 @@
 
     boolean hasHapticChannels(in Uri uri);
 
+    int setAllowedCapturePolicy(in int capturePolicy);
+
+    int getAllowedCapturePolicy();
+
     // WARNING: read warning at top of file, new methods that need to be used by native
     // code via IAudioManager.h need to be added to the top section.
 }
diff --git a/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt b/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt
index 24fa91b..284074e 100644
--- a/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt
@@ -26,7 +26,7 @@
 
 import kotlin.math.roundToInt
 
-const val TAG = "CameraOpTransitionController"
+const val TAG = "CameraAvailabilityListener"
 
 /**
  * Listens for usage of the Camera and controls the ScreenDecorations transition to show extra
diff --git a/packages/SystemUI/src/com/android/systemui/ConfigurationChangedReceiver.java b/packages/SystemUI/src/com/android/systemui/ConfigurationChangedReceiver.java
deleted file mode 100644
index 4fba640..0000000
--- a/packages/SystemUI/src/com/android/systemui/ConfigurationChangedReceiver.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.systemui;
-
-import android.content.res.Configuration;
-
-public interface ConfigurationChangedReceiver {
-    void onConfigurationChanged(Configuration newConfiguration);
-}
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 15bea24..c09c767 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -16,7 +16,6 @@
 
 import android.annotation.Nullable;
 import android.app.INotificationManager;
-import android.content.res.Configuration;
 import android.hardware.SensorPrivacyManager;
 import android.hardware.display.NightDisplayListener;
 import android.os.Handler;
@@ -521,15 +520,6 @@
                 .forEach(o -> ((Dumpable) o).dump(fd, pw, args));
     }
 
-    protected static void staticOnConfigurationChanged(Configuration newConfig) {
-        sDependency.onConfigurationChanged(newConfig);
-    }
-
-    protected synchronized void onConfigurationChanged(Configuration newConfig) {
-        mDependencies.values().stream().filter(obj -> obj instanceof ConfigurationChangedReceiver)
-                .forEach(o -> ((ConfigurationChangedReceiver) o).onConfigurationChanged(newConfig));
-    }
-
     protected final <T> T getDependency(Class<T> cls) {
         return getDependencyInner(cls);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 3a8524a..6ea6a74 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -26,8 +26,10 @@
 import static com.android.systemui.tuner.TunablePadding.FLAG_START;
 
 import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
 import android.annotation.Dimension;
 import android.annotation.NonNull;
 import android.app.ActivityManager;
@@ -869,14 +871,17 @@
     public static class DisplayCutoutView extends View implements DisplayManager.DisplayListener,
             RegionInterceptableView {
 
+        private static final float HIDDEN_CAMERA_PROTECTION_SCALE = 0.5f;
+
         private final DisplayInfo mInfo = new DisplayInfo();
         private final Paint mPaint = new Paint();
         private final List<Rect> mBounds = new ArrayList();
         private final Rect mBoundingRect = new Rect();
         private final Path mBoundingPath = new Path();
-        // Don't initialize these because they are cached elsewhere and may not exist
+        // Don't initialize these yet because they may never exist
         private Rect mProtectionRect;
         private Path mProtectionPath;
+        private Path mProtectionPathOrig;
         private Rect mTotalBounds = new Rect();
         // Whether or not to show the cutout protection path
         private boolean mShowProtection = false;
@@ -888,6 +893,8 @@
         private int mColor = Color.BLACK;
         private boolean mStart;
         private int mRotation;
+        private float mCameraProtectionProgress = HIDDEN_CAMERA_PROTECTION_SCALE;
+        private ValueAnimator mCameraProtectionAnimator;
 
         public DisplayCutoutView(Context context, boolean start,
                 Runnable visibilityChangedListener, ScreenDecorations decorations) {
@@ -928,17 +935,18 @@
             getLocationOnScreen(mLocation);
             canvas.translate(-mLocation[0], -mLocation[1]);
 
-            if (mShowProtection && !mProtectionRect.isEmpty()) {
-                mPaint.setColor(mColor);
-                mPaint.setStyle(Paint.Style.FILL);
-                mPaint.setAntiAlias(true);
-                canvas.drawPath(mProtectionPath, mPaint);
-            } else if (!mBoundingPath.isEmpty()) {
+            if (!mBoundingPath.isEmpty()) {
                 mPaint.setColor(mColor);
                 mPaint.setStyle(Paint.Style.FILL);
                 mPaint.setAntiAlias(true);
                 canvas.drawPath(mBoundingPath, mPaint);
             }
+            if (mCameraProtectionProgress > HIDDEN_CAMERA_PROTECTION_SCALE
+                    && !mProtectionRect.isEmpty()) {
+                canvas.scale(mCameraProtectionProgress, mCameraProtectionProgress,
+                        mProtectionRect.centerX(), mProtectionRect.centerY());
+                canvas.drawPath(mProtectionPath, mPaint);
+            }
         }
 
         @Override
@@ -962,7 +970,11 @@
         }
 
         void setProtection(Path protectionPath, Rect pathBounds) {
-            mProtectionPath = protectionPath;
+            if (mProtectionPathOrig == null) {
+                mProtectionPathOrig = new Path();
+                mProtectionPath = new Path();
+            }
+            mProtectionPathOrig.set(protectionPath);
             mProtectionRect = pathBounds;
         }
 
@@ -973,8 +985,31 @@
 
             mShowProtection = shouldShow;
             updateBoundingPath();
-            requestLayout();
-            invalidate();
+            // Delay the relayout until the end of the animation when hiding the cutout,
+            // otherwise we'd clip it.
+            if (mShowProtection) {
+                requestLayout();
+            }
+            if (mCameraProtectionAnimator != null) {
+                mCameraProtectionAnimator.cancel();
+            }
+            mCameraProtectionAnimator = ValueAnimator.ofFloat(mCameraProtectionProgress,
+                    mShowProtection ? 1.0f : HIDDEN_CAMERA_PROTECTION_SCALE).setDuration(750);
+            mCameraProtectionAnimator.setInterpolator(Interpolators.DECELERATE_QUINT);
+            mCameraProtectionAnimator.addUpdateListener(animation -> {
+                mCameraProtectionProgress = (float) animation.getAnimatedValue();
+                invalidate();
+            });
+            mCameraProtectionAnimator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mCameraProtectionAnimator = null;
+                    if (!mShowProtection) {
+                        requestLayout();
+                    }
+                }
+            });
+            mCameraProtectionAnimator.start();
         }
 
         private boolean isStart() {
@@ -1023,7 +1058,9 @@
             Matrix m = new Matrix();
             transformPhysicalToLogicalCoordinates(mInfo.rotation, dw, dh, m);
             mBoundingPath.transform(m);
-            if (mProtectionPath != null) {
+            if (mProtectionPathOrig != null) {
+                // Reset the protection path so we don't aggregate rotations
+                mProtectionPath.set(mProtectionPathOrig);
                 mProtectionPath.transform(m);
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 9252e57..0d1bd6b 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -286,7 +286,11 @@
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
         if (mServicesStarted) {
-            Dependency.staticOnConfigurationChanged(newConfig);
+            SystemUIFactory
+                    .getInstance()
+                    .getRootComponent()
+                    .getConfigurationController()
+                    .onConfigurationChanged(newConfig);
             int len = mServices.length;
             for (int i = 0; i < len; i++) {
                 if (mServices[i] != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIRootComponent.java b/packages/SystemUI/src/com/android/systemui/SystemUIRootComponent.java
index f18c8b2..a5b386e 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIRootComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIRootComponent.java
@@ -20,6 +20,7 @@
 
 import com.android.systemui.fragments.FragmentService;
 import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.util.InjectionInflationController;
 import com.android.systemui.util.leak.GarbageMonitor;
 
@@ -40,12 +41,20 @@
         SystemUIModule.class,
         SystemUIDefaultModule.class})
 public interface SystemUIRootComponent {
+
     /**
      * Main dependency providing module.
      */
     @Singleton
     Dependency.DependencyInjector createDependency();
 
+
+    /**
+     * Creates a ConfigurationController.
+     */
+    @Singleton
+    ConfigurationController getConfigurationController();
+
     /**
      * Injects the StatusBar.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 1a2d062..74b4f95 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -39,13 +39,13 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.settingslib.applications.InterestingConfigChanges;
-import com.android.systemui.ConfigurationChangedReceiver;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.assist.ui.DefaultUiController;
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 
 import javax.inject.Inject;
@@ -55,7 +55,7 @@
  * Class to manage everything related to assist in SystemUI.
  */
 @Singleton
-public class AssistManager implements ConfigurationChangedReceiver {
+public class AssistManager {
 
     /**
      * Controls the UI for showing Assistant invocation progress.
@@ -153,12 +153,40 @@
         }
     };
 
+    private ConfigurationController.ConfigurationListener mConfigurationListener =
+            new ConfigurationController.ConfigurationListener() {
+                @Override
+                public void onConfigChanged(Configuration newConfig) {
+                    if (!mInterestingConfigChanges.applyNewConfig(mContext.getResources())) {
+                        return;
+                    }
+                    boolean visible = false;
+                    if (mView != null) {
+                        visible = mView.isShowing();
+                        mWindowManager.removeView(mView);
+                    }
+
+                    mView = (AssistOrbContainer) LayoutInflater.from(mContext).inflate(
+                            R.layout.assist_orb, null);
+                    mView.setVisibility(View.GONE);
+                    mView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                            | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
+                    WindowManager.LayoutParams lp = getLayoutParams();
+                    mWindowManager.addView(mView, lp);
+                    if (visible) {
+                        mView.show(true /* show */, false /* animate */);
+                    }
+                }
+            };
+
     @Inject
     public AssistManager(
             DeviceProvisionedController controller,
             Context context,
             AssistUtils assistUtils,
-            AssistHandleBehaviorController handleController) {
+            AssistHandleBehaviorController handleController,
+            ConfigurationController configurationController) {
         mContext = context;
         mDeviceProvisionedController = controller;
         mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
@@ -167,11 +195,13 @@
         mPhoneStateMonitor = new PhoneStateMonitor(context);
         mHandleController = handleController;
 
+        configurationController.addCallback(mConfigurationListener);
+
         registerVoiceInteractionSessionListener();
         mInterestingConfigChanges = new InterestingConfigChanges(ActivityInfo.CONFIG_ORIENTATION
                 | ActivityInfo.CONFIG_LOCALE | ActivityInfo.CONFIG_UI_MODE
                 | ActivityInfo.CONFIG_SCREEN_LAYOUT | ActivityInfo.CONFIG_ASSETS_PATHS);
-        onConfigurationChanged(context.getResources().getConfiguration());
+        mConfigurationListener.onConfigChanged(context.getResources().getConfiguration());
         mShouldEnableOrb = !ActivityManager.isLowRamDeviceStatic();
 
         mUiController = new DefaultUiController(mContext);
@@ -221,29 +251,6 @@
                 });
     }
 
-    public void onConfigurationChanged(Configuration newConfiguration) {
-        if (!mInterestingConfigChanges.applyNewConfig(mContext.getResources())) {
-            return;
-        }
-        boolean visible = false;
-        if (mView != null) {
-            visible = mView.isShowing();
-            mWindowManager.removeView(mView);
-        }
-
-        mView = (AssistOrbContainer) LayoutInflater.from(mContext).inflate(
-                R.layout.assist_orb, null);
-        mView.setVisibility(View.GONE);
-        mView.setSystemUiVisibility(
-                View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
-                        | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
-        WindowManager.LayoutParams lp = getLayoutParams();
-        mWindowManager.addView(mView, lp);
-        if (visible) {
-            mView.show(true /* show */, false /* animate */);
-        }
-    }
-
     protected boolean shouldShowOrb() {
         return false;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index b7c8f70..e6cbab2 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -305,7 +305,7 @@
                         mContext.getResources());
             } else {
                 sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
-                mSensorThreshold = sensor.getMaximumRange();
+                mSensorThreshold = sensor == null ? 0 : sensor.getMaximumRange();
             }
             mSensor = sensor;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
index b4cc571..bbf49e3 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
@@ -20,11 +20,11 @@
 import android.util.ArrayMap;
 import android.view.View;
 
-import com.android.systemui.ConfigurationChangedReceiver;
 import com.android.systemui.Dumpable;
 import com.android.systemui.SystemUIRootComponent;
 import com.android.systemui.qs.QSFragment;
 import com.android.systemui.statusbar.phone.NavigationBarFragment;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -41,7 +41,7 @@
  * Also dispatches the configuration changes to all current FragmentHostStates.
  */
 @Singleton
-public class FragmentService implements ConfigurationChangedReceiver, Dumpable {
+public class FragmentService implements Dumpable {
 
     private static final String TAG = "FragmentService";
 
@@ -50,10 +50,22 @@
     private final Handler mHandler = new Handler();
     private final FragmentCreator mFragmentCreator;
 
+    private ConfigurationController.ConfigurationListener mConfigurationListener =
+            new ConfigurationController.ConfigurationListener() {
+                @Override
+                public void onConfigChanged(Configuration newConfig) {
+                    for (FragmentHostState state : mHosts.values()) {
+                        state.sendConfigurationChange(newConfig);
+                    }
+                }
+            };
+
     @Inject
-    public FragmentService(SystemUIRootComponent rootComponent) {
+    public FragmentService(SystemUIRootComponent rootComponent,
+            ConfigurationController configurationController) {
         mFragmentCreator = rootComponent.createFragmentCreator();
         initInjectionMap();
+        configurationController.addCallback(mConfigurationListener);
     }
 
     ArrayMap<String, Method> getInjectionMap() {
@@ -97,13 +109,6 @@
     }
 
     @Override
-    public void onConfigurationChanged(Configuration newConfig) {
-        for (FragmentHostState state : mHosts.values()) {
-            state.sendConfigurationChange(newConfig);
-        }
-    }
-
-    @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("Dumping fragments:");
         for (FragmentHostState state : mHosts.values()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
index 04f1c32..1524b07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar;
 
+import static java.lang.Float.isNaN;
+
 import android.annotation.NonNull;
 import android.content.Context;
 import android.graphics.Canvas;
@@ -179,6 +181,9 @@
      * @param alpha Gradient alpha from 0 to 1.
      */
     public void setViewAlpha(float alpha) {
+        if (isNaN(alpha)) {
+            throw new IllegalArgumentException("alpha cannot be NaN");
+        }
         if (alpha != mViewAlpha) {
             mViewAlpha = alpha;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
index 424acfd..54ef623 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
@@ -18,14 +18,11 @@
 import android.content.pm.ActivityInfo
 import android.content.res.Configuration
 import android.os.LocaleList
-
-import com.android.systemui.ConfigurationChangedReceiver
 import com.android.systemui.statusbar.policy.ConfigurationController
 
 import java.util.ArrayList
 
-class ConfigurationControllerImpl(context: Context)
-    : ConfigurationController, ConfigurationChangedReceiver {
+class ConfigurationControllerImpl(context: Context) : ConfigurationController {
 
     private val listeners: MutableList<ConfigurationController.ConfigurationListener> = ArrayList()
     private val lastConfig = Configuration()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 9019e9a..08ba508 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static java.lang.Float.isNaN;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
@@ -261,6 +263,10 @@
         mCurrentBehindTint = state.getBehindTint();
         mCurrentInFrontAlpha = state.getFrontAlpha();
         mCurrentBehindAlpha = state.getBehindAlpha();
+        if (isNaN(mCurrentBehindAlpha) || isNaN(mCurrentInFrontAlpha)) {
+            throw new IllegalStateException("Scrim opacity is NaN for state: " + state + ", front: "
+                    + mCurrentInFrontAlpha + ", back: " + mCurrentBehindAlpha);
+        }
         applyExpansionToAlpha();
 
         // Scrim might acquire focus when user is navigating with a D-pad or a keyboard.
@@ -390,6 +396,9 @@
      * @param fraction From 0 to 1 where 0 means collapsed and 1 expanded.
      */
     public void setPanelExpansion(float fraction) {
+        if (isNaN(fraction)) {
+            throw new IllegalArgumentException("Fraction should not be NaN");
+        }
         if (mExpansionFraction != fraction) {
             mExpansionFraction = fraction;
 
@@ -464,6 +473,10 @@
             mCurrentBehindTint = ColorUtils.blendARGB(ScrimState.BOUNCER.getBehindTint(),
                     mState.getBehindTint(), interpolatedFract);
         }
+        if (isNaN(mCurrentBehindAlpha) || isNaN(mCurrentInFrontAlpha)) {
+            throw new IllegalStateException("Scrim opacity is NaN for state: " + mState
+                    + ", front: " + mCurrentInFrontAlpha + ", back: " + mCurrentBehindAlpha);
+        }
     }
 
     /**
@@ -523,6 +536,10 @@
             float newBehindAlpha = mState.getBehindAlpha();
             if (mCurrentBehindAlpha != newBehindAlpha) {
                 mCurrentBehindAlpha = newBehindAlpha;
+                if (isNaN(mCurrentBehindAlpha)) {
+                    throw new IllegalStateException("Scrim opacity is NaN for state: " + mState
+                            + ", back: " + mCurrentBehindAlpha);
+                }
                 updateScrims();
             }
         }
@@ -903,7 +920,9 @@
         pw.print(" alpha="); pw.print(mCurrentBehindAlpha);
         pw.print(" tint=0x"); pw.println(Integer.toHexString(mScrimBehind.getTint()));
 
-        pw.print("   mTracking="); pw.println(mTracking);
+        pw.print("  mTracking="); pw.println(mTracking);
+
+        pw.print("  mExpansionFraction="); pw.println(mExpansionFraction);
     }
 
     public void setWallpaperSupportsAmbientMode(boolean wallpaperSupportsAmbientMode) {
@@ -950,6 +969,10 @@
         // in this case, back-scrim needs to be re-evaluated
         if (mState == ScrimState.AOD || mState == ScrimState.PULSING) {
             float newBehindAlpha = mState.getBehindAlpha();
+            if (isNaN(newBehindAlpha)) {
+                throw new IllegalStateException("Scrim opacity is NaN for state: " + mState
+                        + ", back: " + mCurrentBehindAlpha);
+            }
             if (mCurrentBehindAlpha != newBehindAlpha) {
                 mCurrentBehindAlpha = newBehindAlpha;
                 updateScrims();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
index 0e5c8c1..0a6cf7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
@@ -24,7 +24,11 @@
  */
 public interface ConfigurationController extends CallbackController<ConfigurationListener> {
 
-    public void notifyThemeChanged();
+    /** Alert controller of a change in the configuration. */
+    void onConfigurationChanged(Configuration newConfiguration);
+
+    /** Alert controller of a change in between light and dark themes. */
+    void notifyThemeChanged();
 
     interface ConfigurationListener {
         default void onConfigChanged(Configuration newConfig) {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 7a09455..2ad5a8a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -61,7 +61,6 @@
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.settingslib.net.DataUsageController;
-import com.android.systemui.ConfigurationChangedReceiver;
 import com.android.systemui.DemoMode;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
@@ -87,8 +86,7 @@
 /** Platform implementation of the network controller. **/
 @Singleton
 public class NetworkControllerImpl extends BroadcastReceiver
-        implements NetworkController, DemoMode, DataUsageController.NetworkNameProvider,
-        ConfigurationChangedReceiver, Dumpable {
+        implements NetworkController, DemoMode, DataUsageController.NetworkNameProvider, Dumpable {
     // debug
     static final String TAG = "NetworkController";
     static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -166,6 +164,14 @@
     private boolean mUserSetup;
     private boolean mSimDetected;
 
+    private ConfigurationController.ConfigurationListener mConfigurationListener =
+            new ConfigurationController.ConfigurationListener() {
+                @Override
+                public void onConfigChanged(Configuration newConfig) {
+                    mConfig = Config.readConfig(mContext);
+                    mReceiverHandler.post(() -> handleConfigurationChanged());
+                }
+            };
     /**
      * Construct this controller object and register for updates.
      */
@@ -553,16 +559,6 @@
         }
     }
 
-    public void onConfigurationChanged(Configuration newConfig) {
-        mConfig = Config.readConfig(mContext);
-        mReceiverHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                handleConfigurationChanged();
-            }
-        });
-    }
-
     @VisibleForTesting
     void handleConfigurationChanged() {
         updateMobileControllers();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
index b9d09ce..420acc5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
@@ -36,8 +36,6 @@
 public class DependencyTest extends SysuiTestCase {
 
     public static final DependencyKey<Dumpable> DUMPABLE = new DependencyKey<>("dumpable");
-    public static final DependencyKey<ConfigurationChangedReceiver> CONFIGURATION_CHANGED_RECEIVER
-            = new DependencyKey<>("config_changed_receiver");
 
     @Test
     public void testClassDependency() {
@@ -63,15 +61,6 @@
     }
 
     @Test
-    public void testConfigurationChanged() {
-        ConfigurationChangedReceiver d = mock(ConfigurationChangedReceiver.class);
-        mDependency.injectTestDependency(CONFIGURATION_CHANGED_RECEIVER, d);
-        Dependency.get(CONFIGURATION_CHANGED_RECEIVER);
-        mDependency.onConfigurationChanged(null);
-        verify(d).onConfigurationChanged(eq(null));
-    }
-
-    @Test
     public void testInitDependency() {
         Dependency.clearDependencies();
         Dependency.initDependencies(SystemUIFactory.getInstance().getRootComponent());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeConfigurationController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeConfigurationController.java
index 5ddf7a2..f5ccac3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeConfigurationController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeConfigurationController.java
@@ -14,6 +14,8 @@
 
 package com.android.systemui.utils.leaks;
 
+import android.content.res.Configuration;
+
 import com.android.systemui.statusbar.policy.ConfigurationController;
 
 public class FakeConfigurationController
@@ -25,6 +27,10 @@
     }
 
     @Override
+    public void onConfigurationChanged(Configuration newConfiguration) {
+    }
+
+    @Override
     public void notifyThemeChanged() {
     }
 }
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index 353a187..03495d2 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -635,6 +635,66 @@
     ROUTER_TECH_OTHER = 6;
   }
 
+  enum EapMethod {
+
+    // No EAP method used
+    TYPE_EAP_UNKNOWN = 0;
+
+    // EAP with Transport Layer Security
+    TYPE_EAP_TLS = 1;
+
+    // EAP with Tunneled Transport Layer Security
+    TYPE_EAP_TTLS = 2;
+
+    // EAP with Subscriber Identity Module [RFC-4186]
+    TYPE_EAP_SIM = 3;
+
+    // EAP with Authentication and Key Agreement [RFC-4187]
+    TYPE_EAP_AKA = 4;
+
+    // EAP with Authentication and Key Agreement Prime [RFC-5448]
+    TYPE_EAP_AKA_PRIME = 5;
+
+    // Protected EAP
+    TYPE_EAP_PEAP = 6;
+
+    // EAP for Hotspot 2.0 r2 OSEN
+    TYPE_EAP_UNAUTH_TLS = 7;
+
+    // EAP with Password
+    TYPE_EAP_PWD = 8;
+
+    // EAP with WAPI certifcate
+    TYPE_EAP_WAPI_CERT = 9;
+  }
+
+  enum AuthPhase2Method {
+
+    // No phase2 method
+    TYPE_PHASE2_NONE = 0;
+
+    // Password Authentication Protocol
+    TYPE_PHASE2_PAP = 1;
+
+    // Microsoft Challenge Handshake Authentication Protocol
+    TYPE_PHASE2_MSCHAP = 2;
+
+    // Microsoft Challenge Handshake Authentication Protocol v2
+    TYPE_PHASE2_MSCHAPV2 = 3;
+
+    // Generic Token Card
+    TYPE_PHASE2_GTC = 4;
+
+    // EAP-Subscriber Identity Module [RFC-4186]
+    TYPE_PHASE2_SIM = 5;
+
+    // EAP-Authentication and Key Agreement [RFC-4187]
+    TYPE_PHASE2_AKA = 6;
+
+    // EAP-Authentication and Key Agreement Prime [RFC-5448]
+    TYPE_PHASE2_AKA_PRIME   = 7;
+  }
+
   optional RoamType roam_type = 1;
 
   // Channel on which the connection takes place.
@@ -657,6 +717,12 @@
 
   // If the router is a passpoint / hotspot 2.0 network
   optional bool passpoint = 8;
+
+  // EAP method used by the enterprise network
+  optional EapMethod eap_method = 9;
+
+  // Phase 2 authentication method after setting up a secure channel
+  optional AuthPhase2Method auth_phase2_method = 10;
 }
 
 message ConnectionEvent {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 3a5d4bc..d7bb4c0 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1041,6 +1041,27 @@
             }
         }
 
+        // Restore capture policies
+        synchronized (mPlaybackMonitor) {
+            HashMap<Integer, Integer> allowedCapturePolicies =
+                    mPlaybackMonitor.getAllAllowedCapturePolicies();
+            for (HashMap.Entry<Integer, Integer> entry : allowedCapturePolicies.entrySet()) {
+                int result = AudioSystem.setAllowedCapturePolicy(
+                        entry.getKey(),
+                        AudioAttributes.capturePolicyToFlags(entry.getValue(), 0x0));
+                if (result != AudioSystem.AUDIO_STATUS_OK) {
+                    Log.e(TAG, "Failed to restore capture policy, uid: "
+                            + entry.getKey() + ", capture policy: " + entry.getValue()
+                            + ", result: " + result);
+                    // When restoring capture policy failed, set the capture policy as
+                    // ALLOW_CAPTURE_BY_ALL, which will result in removing the cached
+                    // capture policy in PlaybackActivityMonitor.
+                    mPlaybackMonitor.setAllowedCapturePolicy(
+                            entry.getKey(), AudioAttributes.ALLOW_CAPTURE_BY_ALL);
+                }
+            }
+        }
+
         onIndicateSystemReady();
         // indicate the end of reconfiguration phase to audio HAL
         AudioSystem.setParameters("restarting=false");
@@ -7250,6 +7271,43 @@
         mPlaybackMonitor.releasePlayer(piid, Binder.getCallingUid());
     }
 
+    /**
+     * Specifies whether the audio played by this app may or may not be captured by other apps or
+     * the system.
+     *
+     * @param capturePolicy one of
+     *     {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL},
+     *     {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM},
+     *     {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}.
+     * @return AudioSystem.AUDIO_STATUS_OK if set allowed capture policy succeed.
+     * @throws IllegalArgumentException if the argument is not a valid value.
+     */
+    public int setAllowedCapturePolicy(int capturePolicy) {
+        int callingUid = Binder.getCallingUid();
+        int flags = AudioAttributes.capturePolicyToFlags(capturePolicy, 0x0);
+        final long identity = Binder.clearCallingIdentity();
+        synchronized (mPlaybackMonitor) {
+            int result = AudioSystem.setAllowedCapturePolicy(callingUid, flags);
+            if (result == AudioSystem.AUDIO_STATUS_OK) {
+                mPlaybackMonitor.setAllowedCapturePolicy(callingUid, capturePolicy);
+            }
+            Binder.restoreCallingIdentity(identity);
+            return result;
+        }
+    }
+
+    /**
+     * Return the capture policy.
+     * @return the cached capture policy for the calling uid.
+     */
+    public int getAllowedCapturePolicy() {
+        int callingUid = Binder.getCallingUid();
+        final long identity = Binder.clearCallingIdentity();
+        int capturePolicy = mPlaybackMonitor.getAllowedCapturePolicy(callingUid);
+        Binder.restoreCallingIdentity(identity);
+        return capturePolicy;
+    }
+
     //======================
     // Audio device management
     //======================
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index 3a25d98..93ffe83 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -160,6 +160,12 @@
                 new AudioPlaybackConfiguration(pic, newPiid,
                         Binder.getCallingUid(), Binder.getCallingPid());
         apc.init();
+        synchronized (mAllowedCapturePolicies) {
+            int uid = apc.getClientUid();
+            if (mAllowedCapturePolicies.containsKey(uid)) {
+                updateAllowedCapturePolicy(apc, mAllowedCapturePolicies.get(uid));
+            }
+        }
         sEventLogger.log(new NewPlayerEvent(apc));
         synchronized(mPlayerLock) {
             mPlayers.put(newPiid, apc);
@@ -169,6 +175,13 @@
 
     public void playerAttributes(int piid, @NonNull AudioAttributes attr, int binderUid) {
         final boolean change;
+        synchronized (mAllowedCapturePolicies) {
+            if (mAllowedCapturePolicies.containsKey(binderUid)
+                    && attr.getAllowedCapturePolicy() < mAllowedCapturePolicies.get(binderUid)) {
+                attr = new AudioAttributes.Builder(attr)
+                        .setAllowedCapturePolicy(mAllowedCapturePolicies.get(binderUid)).build();
+            }
+        }
         synchronized(mPlayerLock) {
             final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
             if (checkConfigurationCaller(piid, apc, binderUid)) {
@@ -284,6 +297,69 @@
         }
     }
 
+    /**
+     * A map of uid to capture policy.
+     */
+    private final HashMap<Integer, Integer> mAllowedCapturePolicies =
+            new HashMap<Integer, Integer>();
+
+    /**
+     * Cache allowed capture policy, which specifies whether the audio played by the app may or may
+     * not be captured by other apps or the system.
+     *
+     * @param uid the uid of requested app
+     * @param capturePolicy one of
+     *     {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL},
+     *     {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM},
+     *     {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}.
+     */
+    public void setAllowedCapturePolicy(int uid, int capturePolicy) {
+        synchronized (mAllowedCapturePolicies) {
+            if (capturePolicy == AudioAttributes.ALLOW_CAPTURE_BY_ALL) {
+                // When the capture policy is ALLOW_CAPTURE_BY_ALL, it is okay to
+                // remove it from cached capture policy as it is the default value.
+                mAllowedCapturePolicies.remove(uid);
+                return;
+            } else {
+                mAllowedCapturePolicies.put(uid, capturePolicy);
+            }
+        }
+        synchronized (mPlayerLock) {
+            for (AudioPlaybackConfiguration apc : mPlayers.values()) {
+                if (apc.getClientUid() == uid) {
+                    updateAllowedCapturePolicy(apc, capturePolicy);
+                }
+            }
+        }
+    }
+
+    /**
+     * Return the capture policy for given uid.
+     * @param uid the uid to query its cached capture policy.
+     * @return cached capture policy for given uid or AudioAttributes.ALLOW_CAPTURE_BY_ALL
+     *         if there is not cached capture policy.
+     */
+    public int getAllowedCapturePolicy(int uid) {
+        return mAllowedCapturePolicies.getOrDefault(uid, AudioAttributes.ALLOW_CAPTURE_BY_ALL);
+    }
+
+    /**
+     * Return all cached capture policies.
+     */
+    public HashMap<Integer, Integer> getAllAllowedCapturePolicies() {
+        return mAllowedCapturePolicies;
+    }
+
+    private void updateAllowedCapturePolicy(AudioPlaybackConfiguration apc, int capturePolicy) {
+        AudioAttributes attr = apc.getAudioAttributes();
+        if (attr.getAllowedCapturePolicy() >= capturePolicy) {
+            return;
+        }
+        apc.handleAudioAttributesEvent(
+                new AudioAttributes.Builder(apc.getAudioAttributes())
+                        .setAllowedCapturePolicy(capturePolicy).build());
+    }
+
     // Implementation of AudioPlaybackConfiguration.PlayerDeathMonitor
     @Override
     public void playerDeath(int piid) {
@@ -331,6 +407,12 @@
             // log
             sEventLogger.dump(pw);
         }
+        synchronized (mAllowedCapturePolicies) {
+            pw.println("\n  allowed capture policies:");
+            for (HashMap.Entry<Integer, Integer> entry : mAllowedCapturePolicies.entrySet()) {
+                pw.println("  uid: " + entry.getKey() + " policy: " + entry.getValue());
+            }
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c4acff4..5011168 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -21260,6 +21260,11 @@
         long token = Binder.clearCallingIdentity();
         try {
             if (getPackageInfo(packageName, MATCH_FACTORY_ONLY, UserHandle.USER_SYSTEM) == null) {
+                PackageInfo packageInfo = getPackageInfo(packageName, 0, UserHandle.USER_SYSTEM);
+                if (packageInfo != null) {
+                    EventLog.writeEvent(0x534e4554, "145981139", packageInfo.applicationInfo.uid,
+                            "");
+                }
                 return null;
             }
         } finally {
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index f78d263..add0b01 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -19,8 +19,6 @@
 import android.app.ActivityManager;
 import android.content.Context;
 import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.security.keystore.IKeystoreService;
 import android.util.Slog;
 
 import com.android.internal.policy.IKeyguardService;
@@ -53,16 +51,11 @@
     private final LockPatternUtils mLockPatternUtils;
     private final StateCallback mCallback;
 
-    IKeystoreService mKeystoreService;
-
     public KeyguardStateMonitor(Context context, IKeyguardService service, StateCallback callback) {
         mLockPatternUtils = new LockPatternUtils(context);
         mCurrentUserId = ActivityManager.getCurrentUser();
         mCallback = callback;
 
-        mKeystoreService = IKeystoreService.Stub.asInterface(ServiceManager
-                .getService("android.security.keystore"));
-
         try {
             service.addStateMonitorCallback(this);
         } catch (RemoteException e) {
@@ -95,23 +88,6 @@
         mIsShowing = showing;
 
         mCallback.onShowingChanged();
-        int retry = 2;
-        while (retry > 0) {
-            try {
-                mKeystoreService.onKeyguardVisibilityChanged(showing, mCurrentUserId);
-                break;
-            } catch (RemoteException e) {
-                if (retry == 2) {
-                    Slog.w(TAG, "Error informing keystore of screen lock. Keystore may have died"
-                            + " -> refreshing service token and retrying");
-                    mKeystoreService = IKeystoreService.Stub.asInterface(ServiceManager
-                            .getService("android.security.keystore"));
-                } else {
-                    Slog.e(TAG, "Error informing keystore of screen lock after retrying once", e);
-                }
-                --retry;
-            }
-        }
     }
 
     @Override // Binder interface
@@ -123,10 +99,6 @@
         mCurrentUserId = userId;
     }
 
-    private synchronized int getCurrentUser() {
-        return mCurrentUserId;
-    }
-
     @Override // Binder interface
     public void onInputRestrictedStateChanged(boolean inputRestricted) {
         mInputRestricted = inputRestricted;
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index ef54d04..2394baf 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -53,6 +53,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.security.KeyStore;
 import android.service.trust.TrustAgentService;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -135,6 +136,33 @@
     @GuardedBy("mUserIsTrusted")
     private final SparseBooleanArray mUserIsTrusted = new SparseBooleanArray();
 
+    /**
+     * Stores the locked state for users on the device. There are three different type of users
+     * which are handled slightly differently:
+     * <ul>
+     *  <li> Users with real keyguard
+     *  These are users who can be switched to ({@link UserInfo#supportsSwitchToByUser()}). Their
+     *  locked state is derived by a combination of user secure state, keyguard state, trust agent
+     *  decision and biometric authentication result. These are updated via
+     *  {@link #refreshDeviceLockedForUser(int)} and result stored in {@link #mDeviceLockedForUser}.
+     *  <li> Managed profiles with unified challenge
+     *  Managed profile with unified challenge always shares the same locked state as their parent,
+     *  so their locked state is not recorded in  {@link #mDeviceLockedForUser}. Instead,
+     *  {@link ITrustManager#isDeviceLocked(int)} always resolves their parent user handle and
+     *  queries its locked state instead.
+     *  <li> Managed profiles with separate challenge
+     *  Locked state for profile with separate challenge is determined by other parts of the
+     *  framework (mostly PowerManager) and pushed to TrustManagerService via
+     *  {@link ITrustManager#setDeviceLockedForUser(int, boolean)}. Although in a corner case when
+     *  the profile has a separate but empty challenge, setting its {@link #mDeviceLockedForUser} to
+     *  {@code false} is actually done by {@link #refreshDeviceLockedForUser(int)}.
+     * </ul>
+     * TODO: Rename {@link ITrustManager#setDeviceLockedForUser(int, boolean)} to
+     * {@code setDeviceLockedForProfile} to better reflect its purpose. Unifying
+     * {@code setDeviceLockedForProfile} and {@link #setDeviceLockedForUser} would also be nice.
+     * At the moment they both update {@link #mDeviceLockedForUser} but have slightly different
+     * side-effects: one notifies trust agents while the other sends out a broadcast.
+     */
     @GuardedBy("mDeviceLockedForUser")
     private final SparseBooleanArray mDeviceLockedForUser = new SparseBooleanArray();
 
@@ -601,6 +629,10 @@
         }
     }
 
+    /**
+     * Update the user's locked state. Only applicable to users with a real keyguard
+     * ({@link UserInfo#supportsSwitchToByUser}) and unsecured managed profiles.
+     */
     private void refreshDeviceLockedForUser(int userId) {
         if (userId != UserHandle.USER_ALL && userId < UserHandle.USER_SYSTEM) {
             Log.e(TAG, "refreshDeviceLockedForUser(userId=" + userId + "): Invalid user handle,"
@@ -661,6 +693,15 @@
         }
         if (changed) {
             dispatchDeviceLocked(userId, locked);
+
+            KeyStore.getInstance().onUserLockedStateChanged(userId, locked);
+            // Also update the user's profiles who have unified challenge, since they
+            // share the same unlocked state (see {@link #isDeviceLocked(int)})
+            for (int profileHandle : mUserManager.getEnabledProfileIds(userId)) {
+                if (mLockPatternUtils.isManagedProfileWithUnifiedChallenge(profileHandle)) {
+                    KeyStore.getInstance().onUserLockedStateChanged(profileHandle, locked);
+                }
+            }
         }
     }
 
@@ -1194,6 +1235,10 @@
             return "0x" + Integer.toHexString(i);
         }
 
+        /**
+         * Changes the lock status for the given user. This is only applicable to managed profiles,
+         * other users should be handled by Keyguard.
+         */
         @Override
         public void setDeviceLockedForUser(int userId, boolean locked) {
             enforceReportPermission();
@@ -1204,6 +1249,9 @@
                     synchronized (mDeviceLockedForUser) {
                         mDeviceLockedForUser.put(userId, locked);
                     }
+
+                    KeyStore.getInstance().onUserLockedStateChanged(userId, locked);
+
                     if (locked) {
                         try {
                             ActivityManager.getService().notifyLockedProfile(userId);
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index ed41642..88f2bb2 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -2113,15 +2113,23 @@
                 throw new IllegalStateException("Not an EAP network");
             }
 
-            return trimStringForKeyId(SSID) + "_" + keyMgmt + "_" +
-                    trimStringForKeyId(enterpriseConfig.getKeyId(current != null ?
-                            current.enterpriseConfig : null));
+            String keyId = trimStringForKeyId(SSID) + "_" + keyMgmt + "_"
+                    + trimStringForKeyId(enterpriseConfig.getKeyId(current != null
+                    ? current.enterpriseConfig : null));
+
+            if (!fromWifiNetworkSuggestion) {
+                return keyId;
+            }
+            return keyId + "_" + trimStringForKeyId(BSSID) + "_" + trimStringForKeyId(creatorName);
         } catch (NullPointerException e) {
             throw new IllegalStateException("Invalid config details");
         }
     }
 
     private String trimStringForKeyId(String string) {
+        if (string == null) {
+            return "";
+        }
         // Remove quotes and spaces
         return string.replace("\"", "").replace(" ", "");
     }
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index ba9fc78..f56cdc3 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -350,6 +350,67 @@
     }
 
     /**
+     * Verifies that getKeyIdForCredentials returns the expected string for Suggestion Enterprise
+     * networks
+     * @throws Exception
+     */
+    @Test
+    public void testGetKeyIdForCredentialsForSuggestion() throws Exception {
+        WifiConfiguration config = new WifiConfiguration();
+        final String mSsid = "TestAP";
+        final String packageName = "TestApp";
+        final String bSsid = MacAddress.createRandomUnicastAddress().toString();
+        String suggestionSuffix = "_" + bSsid + "_" + packageName;
+        config.SSID = mSsid;
+        config.fromWifiNetworkSuggestion = true;
+        config.creatorName = packageName;
+        config.BSSID = bSsid;
+
+        // Test various combinations
+        // EAP with TLS
+        config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
+        config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
+        config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.NONE);
+        String keyId = config.getKeyIdForCredentials(config);
+        assertEquals(keyId, mSsid + "_WPA_EAP_TLS_NULL" + suggestionSuffix);
+
+        // EAP with TTLS & MSCHAPv2
+        config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
+        config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TTLS);
+        config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.MSCHAPV2);
+        keyId = config.getKeyIdForCredentials(config);
+        assertEquals(keyId, mSsid + "_WPA_EAP_TTLS_MSCHAPV2" + suggestionSuffix);
+
+        // Suite-B 192 with PWD & GTC
+        config.allowedKeyManagement.clear();
+        config.allowedKeyManagement.set(KeyMgmt.SUITE_B_192);
+        config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.PWD);
+        config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.GTC);
+        keyId = config.getKeyIdForCredentials(config);
+        assertEquals(keyId, mSsid + "_SUITE_B_192_PWD_GTC" + suggestionSuffix);
+
+        // IEEE8021X with SIM
+        config.allowedKeyManagement.clear();
+        config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
+        config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.SIM);
+        config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.NONE);
+        keyId = config.getKeyIdForCredentials(config);
+        assertEquals(keyId, mSsid + "_IEEE8021X_SIM_NULL" + suggestionSuffix);
+
+        // Try calling this method with non-Enterprise network, expect an exception
+        boolean exceptionThrown = false;
+        try {
+            config.allowedKeyManagement.clear();
+            config.allowedKeyManagement.set(KeyMgmt.WPA2_PSK);
+            config.preSharedKey = "TestPsk";
+            keyId = config.getKeyIdForCredentials(config);
+        } catch (IllegalStateException e) {
+            exceptionThrown = true;
+        }
+        assertTrue(exceptionThrown);
+    }
+
+    /**
      * Verifies that getSsidAndSecurityTypeString returns the correct String for networks of
      * various different security types
      */