Merge "GM2 icon updates" into pi-dev
diff --git a/Android.mk b/Android.mk
index ccf3894..66c9529 100644
--- a/Android.mk
+++ b/Android.mk
@@ -945,21 +945,21 @@
 	$(call assert-is-subset,$@,$(LOCAL_SRC_PRIVATE_API))
 	$(call assert-has-no-overlap,$@,$(LOCAL_SRC_FORCE_BLACKLIST))
 
-# Generate dark greylist as remaining members of classes on the light greylist,
-# as well as the members of their inner classes.
+# Generate dark greylist as remaining classes and class members in the same
+# package as classes listed in the light greylist.
 # The algorithm is as follows:
 #   (1) extract the class descriptor from each entry in LOCAL_LIGHT_GREYLIST
-#   (2) strip the final semicolon and anything after (and including) a dollar sign,
-#       e.g. 'Lpackage/class$inner;' turns into 'Lpackage/class'
-#   (3) insert all entries from LOCAL_SRC_PRIVATE_API which begin with the stripped
-#       descriptor followed by a semi-colon or a dollar sign, e.g. matching a regex
-#       '^Lpackage/class[;$]'
+#   (2) strip everything after the last forward-slash,
+#       e.g. 'Lpackage/subpackage/class$inner;' turns into 'Lpackage/subpackage/'
+#   (3) insert all entries from LOCAL_SRC_PRIVATE_API which begin with the package
+#       name but do not contain another forward-slash in the class name, e.g.
+#       matching '^Lpackage/subpackage/[^/;]*;'
 #   (4) subtract entries shared with LOCAL_LIGHT_GREYLIST
 $(LOCAL_DARK_GREYLIST): $(LOCAL_SRC_ALL) $(LOCAL_LIGHT_GREYLIST)
 	comm -13 <(sort $(LOCAL_LIGHT_GREYLIST) $(LOCAL_SRC_FORCE_BLACKLIST)) \
-	         <(sed 's/;\->.*//' $(LOCAL_LIGHT_GREYLIST) | sed 's/$$.*//' | sort | uniq | \
-	               while read CLASS_DESC; do \
-	                   grep -E "^$${CLASS_DESC}[;$$]" $(LOCAL_SRC_PRIVATE_API); \
+	         <(sed 's/\->.*//' $(LOCAL_LIGHT_GREYLIST) | sed 's/\(.*\/\).*/\1/' | sort | uniq | \
+	               while read PKG_NAME; do \
+	                   grep -E "^$${PKG_NAME}[^/;]*;" $(LOCAL_SRC_PRIVATE_API); \
 	               done | sort | uniq) \
 	         > $@
 	$(call assert-is-subset,$@,$(LOCAL_SRC_PRIVATE_API))
@@ -988,4 +988,3 @@
 endif
 
 endif # ANDROID_BUILD_EMBEDDED
-
diff --git a/config/hiddenapi-force-blacklist.txt b/config/hiddenapi-force-blacklist.txt
index 2a10f77..0c689e8 100644
--- a/config/hiddenapi-force-blacklist.txt
+++ b/config/hiddenapi-force-blacklist.txt
@@ -1 +1,37 @@
 Ldalvik/system/VMRuntime;->setHiddenApiExemptions([Ljava/lang/String;)V
+Ljava/lang/invoke/VarHandle;->acquireFence()V
+Ljava/lang/invoke/VarHandle;->compareAndExchange([[Ljava/lang/Object;)Ljava/lang/Object;
+Ljava/lang/invoke/VarHandle;->compareAndExchangeAcquire([[Ljava/lang/Object;)Ljava/lang/Object;
+Ljava/lang/invoke/VarHandle;->compareAndExchangeRelease([[Ljava/lang/Object;)Ljava/lang/Object;
+Ljava/lang/invoke/VarHandle;->compareAndSet([[Ljava/lang/Object;)Z
+Ljava/lang/invoke/VarHandle;->fullFence()V
+Ljava/lang/invoke/VarHandle;->get([[Ljava/lang/Object;)Ljava/lang/Object;
+Ljava/lang/invoke/VarHandle;->getAcquire([[Ljava/lang/Object;)Ljava/lang/Object;
+Ljava/lang/invoke/VarHandle;->getAndAdd([[Ljava/lang/Object;)Ljava/lang/Object;
+Ljava/lang/invoke/VarHandle;->getAndAddAcquire([[Ljava/lang/Object;)Ljava/lang/Object;
+Ljava/lang/invoke/VarHandle;->getAndAddRelease([[Ljava/lang/Object;)Ljava/lang/Object;
+Ljava/lang/invoke/VarHandle;->getAndBitwiseAnd([[Ljava/lang/Object;)Ljava/lang/Object;
+Ljava/lang/invoke/VarHandle;->getAndBitwiseAndAcquire([[Ljava/lang/Object;)Ljava/lang/Object;
+Ljava/lang/invoke/VarHandle;->getAndBitwiseAndRelease([[Ljava/lang/Object;)Ljava/lang/Object;
+Ljava/lang/invoke/VarHandle;->getAndBitwiseOr([[Ljava/lang/Object;)Ljava/lang/Object;
+Ljava/lang/invoke/VarHandle;->getAndBitwiseOrAcquire([[Ljava/lang/Object;)Ljava/lang/Object;
+Ljava/lang/invoke/VarHandle;->getAndBitwiseOrRelease([[Ljava/lang/Object;)Ljava/lang/Object;
+Ljava/lang/invoke/VarHandle;->getAndBitwiseXor([[Ljava/lang/Object;)Ljava/lang/Object;
+Ljava/lang/invoke/VarHandle;->getAndBitwiseXorAcquire([[Ljava/lang/Object;)Ljava/lang/Object;
+Ljava/lang/invoke/VarHandle;->getAndBitwiseXorRelease([[Ljava/lang/Object;)Ljava/lang/Object;
+Ljava/lang/invoke/VarHandle;->getAndSet([[Ljava/lang/Object;)Ljava/lang/Object;
+Ljava/lang/invoke/VarHandle;->getAndSetAcquire([[Ljava/lang/Object;)Ljava/lang/Object;
+Ljava/lang/invoke/VarHandle;->getAndSetRelease([[Ljava/lang/Object;)Ljava/lang/Object;
+Ljava/lang/invoke/VarHandle;->getOpaque([[Ljava/lang/Object;)Ljava/lang/Object;
+Ljava/lang/invoke/VarHandle;->getVolatile([[Ljava/lang/Object;)Ljava/lang/Object;
+Ljava/lang/invoke/VarHandle;->loadLoadFence()V
+Ljava/lang/invoke/VarHandle;->releaseFence()V
+Ljava/lang/invoke/VarHandle;->set([[Ljava/lang/Object;)V
+Ljava/lang/invoke/VarHandle;->setOpaque([[Ljava/lang/Object;)V
+Ljava/lang/invoke/VarHandle;->setRelease([[Ljava/lang/Object;)V
+Ljava/lang/invoke/VarHandle;->setVolatile([[Ljava/lang/Object;)V
+Ljava/lang/invoke/VarHandle;->storeStoreFence()V
+Ljava/lang/invoke/VarHandle;->weakCompareAndSet([[Ljava/lang/Object;)Z
+Ljava/lang/invoke/VarHandle;->weakCompareAndSetAcquire([[Ljava/lang/Object;)Z
+Ljava/lang/invoke/VarHandle;->weakCompareAndSetPlain([[Ljava/lang/Object;)Z
+Ljava/lang/invoke/VarHandle;->weakCompareAndSetRelease([[Ljava/lang/Object;)Z
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index e47a1cf..b9ead8b 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -376,6 +376,7 @@
 Landroid/app/AppOpsManager;->OP_AUDIO_RING_VOLUME:I
 Landroid/app/AppOpsManager;->OP_AUDIO_VOICE_VOLUME:I
 Landroid/app/AppOpsManager;->OP_BIND_ACCESSIBILITY_SERVICE:I
+Landroid/app/AppOpsManager;->OP_BLUETOOTH_SCAN:I
 Landroid/app/AppOpsManager;->OP_BODY_SENSORS:I
 Landroid/app/AppOpsManager;->OP_CALL_PHONE:I
 Landroid/app/AppOpsManager;->OP_CAMERA:I
@@ -634,6 +635,7 @@
 Landroid/app/IActivityManager;->unregisterProcessObserver(Landroid/app/IProcessObserver;)V
 Landroid/app/IActivityManager;->unregisterReceiver(Landroid/content/IIntentReceiver;)V
 Landroid/app/IActivityManager;->unstableProviderDied(Landroid/os/IBinder;)V
+Landroid/app/IActivityManager;->updateConfiguration(Landroid/content/res/Configuration;)Z
 Landroid/app/IActivityManager;->updatePersistentConfiguration(Landroid/content/res/Configuration;)V
 Landroid/app/IAlarmManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/app/IAlarmManager$Stub;-><init>()V
@@ -654,6 +656,7 @@
 Landroid/app/IApplicationThread;->updateTimeZone()V
 Landroid/app/IAppTask;->getTaskInfo()Landroid/app/ActivityManager$RecentTaskInfo;
 Landroid/app/IBackupAgent$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/IBackupAgent;
+Landroid/app/IInputForwarder;->forwardEvent(Landroid/view/InputEvent;)Z
 Landroid/app/IInstrumentationWatcher$Stub;-><init>()V
 Landroid/app/IInstrumentationWatcher$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/IInstrumentationWatcher;
 Landroid/app/IInstrumentationWatcher;->instrumentationFinished(Landroid/content/ComponentName;ILandroid/os/Bundle;)V
@@ -2376,6 +2379,7 @@
 Landroid/hardware/input/IInputManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/input/IInputManager;
 Landroid/hardware/input/IInputManager$Stub;->TRANSACTION_injectInputEvent:I
 Landroid/hardware/input/IInputManager;->injectInputEvent(Landroid/view/InputEvent;I)Z
+Landroid/hardware/input/InputManager;->createInputForwarder(I)Landroid/app/IInputForwarder;
 Landroid/hardware/input/InputManager;->getInstance()Landroid/hardware/input/InputManager;
 Landroid/hardware/input/InputManager;->injectInputEvent(Landroid/view/InputEvent;I)Z
 Landroid/hardware/input/InputManager;->INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH:I
@@ -3958,6 +3962,7 @@
 Landroid/os/storage/StorageVolume;->allowMassStorage()Z
 Landroid/os/storage/StorageVolume;->getFatVolumeId()I
 Landroid/os/storage/StorageVolume;->getMaxFileSize()J
+Landroid/os/storage/StorageVolume;->getOwner()Landroid/os/UserHandle;
 Landroid/os/storage/StorageVolume;->getPath()Ljava/lang/String;
 Landroid/os/storage/StorageVolume;->getPathFile()Ljava/io/File;
 Landroid/os/storage/StorageVolume;->getUserLabel()Ljava/lang/String;
@@ -4916,6 +4921,7 @@
 Landroid/telecom/TelecomManager;->TTY_MODE_OFF:I
 Landroid/telecom/VideoCallImpl;->destroy()V
 Landroid/telephony/CarrierConfigManager;->KEY_CARRIER_DEFAULT_ACTIONS_ON_REDIRECTION_STRING_ARRAY:Ljava/lang/String;
+Landroid/telephony/CarrierConfigManager;->KEY_DISABLE_VOICE_BARRING_NOTIFICATION_BOOL:Ljava/lang/String;
 Landroid/telephony/CarrierMessagingServiceManager;-><init>()V
 Landroid/telephony/CellBroadcastMessage;-><init>(Landroid/telephony/SmsCbMessage;)V
 Landroid/telephony/CellBroadcastMessage;->createFromCursor(Landroid/database/Cursor;)Landroid/telephony/CellBroadcastMessage;
diff --git a/core/java/android/app/slice/SliceManager.java b/core/java/android/app/slice/SliceManager.java
index 22df6c0..f682ec1 100644
--- a/core/java/android/app/slice/SliceManager.java
+++ b/core/java/android/app/slice/SliceManager.java
@@ -23,6 +23,7 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemService;
+import android.annotation.WorkerThread;
 import android.content.ContentProviderClient;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -217,6 +218,7 @@
      * @return All slices within the space.
      * @see SliceProvider#onGetSliceDescendants(Uri)
      */
+    @WorkerThread
     public @NonNull Collection<Uri> getSliceDescendants(@NonNull Uri uri) {
         ContentResolver resolver = mContext.getContentResolver();
         try (ContentProviderClient provider = resolver.acquireContentProviderClient(uri)) {
diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java
index 9e4e97a..6c57d81 100644
--- a/core/java/android/app/slice/SliceProvider.java
+++ b/core/java/android/app/slice/SliceProvider.java
@@ -398,12 +398,7 @@
 
     private Collection<Uri> handleGetDescendants(Uri uri) {
         mCallback = "onGetSliceDescendants";
-        Handler.getMain().postDelayed(mAnr, SLICE_BIND_ANR);
-        try {
-            return onGetSliceDescendants(uri);
-        } finally {
-            Handler.getMain().removeCallbacks(mAnr);
-        }
+        return onGetSliceDescendants(uri);
     }
 
     private void handlePinSlice(Uri sliceUri) {
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 7fb97d3..1b05402 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -572,13 +572,14 @@
      * the sum of usages of apps in the packages array exceeds the {@code timeLimit} specified. The
      * observer will automatically be unregistered when the time limit is reached and the intent
      * is delivered. Registering an {@code observerId} that was already registered will override
-     * the previous one.
+     * the previous one. No more than 1000 unique {@code observerId} may be registered by a single
+     * uid at any one time.
      * @param observerId A unique id associated with the group of apps to be monitored. There can
      *                  be multiple groups with common packages and different time limits.
      * @param packages The list of packages to observe for foreground activity time. Cannot be null
      *                 and must include at least one package.
      * @param timeLimit The total time the set of apps can be in the foreground before the
-     *                  callbackIntent is delivered. Must be greater than 0.
+     *                  callbackIntent is delivered. Must be at least one minute.
      * @param timeUnit The unit for time specified in {@code timeLimit}. Cannot be null.
      * @param callbackIntent The PendingIntent that will be dispatched when the time limit is
      *                       exceeded by the group of apps. The delivered Intent will also contain
diff --git a/core/java/android/content/om/OverlayInfo.java b/core/java/android/content/om/OverlayInfo.java
index a10cc12..edacbb0 100644
--- a/core/java/android/content/om/OverlayInfo.java
+++ b/core/java/android/content/om/OverlayInfo.java
@@ -18,7 +18,6 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -39,6 +38,7 @@
             STATE_NO_IDMAP,
             STATE_DISABLED,
             STATE_ENABLED,
+            STATE_ENABLED_STATIC,
             STATE_TARGET_UPGRADING,
             STATE_OVERLAY_UPGRADING,
     })
@@ -91,7 +91,16 @@
     public static final int STATE_OVERLAY_UPGRADING = 5;
 
     /**
-     * Category for theme overlays.
+     * The overlay package is currently enabled because it is marked as
+     * 'static'. It cannot be disabled but will change state if for instance
+     * its target is uninstalled.
+     */
+    public static final int STATE_ENABLED_STATIC = 6;
+
+    /**
+     * Overlay category: theme.
+     * <p>
+     * Change how Android (including the status bar, dialogs, ...) looks.
      */
     public static final String CATEGORY_THEME = "android.theme";
 
@@ -126,6 +135,23 @@
     public final int userId;
 
     /**
+     * Priority as read from the manifest. Used if isStatic is true. Not
+     * intended to be exposed to 3rd party.
+     *
+     * @hide
+     */
+    public final int priority;
+
+    /**
+     * isStatic as read from the manifest. If true, the overlay is
+     * unconditionally loaded and cannot be unloaded. Not intended to be
+     * exposed to 3rd party.
+     *
+     * @hide
+     */
+    public final boolean isStatic;
+
+    /**
      * Create a new OverlayInfo based on source with an updated state.
      *
      * @param source the source OverlayInfo to base the new instance on
@@ -133,17 +159,20 @@
      */
     public OverlayInfo(@NonNull OverlayInfo source, @State int state) {
         this(source.packageName, source.targetPackageName, source.category, source.baseCodePath,
-                state, source.userId);
+                state, source.userId, source.priority, source.isStatic);
     }
 
     public OverlayInfo(@NonNull String packageName, @NonNull String targetPackageName,
-            @Nullable String category, @NonNull String baseCodePath, int state, int userId) {
+            @NonNull String category, @NonNull String baseCodePath, int state, int userId,
+            int priority, boolean isStatic) {
         this.packageName = packageName;
         this.targetPackageName = targetPackageName;
         this.category = category;
         this.baseCodePath = baseCodePath;
         this.state = state;
         this.userId = userId;
+        this.priority = priority;
+        this.isStatic = isStatic;
         ensureValidState();
     }
 
@@ -154,6 +183,8 @@
         baseCodePath = source.readString();
         state = source.readInt();
         userId = source.readInt();
+        priority = source.readInt();
+        isStatic = source.readBoolean();
         ensureValidState();
     }
 
@@ -173,6 +204,7 @@
             case STATE_NO_IDMAP:
             case STATE_DISABLED:
             case STATE_ENABLED:
+            case STATE_ENABLED_STATIC:
             case STATE_TARGET_UPGRADING:
             case STATE_OVERLAY_UPGRADING:
                 break;
@@ -194,6 +226,8 @@
         dest.writeString(baseCodePath);
         dest.writeInt(state);
         dest.writeInt(userId);
+        dest.writeInt(priority);
+        dest.writeBoolean(isStatic);
     }
 
     public static final Parcelable.Creator<OverlayInfo> CREATOR =
@@ -220,6 +254,7 @@
     public boolean isEnabled() {
         switch (state) {
             case STATE_ENABLED:
+            case STATE_ENABLED_STATIC:
                 return true;
             default:
                 return false;
@@ -244,6 +279,8 @@
                 return "STATE_DISABLED";
             case STATE_ENABLED:
                 return "STATE_ENABLED";
+            case STATE_ENABLED_STATIC:
+                return "STATE_ENABLED_STATIC";
             case STATE_TARGET_UPGRADING:
                 return "STATE_TARGET_UPGRADING";
             case STATE_OVERLAY_UPGRADING:
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 10ee728..29bbddc 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -12740,6 +12740,25 @@
         public static final String SHOW_ZEN_UPGRADE_NOTIFICATION = "show_zen_upgrade_notification";
 
         /**
+         * If nonzero, will show the zen update settings suggestion.
+         * @hide
+         */
+        public static final String SHOW_ZEN_SETTINGS_SUGGESTION = "show_zen_settings_suggestion";
+
+        /**
+         * If nonzero, zen has not been updated to reflect new changes.
+         * @hide
+         */
+        public static final String ZEN_SETTINGS_UPDATED = "zen_settings_updated";
+
+        /**
+         * If nonzero, zen setting suggestion has beem viewed by user
+         * @hide
+         */
+        public static final String ZEN_SETTINGS_SUGGESTION_VIEWED =
+                "zen_settings_suggestion_viewed";
+
+        /**
          * Backup and restore agent timeout parameters.
          * These parameters are represented by a comma-delimited key-value list.
          *
diff --git a/core/java/android/security/keystore/recovery/TrustedRootCertificates.java b/core/java/android/security/keystore/recovery/TrustedRootCertificates.java
index a96dab6..c5f82c1 100644
--- a/core/java/android/security/keystore/recovery/TrustedRootCertificates.java
+++ b/core/java/android/security/keystore/recovery/TrustedRootCertificates.java
@@ -73,34 +73,34 @@
             "INSECURE_PSWD_";
 
     private static final String GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_BASE64 = ""
-            + "MIIFJjCCAw6gAwIBAgIJAIobXsJlzhNdMA0GCSqGSIb3DQEBDQUAMCAxHjAcBgNV"
-            + "BAMMFUdvb2dsZSBDcnlwdEF1dGhWYXVsdDAeFw0xODAyMDIxOTM5MTRaFw0zODAx"
-            + "MjgxOTM5MTRaMCAxHjAcBgNVBAMMFUdvb2dsZSBDcnlwdEF1dGhWYXVsdDCCAiIw"
-            + "DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2OT5i40/H7LINg/lq/0G0hR65P"
-            + "Q4Mud3OnuVt6UIYV2T18+v6qW1yJd5FcnND/ZKPau4aUAYklqJuSVjOXQD0BjgS2"
-            + "98Xa4dSn8Ci1rUR+5tdmrxqbYUdT2ZvJIUMMR6fRoqi+LlAbKECrV+zYQTyLU68w"
-            + "V66hQpAButjJKiZzkXjmKLfJ5IWrNEn17XM988rk6qAQn/BYCCQGf3rQuJeksGmA"
-            + "N1lJOwNYxmWUyouVwqwZthNEWqTuEyBFMkAT+99PXW7oVDc7oU5cevuihxQWNTYq"
-            + "viGB8cck6RW3cmqrDSaJF/E+N0cXFKyYC7FDcggt6k3UrxNKTuySdDEa8+2RTQqU"
-            + "Y9npxBlQE+x9Ig56OI1BG3bSBsGdPgjpyHadZeh2tgk+oqlGsSsum24YxaxuSysT"
-            + "Qfcu/XhyfUXavfmGrBOXerTzIl5oBh/F5aHTV85M2tYEG0qsPPvSpZAWtdJ/2rca"
-            + "OxvhwOL+leZKr8McjXVR00lBsRuKXX4nTUMwya09CO3QHFPFZtZvqjy2HaMOnVLQ"
-            + "I6b6dHEfmsHybzVOe3yPEoFQSU9UhUdmi71kwwoanPD3j9fJHmXTx4PzYYBRf1ZE"
-            + "o+uPgMPk7CDKQFZLjnR40z1uzu3O8aZ3AKZzP+j7T4XQKJLQLmllKtPgLgNdJyib"
-            + "2Glg7QhXH/jBTL6hAgMBAAGjYzBhMB0GA1UdDgQWBBSbZfrqOYH54EJpkdKMZjMc"
-            + "z/Hp+DAfBgNVHSMEGDAWgBSbZfrqOYH54EJpkdKMZjMcz/Hp+DAPBgNVHRMBAf8E"
-            + "BTADAQH/MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQ0FAAOCAgEAKh9nm/vW"
-            + "glMWp3vcCwWwJW286ecREDlI+CjGh5h+f2N4QRrXd/tKE3qQJWCqGx8sFfIUjmI7"
-            + "KYdsC2gyQ2cA2zl0w7pB2QkuqE6zVbnh1D17Hwl19IMyAakFaM9ad4/EoH7oQmqX"
-            + "nF/f5QXGZw4kf1HcgKgoCHWXjqR8MqHOcXR8n6WFqxjzJf1jxzi6Yo2dZ7PJbnE6"
-            + "+kHIJuiCpiHL75v5g1HM41gT3ddFFSrn88ThNPWItT5Z8WpFjryVzank2Yt02LLl"
-            + "WqZg9IC375QULc5B58NMnaiVJIDJQ8zoNgj1yaxqtUMnJX570lotO2OXe4ec9aCQ"
-            + "DIJ84YLM/qStFdeZ9416E80dchskbDG04GuVJKlzWjxAQNMRFhyaPUSBTLLg+kwP"
-            + "t9+AMmc+A7xjtFQLZ9fBYHOBsndJOmeSQeYeckl+z/1WQf7DdwXn/yijon7mxz4z"
-            + "cCczfKwTJTwBh3wR5SQr2vQm7qaXM87qxF8PCAZrdZaw5I80QwkgTj0WTZ2/GdSw"
-            + "d3o5SyzzBAjpwtG+4bO/BD9h9wlTsHpT6yWOZs4OYAKU5ykQrncI8OyavMggArh3"
-            + "/oM58v0orUWINtIc2hBlka36PhATYQiLf+AiWKnwhCaaHExoYKfQlMtXBodNvOK8"
-            + "xqx69x05q/qbHKEcTHrsss630vxrp1niXvA=";
+            + "MIIFDzCCAvegAwIBAgIQbNdueU2o0vM9gGq4N6bhjzANBgkqhkiG9w0BAQsFADAx"
+            + "MS8wLQYDVQQDEyZHb29nbGUgQ2xvdWQgS2V5IFZhdWx0IFNlcnZpY2UgUm9vdCBD"
+            + "QTAeFw0xODA1MDcxODI0MDJaFw0zODA1MDgxOTI0MDJaMDExLzAtBgNVBAMTJkdv"
+            + "b2dsZSBDbG91ZCBLZXkgVmF1bHQgU2VydmljZSBSb290IENBMIICIjANBgkqhkiG"
+            + "9w0BAQEFAAOCAg8AMIICCgKCAgEArUgzu+4o9yl22eql1BiGBq3gWXooh2ql3J+v"
+            + "Vuzf/ThjzdIg0xkkkw/NAFxYFi49Eo1fa/hf8wCIoAqCEs1lD6tE3cCD3T3+EQPq"
+            + "uh6CB2KmZDJ6mPnXvVUlUuFr0O2MwZkwylqBETzK0x5NCHgL/p47vkjhHx6LqVao"
+            + "bigKlHxszvVi4fkt/qq7KW3YTVxhwdLGEab+OqSfwMxdBLhMfE0K0dvFt8bs8yJA"
+            + "F04DJsMbRChFFBpT17Z0u53iIAAu5qVQhKrQXiIAwgboZqd+JkHLXU1fJeVT5WJO"
+            + "JgoJFWHkdWkHta4mSYlS72J1Q927JD1JdET1kFtH+EDtYAtx7x7F9xAAbb2tMITw"
+            + "s/wwd2rAzZTX/kxRbDlXVLToU05LFYPr+dFV1wvXmi0jlkIxnhdaVBqWC93p528U"
+            + "iUcLpib+HVzMWGdYI3G1NOa/lTp0c8LcbJjapiiVneRQJ3cIqDPOSEnEq40hyZd1"
+            + "jx3JnOxJMwHs8v4s9GIlb3BcOmDvA/Mu09xEMKwpHBm4TFDKXeGHOWha7ccWEECb"
+            + "yO5ncu6XuN2iyz9S+TuMyjZBE552p6Pu5gEC2xk+qab0NGDTHdLKLbyWn3IxdmBH"
+            + "yTr7iPCqmpyHngkC/pbGfvGusc5BpBugsBtlz67m4RWLJ72yAeVPO/ly/8w4orNs"
+            + "GWjn3s0CAwEAAaMjMCEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8w"
+            + "DQYJKoZIhvcNAQELBQADggIBAGiWlu+4qyxgPb6RsA0mwR7V21UJ9rEpYhSN+ARp"
+            + "TWGiI22RCJSGK0ZrPGeFQzE2BpnVRdmLTV5jf9JUStjHoPvNYFnwLTJ0E2e9Olj8"
+            + "MrHrAucAUFLhl4woWz0kU/X0EB1j6Y2SXrAaZPiMMpq8BKj3mH1MbV4stZ0kiHUp"
+            + "Zu6PEmrojYG7FKKN30na2xXfiOfl2JusVsyHDqmUn/HjTh6zASKqE6hxE+FJRl2V"
+            + "Q4dcr4SviHtdbimMy2LghLnZ4FE4XhJgRnw9TeRV5C9Sn7pmnAA5X0C8ZXhXvfvr"
+            + "dx4fL3UKlk1Lqlb5skxoK1R9wwr+aNIO+cuR8JA5DmEDWFw5Budh/uWWZlBTyVW2"
+            + "ybbTB6tkmOc8c08XOgxBaKrsXALmJcluabjmN1jp81ae1epeN31jJ4N5IE5aq7Xb"
+            + "TFmKkwpgTTvJmqCR2XzWujlvdbdjfiABliWsnLzLQCP8eZwcM4LA5UK3f1ktHolr"
+            + "1OI9etSOkebE2py8LPYBJWlX36tRAagZhU/NoyOtvhRzq9rb3rbf96APEHKUFsXG"
+            + "9nBEd2BUKZghLKPf+JNCU/2pOGx0jdMcf+K+a1DeG0YzGYMRkFvpN3hvHYrJdByL"
+            + "3kSP3UtD0H2g8Ps7gRLELG2HODxbSn8PV3XtuSvxVanA6uyaaS3AZ6SxeVLvmw50"
+            + "7aYI";
 
     private static final String TEST_ONLY_INSECURE_CERTIFICATE_BASE64 = ""
             + "MIIFMDCCAxigAwIBAgIJAIZ9/G8KQie9MA0GCSqGSIb3DQEBDQUAMCUxIzAhBgNV"
@@ -134,8 +134,6 @@
 
     /**
      * The X509 certificate of the trusted root CA cert for the recoverable key store service.
-     *
-     * TODO: Change it to the production certificate root CA before the final launch.
      */
     private static final X509Certificate GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_CERTIFICATE =
             parseBase64Certificate(GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_BASE64);
diff --git a/core/java/android/view/textclassifier/SelectionSessionLogger.java b/core/java/android/view/textclassifier/SelectionSessionLogger.java
index f2fb63e..cdacdd5 100644
--- a/core/java/android/view/textclassifier/SelectionSessionLogger.java
+++ b/core/java/android/view/textclassifier/SelectionSessionLogger.java
@@ -86,8 +86,10 @@
                 .addTaggedData(SMART_START, event.getSmartStart())
                 .addTaggedData(SMART_END, event.getSmartEnd())
                 .addTaggedData(EVENT_START, event.getStart())
-                .addTaggedData(EVENT_END, event.getEnd())
-                .addTaggedData(SESSION_ID, event.getSessionId().flattenToString());
+                .addTaggedData(EVENT_END, event.getEnd());
+        if (event.getSessionId() != null) {
+            log.addTaggedData(SESSION_ID, event.getSessionId().flattenToString());
+        }
         mMetricsLogger.write(log);
         debugLog(log);
     }
diff --git a/core/java/android/view/textclassifier/SystemTextClassifier.java b/core/java/android/view/textclassifier/SystemTextClassifier.java
index da86b55..10191e0 100644
--- a/core/java/android/view/textclassifier/SystemTextClassifier.java
+++ b/core/java/android/view/textclassifier/SystemTextClassifier.java
@@ -129,6 +129,18 @@
         return mFallback.generateLinks(request);
     }
 
+    @Override
+    public void onSelectionEvent(SelectionEvent event) {
+        Preconditions.checkNotNull(event);
+        Utils.checkMainThread();
+
+        try {
+            mManagerService.onSelectionEvent(mSessionId, event);
+        } catch (RemoteException e) {
+            Log.e(LOG_TAG, "Error reporting selection event.", e);
+        }
+    }
+
     /**
      * @inheritDoc
      */
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index b7395cd..0697c97 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -126,7 +126,6 @@
         android:visibility="gone"
         android:contentDescription="@string/notification_work_profile_content_description"
         />
-
     <LinearLayout
         android:id="@+id/app_ops"
         android:layout_height="match_parent"
@@ -140,6 +139,8 @@
             android:src="@drawable/ic_camera"
             android:background="?android:selectableItemBackgroundBorderless"
             android:visibility="gone"
+            android:clickable="false"
+            android:contentDescription="@string/notification_appops_camera_active"
             />
         <ImageButton
             android:id="@+id/mic"
@@ -149,6 +150,8 @@
             android:background="?android:selectableItemBackgroundBorderless"
             android:layout_marginStart="4dp"
             android:visibility="gone"
+            android:clickable="false"
+            android:contentDescription="@string/notification_appops_microphone_active"
             />
         <ImageButton
             android:id="@+id/overlay"
@@ -158,6 +161,8 @@
             android:background="?android:selectableItemBackgroundBorderless"
             android:layout_marginStart="4dp"
             android:visibility="gone"
+            android:clickable="false"
+            android:contentDescription="@string/notification_appops_overlay_active"
             />
     </LinearLayout>
 </NotificationHeaderView>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 749d3c1..3c5159c 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4969,6 +4969,14 @@
     <!-- Application name displayed in notifications [CHAR LIMIT=60] -->
     <string name="notification_app_name_settings">Settings</string>
 
+    <!-- Active Permission - accessibility support -->
+    <!-- Content description of the camera icon in the notification. [CHAR LIMIT=NONE] -->
+    <string name="notification_appops_camera_active">Camera</string>
+    <!-- Content description of the mic icon in the notification. [CHAR LIMIT=NONE] -->
+    <string name="notification_appops_microphone_active">Microphone</string>
+    <!-- Content description of the overlay icon in the notification. [CHAR LIMIT=NONE] -->
+    <string name="notification_appops_overlay_active">displaying over other apps on your screen</string>
+
     <!-- Strings for car -->
     <!-- String displayed when loading a user in the car [CHAR LIMIT=30] -->
     <string name="car_loading_profile">Loading</string>
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 18bc20c..ab9fc13 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -385,6 +385,9 @@
                     Settings.Global.SHOW_RESTART_IN_CRASH_DIALOG,
                     Settings.Global.SHOW_TEMPERATURE_WARNING,
                     Settings.Global.SHOW_ZEN_UPGRADE_NOTIFICATION,
+                    Settings.Global.SHOW_ZEN_SETTINGS_SUGGESTION,
+                    Settings.Global.ZEN_SETTINGS_UPDATED,
+                    Settings.Global.ZEN_SETTINGS_SUGGESTION_VIEWED,
                     Settings.Global.SMART_SELECTION_UPDATE_CONTENT_URL,
                     Settings.Global.SMART_SELECTION_UPDATE_METADATA_URL,
                     Settings.Global.SMS_OUTGOING_CHECK_INTERVAL_MS,
diff --git a/media/java/android/media/soundtrigger/SoundTriggerDetectionService.java b/media/java/android/media/soundtrigger/SoundTriggerDetectionService.java
index 7381d97..55cd1ab 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerDetectionService.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerDetectionService.java
@@ -191,13 +191,14 @@
                 client = mClients.get(uuid);
 
                 if (client == null) {
-                    throw new IllegalStateException("operationFinished called, but no client for "
+                    Log.w(LOG_TAG, "operationFinished called, but no client for "
                             + uuid + ". Was this called after onDisconnected?");
+                    return;
                 }
             }
             client.onOpFinished(opId);
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            Log.e(LOG_TAG, "operationFinished, remote exception for client " + uuid, e);
         }
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index 6b99024..24037a6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -94,6 +94,11 @@
         return mIsProfileReady;
     }
 
+    @Override
+    public int getProfileId() {
+        return BluetoothProfile.A2DP;
+    }
+
     A2dpProfile(Context context, LocalBluetoothAdapter adapter,
             CachedBluetoothDeviceManager deviceManager,
             LocalBluetoothProfileManager profileManager) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
index a1c8de5..ac5f537 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
@@ -85,6 +85,11 @@
         return mIsProfileReady;
     }
 
+    @Override
+    public int getProfileId() {
+        return BluetoothProfile.A2DP_SINK;
+    }
+
     A2dpSinkProfile(Context context, LocalBluetoothAdapter adapter,
             CachedBluetoothDeviceManager deviceManager,
             LocalBluetoothProfileManager profileManager) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java
index bab59f1..c7f8c20 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java
@@ -30,4 +30,7 @@
     void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state);
     void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile);
     void onAudioModeChanged();
+    default void onProfileConnectionStateChanged(CachedBluetoothDevice cachedDevice,
+            int state, int bluetoothProfile) {
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index e7d7ab3..4e9e566 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -497,4 +497,13 @@
             }
         }
     }
+
+    void dispatchProfileConnectionStateChanged(CachedBluetoothDevice device, int state,
+            int bluetoothProfile) {
+        synchronized (mCallbacks) {
+            for (BluetoothCallback callback : mCallbacks) {
+                callback.onProfileConnectionStateChanged(device, state, bluetoothProfile);
+            }
+        }
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
index ad81336..f7518cd 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
@@ -92,6 +92,11 @@
         return mIsProfileReady;
     }
 
+    @Override
+    public int getProfileId() {
+        return BluetoothProfile.HEADSET;
+    }
+
     HeadsetProfile(Context context, LocalBluetoothAdapter adapter,
             CachedBluetoothDeviceManager deviceManager,
             LocalBluetoothProfileManager profileManager) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
index da2ae7f..a0dfb5d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
@@ -93,6 +93,11 @@
         return mIsProfileReady;
     }
 
+    @Override
+    public int getProfileId() {
+        return BluetoothProfile.HEARING_AID;
+    }
+
     HearingAidProfile(Context context, LocalBluetoothAdapter adapter,
             CachedBluetoothDeviceManager deviceManager,
             LocalBluetoothProfileManager profileManager) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
index 169aac9..d081909 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
@@ -92,6 +92,11 @@
         return mIsProfileReady;
     }
 
+    @Override
+    public int getProfileId() {
+        return BluetoothProfile.HEADSET_CLIENT;
+    }
+
     HfpClientProfile(Context context, LocalBluetoothAdapter adapter,
             CachedBluetoothDeviceManager deviceManager,
             LocalBluetoothProfileManager profileManager) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
index 941964a..45ec4a1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
@@ -98,6 +98,11 @@
     }
 
     @Override
+    public int getProfileId() {
+        return BluetoothProfile.HID_DEVICE;
+    }
+
+    @Override
     public boolean isConnectable() {
         return true;
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
index 93c4017..93e5621 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
@@ -80,6 +80,11 @@
         return mIsProfileReady;
     }
 
+    @Override
+    public int getProfileId() {
+        return BluetoothProfile.HID_HOST;
+    }
+
     HidProfile(Context context, LocalBluetoothAdapter adapter,
         CachedBluetoothDeviceManager deviceManager,
         LocalBluetoothProfileManager profileManager) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java
index abcb989..0447f37 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java
@@ -49,6 +49,8 @@
 
     boolean isProfileReady();
 
+    int getProfileId();
+
     /** Display order for device profile settings. */
     int getOrdinal();
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 0715d69..62f8724 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -375,6 +375,8 @@
                 }
             }
 
+            mEventManager.dispatchProfileConnectionStateChanged(cachedDevice, newState,
+                    mProfile.getProfileId());
             cachedDevice.onProfileStateChanged(mProfile, newState);
             cachedDevice.refresh();
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
index 6efa468..ad0d8ba 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
@@ -94,6 +94,11 @@
         return mIsProfileReady;
     }
 
+    @Override
+    public int getProfileId() {
+        return BluetoothProfile.MAP_CLIENT;
+    }
+
     MapClientProfile(Context context, LocalBluetoothAdapter adapter,
             CachedBluetoothDeviceManager deviceManager,
             LocalBluetoothProfileManager profileManager) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
index 0b45f51..aa7a7af 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
@@ -93,6 +93,11 @@
         return mIsProfileReady;
     }
 
+    @Override
+    public int getProfileId() {
+        return BluetoothProfile.MAP;
+    }
+
     MapProfile(Context context, LocalBluetoothAdapter adapter,
             CachedBluetoothDeviceManager deviceManager,
             LocalBluetoothProfileManager profileManager) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
index 31e675c..e5c0b14 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
@@ -67,6 +67,11 @@
         return true;
     }
 
+    @Override
+    public int getProfileId() {
+        return BluetoothProfile.OPP;
+    }
+
     public String toString() {
         return NAME;
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
index e077a67..b18b19b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
@@ -69,6 +69,11 @@
         return mIsProfileReady;
     }
 
+    @Override
+    public int getProfileId() {
+        return BluetoothProfile.PAN;
+    }
+
     PanProfile(Context context, LocalBluetoothAdapter adapter) {
         mLocalAdapter = adapter;
         mLocalAdapter.getProfileProxy(context, new PanServiceListener(),
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
index 28137ff..b735c23 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
@@ -100,6 +100,11 @@
         return mIsProfileReady;
     }
 
+    @Override
+    public int getProfileId() {
+        return BluetoothProfile.PBAP_CLIENT;
+    }
+
     PbapClientProfile(Context context, LocalBluetoothAdapter adapter,
             CachedBluetoothDeviceManager deviceManager,
             LocalBluetoothProfileManager profileManager) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
index 58465f2..e9d8cb5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
@@ -71,6 +71,11 @@
         return mIsProfileReady;
     }
 
+    @Override
+    public int getProfileId() {
+        return BluetoothProfile.PBAP;
+    }
+
     PbapServerProfile(Context context) {
         BluetoothPbap pbap = new BluetoothPbap(context, new PbapServiceListener());
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
index 25c53e6..93e6be6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
@@ -91,6 +91,11 @@
         return mIsProfileReady;
     }
 
+    @Override
+    public int getProfileId() {
+        return BluetoothProfile.SAP;
+    }
+
     SapProfile(Context context, LocalBluetoothAdapter adapter,
             CachedBluetoothDeviceManager deviceManager,
             LocalBluetoothProfileManager profileManager) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
index 6a2a04a..dd8bfda 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
@@ -49,8 +49,8 @@
             "com.android.settings.category.ia.notifications";
     public static final String CATEGORY_DO_NOT_DISTURB = "com.android.settings.category.ia.dnd";
     public static final String CATEGORY_GESTURES = "com.android.settings.category.ia.gestures";
-    public static final String CATEGORY_NIGHT_LIGHT =
-            "com.android.settings.category.ia.night_light";
+    public static final String CATEGORY_NIGHT_DISPLAY =
+            "com.android.settings.category.ia.night_display";
 
     public static final Map<String, String> KEY_COMPAT_MAP;
 
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
index d1e37f6..466980c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
@@ -15,13 +15,17 @@
  */
 package com.android.settingslib.bluetooth;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.verify;
 
 import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothProfile;
 import android.content.Context;
 import android.content.Intent;
 
 import android.telephony.TelephonyManager;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -39,6 +43,8 @@
     private CachedBluetoothDeviceManager mCachedDeviceManager;
     @Mock
     private BluetoothCallback mBluetoothCallback;
+    @Mock
+    private CachedBluetoothDevice mCachedBluetoothDevice;
 
     private Context mContext;
     private Intent mIntent;
@@ -78,4 +84,19 @@
 
         verify(mBluetoothCallback).onAudioModeChanged();
     }
+
+    /**
+     * dispatchProfileConnectionStateChanged should dispatch to onProfileConnectionStateChanged
+     * callback.
+     */
+    @Test
+    public void dispatchProfileConnectionStateChanged_registerCallback_shouldDispatchCallback() {
+        mBluetoothEventManager.registerCallback(mBluetoothCallback);
+
+        mBluetoothEventManager.dispatchProfileConnectionStateChanged(mCachedBluetoothDevice,
+                BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP);
+
+        verify(mBluetoothCallback).onProfileConnectionStateChanged(mCachedBluetoothDevice,
+                BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP);
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
index 88c7a55..d342bc8 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
@@ -18,12 +18,23 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothPan;
+import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothUuid;
 import android.content.Context;
+import android.content.Intent;
 import android.os.ParcelUuid;
 
 import java.util.ArrayList;
@@ -41,18 +52,29 @@
 @RunWith(RobolectricTestRunner.class)
 @Config(resourceDir = "../../res")
 public class LocalBluetoothProfileManagerTest {
-    @Mock private CachedBluetoothDeviceManager mDeviceManager;
-    @Mock private BluetoothEventManager mEventManager;
-    @Mock private LocalBluetoothAdapter mAdapter;
-    @Mock private BluetoothDevice mDevice;
+    @Mock
+    private CachedBluetoothDeviceManager mDeviceManager;
+    @Mock
+    private BluetoothEventManager mEventManager;
+    @Mock
+    private LocalBluetoothAdapter mAdapter;
+    @Mock
+    private BluetoothDevice mDevice;
+    @Mock
+    private CachedBluetoothDevice mCachedBluetoothDevice;
+
     private Context mContext;
     private LocalBluetoothProfileManager mProfileManager;
+    private Intent mIntent;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
+        mContext = spy(RuntimeEnvironment.application);
+        mEventManager = spy(new BluetoothEventManager(mAdapter,
+                mDeviceManager, mContext));
         when(mAdapter.getBluetoothState()).thenReturn(BluetoothAdapter.STATE_ON);
+        when(mDeviceManager.findDevice(mDevice)).thenReturn(mCachedBluetoothDevice);
     }
 
     /**
@@ -74,7 +96,7 @@
     public void updateLocalProfiles_addA2dpToLocalProfiles() {
         mProfileManager =
                 new LocalBluetoothProfileManager(mContext, mAdapter, mDeviceManager, mEventManager);
-        when(mAdapter.getUuids()).thenReturn(new ParcelUuid[] {BluetoothUuid.AudioSource});
+        when(mAdapter.getUuids()).thenReturn(new ParcelUuid[]{BluetoothUuid.AudioSource});
         assertThat(mProfileManager.getA2dpProfile()).isNull();
         assertThat(mProfileManager.getHeadsetProfile()).isNull();
 
@@ -104,4 +126,143 @@
         assertThat(profiles.contains(mProfileManager.getHidProfile())).isTrue();
         assertThat(removedProfiles.contains(mProfileManager.getHidProfile())).isFalse();
     }
+
+    /**
+     * Verify BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED with uuid intent will dispatch to
+     * profile connection state changed callback
+     */
+    @Test
+    public void stateChangedHandler_receiveA2dpConnectionStateChanged_shouldDispatchCallback() {
+        when(mAdapter.getUuids()).thenReturn(new ParcelUuid[]{BluetoothUuid.AudioSource});
+        mProfileManager = new LocalBluetoothProfileManager(mContext, mAdapter, mDeviceManager,
+                mEventManager);
+        // Refer to BluetoothControllerImpl, it will call setReceiverHandler after
+        // LocalBluetoothProfileManager created.
+        mEventManager.setReceiverHandler(null);
+        mIntent = new Intent(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
+        mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
+        mIntent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_CONNECTING);
+        mIntent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_CONNECTED);
+
+        mContext.sendBroadcast(mIntent);
+
+        verify(mEventManager).dispatchProfileConnectionStateChanged(
+                mCachedBluetoothDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP);
+    }
+
+    /**
+     * Verify BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED with uuid intent will dispatch to
+     * profile connection state changed callback
+     */
+    @Test
+    public void stateChangedHandler_receiveHeadsetConnectionStateChanged_shouldDispatchCallback() {
+        when(mAdapter.getUuids()).thenReturn(new ParcelUuid[]{BluetoothUuid.Handsfree_AG});
+        mProfileManager = new LocalBluetoothProfileManager(mContext, mAdapter, mDeviceManager,
+                mEventManager);
+        // Refer to BluetoothControllerImpl, it will call setReceiverHandler after
+        // LocalBluetoothProfileManager created.
+        mEventManager.setReceiverHandler(null);
+        mIntent = new Intent(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
+        mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
+        mIntent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_CONNECTING);
+        mIntent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_CONNECTED);
+
+        mContext.sendBroadcast(mIntent);
+
+        verify(mEventManager).dispatchProfileConnectionStateChanged(mCachedBluetoothDevice,
+                BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEADSET);
+    }
+
+    /**
+     * Verify BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED with uuid intent will dispatch to
+     * profile connection state changed callback
+     */
+    @Test
+    public void stateChangedHandler_receiveHAPConnectionStateChanged_shouldDispatchCallback() {
+        ArrayList<Integer> supportProfiles = new ArrayList<>();
+        supportProfiles.add(BluetoothProfile.HEARING_AID);
+        when(mAdapter.getSupportedProfiles()).thenReturn(supportProfiles);
+        when(mAdapter.getUuids()).thenReturn(new ParcelUuid[]{BluetoothUuid.HearingAid});
+        mProfileManager = new LocalBluetoothProfileManager(mContext, mAdapter, mDeviceManager,
+                mEventManager);
+        // Refer to BluetoothControllerImpl, it will call setReceiverHandler after
+        // LocalBluetoothProfileManager created.
+        mEventManager.setReceiverHandler(null);
+        mIntent = new Intent(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
+        mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
+        mIntent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_CONNECTING);
+        mIntent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_CONNECTED);
+
+        mContext.sendBroadcast(mIntent);
+
+        verify(mEventManager).dispatchProfileConnectionStateChanged(mCachedBluetoothDevice,
+                BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEARING_AID);
+    }
+
+    /**
+     * Verify BluetoothPan.ACTION_CONNECTION_STATE_CHANGED intent with uuid will dispatch to
+     * profile connection state changed callback
+     */
+    @Test
+    public void stateChangedHandler_receivePanConnectionStateChanged_shouldNotDispatchCallback() {
+        when(mAdapter.getUuids()).thenReturn(new ParcelUuid[]{BluetoothUuid.AudioSource});
+        mProfileManager = new LocalBluetoothProfileManager(mContext, mAdapter, mDeviceManager,
+                mEventManager);
+        // Refer to BluetoothControllerImpl, it will call setReceiverHandler after
+        // LocalBluetoothProfileManager created.
+        mEventManager.setReceiverHandler(null);
+        mIntent = new Intent(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
+        mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
+        mIntent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_CONNECTING);
+        mIntent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_CONNECTED);
+
+        mContext.sendBroadcast(mIntent);
+
+        verify(mEventManager).dispatchProfileConnectionStateChanged(
+                any(CachedBluetoothDevice.class), anyInt(), anyInt());
+    }
+
+    /**
+     * Verify BluetoothPan.ACTION_CONNECTION_STATE_CHANGED intent without uuids will not dispatch to
+     * handler and refresh CachedBluetoothDevice
+     */
+    @Test
+    public void stateChangedHandler_receivePanConnectionStateChangedWithoutUuid_shouldNotRefresh() {
+        when(mAdapter.getUuids()).thenReturn(null);
+        mProfileManager = new LocalBluetoothProfileManager(mContext, mAdapter, mDeviceManager,
+                mEventManager);
+        // Refer to BluetoothControllerImpl, it will call setReceiverHandler after
+        // LocalBluetoothProfileManager created.
+        mEventManager.setReceiverHandler(null);
+        mIntent = new Intent(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
+        mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
+        mIntent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_CONNECTING);
+        mIntent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_CONNECTED);
+
+        mContext.sendBroadcast(mIntent);
+
+        verify(mCachedBluetoothDevice).refresh();
+    }
+
+    /**
+     * Verify BluetoothPan.ACTION_CONNECTION_STATE_CHANGED intent with uuids will dispatch to
+     * handler and refresh CachedBluetoothDevice
+     */
+    @Test
+    public void stateChangedHandler_receivePanConnectionStateChangedWithUuids_shouldRefresh() {
+        when(mAdapter.getUuids()).thenReturn(new ParcelUuid[]{BluetoothUuid.AudioSource});
+        mProfileManager = new LocalBluetoothProfileManager(mContext, mAdapter, mDeviceManager,
+                mEventManager);
+        // Refer to BluetoothControllerImpl, it will call setReceiverHandler after
+        // LocalBluetoothProfileManager created.
+        mEventManager.setReceiverHandler(null);
+        mIntent = new Intent(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
+        mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
+        mIntent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_CONNECTING);
+        mIntent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_CONNECTED);
+
+        mContext.sendBroadcast(mIntent);
+
+        verify(mCachedBluetoothDevice).refresh();
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java
index f34605c..605c861 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java
@@ -58,7 +58,7 @@
         allKeys.add(CategoryKey.CATEGORY_SYSTEM_LANGUAGE);
         allKeys.add(CategoryKey.CATEGORY_SYSTEM_DEVELOPMENT);
         allKeys.add(CategoryKey.CATEGORY_GESTURES);
-        allKeys.add(CategoryKey.CATEGORY_NIGHT_LIGHT);
+        allKeys.add(CategoryKey.CATEGORY_NIGHT_DISPLAY);
         // DO NOT REMOVE ANYTHING ABOVE
 
         assertThat(allKeys.size()).isEqualTo(18);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 32aafea..7b76fce 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2935,7 +2935,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 165;
+            private static final int SETTINGS_VERSION = 166;
 
             private final int mUserId;
 
@@ -3733,7 +3733,7 @@
                 }
 
                 if (currentVersion == 164) {
-                    // Version 164: Add a gesture for silencing phones
+                    // Version 164: show zen upgrade notification
                     final SettingsState settings = getGlobalSettingsLocked();
                     final Setting currentSetting = settings.getSettingLocked(
                             Global.SHOW_ZEN_UPGRADE_NOTIFICATION);
@@ -3747,6 +3747,36 @@
                     currentVersion = 165;
                 }
 
+                if (currentVersion == 165) {
+                    // Version 165: Show zen settings suggestion and zen updated
+                    final SettingsState settings = getGlobalSettingsLocked();
+                    final Setting currentSetting = settings.getSettingLocked(
+                            Global.SHOW_ZEN_SETTINGS_SUGGESTION);
+                    if (currentSetting.isNull()) {
+                        settings.insertSettingLocked(
+                                Global.SHOW_ZEN_SETTINGS_SUGGESTION, "1",
+                                null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+                    }
+
+                    final Setting currentUpdatedSetting = settings.getSettingLocked(
+                            Global.ZEN_SETTINGS_UPDATED);
+                    if (currentUpdatedSetting.isNull()) {
+                        settings.insertSettingLocked(
+                                Global.ZEN_SETTINGS_UPDATED, "0",
+                                null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+                    }
+
+                    final Setting currentSettingSuggestionViewed = settings.getSettingLocked(
+                            Global.ZEN_SETTINGS_SUGGESTION_VIEWED);
+                    if (currentSettingSuggestionViewed.isNull()) {
+                        settings.insertSettingLocked(
+                                Global.ZEN_SETTINGS_SUGGESTION_VIEWED, "0",
+                                null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+                    }
+
+                    currentVersion = 166;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index 00cd5a7..48b4134 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -246,7 +246,12 @@
 
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
-        onUserInput();
+        // Fingerprint sensor sends a KeyEvent.KEYCODE_UNKNOWN.
+        // We don't want to consider it valid user input because the UI
+        // will already respond to the event.
+        if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
+            onUserInput();
+        }
         return false;
     }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index a2befef..cb8c119 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -31,8 +31,7 @@
 public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
         implements View.OnKeyListener, View.OnTouchListener {
 
-    @VisibleForTesting
-    PasswordTextView mPasswordEntry;
+    protected PasswordTextView mPasswordEntry;
     private View mOkButton;
     private View mDeleteButton;
     private View mButton0;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index fb13925..9f382b00 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -55,6 +55,7 @@
 import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.IRemoteCallback;
+import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -244,7 +245,7 @@
     private static final int HW_UNAVAILABLE_TIMEOUT = 3000; // ms
     private static final int HW_UNAVAILABLE_RETRY_MAX = 3;
 
-    private final Handler mHandler = new Handler() {
+    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
@@ -339,6 +340,9 @@
                 case MSG_DEVICE_POLICY_MANAGER_STATE_CHANGED:
                     updateLogoutEnabled();
                     break;
+                default:
+                    super.handleMessage(msg);
+                    break;
             }
         }
     };
@@ -1181,12 +1185,12 @@
         filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
         filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
         filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
-        context.registerReceiver(mBroadcastReceiver, filter);
+        context.registerReceiver(mBroadcastReceiver, filter, null, mHandler);
 
         final IntentFilter bootCompleteFilter = new IntentFilter();
         bootCompleteFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
         bootCompleteFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
-        context.registerReceiver(mBroadcastReceiver, bootCompleteFilter);
+        context.registerReceiver(mBroadcastReceiver, bootCompleteFilter, null, mHandler);
 
         final IntentFilter allUserFilter = new IntentFilter();
         allUserFilter.addAction(Intent.ACTION_USER_INFO_CHANGED);
@@ -1196,7 +1200,7 @@
         allUserFilter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
         allUserFilter.addAction(ACTION_USER_UNLOCKED);
         context.registerReceiverAsUser(mBroadcastAllReceiver, UserHandle.ALL, allUserFilter,
-                null, null);
+                null, mHandler);
 
         mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener);
         try {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 991b47e..82cf93e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -1651,6 +1651,45 @@
         mMenuRow.resetMenu();
     }
 
+    void onGutsOpened() {
+        resetTranslation();
+        updateContentAccessibilityImportanceForGuts(false /* isEnabled */);
+    }
+
+    void onGutsClosed() {
+        updateContentAccessibilityImportanceForGuts(true /* isEnabled */);
+    }
+
+    /**
+     * Updates whether all the non-guts content inside this row is important for accessibility.
+     *
+     * @param isEnabled whether the content views should be enabled for accessibility
+     */
+    private void updateContentAccessibilityImportanceForGuts(boolean isEnabled) {
+        if (mChildrenContainer != null) {
+            updateChildAccessibilityImportance(mChildrenContainer, isEnabled);
+        }
+        if (mLayouts != null) {
+            for (View view : mLayouts) {
+                updateChildAccessibilityImportance(view, isEnabled);
+            }
+        }
+
+        if (isEnabled) {
+            this.requestAccessibilityFocus();
+        }
+    }
+
+    /**
+     * Updates whether the given childView is important for accessibility based on
+     * {@code isEnabled}.
+     */
+    private void updateChildAccessibilityImportance(View childView, boolean isEnabled) {
+        childView.setImportantForAccessibility(isEnabled
+                ? View.IMPORTANT_FOR_ACCESSIBILITY_AUTO
+                : View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+    }
+
     public CharSequence getActiveRemoteInputText() {
         return mPrivateLayout.getActiveRemoteInputText();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
index 46600cf..8d7668a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
@@ -159,6 +159,7 @@
         row.setGutsView(item);
         row.setTag(sbn.getPackageName());
         row.getGuts().setClosedListener((NotificationGuts g) -> {
+            row.onGutsClosed();
             if (!g.willBeRemoved() && !row.isRemoved()) {
                 mListContainer.onHeightChanged(
                         row, !mPresenter.isPresenterFullyCollapsed() /* needsAnimation */);
@@ -390,7 +391,7 @@
                         x,
                         y,
                         needsFalsingProtection,
-                        row::resetTranslation);
+                        row::onGutsOpened);
 
                 row.closeRemoteInput();
                 mListContainer.onHeightChanged(row, true /* needsAnimation */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index c279e63..cc802a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -495,12 +495,14 @@
             // measured with the wrong number of lines).
             if (child.getPaddingLeft() != buttonPaddingHorizontal) {
                 requiresNewMeasure = true;
-                if (buttonPaddingHorizontal == mSingleLineButtonPaddingHorizontal) {
-                    // Decrease padding (2->1 line).
-                    newWidth -= mSingleToDoubleLineButtonWidthIncrease;
-                } else {
-                    // Increase padding (1->2 lines).
-                    newWidth += mSingleToDoubleLineButtonWidthIncrease;
+                if (newWidth != Integer.MAX_VALUE) {
+                    if (buttonPaddingHorizontal == mSingleLineButtonPaddingHorizontal) {
+                        // Change padding (2->1 line).
+                        newWidth -= mSingleToDoubleLineButtonWidthIncrease;
+                    } else {
+                        // Change padding (1->2 lines).
+                        newWidth += mSingleToDoubleLineButtonWidthIncrease;
+                    }
                 }
                 child.setPadding(buttonPaddingHorizontal, child.getPaddingTop(),
                         buttonPaddingHorizontal, child.getPaddingBottom());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 176905a..236ead0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -2222,7 +2222,7 @@
     }
 
     private void updateScrollability() {
-        boolean scrollable = getScrollRange() > 0;
+        boolean scrollable = !mQsExpanded && getScrollRange() > 0;
         if (scrollable != mScrollable) {
             mScrollable = scrollable;
             setFocusable(scrollable);
@@ -4500,6 +4500,7 @@
     public void setQsExpanded(boolean qsExpanded) {
         mQsExpanded = qsExpanded;
         updateAlgorithmLayoutMinHeight();
+        updateScrollability();
     }
 
     public void setQsExpansionFraction(float qsExpansionFraction) {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewTest.java
index e79c9d0..359832f 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewTest.java
@@ -16,11 +16,15 @@
 
 package com.android.keyguard;
 
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
 
 import android.support.test.filters.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
+import android.view.KeyEvent;
 import android.view.LayoutInflater;
 
 import com.android.systemui.SysuiTestCase;
@@ -28,6 +32,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -37,21 +42,35 @@
 public class KeyguardPinBasedInputViewTest extends SysuiTestCase {
 
     @Mock
-    private PasswordTextView mPasswordTextView;
+    private PasswordTextView mPasswordEntry;
+    @Mock
+    private SecurityMessageDisplay mSecurityMessageDisplay;
+    @InjectMocks
     private KeyguardPinBasedInputView mKeyguardPinView;
 
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
         LayoutInflater inflater = LayoutInflater.from(getContext());
         mKeyguardPinView =
                 (KeyguardPinBasedInputView) inflater.inflate(R.layout.keyguard_pin_view, null);
-        mKeyguardPinView.mPasswordEntry = mPasswordTextView;
+        MockitoAnnotations.initMocks(this);
     }
 
     @Test
     public void onResume_requestsFocus() {
         mKeyguardPinView.onResume(KeyguardSecurityView.SCREEN_ON);
-        verify(mPasswordTextView).requestFocus();
+        verify(mPasswordEntry).requestFocus();
+    }
+
+    @Test
+    public void onKeyDown_clearsSecurityMessage() {
+        mKeyguardPinView.onKeyDown(KeyEvent.KEYCODE_0, mock(KeyEvent.class));
+        verify(mSecurityMessageDisplay).setMessage(eq(""));
+    }
+
+    @Test
+    public void onKeyDown_noSecurityMessageInteraction() {
+        mKeyguardPinView.onKeyDown(KeyEvent.KEYCODE_UNKNOWN, mock(KeyEvent.class));
+        verifyZeroInteractions(mSecurityMessageDisplay);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
index f3d79fd..c573ca8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
@@ -347,6 +347,30 @@
         assertEqualLayouts(expectedView.getChildAt(2), mView.getChildAt(2));
     }
 
+    @Test
+    public void testMeasure_dropLongest() {
+        final CharSequence[] choices = new CharSequence[]{"Short", "Short",
+                "LooooooongUnbreakableReplyyyyy"};
+
+        // Short choices should be shown as single line views
+        ViewGroup expectedView = buildExpectedView(
+                new CharSequence[]{"Short", "Short"}, 1);
+        expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+        expectedView.layout(10, 10, 10 + expectedView.getMeasuredWidth(),
+                10 + expectedView.getMeasuredHeight());
+
+        setRepliesFromRemoteInput(choices);
+        mView.measure(
+                MeasureSpec.makeMeasureSpec(expectedView.getMeasuredWidth(), MeasureSpec.AT_MOST),
+                MeasureSpec.UNSPECIFIED);
+        mView.layout(10, 10, 10 + mView.getMeasuredWidth(), 10 + mView.getMeasuredHeight());
+
+        assertEqualLayouts(expectedView, mView);
+        assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(0));
+        assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(1));
+        assertReplyButtonHidden(mView.getChildAt(2));
+    }
+
     private void setRepliesFromRemoteInput(CharSequence[] choices) {
         PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0,
                 new Intent(TEST_ACTION), 0);
@@ -407,10 +431,7 @@
     private static void assertReplyButtonShownWithEqualMeasures(View expected, View actual) {
         assertReplyButtonShown(actual);
         assertEqualMeasures(expected, actual);
-        assertEquals(expected.getPaddingLeft(), actual.getPaddingLeft());
-        assertEquals(expected.getPaddingTop(), actual.getPaddingTop());
-        assertEquals(expected.getPaddingRight(), actual.getPaddingRight());
-        assertEquals(expected.getPaddingBottom(), actual.getPaddingBottom());
+        assertEqualPadding(expected, actual);
     }
 
     private static void assertReplyButtonShown(View view) {
@@ -427,4 +448,11 @@
         assertEquals(expected.getRight(), actual.getRight());
         assertEquals(expected.getBottom(), actual.getBottom());
     }
+
+    private static void assertEqualPadding(View expected, View actual) {
+        assertEquals(expected.getPaddingLeft(), actual.getPaddingLeft());
+        assertEquals(expected.getPaddingTop(), actual.getPaddingTop());
+        assertEquals(expected.getPaddingRight(), actual.getPaddingRight());
+        assertEquals(expected.getPaddingBottom(), actual.getPaddingBottom());
+    }
 }
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 7c05b2b..95dc3ab 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5828,6 +5828,30 @@
     // OS: P
     DIALOG_SWITCH_HFP_DEVICES = 1416;
 
+    // ACTION: User has started or ended charging
+    // Type TYPE_DISMISS: Charging has ended
+    // Type TYPE_ACTION: Charging has started, contains fields: battery level
+    // Tag FIELD_BATTERY_LEVEL_START: Battery level at the start
+    // Tag FIELD_BATTERY_LEVEL_END: Battery level at the end
+    // Tag FIELD_CHARGING_DURATION: Time in ms phone was charging
+    // Tag FIELD_PLUG_TYPE: Charging plug type
+    ACTION_CHARGE = 1417;
+
+    // Tag used to determine battery level when device started charging
+    FIELD_BATTERY_LEVEL_START = 1418;
+
+    // Tag used to determine battery level when device ended charging
+    FIELD_BATTERY_LEVEL_END = 1419;
+
+    // Tag used to determine length of charging
+    FIELD_CHARGING_DURATION_MILLIS = 1420;
+
+    // Tag used to determine what type of charging was started/ended
+    // 1 = Plugged AC
+    // 2 = Plugged USB
+    // 3 = Wireless
+    FIELD_PLUG_TYPE = 1421;
+
     // ---- End P Constants, all P constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 7f26575..169f2a8 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -228,7 +228,7 @@
         public void startMonitoring(ContentResolver resolver) {
             mResolver = resolver;
             mResolver.registerContentObserver(
-                    Settings.Global.getUriFor(Settings.Global.DEVICE_IDLE_CONSTANTS),
+                    Settings.Global.getUriFor(Settings.Global.APP_OPS_CONSTANTS),
                     false, this);
             updateConstants();
         }
@@ -239,20 +239,17 @@
         }
 
         private void updateConstants() {
+            String value = mResolver != null ? Settings.Global.getString(mResolver,
+                    Settings.Global.APP_OPS_CONSTANTS) : "";
+
             synchronized (AppOpsService.this) {
                 try {
-                    if (mResolver != null) {
-                        mParser.setString(Settings.Global.getString(mResolver,
-                                Settings.Global.APP_OPS_CONSTANTS));
-                    } else {
-                        mParser.setString("");
-                    }
+                    mParser.setString(value);
                 } catch (IllegalArgumentException e) {
                     // Failed to parse the settings string, log this and move on
                     // with defaults.
                     Slog.e(TAG, "Bad app ops settings", e);
                 }
-
                 STATE_SETTLE_TIME = mParser.getDurationMillis(
                         KEY_STATE_SETTLE_TIME, 10 * 1000L);
             }
@@ -557,8 +554,9 @@
     }
 
     public void systemReady() {
+        mConstants.startMonitoring(mContext.getContentResolver());
+
         synchronized (this) {
-            mConstants.startMonitoring(mContext.getContentResolver());
             boolean changed = false;
             for (int i = mUidStates.size() - 1; i >= 0; i--) {
                 UidState uidState = mUidStates.valueAt(i);
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index d31a605..87647ca 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -16,36 +16,27 @@
 
 package com.android.server;
 
-import android.app.ActivityManagerInternal;
-import android.database.ContentObserver;
-import android.os.BatteryStats;
-
-import android.os.Bundle;
-import android.os.PowerManager;
-import android.os.ResultReceiver;
-import android.os.ShellCallback;
-import android.os.ShellCommand;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.app.IBatteryStats;
-import com.android.internal.util.DumpUtils;
-import com.android.server.am.BatteryStatsService;
-import com.android.server.lights.Light;
-import com.android.server.lights.LightsManager;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
 import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.database.ContentObserver;
+import android.hardware.health.V1_0.HealthInfo;
+import android.hardware.health.V2_0.IHealth;
+import android.hardware.health.V2_0.IHealthInfoCallback;
+import android.hardware.health.V2_0.Result;
 import android.hidl.manager.V1_0.IServiceManager;
 import android.hidl.manager.V1_0.IServiceNotification;
-import android.hardware.health.V1_0.HealthInfo;
-import android.hardware.health.V2_0.IHealthInfoCallback;
-import android.hardware.health.V2_0.IHealth;
-import android.hardware.health.V2_0.Result;
+import android.metrics.LogMaker;
 import android.os.BatteryManager;
 import android.os.BatteryManagerInternal;
 import android.os.BatteryProperty;
+import android.os.BatteryStats;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.DropBoxManager;
 import android.os.FileUtils;
 import android.os.Handler;
@@ -54,8 +45,12 @@
 import android.os.IBatteryPropertiesRegistrar;
 import android.os.IBinder;
 import android.os.OsProtoEnums;
+import android.os.PowerManager;
 import android.os.RemoteException;
+import android.os.ResultReceiver;
 import android.os.ServiceManager;
+import android.os.ShellCallback;
+import android.os.ShellCommand;
 import android.os.SystemClock;
 import android.os.Trace;
 import android.os.UEventObserver;
@@ -67,12 +62,19 @@
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.IBatteryStats;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.util.DumpUtils;
+import com.android.server.am.BatteryStatsService;
+import com.android.server.lights.Light;
+import com.android.server.lights.LightsManager;
+
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
-
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -171,6 +173,9 @@
     private long mDischargeStartTime;
     private int mDischargeStartLevel;
 
+    private long mChargeStartTime;
+    private int mChargeStartLevel;
+
     private boolean mUpdatesStopped;
 
     private Led mLed;
@@ -185,6 +190,8 @@
     private ArrayDeque<Bundle> mBatteryLevelsEventQueue;
     private long mLastBatteryLevelChangedSentMs;
 
+    private MetricsLogger mMetricsLogger;
+
     public BatteryService(Context context) {
         super(context);
 
@@ -204,6 +211,7 @@
                 com.android.internal.R.integer.config_shutdownBatteryTemperature);
 
         mBatteryLevelsEventQueue = new ArrayDeque<>();
+        mMetricsLogger = new MetricsLogger();
 
         // watch for invalid charger messages if the invalid_charger switch exists
         if (new File("/sys/devices/virtual/switch/invalid_charger/state").exists()) {
@@ -476,6 +484,15 @@
             if (mPlugType != mLastPlugType) {
                 if (mLastPlugType == BATTERY_PLUGGED_NONE) {
                     // discharging -> charging
+                    mChargeStartLevel = mHealthInfo.batteryLevel;
+                    mChargeStartTime = SystemClock.elapsedRealtime();
+
+                    final LogMaker builder = new LogMaker(MetricsEvent.ACTION_CHARGE);
+                    builder.setType(MetricsEvent.TYPE_ACTION);
+                    builder.addTaggedData(MetricsEvent.FIELD_PLUG_TYPE, mPlugType);
+                    builder.addTaggedData(MetricsEvent.FIELD_BATTERY_LEVEL_START,
+                            mHealthInfo.batteryLevel);
+                    mMetricsLogger.write(builder);
 
                     // There's no value in this data unless we've discharged at least once and the
                     // battery level has changed; so don't log until it does.
@@ -491,6 +508,21 @@
                     // charging -> discharging or we just powered up
                     mDischargeStartTime = SystemClock.elapsedRealtime();
                     mDischargeStartLevel = mHealthInfo.batteryLevel;
+
+                    long chargeDuration = SystemClock.elapsedRealtime() - mChargeStartTime;
+                    if (mChargeStartTime != 0 && chargeDuration != 0) {
+                        final LogMaker builder = new LogMaker(MetricsEvent.ACTION_CHARGE);
+                        builder.setType(MetricsEvent.TYPE_DISMISS);
+                        builder.addTaggedData(MetricsEvent.FIELD_PLUG_TYPE, mLastPlugType);
+                        builder.addTaggedData(MetricsEvent.FIELD_CHARGING_DURATION_MILLIS,
+                                chargeDuration);
+                        builder.addTaggedData(MetricsEvent.FIELD_BATTERY_LEVEL_START,
+                                mChargeStartLevel);
+                        builder.addTaggedData(MetricsEvent.FIELD_BATTERY_LEVEL_END,
+                                mHealthInfo.batteryLevel);
+                        mMetricsLogger.write(builder);
+                    }
+                    mChargeStartTime = 0;
                 }
             }
             if (mHealthInfo.batteryStatus != mLastBatteryStatus ||
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 48090f2..f83d9e6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -20722,7 +20722,7 @@
     // BROADCASTS
     // =========================================================
 
-    private boolean isInstantApp(ProcessRecord record, String callerPackage, int uid) {
+    private boolean isInstantApp(ProcessRecord record, @Nullable String callerPackage, int uid) {
         if (UserHandle.getAppId(uid) < FIRST_APPLICATION_UID) {
             return false;
         }
@@ -20731,13 +20731,17 @@
             return record.info.isInstantApp();
         }
         // Otherwise check with PackageManager.
-        if (callerPackage == null) {
-            Slog.e(TAG, "isInstantApp with an application's uid, no record, and no package name");
-            throw new IllegalArgumentException("Calling application did not provide package name");
-        }
-        mAppOpsService.checkPackage(uid, callerPackage);
+        IPackageManager pm = AppGlobals.getPackageManager();
         try {
-            IPackageManager pm = AppGlobals.getPackageManager();
+            if (callerPackage == null) {
+                final String[] packageNames = pm.getPackagesForUid(uid);
+                if (packageNames == null || packageNames.length == 0) {
+                    throw new IllegalArgumentException("Unable to determine caller package name");
+                }
+                // Instant Apps can't use shared uids, so its safe to only check the first package.
+                callerPackage = packageNames[0];
+            }
+            mAppOpsService.checkPackage(uid, callerPackage);
             return pm.isInstantApp(callerPackage, UserHandle.getUserId(uid));
         } catch (RemoteException e) {
             Slog.e(TAG, "Error looking up if " + callerPackage + " is an instant app.", e);
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index a5dfd8c..d194db3 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1224,7 +1224,7 @@
     ActivityRecord topRunningActivityLocked(boolean considerKeyguardState) {
         final ActivityStack focusedStack = mFocusedStack;
         ActivityRecord r = focusedStack.topRunningActivityLocked();
-        if (r != null) {
+        if (r != null && isValidTopRunningActivity(r, considerKeyguardState)) {
             return r;
         }
 
@@ -1257,12 +1257,11 @@
                 continue;
             }
 
-            final boolean keyguardLocked = getKeyguardController().isKeyguardLocked();
 
             // This activity can be considered the top running activity if we are not
             // considering the locked state, the keyguard isn't locked, or we can show when
             // locked.
-            if (!considerKeyguardState || !keyguardLocked || topActivity.canShowWhenLocked()) {
+            if (isValidTopRunningActivity(topActivity, considerKeyguardState)) {
                 return topActivity;
             }
         }
@@ -1270,6 +1269,25 @@
         return null;
     }
 
+    /**
+     * Verifies an {@link ActivityRecord} can be the top activity based on keyguard state and
+     * whether we are considering it.
+     */
+    private boolean isValidTopRunningActivity(ActivityRecord record,
+            boolean considerKeyguardState) {
+        if (!considerKeyguardState) {
+            return true;
+        }
+
+        final boolean keyguardLocked = getKeyguardController().isKeyguardLocked();
+
+        if (!keyguardLocked) {
+            return true;
+        }
+
+        return record.canShowWhenLocked();
+    }
+
     @VisibleForTesting
     void getRunningTasks(int maxNum, List<RunningTaskInfo> list,
             @ActivityType int ignoreActivityType, @WindowingMode int ignoreWindowingMode,
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 658c7f1..669d556 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -508,6 +508,8 @@
 
     public void setManualZenMode(int zenMode, Uri conditionId, String caller, String reason) {
         setManualZenMode(zenMode, conditionId, reason, caller, true /*setRingerMode*/);
+        Settings.Global.putInt(mContext.getContentResolver(), Global.SHOW_ZEN_SETTINGS_SUGGESTION,
+                0);
     }
 
     private void setManualZenMode(int zenMode, Uri conditionId, String reason, String caller,
@@ -635,6 +637,10 @@
                     appendDefaultRules(config);
                     reason += ", reset to default rules";
                 }
+            } else {
+                // devices not restoring/upgrading already have updated zen settings
+                Settings.Global.putInt(mContext.getContentResolver(),
+                        Global.ZEN_SETTINGS_UPDATED, 1);
             }
             if (DEBUG) Log.d(TAG, reason);
             synchronized (mConfig) {
@@ -813,6 +819,12 @@
             for (ZenRule automaticRule : mConfig.automaticRules.values()) {
                 if (automaticRule.isAutomaticActive()) {
                     if (zenSeverity(automaticRule.zenMode) > zenSeverity(zen)) {
+                        // automatic rule triggered dnd and user hasn't seen update dnd dialog
+                        if (Settings.Global.getInt(mContext.getContentResolver(),
+                                Global.ZEN_SETTINGS_SUGGESTION_VIEWED, 1) == 0) {
+                            Settings.Global.putInt(mContext.getContentResolver(),
+                                    Global.SHOW_ZEN_SETTINGS_SUGGESTION, 1);
+                        }
                         zen = automaticRule.zenMode;
                     }
                 }
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 3639082..112059d 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -18,6 +18,7 @@
 
 import static android.content.om.OverlayInfo.STATE_DISABLED;
 import static android.content.om.OverlayInfo.STATE_ENABLED;
+import static android.content.om.OverlayInfo.STATE_ENABLED_STATIC;
 import static android.content.om.OverlayInfo.STATE_MISSING_TARGET;
 import static android.content.om.OverlayInfo.STATE_NO_IDMAP;
 import static android.content.om.OverlayInfo.STATE_OVERLAY_UPGRADING;
@@ -63,6 +64,38 @@
     private final String[] mDefaultOverlays;
     private final OverlayChangeListener mListener;
 
+    /**
+     * Helper method to merge the overlay manager's (as read from overlays.xml)
+     * and package manager's (as parsed from AndroidManifest.xml files) views
+     * on overlays.
+     *
+     * Both managers are usually in agreement, but especially after an OTA things
+     * may differ. The package manager is always providing the truth; the overlay
+     * manager has to adapt. Depending on what has changed about an overlay, we
+     * should either scrap the overlay manager's previous settings or merge the old
+     * settings with the new.
+     */
+    private static boolean mustReinitializeOverlay(@NonNull final PackageInfo theTruth,
+            @Nullable final OverlayInfo oldSettings) {
+        if (oldSettings == null) {
+            return true;
+        }
+        if (!Objects.equals(theTruth.overlayTarget, oldSettings.targetPackageName)) {
+            return true;
+        }
+        if (theTruth.isStaticOverlayPackage() != oldSettings.isStatic) {
+            return true;
+        }
+        // a change in priority is only relevant for static RROs: specifically,
+        // a regular RRO should not have its state reset only because a change
+        // in priority
+        if (theTruth.isStaticOverlayPackage() &&
+                theTruth.overlayPriority != oldSettings.priority) {
+            return true;
+        }
+        return false;
+    }
+
     OverlayManagerServiceImpl(@NonNull final PackageManagerHelper packageManager,
             @NonNull final IdmapManager idmapManager,
             @NonNull final OverlayManagerSettings settings,
@@ -99,42 +132,29 @@
             }
         }
 
+        // Reset overlays if something critical like the target package name
+        // has changed
         List<PackageInfo> overlayPackages = mPackageManager.getOverlayPackages(newUserId);
         final int overlayPackagesSize = overlayPackages.size();
         for (int i = 0; i < overlayPackagesSize; i++) {
             final PackageInfo overlayPackage = overlayPackages.get(i);
             final OverlayInfo oi = storedOverlayInfos.get(overlayPackage.packageName);
-            if (oi == null || !oi.targetPackageName.equals(overlayPackage.overlayTarget)) {
-                // Reset the overlay if it didn't exist or had the wrong target package.
+
+            if (mustReinitializeOverlay(overlayPackage, oi)) {
+                // if targetPackageName has changed the package that *used* to
+                // be the target must also update its assets
+                if (oi != null) {
+                    packagesToUpdateAssets.add(oi.targetPackageName);
+                }
+
                 mSettings.init(overlayPackage.packageName, newUserId,
                         overlayPackage.overlayTarget,
                         overlayPackage.applicationInfo.getBaseCodePath(),
                         overlayPackage.isStaticOverlayPackage(),
                         overlayPackage.overlayPriority,
                         overlayPackage.overlayCategory);
-
-                if (oi != null) {
-                    // The targetPackageName we have stored doesn't match the overlay's target.
-                    // Queue the old target for an update as well.
-                    packagesToUpdateAssets.add(oi.targetPackageName);
-                }
-            } else {
-                // Update all other components of an overlay that don't require a hard reset.
-                if (!Objects.equals(oi.category, overlayPackage.overlayCategory)) {
-                    // When changing categories, it is ok just to update our internal state.
-                    mSettings.setCategory(overlayPackage.packageName, newUserId,
-                            overlayPackage.overlayCategory);
-                }
             }
 
-            try {
-                updateState(overlayPackage.overlayTarget, overlayPackage.packageName, newUserId, 0);
-            } catch (OverlayManagerSettings.BadKeyException e) {
-                Slog.e(TAG, "failed to update settings", e);
-                mSettings.remove(overlayPackage.packageName, newUserId);
-            }
-
-            packagesToUpdateAssets.add(overlayPackage.overlayTarget);
             storedOverlayInfos.remove(overlayPackage.packageName);
         }
 
@@ -148,6 +168,22 @@
             packagesToUpdateAssets.add(oi.targetPackageName);
         }
 
+        // make sure every overlay's state is up-to-date; this needs to happen
+        // after old overlays have been removed, or we risk removing a
+        // legitimate idmap file if a new overlay package has the same apk path
+        // as the removed overlay package used to have
+        for (int i = 0; i < overlayPackagesSize; i++) {
+            final PackageInfo overlayPackage = overlayPackages.get(i);
+            try {
+                updateState(overlayPackage.overlayTarget, overlayPackage.packageName,
+                        newUserId, 0);
+            } catch (OverlayManagerSettings.BadKeyException e) {
+                Slog.e(TAG, "failed to update settings", e);
+                mSettings.remove(overlayPackage.packageName, newUserId);
+            }
+            packagesToUpdateAssets.add(overlayPackage.overlayTarget);
+        }
+
         // remove target packages that are not installed
         final Iterator<String> iter = packagesToUpdateAssets.iterator();
         while (iter.hasNext()) {
@@ -355,15 +391,13 @@
 
         try {
             final OverlayInfo oldOi = mSettings.getOverlayInfo(packageName, userId);
-            if (!oldOi.targetPackageName.equals(pkg.overlayTarget)) {
+            if (mustReinitializeOverlay(pkg, oldOi)) {
+                if (oldOi != null && !oldOi.targetPackageName.equals(pkg.overlayTarget)) {
+                    mListener.onOverlaysChanged(pkg.overlayTarget, userId);
+                }
                 mSettings.init(packageName, userId, pkg.overlayTarget,
                         pkg.applicationInfo.getBaseCodePath(), pkg.isStaticOverlayPackage(),
                         pkg.overlayPriority, pkg.overlayCategory);
-            } else {
-                if (!Objects.equals(oldOi.category, pkg.overlayCategory)) {
-                    // Update the category in-place.
-                    mSettings.setCategory(packageName, userId, pkg.overlayCategory);
-                }
             }
 
             if (updateState(pkg.overlayTarget, packageName, userId, 0)) {
@@ -608,6 +642,8 @@
         if (overlayPackage != null) {
             modified |= mSettings.setBaseCodePath(overlayPackageName, userId,
                     overlayPackage.applicationInfo.getBaseCodePath());
+            modified |= mSettings.setCategory(overlayPackageName, userId,
+                    overlayPackage.overlayCategory);
         }
 
         final @OverlayInfo.State int currentState = mSettings.getState(overlayPackageName, userId);
@@ -650,6 +686,10 @@
             return STATE_NO_IDMAP;
         }
 
+        if (overlayPackage.isStaticOverlayPackage()) {
+            return STATE_ENABLED_STATIC;
+        }
+
         final boolean enabled = mSettings.getEnabled(overlayPackage.packageName, userId);
         return enabled ? STATE_ENABLED : STATE_DISABLED;
     }
diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java
index e176351..36bf83d 100644
--- a/services/core/java/com/android/server/om/OverlayManagerSettings.java
+++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java
@@ -309,6 +309,7 @@
             pw.print("mState.............: "); pw.println(OverlayInfo.stateToString(item.getState()));
             pw.print("mIsEnabled.........: "); pw.println(item.isEnabled());
             pw.print("mIsStatic..........: "); pw.println(item.isStatic());
+            pw.print("mPriority..........: "); pw.println(item.mPriority);
             pw.print("mCategory..........: "); pw.println(item.mCategory);
 
             pw.decreaseIndent();
@@ -528,7 +529,7 @@
         private OverlayInfo getOverlayInfo() {
             if (mCache == null) {
                 mCache = new OverlayInfo(mPackageName, mTargetPackageName, mCategory, mBaseCodePath,
-                        mState, mUserId);
+                        mState, mUserId, mPriority, mIsStatic);
             }
             return mCache;
         }
diff --git a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
index 54bb115..d576d33 100644
--- a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
+++ b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java
@@ -126,6 +126,7 @@
                 final OverlayInfo oi = overlaysForTarget.get(i);
                 String status;
                 switch (oi.state) {
+                    case OverlayInfo.STATE_ENABLED_STATIC:
                     case OverlayInfo.STATE_ENABLED:
                         status = "[x]";
                         break;
diff --git a/services/core/java/com/android/server/pm/InstantAppResolver.java b/services/core/java/com/android/server/pm/InstantAppResolver.java
index d0a3757..9a5dd5e 100644
--- a/services/core/java/com/android/server/pm/InstantAppResolver.java
+++ b/services/core/java/com/android/server/pm/InstantAppResolver.java
@@ -47,7 +47,6 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.RemoteException;
-import android.text.TextUtils;
 import android.util.Log;
 import android.util.Slog;
 
@@ -164,6 +163,11 @@
                 Log.d(TAG, "[" + token + "] Phase1; No results matched");
             }
         }
+        // if the match external flag is set, return an empty resolve info instead of a null result.
+        if (resolveInfo == null && (origIntent.getFlags() & FLAG_ACTIVITY_MATCH_EXTERNAL) != 0) {
+            return new AuxiliaryResolveInfo(token, false, createFailureIntent(origIntent, token),
+                    null /* filters */);
+        }
         return resolveInfo;
     }
 
@@ -365,23 +369,20 @@
             InstantAppDigest digest, String token) {
         final int[] shaPrefix = digest.getDigestPrefix();
         final byte[][] digestBytes = digest.getDigestBytes();
-        final Intent failureIntent = new Intent(origIntent);
         boolean requiresSecondPhase = false;
-        failureIntent.setFlags(failureIntent.getFlags() | Intent.FLAG_IGNORE_EPHEMERAL);
-        failureIntent.setFlags(failureIntent.getFlags() & ~Intent.FLAG_ACTIVITY_MATCH_EXTERNAL);
-        failureIntent.setLaunchToken(token);
         ArrayList<AuxiliaryResolveInfo.AuxiliaryFilter> filters = null;
-        boolean isWebIntent = origIntent.isWebIntent();
+        boolean requiresPrefixMatch = origIntent.isWebIntent() || (shaPrefix.length > 0
+                        && (origIntent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) == 0);
         for (InstantAppResolveInfo instantAppResolveInfo : instantAppResolveInfoList) {
-            if (shaPrefix.length > 0 && instantAppResolveInfo.shouldLetInstallerDecide()) {
-                Slog.e(TAG, "InstantAppResolveInfo with mShouldLetInstallerDecide=true when digest"
-                        + " provided; ignoring");
+            if (requiresPrefixMatch && instantAppResolveInfo.shouldLetInstallerDecide()) {
+                Slog.d(TAG, "InstantAppResolveInfo with mShouldLetInstallerDecide=true when digest"
+                        + " required; ignoring");
                 continue;
             }
             byte[] filterDigestBytes = instantAppResolveInfo.getDigestBytes();
             // Only include matching digests if we have a prefix and we're either dealing with a
-            // web intent or the resolveInfo specifies digest details.
-            if (shaPrefix.length > 0 && (isWebIntent || filterDigestBytes.length > 0)) {
+            // prefixed request or the resolveInfo specifies digest details.
+            if (shaPrefix.length > 0 && (requiresPrefixMatch || filterDigestBytes.length > 0)) {
                 boolean matchFound = false;
                 // Go in reverse order so we match the narrowest scope first.
                 for (int i = shaPrefix.length - 1; i >= 0; --i) {
@@ -409,17 +410,26 @@
             }
         }
         if (filters != null && !filters.isEmpty()) {
-            return new AuxiliaryResolveInfo(token, requiresSecondPhase, failureIntent, filters);
-        }
-        // if the match external flag is set, return an empty resolve info
-        if ((origIntent.getFlags() & FLAG_ACTIVITY_MATCH_EXTERNAL) != 0) {
-            return new AuxiliaryResolveInfo(token, false, failureIntent, null /* filters */);
+            return new AuxiliaryResolveInfo(token, requiresSecondPhase,
+                    createFailureIntent(origIntent, token), filters);
         }
         // Hash or filter mis-match; no instant apps for this domain.
         return null;
     }
 
     /**
+     * Creates a failure intent for the installer to send in the case that the instant app cannot be
+     * launched for any reason.
+     */
+    private static Intent createFailureIntent(Intent origIntent, String token) {
+        final Intent failureIntent = new Intent(origIntent);
+        failureIntent.setFlags(failureIntent.getFlags() | Intent.FLAG_IGNORE_EPHEMERAL);
+        failureIntent.setFlags(failureIntent.getFlags() & ~Intent.FLAG_ACTIVITY_MATCH_EXTERNAL);
+        failureIntent.setLaunchToken(token);
+        return failureIntent;
+    }
+
+    /**
      * Returns one of three states: <p/>
      * <ul>
      *     <li>{@code null} if there are no matches will not be; resolution is unnecessary.</li>
diff --git a/services/core/java/com/android/server/slice/SlicePermissionManager.java b/services/core/java/com/android/server/slice/SlicePermissionManager.java
index d25ec89..c67f94b 100644
--- a/services/core/java/com/android/server/slice/SlicePermissionManager.java
+++ b/services/core/java/com/android/server/slice/SlicePermissionManager.java
@@ -251,6 +251,9 @@
             }
             // Can't read or no permissions exist, create a clean object.
             client = new SliceClientPermissions(pkgUser, this);
+            synchronized (mCachedClients) {
+                mCachedClients.put(pkgUser, client);
+            }
         }
         return client;
     }
@@ -278,6 +281,9 @@
             }
             // Can't read or no permissions exist, create a clean object.
             provider = new SliceProviderPermissions(pkgUser, this);
+            synchronized (mCachedProviders) {
+                mCachedProviders.put(pkgUser, provider);
+            }
         }
         return provider;
     }
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index ee03aff..e637df4 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -923,10 +923,12 @@
     }
 
     void detachChildren() {
+        SurfaceControl.openTransaction();
         for (int i = mChildren.size() - 1; i >= 0; i--) {
             final WindowState w = mChildren.get(i);
             w.mWinAnimator.detachChildren();
         }
+        SurfaceControl.closeTransaction();
     }
 
     void finishRelaunching() {
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
index 1415ada..1ce41a6 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
@@ -325,13 +325,12 @@
     }
 
     /**
-     * Verifies the correct activity is returned when querying the top running activity with an
-     * empty focused stack.
+     * Verifies the correct activity is returned when querying the top running activity.
      */
     @Test
-    public void testNonFocusedTopRunningActivity() throws Exception {
+    public void testTopRunningActivity() throws Exception {
         // Create stack to hold focus
-        final ActivityStack focusedStack = mService.mStackSupervisor.getDefaultDisplay()
+        final ActivityStack emptyStack = mService.mStackSupervisor.getDefaultDisplay()
                 .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
 
         final KeyguardController keyguard = mSupervisor.getKeyguardController();
@@ -340,7 +339,7 @@
         final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true)
                 .setStack(stack).build();
 
-        mSupervisor.mFocusedStack = focusedStack;
+        mSupervisor.mFocusedStack = emptyStack;
 
         doAnswer((InvocationOnMock invocationOnMock) -> {
             final SparseIntArray displayIds = invocationOnMock.<SparseIntArray>getArgument(0);
@@ -359,6 +358,12 @@
         assertEquals(null, mService.mStackSupervisor.topRunningActivityLocked(
                 true /* considerKeyguardState */));
 
+        // Change focus to stack with activity.
+        mSupervisor.mFocusedStack = stack;
+        assertEquals(activity, mService.mStackSupervisor.topRunningActivityLocked());
+        assertEquals(null, mService.mStackSupervisor.topRunningActivityLocked(
+                true /* considerKeyguardState */));
+
         // Add activity that should be shown on the keyguard.
         final ActivityRecord showWhenLockedActivity = new ActivityBuilder(mService)
                 .setCreateTask(true)
@@ -370,6 +375,13 @@
         assertEquals(showWhenLockedActivity, mService.mStackSupervisor.topRunningActivityLocked());
         assertEquals(showWhenLockedActivity, mService.mStackSupervisor.topRunningActivityLocked(
                 true /* considerKeyguardState */));
+
+        // Change focus back to empty stack
+        mSupervisor.mFocusedStack = emptyStack;
+        // Ensure the show when locked activity is returned when not the focused stack
+        assertEquals(showWhenLockedActivity, mService.mStackSupervisor.topRunningActivityLocked());
+        assertEquals(showWhenLockedActivity, mService.mStackSupervisor.topRunningActivityLocked(
+                true /* considerKeyguardState */));
     }
 
     /**
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
index a9d6c29..90947f4 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
@@ -503,7 +503,8 @@
     @Test
     public void run_sendsEncryptedKeysIfAvailableToSync_withRawPublicKey() throws Exception {
         mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
-                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS,
+                TestData.getInsecureCertPathForEndpoint1());
 
         mRecoverableKeyStoreDb.setServerParams(
                 TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_VAULT_HANDLE);
@@ -528,7 +529,8 @@
                 lockScreenHash,
                 keyChainSnapshot.getEncryptedRecoveryKeyBlob(),
                 /*vaultParams=*/ KeySyncUtils.packVaultParams(
-                        TestData.CERT_1_PUBLIC_KEY,
+                        TestData.getInsecureCertPathForEndpoint1().getCertificates().get(0)
+                                .getPublicKey(),
                         counterId,
                         /*maxAttempts=*/ 10,
                         TEST_VAULT_HANDLE));
@@ -537,7 +539,7 @@
         assertThat(keyChainSnapshot.getCounterId()).isEqualTo(counterId);
         assertThat(keyChainSnapshot.getMaxAttempts()).isEqualTo(10);
         assertThat(keyChainSnapshot.getTrustedHardwareCertPath())
-                .isEqualTo(TestData.CERT_PATH_1);
+                .isEqualTo(TestData.getInsecureCertPathForEndpoint1());
         assertThat(keyChainSnapshot.getServerParams()).isEqualTo(TEST_VAULT_HANDLE);
         WrappedApplicationKey keyData = applicationKeys.get(0);
         assertEquals(TEST_APP_KEY_ALIAS, keyData.getAlias());
@@ -805,7 +807,7 @@
     private byte[] decryptThmEncryptedKey(
             byte[] lockScreenHash, byte[] encryptedKey, byte[] vaultParams) throws Exception {
         byte[] locallyEncryptedKey = SecureBox.decrypt(
-                TestData.CERT_1_PRIVATE_KEY,
+                TestData.getInsecurePrivateKeyForEndpoint1(),
                 /*sharedSecret=*/ KeySyncUtils.calculateThmKfHash(lockScreenHash),
                 /*header=*/ KeySyncUtils.concat(THM_ENCRYPTED_RECOVERY_KEY_HEADER, vaultParams),
                 encryptedKey
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
index e82478f..8e86a87 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
@@ -101,35 +101,22 @@
     private static final String INSECURE_CERTIFICATE_ALIAS =
             TrustedRootCertificates.TEST_ONLY_INSECURE_CERTIFICATE_ALIAS;
     private static final String TEST_SESSION_ID = "karlin";
-    private static final byte[] TEST_PUBLIC_KEY = new byte[] {
-        (byte) 0x30, (byte) 0x59, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x07, (byte) 0x2a,
-        (byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x02, (byte) 0x01, (byte) 0x06,
-        (byte) 0x08, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x03,
-        (byte) 0x01, (byte) 0x07, (byte) 0x03, (byte) 0x42, (byte) 0x00, (byte) 0x04, (byte) 0xb8,
-        (byte) 0x00, (byte) 0x11, (byte) 0x18, (byte) 0x98, (byte) 0x1d, (byte) 0xf0, (byte) 0x6e,
-        (byte) 0xb4, (byte) 0x94, (byte) 0xfe, (byte) 0x86, (byte) 0xda, (byte) 0x1c, (byte) 0x07,
-        (byte) 0x8d, (byte) 0x01, (byte) 0xb4, (byte) 0x3a, (byte) 0xf6, (byte) 0x8d, (byte) 0xdc,
-        (byte) 0x61, (byte) 0xd0, (byte) 0x46, (byte) 0x49, (byte) 0x95, (byte) 0x0f, (byte) 0x10,
-        (byte) 0x86, (byte) 0x93, (byte) 0x24, (byte) 0x66, (byte) 0xe0, (byte) 0x3f, (byte) 0xd2,
-        (byte) 0xdf, (byte) 0xf3, (byte) 0x79, (byte) 0x20, (byte) 0x1d, (byte) 0x91, (byte) 0x55,
-        (byte) 0xb0, (byte) 0xe5, (byte) 0xbd, (byte) 0x7a, (byte) 0x8b, (byte) 0x32, (byte) 0x7d,
-        (byte) 0x25, (byte) 0x53, (byte) 0xa2, (byte) 0xfc, (byte) 0xa5, (byte) 0x65, (byte) 0xe1,
-        (byte) 0xbd, (byte) 0x21, (byte) 0x44, (byte) 0x7e, (byte) 0x78, (byte) 0x52, (byte) 0xfa};
+    private static final byte[] TEST_PUBLIC_KEY = TestData.CERT_1_PUBLIC_KEY.getEncoded();
     private static final byte[] TEST_SALT = getUtf8Bytes("salt");
     private static final byte[] TEST_SECRET = getUtf8Bytes("password1234");
     private static final byte[] TEST_VAULT_CHALLENGE = getUtf8Bytes("vault_challenge");
     private static final byte[] TEST_VAULT_PARAMS = new byte[] {
         // backend_key
-        (byte) 0x04, (byte) 0xb8, (byte) 0x00, (byte) 0x11, (byte) 0x18, (byte) 0x98, (byte) 0x1d,
-        (byte) 0xf0, (byte) 0x6e, (byte) 0xb4, (byte) 0x94, (byte) 0xfe, (byte) 0x86, (byte) 0xda,
-        (byte) 0x1c, (byte) 0x07, (byte) 0x8d, (byte) 0x01, (byte) 0xb4, (byte) 0x3a, (byte) 0xf6,
-        (byte) 0x8d, (byte) 0xdc, (byte) 0x61, (byte) 0xd0, (byte) 0x46, (byte) 0x49, (byte) 0x95,
-        (byte) 0x0f, (byte) 0x10, (byte) 0x86, (byte) 0x93, (byte) 0x24, (byte) 0x66, (byte) 0xe0,
-        (byte) 0x3f, (byte) 0xd2, (byte) 0xdf, (byte) 0xf3, (byte) 0x79, (byte) 0x20, (byte) 0x1d,
-        (byte) 0x91, (byte) 0x55, (byte) 0xb0, (byte) 0xe5, (byte) 0xbd, (byte) 0x7a, (byte) 0x8b,
-        (byte) 0x32, (byte) 0x7d, (byte) 0x25, (byte) 0x53, (byte) 0xa2, (byte) 0xfc, (byte) 0xa5,
-        (byte) 0x65, (byte) 0xe1, (byte) 0xbd, (byte) 0x21, (byte) 0x44, (byte) 0x7e, (byte) 0x78,
-        (byte) 0x52, (byte) 0xfa,
+        (byte) 0x04, (byte) 0x8e, (byte) 0x0c, (byte) 0x11, (byte) 0x4a, (byte) 0x79, (byte) 0x20,
+        (byte) 0x7c, (byte) 0x00, (byte) 0x4c, (byte) 0xd7, (byte) 0xe9, (byte) 0x06, (byte) 0xe2,
+        (byte) 0x58, (byte) 0x21, (byte) 0x45, (byte) 0xfa, (byte) 0x24, (byte) 0xcb, (byte) 0x07,
+        (byte) 0x66, (byte) 0xde, (byte) 0xfd, (byte) 0xf1, (byte) 0x83, (byte) 0xb4, (byte) 0x26,
+        (byte) 0x55, (byte) 0x98, (byte) 0xcb, (byte) 0xa9, (byte) 0xd5, (byte) 0x55, (byte) 0xad,
+        (byte) 0x65, (byte) 0xc5, (byte) 0xff, (byte) 0x5c, (byte) 0xfb, (byte) 0x1c, (byte) 0x4e,
+        (byte) 0x34, (byte) 0x98, (byte) 0x7e, (byte) 0x4f, (byte) 0x96, (byte) 0xa2, (byte) 0xa3,
+        (byte) 0x7e, (byte) 0xf4, (byte) 0x46, (byte) 0x52, (byte) 0x04, (byte) 0xba, (byte) 0x2a,
+        (byte) 0xb9, (byte) 0x47, (byte) 0xbb, (byte) 0xc2, (byte) 0x1e, (byte) 0xdd, (byte) 0x15,
+        (byte) 0x1a, (byte) 0xc0,
         // counter_id
         (byte) 0x31, (byte) 0x32, (byte) 0x33, (byte) 0x34, (byte) 0x00, (byte) 0x00, (byte) 0x00,
         (byte) 0x00,
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java
index 64eb49b..5d4be1b 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java
@@ -29,6 +29,7 @@
 import java.security.cert.CertificateFactory;
 import java.security.cert.CertPath;
 import java.security.spec.ECPrivateKeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
 import java.util.Base64;
 
 import javax.crypto.KeyGenerator;
@@ -37,56 +38,56 @@
 public final class TestData {
 
     private static final String KEY_ALGORITHM = "AES";
-    private static final long DEFAULT_SERIAL = 1000;
+    private static final long DEFAULT_SERIAL = 10001;
     private static final String CERT_PATH_ENCODING = "PkiPath";
 
     private static final String CERT_PATH_1_BASE64 = ""
-            + "MIIIPzCCBS8wggMXoAMCAQICAhAAMA0GCSqGSIb3DQEBCwUAMCAxHjAcBgNVBAMM"
-            + "FUdvb2dsZSBDcnlwdEF1dGhWYXVsdDAeFw0xODAyMDMwMDQyMDNaFw0yODAyMDEw"
-            + "MDQyMDNaMC0xKzApBgNVBAMMIkdvb2dsZSBDcnlwdEF1dGhWYXVsdCBJbnRlcm1l"
-            + "ZGlhdGUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDckHib0X6rQyDq"
-            + "k4519b5du0OrCPk30XXKwz+Hz5y4cGZaWKGcHOHWS2X9YApRzO00/EbvFkWVUTVG"
-            + "27wJ54V+C3HHSOAUWHhEgfFWvvHwfn9HTDx1BEk79aQqJ7DuJ06Sn/WOiMtKVAT5"
-            + "6Mi8mekBxpMOrdZqwlcLrUVsZxEHsw5/ceZu4cSWzc7SzlnbNK1cCgyRDGqWf6Gp"
-            + "3hGE86kUOtM1i95RgUIpw+w/z0wxpF6kIyQTjK+KjiYH/RBOJIEcm6sSWZlMotKL"
-            + "Sn2lhf+XL8yUxExIHTosfeb077QWW4w2BB2NZM4wPAO3w4aw33FNigDQc2SQYmnU"
-            + "EYmIcD8kx77+JWCgCxBJc2zTHXtBxWuXAQ+iegt8RO+QD97pd6XKM9xPsAOkcWLp"
-            + "79o+AJol4P5fwvgYM69mM4lwH12v86RI4aptPQOag0KDIHXyKbjaQyAgv30l4KkD"
-            + "pf2uWODhOOTwNbVPYUm3sYUlhBcbyhTk8YqN9sPU4QAao5sKTAYZgB/mlheQypTU"
-            + "wyvqz6bRzGehVB3ltP9gCyKdI04VXEUuUBWk3STyV2REQen5/LKAns6v11Cz22Zr"
-            + "EdCvNLgetnyV7CJsOa/wD/GiUWL2Ta7pzshi9ahJqrrcNPRbAzOLcNKZkFexhzPp"
-            + "onuo/pNrcaRda1frepXxVkmbsgOULwIDAQABo2YwZDAdBgNVHQ4EFgQUd6md2hCP"
-            + "lmf3VkEX5FfDxKBLbaAwHwYDVR0jBBgwFoAUm2X66jmB+eBCaZHSjGYzHM/x6fgw"
-            + "EgYDVR0TAQH/BAgwBgEB/wIBATAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQEL"
-            + "BQADggIBAFgShhuW+WVTowN080PLf0TWPlHACHHUPghf7rFGxgUjJypCloE84Beg"
-            + "3ROpP5l19CDqZ9OyPzA1z6VAzeGXyFhZvby7G2tZDBRP/v0u8pnSAdC5F8l8Vh2Y"
-            + "GdgE3sZD25vpdBi7P0Ef6LYQetOJXn86PqgmgW1F6lzxDjKCsi9kpeU0AWwDdOVg"
-            + "748wku50o8UEzsVwxzFd9toGlge/nn3FH5J7EuGzAlFwToHqpwTVEegaAd0l9mr5"
-            + "+rS7Urd3X80BHDqCBcXE7Uqbtzw5Y+lmowMCnW0kFN02dC9dLt2c9IxC+9sPIA5e"
-            + "TkrZBkrkTVRGLj2r29j7nC9m5VaKcBqcLZDWy8pRna8yaZprgNdE8d/WTY9nVsic"
-            + "09N8zNF5Q0bhhWa3QonlB9XW5ZqDguiclvn+5TtREzSAtSOyxM+gfG3l0wjOywIk"
-            + "1aFa52RaqAWPL67KOM6G3vKNpMnW5hrmHrijuKxiarGIoZfkZMR5ijK0uFgv3/p6"
-            + "NHL/YQBaHJJhkKet5ThiPxwW9+1k/ZcXVeY26Xh+22Gp/8to7ZW8guPPiN1hfpD+"
-            + "7f1IdSmHDrsZQQ7bfzV0bppsyNNB7e2Ecyw+GQny27nytBLJDGdRBurbwQvzppQO"
-            + "6Qmlk0rfCszh7bGCoCQNxXmuDsQ5BC+pQUqJplTqds1smyi29xs3MIIDCDCB8aAD"
-            + "AgECAgYBYVkuU0cwDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwiR29vZ2xlIENy"
-            + "eXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAyMDIwMTAxMDNaFw0yMDAy"
-            + "MDMwMTAxMDNaMCkxJzAlBgNVBAMTHkdvb2dsZSBDcnlwdEF1dGhWYXVsdCBJbnN0"
-            + "YW5jZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgAERiYHfButJT+htocB40B"
-            + "tDr2jdxh0EZJlQ8QhpMkZuA/0t/zeSAdkVWw5b16izJ9JVOi/KVl4b0hRH54Uvow"
-            + "DQYJKoZIhvcNAQELBQADggIBAJ3PM4GNTNYzMr8E/IGsWZkLx9ARAALqBXz7As59"
-            + "F8y5UcLMqkXD/ewOfBZgF5VzjlAePyE/wSw0wc3xzvrDVVDiZaMBW1DVtSlbn25q"
-            + "00m00mmcUeyyMc7vuRkPoDshIMQTc8+U3yyYsVScSV+B4TvSx6wPZ9FpwnSPjVPD"
-            + "2GkqeMTWszuxNVEWq0wmm0K5lMaX0hfiak+4/IZxOPPGIg2py1KLA/H2gdyeqyJR"
-            + "cAsyEkfwLlushR5T9abSiPsIRcYoX8Ck8Lt+gQ7RCMefnm8CoOBKIfcjuV4PGOoe"
-            + "Xrq57VR5SsOeT07bL+D7B+mohYFI1v2G3WClAE8XgM3q8NoFFvaYmoi0+UcTduil"
-            + "47qvozjdNmjRAgu5j6vMKXEdG5Rqsja8hy0LG1hwfnR0gNiwcZ5Le3GyFnwH1Igq"
-            + "vsGOUM0ohnDUAU0zJY7nG0QYrDYe5/QPRNhWDpYkwHDiqcG28wIQCOTPAZHU2EoS"
-            + "KjSqEG2l0S5JPcor2BEde9ikSkcmK8foxlOHIdFn+n7RNF3bSEfKn1IOuXoqPidm"
-            + "eBQLevqG8KTy/C9CHqlaCNlpbIA9h+WVfsjm2s6JXBu0YbcfoIbJAmSuZVeqB/+Z"
-            + "Vvpfiad/jQWzY49fRnsSmV7VveTFPGtJxC89EadbMAinMZo+72u59319RqN5wsP2"
-            + "Zus8";
-    private static String CERT_PATH_2_BASE64 = ""
+            + "MIIIXTCCBRowggMCoAMCAQICEB35ZwzVpI9ssXg9SAehnU0wDQYJKoZIhvcNAQEL"
+            + "BQAwMTEvMC0GA1UEAxMmR29vZ2xlIENsb3VkIEtleSBWYXVsdCBTZXJ2aWNlIFJv"
+            + "b3QgQ0EwHhcNMTgwNTA3MTg1ODEwWhcNMjgwNTA4MTg1ODEwWjA5MTcwNQYDVQQD"
+            + "Ey5Hb29nbGUgQ2xvdWQgS2V5IFZhdWx0IFNlcnZpY2UgSW50ZXJtZWRpYXRlIENB"
+            + "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA73TrvH3j6zEimpcc32tx"
+            + "2iupWwfyzdE5l4Ejc5EBYzx0aZH6b/KDuutwustk0IoyjlGySMBz/21YgWejIm+n"
+            + "duAlpk7WY5kYHp0XWtzdmxZknmWTqugPeNZeiKEjoDmpyIbY6N+f13hQ2RVh+WDT"
+            + "EowQ/i04WBL75chshlIG+3A42g5Qr7DZEKdT9oJQqkntzj0cGyJ5X8BwjeTiJrvY"
+            + "k2Kn/0555/Kpp65G3Rf29VPPU3i67kthAT3SavLBpH03S4WZ+QlfrAiGQziydtz9"
+            + "t7mSk1xefjax5ZWAuJAfCbKfI3VWAcaUr4P57BzmDcSi0jgs1aM3t2BrPfAMRxWv"
+            + "35yDZnrC+HipzkjyDGBfHmFgoglyhc9e/Kj3mSusO0Rq1wguVXKs2hKXRoaGJuHt"
+            + "e3YIwTC1pLznqvolhD1nPoXf8rMzgHRzlc9H8iXsgB1p7975nh5WCPrMDX2eAmYd"
+            + "a0xTMccTeBzIM2ohxQsxlh5rsjXVNU3ihbWkHquzIiwFcAtldP3dMksj0dn/DnYD"
+            + "yokjEgU/z2I216E93x9hmKkEk6Pp7o8t/z6lwMT9FJIuzp7NREnWCSi+e5s2E7FD"
+            + "j6S7xY2zEIUHrmwuuJc0jzJnwdZ+0myinaTmBDvBXR5cU1cmEAZoheCAoRv9Z/6o"
+            + "ASczLF0C4uuVfA5GXcAm14cCAwEAAaMmMCQwDgYDVR0PAQH/BAQDAgGGMBIGA1Ud"
+            + "EwEB/wQIMAYBAf8CAQEwDQYJKoZIhvcNAQELBQADggIBAEPht79yQm8woQbPB1Bs"
+            + "eotkzJtTWTO9fnIWwNiRfQ3vJFXf69ghE77wUS13Ez3FlgNPj0Qxmg5ouE0d2yYV"
+            + "4AUrXnEGZELcyN2XHRXyNK0zXgnr3x6eZyY7QfgGKJgkyja5TS6ZPWGyaLKhClS0"
+            + "AYZSzWJtz0+AkGCdTbmyy7ShdXJ+GfnmssbndZA62VhcjeQmHsDq7V3PKAsp4/B9"
+            + "PzcnTrgkUFNnP1F1pr7JpUUX3xyRFy6gjIrUx1fcOFRxFYPWGLLMZ6P41rafm+M/"
+            + "CbBNr5CY7NrZjr34jLqWycfYes49o9OK44X/wPrxj0Sjg+VrW21+AJ9vrM7DS5hE"
+            + "QX1lDbDtQGkk3N1vgCTo6xt9LXsEu4xUT5bk7YAfpJqM0ltDFPwYAGCbjSkVT/M5"
+            + "JVZkKiUW668Us67x8yZc/5bxbvTA+5xrYhak/VYIBY6qub4J+bKwadw6uBgxnq4P"
+            + "hwgwjfaoJy9YAXCswjCtaE9GwkVmRnJE9vFjJ33IGf37hFTYEHBFy4FomVmQwRFZ"
+            + "TIe7tkKDq9i18F7lzBPJPO6wEG8bxi4csatrjcVHR9erpY5u6ebtkKG8qsan9qzh"
+            + "iWAgSytiT++HejZeoQ+RRgQWjupjdDo5/0oSdQqvaN8Ah6C2J+ecCZ12Lu0FwF+t"
+            + "t9Ie3pF6W8TzxzuMdFWq+afvMIIDOzCCASOgAwIBAgIRAOTj/iNQb6/Qit7zAW9n"
+            + "cL0wDQYJKoZIhvcNAQELBQAwOTE3MDUGA1UEAxMuR29vZ2xlIENsb3VkIEtleSBW"
+            + "YXVsdCBTZXJ2aWNlIEludGVybWVkaWF0ZSBDQTAeFw0xODA1MDcyMjE4MTFaFw0y"
+            + "MzA1MDgyMjE4MTFaMDIxMDAuBgNVBAMTJ0dvb2dsZSBDbG91ZCBLZXkgVmF1bHQg"
+            + "U2VydmljZSBFbmRwb2ludDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABI4MEUp5"
+            + "IHwATNfpBuJYIUX6JMsHZt798YO0JlWYy6nVVa1lxf9c+xxONJh+T5aio370RlIE"
+            + "uiq5R7vCHt0VGsCjEDAOMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIB"
+            + "AGf6QU58lU+gGzy8hnp0suR/ixC++CExtf39pDHkdfU/e3ui4ROR+pjQ5F7okDFW"
+            + "eKSCNcJZ7tyXMJ9g7/I0qVY8Bj/gRnlVokdl/wD5PiL9GIzqWfnHNe3T+xrAAAgO"
+            + "D0bEmjgwNYmekfUIYQczd04d7ZMGnmAkpVH/0O2mf9q5x9fMlbKuAygUqQ/gmnlg"
+            + "xKfl9DSRWi4oMBOqlKlCRP1XAh3anu92+M/EhsFbyc07CWZY0SByX5M/cHVMLhUX"
+            + "jZHvcYLyOmJWJmXznidgyNeIR6t9yDB55iCt7WSn3qMY+9vA9ELzt8jYpBNaKc0G"
+            + "bWQkRzYWegkf4kMis98eQ3SnAKbRz6669nmuAdxKs9/LK6BlFOFw1xvsTRQ96dBa"
+            + "oiX2XGhou+Im0Td/AMs0Aigz2N+Ujq/yW//35GZQfdGGIYtFbkcltStygjIJyAM1"
+            + "pBhyBBkJhOhRpO4fXh98aq8H5J7R9i5A9WpnDstAxPxcNCDWn0O/WxhPvVZkFTpi"
+            + "NXh9dnlJ/kZe+j+z5ZMaxW435drLPx2AQKjXA9GgGrFPltTUyGycmEGtuxLvSnm/"
+            + "zPlmk5FUk7x2wEr0+bZ3cx0JHHgAtgXpe0jkDi8Bw8O3X7mUOjxVhYU6auiYJezW"
+            + "9LGmweaKwYvS04UCWOReolUVexob9LI/VX1JrrwD3s7k";
+    private static final String CERT_PATH_2_BASE64 = ""
             + "MIIFMzCCBS8wggMXoAMCAQICAhAAMA0GCSqGSIb3DQEBCwUAMCAxHjAcBgNVBAMM"
             + "FUdvb2dsZSBDcnlwdEF1dGhWYXVsdDAeFw0xODAyMDMwMDQyMDNaFw0yODAyMDEw"
             + "MDQyMDNaMC0xKzApBgNVBAMMIkdvb2dsZSBDcnlwdEF1dGhWYXVsdCBJbnRlcm1l"
@@ -117,194 +118,44 @@
             + "6Qmlk0rfCszh7bGCoCQNxXmuDsQ5BC+pQUqJplTqds1smyi29xs3";
 
     private static final String THM_CERT_XML_BEFORE_SERIAL = ""
-            + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
-                    + "<certificates>\n"
-                    + "  <metadata>\n"
-                    + "    <serial>\n"
-                    + "      ";
-    private static final String THM_CERT_XML_AFTER_SERIAL = "\n"
-            + "    </serial>\n"
-            + "    <creation-time>\n"
-            + "      1515697631\n"
-            + "    </creation-time>\n"
-            + "    <refresh-interval>\n"
-            + "      2592000\n"
-            + "    </refresh-interval>\n"
+            + "<certificate>\n"
+            + "  <metadata>\n"
+            + "    <serial>";
+    private static final String THM_CERT_XML_AFTER_SERIAL = ""
+            + "</serial>\n"
+            + "    <creation-time>1525817891</creation-time>\n"
+            + "    <refresh-interval>2592000</refresh-interval>\n"
             + "    <previous>\n"
-            + "      <serial>\n"
-            + "        0\n"
-            + "      </serial>\n"
-            + "      <hash>\n"
-            + "        47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=\n"
-            + "      </hash>\n"
+            + "      <serial>10000</serial>\n"
+            + "      <hash>ahyI+59KW2tVxi0inRdUSo1Y8kmx5xK1isDvYfzxWbo=</hash>\n"
             + "    </previous>\n"
             + "  </metadata>\n"
             + "  <intermediates>\n"
-            + "    <cert>\n"
-            + "      MIIFLzCCAxegAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UEAwwVR29v\n"
-            + "      Z2xlIENyeXB0QXV0aFZhdWx0MB4XDTE4MDIwMzAwNDIwM1oXDTI4MDIwMTAwNDIw\n"
-            + "      M1owLTErMCkGA1UEAwwiR29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0\n"
-            + "      ZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANyQeJvRfqtDIOqTjnX1\n"
-            + "      vl27Q6sI+TfRdcrDP4fPnLhwZlpYoZwc4dZLZf1gClHM7TT8Ru8WRZVRNUbbvAnn\n"
-            + "      hX4LccdI4BRYeESB8Va+8fB+f0dMPHUESTv1pConsO4nTpKf9Y6Iy0pUBPnoyLyZ\n"
-            + "      6QHGkw6t1mrCVwutRWxnEQezDn9x5m7hxJbNztLOWds0rVwKDJEMapZ/oaneEYTz\n"
-            + "      qRQ60zWL3lGBQinD7D/PTDGkXqQjJBOMr4qOJgf9EE4kgRybqxJZmUyi0otKfaWF\n"
-            + "      /5cvzJTETEgdOix95vTvtBZbjDYEHY1kzjA8A7fDhrDfcU2KANBzZJBiadQRiYhw\n"
-            + "      PyTHvv4lYKALEElzbNMde0HFa5cBD6J6C3xE75AP3ul3pcoz3E+wA6RxYunv2j4A\n"
-            + "      miXg/l/C+Bgzr2YziXAfXa/zpEjhqm09A5qDQoMgdfIpuNpDICC/fSXgqQOl/a5Y\n"
-            + "      4OE45PA1tU9hSbexhSWEFxvKFOTxio32w9ThABqjmwpMBhmAH+aWF5DKlNTDK+rP\n"
-            + "      ptHMZ6FUHeW0/2ALIp0jThVcRS5QFaTdJPJXZERB6fn8soCezq/XULPbZmsR0K80\n"
-            + "      uB62fJXsImw5r/AP8aJRYvZNrunOyGL1qEmqutw09FsDM4tw0pmQV7GHM+mie6j+\n"
-            + "      k2txpF1rV+t6lfFWSZuyA5QvAgMBAAGjZjBkMB0GA1UdDgQWBBR3qZ3aEI+WZ/dW\n"
-            + "      QRfkV8PEoEttoDAfBgNVHSMEGDAWgBSbZfrqOYH54EJpkdKMZjMcz/Hp+DASBgNV\n"
-            + "      HRMBAf8ECDAGAQH/AgEBMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC\n"
-            + "      AgEAWBKGG5b5ZVOjA3TzQ8t/RNY+UcAIcdQ+CF/usUbGBSMnKkKWgTzgF6DdE6k/\n"
-            + "      mXX0IOpn07I/MDXPpUDN4ZfIWFm9vLsba1kMFE/+/S7ymdIB0LkXyXxWHZgZ2ATe\n"
-            + "      xkPbm+l0GLs/QR/othB604lefzo+qCaBbUXqXPEOMoKyL2Sl5TQBbAN05WDvjzCS\n"
-            + "      7nSjxQTOxXDHMV322gaWB7+efcUfknsS4bMCUXBOgeqnBNUR6BoB3SX2avn6tLtS\n"
-            + "      t3dfzQEcOoIFxcTtSpu3PDlj6WajAwKdbSQU3TZ0L10u3Zz0jEL72w8gDl5OStkG\n"
-            + "      SuRNVEYuPavb2PucL2blVopwGpwtkNbLylGdrzJpmmuA10Tx39ZNj2dWyJzT03zM\n"
-            + "      0XlDRuGFZrdCieUH1dblmoOC6JyW+f7lO1ETNIC1I7LEz6B8beXTCM7LAiTVoVrn\n"
-            + "      ZFqoBY8vrso4zobe8o2kydbmGuYeuKO4rGJqsYihl+RkxHmKMrS4WC/f+no0cv9h\n"
-            + "      AFockmGQp63lOGI/HBb37WT9lxdV5jbpeH7bYan/y2jtlbyC48+I3WF+kP7t/Uh1\n"
-            + "      KYcOuxlBDtt/NXRummzI00Ht7YRzLD4ZCfLbufK0EskMZ1EG6tvBC/OmlA7pCaWT\n"
-            + "      St8KzOHtsYKgJA3Fea4OxDkEL6lBSommVOp2zWybKLb3Gzc=\n"
-            + "    </cert>\n"
+            + "    <cert>MIIFGjCCAwKgAwIBAgIQHflnDNWkj2yxeD1IB6GdTTANBgkqhkiG9w0BAQsFADAxMS8wLQYDVQQDEyZHb29nbGUgQ2xvdWQgS2V5IFZhdWx0IFNlcnZpY2UgUm9vdCBDQTAeFw0xODA1MDcxODU4MTBaFw0yODA1MDgxODU4MTBaMDkxNzA1BgNVBAMTLkdvb2dsZSBDbG91ZCBLZXkgVmF1bHQgU2VydmljZSBJbnRlcm1lZGlhdGUgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDvdOu8fePrMSKalxzfa3HaK6lbB/LN0TmXgSNzkQFjPHRpkfpv8oO663C6y2TQijKOUbJIwHP/bViBZ6Mib6d24CWmTtZjmRgenRda3N2bFmSeZZOq6A941l6IoSOgOanIhtjo35/XeFDZFWH5YNMSjBD+LThYEvvlyGyGUgb7cDjaDlCvsNkQp1P2glCqSe3OPRwbInlfwHCN5OImu9iTYqf/Tnnn8qmnrkbdF/b1U89TeLruS2EBPdJq8sGkfTdLhZn5CV+sCIZDOLJ23P23uZKTXF5+NrHllYC4kB8Jsp8jdVYBxpSvg/nsHOYNxKLSOCzVoze3YGs98AxHFa/fnINmesL4eKnOSPIMYF8eYWCiCXKFz178qPeZK6w7RGrXCC5VcqzaEpdGhoYm4e17dgjBMLWkvOeq+iWEPWc+hd/yszOAdHOVz0fyJeyAHWnv3vmeHlYI+swNfZ4CZh1rTFMxxxN4HMgzaiHFCzGWHmuyNdU1TeKFtaQeq7MiLAVwC2V0/d0ySyPR2f8OdgPKiSMSBT/PYjbXoT3fH2GYqQSTo+nujy3/PqXAxP0Uki7Ons1ESdYJKL57mzYTsUOPpLvFjbMQhQeubC64lzSPMmfB1n7SbKKdpOYEO8FdHlxTVyYQBmiF4IChG/1n/qgBJzMsXQLi65V8DkZdwCbXhwIDAQABoyYwJDAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBATANBgkqhkiG9w0BAQsFAAOCAgEAQ+G3v3JCbzChBs8HUGx6i2TMm1NZM71+chbA2JF9De8kVd/r2CETvvBRLXcTPcWWA0+PRDGaDmi4TR3bJhXgBStecQZkQtzI3ZcdFfI0rTNeCevfHp5nJjtB+AYomCTKNrlNLpk9YbJosqEKVLQBhlLNYm3PT4CQYJ1NubLLtKF1cn4Z+eayxud1kDrZWFyN5CYewOrtXc8oCynj8H0/NydOuCRQU2c/UXWmvsmlRRffHJEXLqCMitTHV9w4VHEVg9YYssxno/jWtp+b4z8JsE2vkJjs2tmOvfiMupbJx9h6zj2j04rjhf/A+vGPRKOD5WtbbX4An2+szsNLmERBfWUNsO1AaSTc3W+AJOjrG30tewS7jFRPluTtgB+kmozSW0MU/BgAYJuNKRVP8zklVmQqJRbrrxSzrvHzJlz/lvFu9MD7nGtiFqT9VggFjqq5vgn5srBp3Dq4GDGerg+HCDCN9qgnL1gBcKzCMK1oT0bCRWZGckT28WMnfcgZ/fuEVNgQcEXLgWiZWZDBEVlMh7u2QoOr2LXwXuXME8k87rAQbxvGLhyxq2uNxUdH16uljm7p5u2Qobyqxqf2rOGJYCBLK2JP74d6Nl6hD5FGBBaO6mN0Ojn/ShJ1Cq9o3wCHoLYn55wJnXYu7QXAX6230h7ekXpbxPPHO4x0Var5p+8=</cert>\n"
             + "  </intermediates>\n"
             + "  <endpoints>\n"
-            + "    <cert>\n"
-            + "      MIIDCDCB8aADAgECAgYBYVkuU0cwDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwi\n"
-            + "      R29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAyMDIwMTAx\n"
-            + "      MDNaFw0yMDAyMDMwMTAxMDNaMCkxJzAlBgNVBAMTHkdvb2dsZSBDcnlwdEF1dGhW\n"
-            + "      YXVsdCBJbnN0YW5jZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgAERiYHfBu\n"
-            + "      tJT+htocB40BtDr2jdxh0EZJlQ8QhpMkZuA/0t/zeSAdkVWw5b16izJ9JVOi/KVl\n"
-            + "      4b0hRH54UvowDQYJKoZIhvcNAQELBQADggIBAJ3PM4GNTNYzMr8E/IGsWZkLx9AR\n"
-            + "      AALqBXz7As59F8y5UcLMqkXD/ewOfBZgF5VzjlAePyE/wSw0wc3xzvrDVVDiZaMB\n"
-            + "      W1DVtSlbn25q00m00mmcUeyyMc7vuRkPoDshIMQTc8+U3yyYsVScSV+B4TvSx6wP\n"
-            + "      Z9FpwnSPjVPD2GkqeMTWszuxNVEWq0wmm0K5lMaX0hfiak+4/IZxOPPGIg2py1KL\n"
-            + "      A/H2gdyeqyJRcAsyEkfwLlushR5T9abSiPsIRcYoX8Ck8Lt+gQ7RCMefnm8CoOBK\n"
-            + "      IfcjuV4PGOoeXrq57VR5SsOeT07bL+D7B+mohYFI1v2G3WClAE8XgM3q8NoFFvaY\n"
-            + "      moi0+UcTduil47qvozjdNmjRAgu5j6vMKXEdG5Rqsja8hy0LG1hwfnR0gNiwcZ5L\n"
-            + "      e3GyFnwH1IgqvsGOUM0ohnDUAU0zJY7nG0QYrDYe5/QPRNhWDpYkwHDiqcG28wIQ\n"
-            + "      COTPAZHU2EoSKjSqEG2l0S5JPcor2BEde9ikSkcmK8foxlOHIdFn+n7RNF3bSEfK\n"
-            + "      n1IOuXoqPidmeBQLevqG8KTy/C9CHqlaCNlpbIA9h+WVfsjm2s6JXBu0YbcfoIbJ\n"
-            + "      AmSuZVeqB/+ZVvpfiad/jQWzY49fRnsSmV7VveTFPGtJxC89EadbMAinMZo+72u5\n"
-            + "      9319RqN5wsP2Zus8\n"
-            + "    </cert>\n"
+            // The public key is chosen by using the following hash as the first 32 bytes (x-axis)
+            //     SHA256("Google Cloud Key Vault Service Test Endpoint") = 8e0c114a79207c004cd7e906e2582145fa24cb0766defdf183b4265598cba9d5
+            // so its private key is unknown.
+            + "    <cert>MIIDOzCCASOgAwIBAgIRAOTj/iNQb6/Qit7zAW9ncL0wDQYJKoZIhvcNAQELBQAwOTE3MDUGA1UEAxMuR29vZ2xlIENsb3VkIEtleSBWYXVsdCBTZXJ2aWNlIEludGVybWVkaWF0ZSBDQTAeFw0xODA1MDcyMjE4MTFaFw0yMzA1MDgyMjE4MTFaMDIxMDAuBgNVBAMTJ0dvb2dsZSBDbG91ZCBLZXkgVmF1bHQgU2VydmljZSBFbmRwb2ludDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABI4MEUp5IHwATNfpBuJYIUX6JMsHZt798YO0JlWYy6nVVa1lxf9c+xxONJh+T5aio370RlIEuiq5R7vCHt0VGsCjEDAOMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAGf6QU58lU+gGzy8hnp0suR/ixC++CExtf39pDHkdfU/e3ui4ROR+pjQ5F7okDFWeKSCNcJZ7tyXMJ9g7/I0qVY8Bj/gRnlVokdl/wD5PiL9GIzqWfnHNe3T+xrAAAgOD0bEmjgwNYmekfUIYQczd04d7ZMGnmAkpVH/0O2mf9q5x9fMlbKuAygUqQ/gmnlgxKfl9DSRWi4oMBOqlKlCRP1XAh3anu92+M/EhsFbyc07CWZY0SByX5M/cHVMLhUXjZHvcYLyOmJWJmXznidgyNeIR6t9yDB55iCt7WSn3qMY+9vA9ELzt8jYpBNaKc0GbWQkRzYWegkf4kMis98eQ3SnAKbRz6669nmuAdxKs9/LK6BlFOFw1xvsTRQ96dBaoiX2XGhou+Im0Td/AMs0Aigz2N+Ujq/yW//35GZQfdGGIYtFbkcltStygjIJyAM1pBhyBBkJhOhRpO4fXh98aq8H5J7R9i5A9WpnDstAxPxcNCDWn0O/WxhPvVZkFTpiNXh9dnlJ/kZe+j+z5ZMaxW435drLPx2AQKjXA9GgGrFPltTUyGycmEGtuxLvSnm/zPlmk5FUk7x2wEr0+bZ3cx0JHHgAtgXpe0jkDi8Bw8O3X7mUOjxVhYU6auiYJezW9LGmweaKwYvS04UCWOReolUVexob9LI/VX1JrrwD3s7k</cert>\n"
             + "  </endpoints>\n"
-            + "</certificates>\n";
+            + "</certificate>\n";
     private static final String THM_SIG_XML = ""
-            + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
             + "<signature>\n"
-            + "  <intermediates>\n"
-            + "  </intermediates>\n"
-            + "  <certificate>\n"
-            + "    MIIFLzCCAxegAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UEAwwVR29v\n"
-            + "    Z2xlIENyeXB0QXV0aFZhdWx0MB4XDTE4MDIwMzAwNDIwM1oXDTI4MDIwMTAwNDIw\n"
-            + "    M1owLTErMCkGA1UEAwwiR29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0\n"
-            + "    ZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANyQeJvRfqtDIOqTjnX1\n"
-            + "    vl27Q6sI+TfRdcrDP4fPnLhwZlpYoZwc4dZLZf1gClHM7TT8Ru8WRZVRNUbbvAnn\n"
-            + "    hX4LccdI4BRYeESB8Va+8fB+f0dMPHUESTv1pConsO4nTpKf9Y6Iy0pUBPnoyLyZ\n"
-            + "    6QHGkw6t1mrCVwutRWxnEQezDn9x5m7hxJbNztLOWds0rVwKDJEMapZ/oaneEYTz\n"
-            + "    qRQ60zWL3lGBQinD7D/PTDGkXqQjJBOMr4qOJgf9EE4kgRybqxJZmUyi0otKfaWF\n"
-            + "    /5cvzJTETEgdOix95vTvtBZbjDYEHY1kzjA8A7fDhrDfcU2KANBzZJBiadQRiYhw\n"
-            + "    PyTHvv4lYKALEElzbNMde0HFa5cBD6J6C3xE75AP3ul3pcoz3E+wA6RxYunv2j4A\n"
-            + "    miXg/l/C+Bgzr2YziXAfXa/zpEjhqm09A5qDQoMgdfIpuNpDICC/fSXgqQOl/a5Y\n"
-            + "    4OE45PA1tU9hSbexhSWEFxvKFOTxio32w9ThABqjmwpMBhmAH+aWF5DKlNTDK+rP\n"
-            + "    ptHMZ6FUHeW0/2ALIp0jThVcRS5QFaTdJPJXZERB6fn8soCezq/XULPbZmsR0K80\n"
-            + "    uB62fJXsImw5r/AP8aJRYvZNrunOyGL1qEmqutw09FsDM4tw0pmQV7GHM+mie6j+\n"
-            + "    k2txpF1rV+t6lfFWSZuyA5QvAgMBAAGjZjBkMB0GA1UdDgQWBBR3qZ3aEI+WZ/dW\n"
-            + "    QRfkV8PEoEttoDAfBgNVHSMEGDAWgBSbZfrqOYH54EJpkdKMZjMcz/Hp+DASBgNV\n"
-            + "    HRMBAf8ECDAGAQH/AgEBMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC\n"
-            + "    AgEAWBKGG5b5ZVOjA3TzQ8t/RNY+UcAIcdQ+CF/usUbGBSMnKkKWgTzgF6DdE6k/\n"
-            + "    mXX0IOpn07I/MDXPpUDN4ZfIWFm9vLsba1kMFE/+/S7ymdIB0LkXyXxWHZgZ2ATe\n"
-            + "    xkPbm+l0GLs/QR/othB604lefzo+qCaBbUXqXPEOMoKyL2Sl5TQBbAN05WDvjzCS\n"
-            + "    7nSjxQTOxXDHMV322gaWB7+efcUfknsS4bMCUXBOgeqnBNUR6BoB3SX2avn6tLtS\n"
-            + "    t3dfzQEcOoIFxcTtSpu3PDlj6WajAwKdbSQU3TZ0L10u3Zz0jEL72w8gDl5OStkG\n"
-            + "    SuRNVEYuPavb2PucL2blVopwGpwtkNbLylGdrzJpmmuA10Tx39ZNj2dWyJzT03zM\n"
-            + "    0XlDRuGFZrdCieUH1dblmoOC6JyW+f7lO1ETNIC1I7LEz6B8beXTCM7LAiTVoVrn\n"
-            + "    ZFqoBY8vrso4zobe8o2kydbmGuYeuKO4rGJqsYihl+RkxHmKMrS4WC/f+no0cv9h\n"
-            + "    AFockmGQp63lOGI/HBb37WT9lxdV5jbpeH7bYan/y2jtlbyC48+I3WF+kP7t/Uh1\n"
-            + "    KYcOuxlBDtt/NXRummzI00Ht7YRzLD4ZCfLbufK0EskMZ1EG6tvBC/OmlA7pCaWT\n"
-            + "    St8KzOHtsYKgJA3Fea4OxDkEL6lBSommVOp2zWybKLb3Gzc=\n"
-            + "  </certificate>\n"
-            + "  <value>\n"
-            + "    uKJ4W8BPCdVaIBe2ZiMxxk5L5vGBV9QwaOEGU80LgtA/gEqkiO2IMUBlQJFqvvhh6RSph5lWpLuv\n"
-            + "    /Xt7WBzDsZOcxXNffg2+pWNpbpwZdHohlwQEI1OqiVYVnfG4euAkzeWZZLsRUuAjHfcWVIzDoSoK\n"
-            + "    wC+gqdUQHBV+pWyn6PXVslS0JIldeegbiwF076M1D7ybeCABXoQelSZRHkx1szO8UnxSR3X7Cemu\n"
-            + "    p9De/7z9+WPPclqybINVIPy6Kvl8mHrGSlzawQRDKtoMrJa8bo93PookF8sbg5EoGapV0yNpMEiA\n"
-            + "    spq3DEcdXB6mGDGPnLbS2WXq4zjKopASRKkZvOMdgfS6NdUMDtKS1TsOrv2KKTkLnGYfvdAeWiMg\n"
-            + "    oFbuyYQ0mnDlLH1UW6anI8RxXn+wmdyZA+/ksapGvRmkvz0Mb997WzqNl7v7UTr0SU3Ws01hFsm6\n"
-            + "    lW++MsotkyfpR9mWB8/dqVNVShLmIlt7U/YFVfziYSrVdjcAdIlgJ6Ihxb92liQHOU+Qr1YDOmm1\n"
-            + "    JSnhlQVvFxWZG7hm5laNL6lqXz5VV6Gk5IeLtMb8kdHz3zj4ascdldapVPLJIa5741GNNgQNU0nH\n"
-            + "    FhAyKk0zN7PbL1/XGWPU+s5lai4HE6JM2CKA7jE7cYrdaDZxbba+9iWzQ4YEBDr5Z3OoloK5dvs=\n"
-            + "  </value>\n"
+            + "  <intermediates></intermediates>\n"
+            + "  <certificate>MIIFGjCCAwKgAwIBAgIQHflnDNWkj2yxeD1IB6GdTTANBgkqhkiG9w0BAQsFADAxMS8wLQYDVQQDEyZHb29nbGUgQ2xvdWQgS2V5IFZhdWx0IFNlcnZpY2UgUm9vdCBDQTAeFw0xODA1MDcxODU4MTBaFw0yODA1MDgxODU4MTBaMDkxNzA1BgNVBAMTLkdvb2dsZSBDbG91ZCBLZXkgVmF1bHQgU2VydmljZSBJbnRlcm1lZGlhdGUgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDvdOu8fePrMSKalxzfa3HaK6lbB/LN0TmXgSNzkQFjPHRpkfpv8oO663C6y2TQijKOUbJIwHP/bViBZ6Mib6d24CWmTtZjmRgenRda3N2bFmSeZZOq6A941l6IoSOgOanIhtjo35/XeFDZFWH5YNMSjBD+LThYEvvlyGyGUgb7cDjaDlCvsNkQp1P2glCqSe3OPRwbInlfwHCN5OImu9iTYqf/Tnnn8qmnrkbdF/b1U89TeLruS2EBPdJq8sGkfTdLhZn5CV+sCIZDOLJ23P23uZKTXF5+NrHllYC4kB8Jsp8jdVYBxpSvg/nsHOYNxKLSOCzVoze3YGs98AxHFa/fnINmesL4eKnOSPIMYF8eYWCiCXKFz178qPeZK6w7RGrXCC5VcqzaEpdGhoYm4e17dgjBMLWkvOeq+iWEPWc+hd/yszOAdHOVz0fyJeyAHWnv3vmeHlYI+swNfZ4CZh1rTFMxxxN4HMgzaiHFCzGWHmuyNdU1TeKFtaQeq7MiLAVwC2V0/d0ySyPR2f8OdgPKiSMSBT/PYjbXoT3fH2GYqQSTo+nujy3/PqXAxP0Uki7Ons1ESdYJKL57mzYTsUOPpLvFjbMQhQeubC64lzSPMmfB1n7SbKKdpOYEO8FdHlxTVyYQBmiF4IChG/1n/qgBJzMsXQLi65V8DkZdwCbXhwIDAQABoyYwJDAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBATANBgkqhkiG9w0BAQsFAAOCAgEAQ+G3v3JCbzChBs8HUGx6i2TMm1NZM71+chbA2JF9De8kVd/r2CETvvBRLXcTPcWWA0+PRDGaDmi4TR3bJhXgBStecQZkQtzI3ZcdFfI0rTNeCevfHp5nJjtB+AYomCTKNrlNLpk9YbJosqEKVLQBhlLNYm3PT4CQYJ1NubLLtKF1cn4Z+eayxud1kDrZWFyN5CYewOrtXc8oCynj8H0/NydOuCRQU2c/UXWmvsmlRRffHJEXLqCMitTHV9w4VHEVg9YYssxno/jWtp+b4z8JsE2vkJjs2tmOvfiMupbJx9h6zj2j04rjhf/A+vGPRKOD5WtbbX4An2+szsNLmERBfWUNsO1AaSTc3W+AJOjrG30tewS7jFRPluTtgB+kmozSW0MU/BgAYJuNKRVP8zklVmQqJRbrrxSzrvHzJlz/lvFu9MD7nGtiFqT9VggFjqq5vgn5srBp3Dq4GDGerg+HCDCN9qgnL1gBcKzCMK1oT0bCRWZGckT28WMnfcgZ/fuEVNgQcEXLgWiZWZDBEVlMh7u2QoOr2LXwXuXME8k87rAQbxvGLhyxq2uNxUdH16uljm7p5u2Qobyqxqf2rOGJYCBLK2JP74d6Nl6hD5FGBBaO6mN0Ojn/ShJ1Cq9o3wCHoLYn55wJnXYu7QXAX6230h7ekXpbxPPHO4x0Var5p+8=</certificate>\n"
+            + "  <value>WkmYBCY4heNutMf3tEbyg+Omm+MvWF4EoDmv2vCd259oy3t8URqDqu5vEi3TqQguX0GO3r5mRKCcEYged121xJltC6zShbDMZZNAlB6sqvS6/vIVBBx5jKecUaEpRuQ4ruTyF93YXDi7DgaCNGaYCjkDrnr8lSAyelZl2tfe2BbpOMiwH1fNvI6Xmb++iyMmZGoJo91ovucC635SnnULNUtivL2CjLgU3mKb2uZMB8XPr1t1FOTJEA81ghDU+p3ZrPLxLB3KBTtfAwPQyqStRuY8+3bnPqi7VWeZgfoesvJiPF6q1PraoaL/inlRFo7wr37CS9EtNR/k5cq1UJ4/4Ernvj5k2Zw/IclzYHUGSd3ljCOTJJB6cDtR7WDqprlr1J4nr9hf1Ya4DFJmlX3FXix43Dw6lfk/1gCiWu0y2i1A2NCn0QRxuPh5b385Epj98QlZnd2roB2GfzchJTAxI+oeLc3CowkyLDS5jjuTMERbKbPpkhQu9gtskYtB0I4fEGOMn17+ZrXRcTPJexCS2NGgSqiF4X9Fwe+9XRg3Nk+SoUj9gBCysP8UeSz1POZHQIlZ24mQzxOK2hwGwDtxVchGCrNyf8rh5bZE2hUKHYNH9UWQ+YWrieKeulfP+o1wL9NLZOTz3SHcV/kCv5WqgynzkrKf382FwunxF56NapA=</value>\n"
             + "</signature>\n";
 
-    public static final PublicKey CERT_1_PUBLIC_KEY;
-    public static final PrivateKey CERT_1_PRIVATE_KEY;
-
-    static {
-        try {
-            CERT_1_PUBLIC_KEY =
-                    SecureBox.decodePublicKey(
-                            new byte[] {
-                                (byte) 0x04, (byte) 0xb8, (byte) 0x00, (byte) 0x11, (byte) 0x18,
-                                (byte) 0x98, (byte) 0x1d, (byte) 0xf0, (byte) 0x6e, (byte) 0xb4,
-                                (byte) 0x94, (byte) 0xfe, (byte) 0x86, (byte) 0xda, (byte) 0x1c,
-                                (byte) 0x07, (byte) 0x8d, (byte) 0x01, (byte) 0xb4, (byte) 0x3a,
-                                (byte) 0xf6, (byte) 0x8d, (byte) 0xdc, (byte) 0x61, (byte) 0xd0,
-                                (byte) 0x46, (byte) 0x49, (byte) 0x95, (byte) 0x0f, (byte) 0x10,
-                                (byte) 0x86, (byte) 0x93, (byte) 0x24, (byte) 0x66, (byte) 0xe0,
-                                (byte) 0x3f, (byte) 0xd2, (byte) 0xdf, (byte) 0xf3, (byte) 0x79,
-                                (byte) 0x20, (byte) 0x1d, (byte) 0x91, (byte) 0x55, (byte) 0xb0,
-                                (byte) 0xe5, (byte) 0xbd, (byte) 0x7a, (byte) 0x8b, (byte) 0x32,
-                                (byte) 0x7d, (byte) 0x25, (byte) 0x53, (byte) 0xa2, (byte) 0xfc,
-                                (byte) 0xa5, (byte) 0x65, (byte) 0xe1, (byte) 0xbd, (byte) 0x21,
-                                (byte) 0x44, (byte) 0x7e, (byte) 0x78, (byte) 0x52, (byte) 0xfa
-                            });
-            CERT_1_PRIVATE_KEY =
-                    decodePrivateKey(
-                            new byte[] {
-                                (byte) 0x70, (byte) 0x01, (byte) 0xc7, (byte) 0x87, (byte) 0x32,
-                                (byte) 0x2f, (byte) 0x1c, (byte) 0x9a, (byte) 0x6e, (byte) 0xb1,
-                                (byte) 0x91, (byte) 0xca, (byte) 0x4e, (byte) 0xb5, (byte) 0x44,
-                                (byte) 0xba, (byte) 0xc8, (byte) 0x68, (byte) 0xc6, (byte) 0x0a,
-                                (byte) 0x76, (byte) 0xcb, (byte) 0xd3, (byte) 0x63, (byte) 0x67,
-                                (byte) 0x7c, (byte) 0xb0, (byte) 0x11, (byte) 0x82, (byte) 0x65,
-                                (byte) 0x77, (byte) 0x01
-                            });
-        } catch (Exception ex) {
-            throw new RuntimeException(ex);
-        }
-    }
-
-    public static byte[] getCertPath1Bytes() {
-        try {
-            return CertUtils.decodeBase64(CERT_PATH_1_BASE64);
-        } catch (Exception e){
-            throw new RuntimeException(e);
-        }
-    }
-
-    public static byte[] getCertPath2Bytes() {
-        try {
-            return CertUtils.decodeBase64(CERT_PATH_2_BASE64);
-        } catch (Exception e){
-            throw new RuntimeException(e);
-        }
-    }
-
     public static final CertPath CERT_PATH_1;
     public static final CertPath CERT_PATH_2;
+    public static final PublicKey CERT_1_PUBLIC_KEY;
 
     static {
         try {
-            CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
-            CERT_PATH_1 = certFactory.generateCertPath(
-                    new ByteArrayInputStream(getCertPath1Bytes()), CERT_PATH_ENCODING);
-            CERT_PATH_2 = certFactory.generateCertPath(
-                    new ByteArrayInputStream(getCertPath2Bytes()), CERT_PATH_ENCODING);
+            CERT_PATH_1 = decodeCertPath(CERT_PATH_1_BASE64);
+            CERT_PATH_2 = decodeCertPath(CERT_PATH_2_BASE64);
+            CERT_1_PUBLIC_KEY = CERT_PATH_1.getCertificates().get(0).getPublicKey();
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
@@ -323,13 +174,6 @@
         return THM_SIG_XML.getBytes(StandardCharsets.UTF_8);
     }
 
-    private static PrivateKey decodePrivateKey(byte[] keyBytes) throws Exception {
-        assertThat(keyBytes.length).isEqualTo(32);
-        BigInteger priv = new BigInteger(/*signum=*/ 1, keyBytes);
-        KeyFactory keyFactory = KeyFactory.getInstance("EC");
-        return keyFactory.generatePrivate(new ECPrivateKeySpec(priv, SecureBox.EC_PARAM_SPEC));
-    }
-
     public static SecretKey generateKey() throws Exception {
         KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
         keyGenerator.init(/*keySize=*/ 256);
@@ -576,6 +420,10 @@
             + "2nxygOQKtfb0EPTvVYMErvWrA69rr+wPMSWPetvcDGEZ8hWFr3iRtduExC9sRqnV"
             + "5DhvZROQSZQtQ+Ja6g8BehUC9gPCES93EOQUYPpRQEeD1CE+1IKTyuH+ApynIKSj"
             + "5+U1x+OE3UZYTTzEck/TJxTm+Sv4FfCvpwdmDAMTjEZXfuFR+7+5Og==";
+    private static final String INSECURE_PRIVATE_KEY_FOR_ENDPOINT1_BASE64 = ""
+            + "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgdCqcARU7lWJVXKY/"
+            + "+DTlFC0dzcTvh1ufkfZdnoZoR7ShRANCAAS3S6JtfbCyXlLSA+WZHwk0Rr2hdjJX"
+            + "xGeJLnsAbVkESmoGL9wG2Qty2InpFQ9jFFJHvGR8a73RMQVqmNxwQvFh";
 
     public static byte[] getInsecureCertXmlBytesWithEndpoint1(int serial) {
         String str = INSECURE_CERT_XML_HEADER;
@@ -603,6 +451,13 @@
         return decodeCertPath(INSECURE_CERT_PATH_FOR_ENDPOINT2_BASE64);
     }
 
+    public static PrivateKey getInsecurePrivateKeyForEndpoint1() throws Exception {
+        byte[] keyBytes = Base64.getDecoder().decode(INSECURE_PRIVATE_KEY_FOR_ENDPOINT1_BASE64);
+        KeyFactory kf = KeyFactory.getInstance("EC");
+        PKCS8EncodedKeySpec skSpec = new PKCS8EncodedKeySpec(keyBytes);
+        return kf.generatePrivate(skSpec);
+    }
+
     private static CertPath decodeCertPath(String base64CertPath) throws Exception {
         byte[] certPathBytes = Base64.getDecoder().decode(base64CertPath);
         CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
index 6b52ee5..84475bb 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
@@ -19,6 +19,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import android.app.PendingIntent;
 import android.os.HandlerThread;
@@ -49,9 +50,20 @@
     private static final int OBS_ID1 = 1;
     private static final int OBS_ID2 = 2;
     private static final int OBS_ID3 = 3;
+    private static final int OBS_ID4 = 4;
+    private static final int OBS_ID5 = 5;
+    private static final int OBS_ID6 = 6;
+    private static final int OBS_ID7 = 7;
+    private static final int OBS_ID8 = 8;
+    private static final int OBS_ID9 = 9;
+    private static final int OBS_ID10 = 10;
+    private static final int OBS_ID11 = 11;
 
-    private static final long TIME_30_MIN = 30 * 60_1000L;
-    private static final long TIME_10_MIN = 10 * 60_1000L;
+    private static final long TIME_30_MIN = 30 * 60_000L;
+    private static final long TIME_10_MIN = 10 * 60_000L;
+
+    private static final long MAX_OBSERVER_PER_UID = 10;
+    private static final long MIN_TIME_LIMIT = 4_000L;
 
     private static final String[] GROUP1 = {
             PKG_SOC1, PKG_GAME1, PKG_PROD
@@ -93,6 +105,16 @@
         protected long getUptimeMillis() {
             return mUptimeMillis;
         }
+
+        @Override
+        protected long getObserverPerUidLimit() {
+            return MAX_OBSERVER_PER_UID;
+        }
+
+        @Override
+        protected long getMinTimeLimit() {
+            return MIN_TIME_LIMIT;
+        }
     }
 
     @Before
@@ -233,6 +255,47 @@
         assertFalse(hasObserver(OBS_ID1));
     }
 
+    /** Verify that App Time Limit Controller will limit the number of observerIds */
+    @Test
+    public void testMaxObserverLimit() throws Exception {
+        boolean receivedException = false;
+        int ANOTHER_UID = UID + 1;
+        addObserver(OBS_ID1, GROUP1, TIME_30_MIN);
+        addObserver(OBS_ID2, GROUP1, TIME_30_MIN);
+        addObserver(OBS_ID3, GROUP1, TIME_30_MIN);
+        addObserver(OBS_ID4, GROUP1, TIME_30_MIN);
+        addObserver(OBS_ID5, GROUP1, TIME_30_MIN);
+        addObserver(OBS_ID6, GROUP1, TIME_30_MIN);
+        addObserver(OBS_ID7, GROUP1, TIME_30_MIN);
+        addObserver(OBS_ID8, GROUP1, TIME_30_MIN);
+        addObserver(OBS_ID9, GROUP1, TIME_30_MIN);
+        addObserver(OBS_ID10, GROUP1, TIME_30_MIN);
+        // Readding an observer should not cause an IllegalStateException
+        addObserver(OBS_ID5, GROUP1, TIME_30_MIN);
+        // Adding an observer for a different uid shouldn't cause an IllegalStateException
+        mController.addObserver(ANOTHER_UID, OBS_ID11, GROUP1, TIME_30_MIN, null, USER_ID);
+        try {
+            addObserver(OBS_ID11, GROUP1, TIME_30_MIN);
+        } catch (IllegalStateException ise) {
+            receivedException = true;
+        }
+        assertTrue("Should have caused an IllegalStateException", receivedException);
+    }
+
+    /** Verify that addObserver minimum time limit is one minute */
+    @Test
+    public void testMinimumTimeLimit() throws Exception {
+        boolean receivedException = false;
+        // adding an observer with a one minute time limit should not cause an exception
+        addObserver(OBS_ID1, GROUP1, MIN_TIME_LIMIT);
+        try {
+            addObserver(OBS_ID1, GROUP1, MIN_TIME_LIMIT - 1);
+        } catch (IllegalArgumentException iae) {
+            receivedException = true;
+        }
+        assertTrue("Should have caused an IllegalArgumentException", receivedException);
+    }
+
     private void moveToForeground(String packageName) {
         mController.moveToForeground(packageName, "class", USER_ID);
     }
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/SlicePermissionManagerTest.java b/services/tests/uiservicestests/src/com/android/server/slice/SlicePermissionManagerTest.java
index 5443e73..dc057d5 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/SlicePermissionManagerTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/SlicePermissionManagerTest.java
@@ -26,7 +26,6 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
-import android.util.Log;
 import android.util.Xml.Encoding;
 
 import com.android.server.UiServiceTestCase;
@@ -49,6 +48,20 @@
 public class SlicePermissionManagerTest extends UiServiceTestCase {
 
     @Test
+    public void testGrant() {
+        File sliceDir = new File(mContext.getDataDir(), "system/slices");
+        SlicePermissionManager permissions = new SlicePermissionManager(mContext,
+                TestableLooper.get(this).getLooper(), sliceDir);
+        Uri uri = new Builder().scheme(ContentResolver.SCHEME_CONTENT)
+                .authority("authority")
+                .path("something").build();
+
+        permissions.grantSliceAccess("my.pkg", 0, "provider.pkg", 0, uri);
+
+        assertTrue(permissions.hasPermission("my.pkg", 0, uri));
+    }
+
+    @Test
     public void testBackup() throws XmlPullParserException, IOException {
         File sliceDir = new File(mContext.getDataDir(), "system/slices");
         Uri uri = new Builder().scheme(ContentResolver.SCHEME_CONTENT)
diff --git a/services/usage/java/com/android/server/usage/AppTimeLimitController.java b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
index e201851..e7c54d8 100644
--- a/services/usage/java/com/android/server/usage/AppTimeLimitController.java
+++ b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
@@ -26,6 +26,7 @@
 import android.util.ArrayMap;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseIntArray;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -58,6 +59,10 @@
 
     private OnLimitReachedListener mListener;
 
+    private static final long MAX_OBSERVER_PER_UID = 1000;
+
+    private static final long ONE_MINUTE = 60_000L;
+
     @GuardedBy("mLock")
     private final SparseArray<UserData> mUsers = new SparseArray<>();
 
@@ -77,6 +82,9 @@
         /** Map of observerId to details of the time limit group */
         private SparseArray<TimeLimitGroup> groups = new SparseArray<>();
 
+        /** Map of the number of observerIds registered by uid */
+        private SparseIntArray observerIdCounts = new SparseIntArray();
+
         private UserData(@UserIdInt int userId) {
             this.userId = userId;
         }
@@ -147,6 +155,18 @@
         return SystemClock.uptimeMillis();
     }
 
+    /** Overrideable for testing purposes */
+    @VisibleForTesting
+    protected long getObserverPerUidLimit() {
+        return MAX_OBSERVER_PER_UID;
+    }
+
+    /** Overrideable for testing purposes */
+    @VisibleForTesting
+    protected long getMinTimeLimit() {
+        return ONE_MINUTE;
+    }
+
     /** Returns an existing UserData object for the given userId, or creates one */
     private UserData getOrCreateUserDataLocked(int userId) {
         UserData userData = mUsers.get(userId);
@@ -171,10 +191,20 @@
      */
     public void addObserver(int requestingUid, int observerId, String[] packages, long timeLimit,
             PendingIntent callbackIntent, @UserIdInt int userId) {
+
+        if (timeLimit < getMinTimeLimit()) {
+            throw new IllegalArgumentException("Time limit must be >= " + getMinTimeLimit());
+        }
         synchronized (mLock) {
             UserData user = getOrCreateUserDataLocked(userId);
+            removeObserverLocked(user, requestingUid, observerId, /*readding =*/ true);
 
-            removeObserverLocked(user, requestingUid, observerId);
+            final int observerIdCount = user.observerIdCounts.get(requestingUid, 0);
+            if (observerIdCount >= getObserverPerUidLimit()) {
+                throw new IllegalStateException(
+                        "Too many observers added by uid " + requestingUid);
+            }
+            user.observerIdCounts.put(requestingUid, observerIdCount + 1);
 
             TimeLimitGroup group = new TimeLimitGroup();
             group.observerId = observerId;
@@ -216,7 +246,7 @@
     public void removeObserver(int requestingUid, int observerId, @UserIdInt int userId) {
         synchronized (mLock) {
             UserData user = getOrCreateUserDataLocked(userId);
-            removeObserverLocked(user, requestingUid, observerId);
+            removeObserverLocked(user, requestingUid, observerId, /*readding =*/ false);
         }
     }
 
@@ -232,12 +262,19 @@
     }
 
     @GuardedBy("mLock")
-    private void removeObserverLocked(UserData user, int requestingUid, int observerId) {
+    private void removeObserverLocked(UserData user, int requestingUid, int observerId,
+            boolean readding) {
         TimeLimitGroup group = user.groups.get(observerId);
         if (group != null && group.requestingUid == requestingUid) {
             removeGroupFromPackageMapLocked(user, group);
             user.groups.remove(observerId);
             mHandler.removeMessages(MyHandler.MSG_CHECK_TIMEOUT, group);
+            final int observerIdCount = user.observerIdCounts.get(requestingUid);
+            if (observerIdCount <= 1 && !readding) {
+                user.observerIdCounts.delete(requestingUid);
+            } else {
+                user.observerIdCounts.put(requestingUid, observerIdCount - 1);
+            }
         }
     }
 
@@ -321,7 +358,7 @@
         // Unregister since the limit has been met and observer was informed.
         synchronized (mLock) {
             UserData user = getOrCreateUserDataLocked(group.userId);
-            removeObserverLocked(user, group.requestingUid, group.observerId);
+            removeObserverLocked(user, group.requestingUid, group.observerId, false);
         }
     }
 
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index f777f1d..243718a 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -115,6 +115,7 @@
     PackageManagerInternal mPackageManagerInternal;
     PackageMonitor mPackageMonitor;
     IDeviceIdleController mDeviceIdleController;
+    // Do not use directly. Call getDpmInternal() instead
     DevicePolicyManagerInternal mDpmInternal;
 
     private final SparseArray<UserUsageStatsService> mUserState = new SparseArray<>();
@@ -159,7 +160,6 @@
         mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
         mPackageManager = getContext().getPackageManager();
         mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
-        mDpmInternal = LocalServices.getService(DevicePolicyManagerInternal.class);
         mHandler = new H(BackgroundThread.get().getLooper());
 
         mAppStandby = new AppStandbyController(getContext(), BackgroundThread.get().getLooper());
@@ -209,6 +209,8 @@
     public void onBootPhase(int phase) {
         if (phase == PHASE_SYSTEM_SERVICES_READY) {
             mAppStandby.onBootPhase(phase);
+            // initialize mDpmInternal
+            getDpmInternal();
 
             mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
                     ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
@@ -228,6 +230,13 @@
         }
     }
 
+    private DevicePolicyManagerInternal getDpmInternal() {
+        if (mDpmInternal == null) {
+            mDpmInternal = LocalServices.getService(DevicePolicyManagerInternal.class);
+        }
+        return mDpmInternal;
+    }
+
     private class UserActionsReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -675,9 +684,10 @@
 
         private boolean hasObserverPermission(String callingPackage) {
             final int callingUid = Binder.getCallingUid();
+            DevicePolicyManagerInternal dpmInternal = getDpmInternal();
             if (callingUid == Process.SYSTEM_UID
-                    || (mDpmInternal != null
-                        && mDpmInternal.isActiveAdminWithPolicy(callingUid,
+                    || (dpmInternal != null
+                        && dpmInternal.isActiveAdminWithPolicy(callingUid,
                             DeviceAdminInfo.USES_POLICY_PROFILE_OWNER))) {
                 // Caller is the system or the profile owner, so proceed.
                 return true;
@@ -1042,9 +1052,6 @@
             if (packages == null || packages.length == 0) {
                 throw new IllegalArgumentException("Must specify at least one package");
             }
-            if (timeLimitMs <= 0) {
-                throw new IllegalArgumentException("Time limit must be > 0");
-            }
             if (callbackIntent == null) {
                 throw new NullPointerException("callbackIntent can't be null");
             }
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 165702c..bfff148 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -275,6 +275,23 @@
                            options_.version_code_default.value()});
       }
     }
+
+    if (el->FindAttribute("", "platformBuildVersionCode") == nullptr) {
+      auto versionCode = el->FindAttribute(xml::kSchemaAndroid, "versionCode");
+      if (versionCode != nullptr) {
+        el->attributes.push_back(xml::Attribute{"", "platformBuildVersionCode",
+                                                versionCode->value});
+      }
+    }
+
+    if (el->FindAttribute("", "platformBuildVersionName") == nullptr) {
+      auto versionName = el->FindAttribute(xml::kSchemaAndroid, "versionName");
+      if (versionName != nullptr) {
+        el->attributes.push_back(xml::Attribute{"", "platformBuildVersionName",
+                                                versionName->value});
+      }
+    }
+
     return true;
   });
 
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index 8db9374..5f406e8 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -556,6 +556,58 @@
   ASSERT_THAT(manifest, IsNull());
 }
 
+TEST_F(ManifestFixerTest, InsertPlatformBuildVersions) {
+  // Test for insertion when versionCode and versionName are included in the manifest
+  {
+    std::string input = R"(
+        <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"
+          android:versionCode="27" android:versionName="O"/>)";
+    std::unique_ptr<xml::XmlResource> manifest = Verify(input);
+    ASSERT_THAT(manifest, NotNull());
+
+    xml::Attribute* attr = manifest->root->FindAttribute("", "platformBuildVersionCode");
+    ASSERT_THAT(attr, NotNull());
+    EXPECT_THAT(attr->value, StrEq("27"));
+    attr = manifest->root->FindAttribute("", "platformBuildVersionName");
+    ASSERT_THAT(attr, NotNull());
+    EXPECT_THAT(attr->value, StrEq("O"));
+  }
+
+  // Test for insertion when versionCode and versionName defaults are specified
+  {
+    std::string input = R"(
+      <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"/>)";
+    ManifestFixerOptions options;
+    options.version_code_default = {"27"};
+    options.version_name_default = {"O"};
+    std::unique_ptr<xml::XmlResource> manifest = VerifyWithOptions(input, options);
+    ASSERT_THAT(manifest, NotNull());
+
+    xml::Attribute* attr = manifest->root->FindAttribute("", "platformBuildVersionCode");
+    ASSERT_THAT(attr, NotNull());
+    EXPECT_THAT(attr->value, StrEq("27"));
+    attr = manifest->root->FindAttribute("", "platformBuildVersionName");
+    ASSERT_THAT(attr, NotNull());
+    EXPECT_THAT(attr->value, StrEq("O"));
+  }
+
+  // Test that the platform build version attributes are not changed if they are currently present
+  {
+    std::string input = R"(
+        <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android"
+          android:versionCode="28" android:versionName="P"
+          platformBuildVersionCode="27" platformBuildVersionName="O"/>)";
+    std::unique_ptr<xml::XmlResource> manifest = Verify(input);
+    ASSERT_THAT(manifest, NotNull());
+
+    xml::Attribute* attr = manifest->root->FindAttribute("", "platformBuildVersionCode");
+    ASSERT_THAT(attr, NotNull());
+    EXPECT_THAT(attr->value, StrEq("27"));
+    attr = manifest->root->FindAttribute("", "platformBuildVersionName");
+    ASSERT_THAT(attr, NotNull());
+    EXPECT_THAT(attr->value, StrEq("O"));
+  }
+}
 
 TEST_F(ManifestFixerTest, UsesLibraryMustHaveNonEmptyName) {
   std::string input = R"(