Merge "Add extra debug logging" into udc-dev
diff --git a/core/java/android/service/notification/TEST_MAPPING b/core/java/android/service/notification/TEST_MAPPING
new file mode 100644
index 0000000..59b2bc1
--- /dev/null
+++ b/core/java/android/service/notification/TEST_MAPPING
@@ -0,0 +1,49 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsNotificationTestCases",
+      "options": [
+        {
+          "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        },
+        {
+          "exclude-annotation": "android.platform.test.annotations.LargeTest"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.LargeTest"
+        }
+      ]
+    },
+    {
+      "name": "FrameworksUiServicesTests",
+      "options": [
+        {
+          "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        },
+        {
+          "exclude-annotation": "android.platform.test.annotations.LargeTest"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.LargeTest"
+        }
+      ]
+    }
+  ],
+  "postsubmit": [
+    {
+      "name": "CtsNotificationTestCases"
+    }
+  ]
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index 9fcd207..e1a3f3a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -55,6 +55,7 @@
 import android.util.IntProperty;
 import android.util.Log;
 import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -459,7 +460,9 @@
         if (mManageButton != null) {
             int visibility = mManageButton.getVisibility();
             removeView(mManageButton);
-            mManageButton = (AlphaOptimizedButton) LayoutInflater.from(getContext()).inflate(
+            ContextThemeWrapper ctw = new ContextThemeWrapper(getContext(),
+                    com.android.internal.R.style.Theme_DeviceDefault_DayNight);
+            mManageButton = (AlphaOptimizedButton) LayoutInflater.from(ctw).inflate(
                     R.layout.bubble_manage_button, this /* parent */, false /* attach */);
             addView(mManageButton);
             mManageButton.setVisibility(visibility);
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 32680da..38bb447 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -359,6 +359,51 @@
  codec to use a previously created {@linkplain #createPersistentInputSurface persistent input
  surface} by calling {@link #setInputSurface}.
 
+ <h4 id=EncoderProfiles><a name="EncoderProfiles"></a>Encoder Profiles</h4>
+ <p>
+ When using an encoder, it is recommended to set the desired codec {@link MediaFormat#KEY_PROFILE
+ profile} during {@link #configure configure()}. (This is only meaningful for
+ {@link MediaFormat#KEY_MIME media formats} for which profiles are defined.)
+ <p>
+ If a profile is not specified during {@code configure}, the encoder will choose a profile for the
+ session based on the available information. We will call this value the <i>default profile</i>.
+ The selection of the default profile is device specific and may not be deterministic
+ (could be ad hoc or even experimental). The encoder may choose a default profile that is not
+ suitable for the intended encoding session, which may result in the encoder ultimately rejecting
+ the session.
+ <p>
+ The encoder may reject the encoding session if the configured (or default if unspecified) profile
+ does not support the codec input (mainly the {@link MediaFormat#KEY_COLOR_FORMAT color format} for
+ video/image codecs, or the {@link MediaFormat#KEY_PCM_ENCODING sample encoding} and the {@link
+ MediaFormat#KEY_CHANNEL_COUNT number of channels} for audio codecs, but also possibly
+ {@link MediaFormat#KEY_WIDTH width}, {@link MediaFormat#KEY_HEIGHT height},
+ {@link MediaFormat#KEY_FRAME_RATE frame rate}, {@link MediaFormat#KEY_BIT_RATE bitrate} or
+ {@link MediaFormat#KEY_SAMPLE_RATE sample rate}.)
+ Alternatively, the encoder may choose to (but is not required to) convert the input to support the
+ selected (or default) profile - or adjust the chosen profile based on the presumed or detected
+ input format - to ensure a successful encoding session. <b>Note</b>: Converting the input to match
+ an incompatible profile will in most cases result in decreased codec performance.
+ <p>
+ To ensure backward compatibility, the following guarantees are provided by Android:
+ <ul>
+ <li>The default video encoder profile always supports 8-bit YUV 4:2:0 color format ({@link
+ CodecCapabilities#COLOR_FormatYUV420Flexible COLOR_FormatYUV420Flexible} and equivalent
+ {@link CodecCapabilities#colorFormats supported formats}) for both Surface and ByteBuffer modes.
+ <li>The default video encoder profile always supports the default 8-bit RGBA color format in
+ Surface mode even if no such formats are enumerated in the {@link CodecCapabilities#colorFormats
+ supported formats}.
+ </ul>
+ <p class=note>
+ <b>Note</b>: the accepted profile can be queried through the {@link #getOutputFormat output
+ format} of the encoder after {@code configure} to allow applications to set up their
+ codec input to a format supported by the encoder profile.
+ <p>
+ <b>Implication:</b>
+ <ul>
+ <li>Applications that want to encode 4:2:2, 4:4:4, 10+ bit or HDR video input <b>MUST</b> configure
+ a suitable profile for encoders.
+ </ul>
+
  <h4 id=CSD><a name="CSD"></a>Codec-specific Data</h4>
  <p>
  Some formats, notably AAC audio and MPEG4, H.264 and H.265 video formats require the actual data
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index b1b7d40..46db777 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -1136,11 +1136,14 @@
      * may fail if other parameters are not compatible with the desired
      * profile or if the desired profile is not supported, but it may also
      * fail silently (where the encoder ends up using a different, compatible profile.)
+     * <p>
+     * It is recommended that the profile is set for all encoders. For more information, see
+     * the <i>Encoder Profiles</i> section of the {@link MediaCodec} API reference.
      * <p class="note">
      * <strong>Note:</strong> Codecs are free to use all the available
      * coding tools at the specified profile, but may ultimately choose to not do so.
      * <p class="note">
-     * <strong>Note:</strong> When configuring video encoders, profile must be
+     * <strong>Note:</strong> When configuring video encoders, profile (if set) must be
      * set together with {@link #KEY_LEVEL level}.
      *
      * @see MediaCodecInfo.CodecCapabilities#profileLevels
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
index 2dafbcb..a78509d 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
@@ -66,8 +66,9 @@
         )
 
         val originName: String? = when (requestInfo?.type) {
-            RequestInfo.TYPE_CREATE -> requestInfo.createCredentialRequest?.origin
-            RequestInfo.TYPE_GET -> requestInfo.getCredentialRequest?.origin
+            RequestInfo.TYPE_CREATE -> processHttpsOrigin(
+                requestInfo.createCredentialRequest?.origin)
+            RequestInfo.TYPE_GET -> processHttpsOrigin(requestInfo.getCredentialRequest?.origin)
             else -> null
         }
 
@@ -247,6 +248,9 @@
     }
 
     companion object {
+        private const val HTTPS = "https://"
+        private const val FORWARD_SLASH = "/"
+
         fun sendCancellationCode(
             cancelCode: Int,
             requestToken: IBinder?,
@@ -266,5 +270,17 @@
                 CancelUiRequest::class.java
             )
         }
+
+        /** Removes "https://", and the trailing slash if present for an https request. */
+        private fun processHttpsOrigin(origin: String?): String? {
+            var processed = origin
+            if (processed?.startsWith(HTTPS) == true) { // Removes "https://"
+                processed = processed.substring(HTTPS.length)
+                if (processed?.endsWith(FORWARD_SLASH) == true) { // Removes the trailing slash
+                    processed = processed.substring(0, processed.length - 1)
+                }
+            }
+            return processed
+        }
     }
 }
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderClient.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderClient.kt
index 519ae0a..e050604 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderClient.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderClient.kt
@@ -148,11 +148,11 @@
          */
         val isEnabled: Boolean = true,
         /**
-         * If the affordance is disabled, this is a set of instruction messages to be shown to the
-         * user when the disabled affordance is selected. The instructions should help the user
-         * figure out what to do in order to re-neable this affordance.
+         * If the affordance is disabled, this is the explanation to be shown to the user when the
+         * disabled affordance is selected. The instructions should help the user figure out what to
+         * do in order to re-neable this affordance.
          */
-        val enablementInstructions: List<String>? = null,
+        val enablementExplanation: String? = null,
         /**
          * If the affordance is disabled, this is a label for a button shown together with the set
          * of instruction messages when the disabled affordance is selected. The button should help
@@ -326,10 +326,10 @@
                                 Contract.LockScreenQuickAffordances.AffordanceTable.Columns
                                     .IS_ENABLED
                             )
-                        val enablementInstructionsColumnIndex =
+                        val enablementExplanationColumnIndex =
                             cursor.getColumnIndex(
                                 Contract.LockScreenQuickAffordances.AffordanceTable.Columns
-                                    .ENABLEMENT_INSTRUCTIONS
+                                    .ENABLEMENT_EXPLANATION
                             )
                         val enablementActionTextColumnIndex =
                             cursor.getColumnIndex(
@@ -351,7 +351,7 @@
                                 nameColumnIndex == -1 ||
                                 iconColumnIndex == -1 ||
                                 isEnabledColumnIndex == -1 ||
-                                enablementInstructionsColumnIndex == -1 ||
+                                enablementExplanationColumnIndex == -1 ||
                                 enablementActionTextColumnIndex == -1 ||
                                 enablementActionIntentColumnIndex == -1 ||
                                 configureIntentColumnIndex == -1
@@ -367,13 +367,8 @@
                                     name = cursor.getString(nameColumnIndex),
                                     iconResourceId = cursor.getInt(iconColumnIndex),
                                     isEnabled = cursor.getInt(isEnabledColumnIndex) == 1,
-                                    enablementInstructions =
-                                        cursor
-                                            .getString(enablementInstructionsColumnIndex)
-                                            ?.split(
-                                                Contract.LockScreenQuickAffordances.AffordanceTable
-                                                    .ENABLEMENT_INSTRUCTIONS_DELIMITER
-                                            ),
+                                    enablementExplanation =
+                                        cursor.getString(enablementExplanationColumnIndex),
                                     enablementActionText =
                                         cursor.getString(enablementActionTextColumnIndex),
                                     enablementActionIntent =
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt
index 7f5fb25..b6d5ef3 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/customization/data/content/CustomizationProviderContract.kt
@@ -81,7 +81,6 @@
             const val TABLE_NAME = "affordances"
             val URI: Uri =
                 LOCK_SCREEN_QUICK_AFFORDANCE_BASE_URI.buildUpon().appendPath(TABLE_NAME).build()
-            const val ENABLEMENT_INSTRUCTIONS_DELIMITER = "]["
 
             object Columns {
                 /** String. Unique ID for this affordance. */
@@ -96,11 +95,10 @@
                 /** Integer. `1` if the affordance is enabled or `0` if it disabled. */
                 const val IS_ENABLED = "is_enabled"
                 /**
-                 * String. List of strings, delimited by [ENABLEMENT_INSTRUCTIONS_DELIMITER] to be
-                 * shown to the user if the affordance is disabled and the user selects the
-                 * affordance.
+                 * String. Text to be shown to the user if the affordance is disabled and the user
+                 * selects the affordance.
                  */
-                const val ENABLEMENT_INSTRUCTIONS = "enablement_instructions"
+                const val ENABLEMENT_EXPLANATION = "enablement_explanation"
                 /**
                  * String. Optional label for a button that, when clicked, opens a destination
                  * activity where the user can re-enable the disabled affordance.
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index e779672..663efea 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -3016,52 +3016,54 @@
     -->
     <string name="keyguard_affordance_enablement_dialog_action_template">Open <xliff:g id="appName" example="Wallet">%1$s</xliff:g></string>
 
-    <!--
-    Requirement for the wallet app to be available for the user to use. This is shown as part of a
-    bulleted list of requirements. When all requirements are met, the app can be accessed through a
-    shortcut button on the lock screen. [CHAR LIMIT=NONE].
+    <!---
+    Explains that the wallet app is not available because it is not installed. This is shown as part
+    of a dialog that explains to the user why they cannot select this shortcut for their lock screen
+    right now.
+    [CHAR LIMIT=NONE].
     -->
-    <string name="keyguard_affordance_enablement_dialog_wallet_instruction_1">&#8226; The app is set up</string>
+    <string name="wallet_quick_affordance_unavailable_install_the_app">To add the Wallet app as a shortcut, make sure the app is installed</string>
 
-    <!--
-    Requirement for the wallet app to be available for the user to use. This is shown as part of a
-    bulleted list of requirements. When all requirements are met, the app can be accessed through a
-    shortcut button on the lock screen. [CHAR LIMIT=NONE].
+    <!---
+    Explains that the wallet app is not available because it is not installed. This is shown as part
+    of a dialog that explains to the user why they cannot select this shortcut for their lock screen
+    right now.
+    [CHAR LIMIT=NONE].
     -->
-    <string name="keyguard_affordance_enablement_dialog_wallet_instruction_2">&#8226; At least one card has been added to Wallet</string>
+    <string name="wallet_quick_affordance_unavailable_configure_the_app">To add the Wallet app as a shortcut, make sure at least one card has been added</string>
 
     <!--
     Requirement for the QR code scanner functionality to be available for the user to use. This is
     shown as part of a bulleted list of requirements. When all requirements are met, the piece of
     functionality can be accessed through a shortcut button on the lock screen. [CHAR LIMIT=NONE].
     -->
-    <string name="keyguard_affordance_enablement_dialog_qr_scanner_instruction">&#8226; Install a camera app</string>
+    <string name="qr_scanner_quick_affordance_unavailable_explanation">To add the QR code scanner as a shortcut, make sure a camera app is installed</string>
 
     <!--
-    Requirement for the home app to be available for the user to use. This is shown as part of a
-    bulleted list of requirements. When all requirements are met, the app can be accessed through a
-    shortcut button on the lock screen. [CHAR LIMIT=NONE].
+    Explains that the lock screen shortcut for the "home" app is not available because the app isn't
+    installed. This is shown as part of a dialog that explains to the user why they cannot select
+    this shortcut for their lock screen right now. [CHAR LIMIT=NONE].
     -->
-    <string name="keyguard_affordance_enablement_dialog_home_instruction_1">&#8226; The app is set up</string>
+    <string name="home_quick_affordance_unavailable_install_the_app">To add the Home app as a shortcut, make sure the app is installed</string>
 
     <!--
-    Requirement for the home app to be available for the user to use. This is shown as part of a
-    bulleted list of requirements. When all requirements are met, the app can be accessed through a
-    shortcut button on the lock screen. [CHAR LIMIT=NONE].
+    Explains that the lock screen shortcut for the "home" app is not available because the app isn't
+    configured. This is shown as part of a dialog that explains to the user why they cannot select
+    this shortcut for their lock screen right now. [CHAR LIMIT=NONE].
     -->
-    <string name="keyguard_affordance_enablement_dialog_home_instruction_2">&#8226; At least one device is available</string>
+    <string name="home_quick_affordance_unavailable_configure_the_app">&#8226; At least one device is available</string>
 
     <!---
-    Requirement for the notes app to be available for the user to use. This is shown as part of a
-    bulleted list of requirements. When all requirements are met, the app can be accessed through a
-    shortcut button on the lock screen. [CHAR LIMIT=NONE] -->
-    <string name="keyguard_affordance_enablement_dialog_notes_app_instruction">Select a default notes app to use the notetaking shortcut</string>
+    Explains that the notes app is not available. This is shown as part of a dialog that explains to
+    the user why they cannot select this shortcut for their lock screen right now.
+    [CHAR LIMIT=NONE].
+    -->
+    <string name="notes_app_quick_affordance_unavailable_explanation">Select a default notes app to use the notetaking shortcut</string>
 
     <!---
     The action to make the lock screen shortcut for the notes app to be available for the user to
-    use. This is shown as the action button in the dialog listing the requirements. When all
-    requirements are met, the app can be accessed through a shortcut button on the lock screen.
-    [CHAR LIMIT=NONE] -->
+    use. This is shown as the action button in the dialog explaining why the shortcut isn't
+    available. [CHAR LIMIT=NONE] -->
     <string name="keyguard_affordance_enablement_dialog_notes_app_action">Select app</string>
 
     <!--
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt b/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
index 064a44a..bc07139 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
@@ -283,7 +283,7 @@
                     Contract.LockScreenQuickAffordances.AffordanceTable.Columns.ICON,
                     Contract.LockScreenQuickAffordances.AffordanceTable.Columns.IS_ENABLED,
                     Contract.LockScreenQuickAffordances.AffordanceTable.Columns
-                        .ENABLEMENT_INSTRUCTIONS,
+                        .ENABLEMENT_EXPLANATION,
                     Contract.LockScreenQuickAffordances.AffordanceTable.Columns
                         .ENABLEMENT_ACTION_TEXT,
                     Contract.LockScreenQuickAffordances.AffordanceTable.Columns
@@ -299,10 +299,7 @@
                             representation.name,
                             representation.iconResourceId,
                             if (representation.isEnabled) 1 else 0,
-                            representation.instructions?.joinToString(
-                                Contract.LockScreenQuickAffordances.AffordanceTable
-                                    .ENABLEMENT_INSTRUCTIONS_DELIMITER
-                            ),
+                            representation.explanation,
                             representation.actionText,
                             representation.actionIntent?.toUri(Intent.URI_INTENT_SCHEME),
                             representation.configureIntent?.toUri(Intent.URI_INTENT_SCHEME),
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
index 0991b5f..f3fc809 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
@@ -83,18 +83,31 @@
             currentServices.isNullOrEmpty() && !componentPackageName.isNullOrEmpty() -> {
                 // No home app installed but we know which app we want to install.
                 return disabledPickerState(
+                    explanation =
+                        context.getString(
+                            R.string.home_quick_affordance_unavailable_install_the_app
+                        ),
                     actionText = context.getString(R.string.install_app),
                     actionIntent = appStoreIntent(context, componentPackageName),
                 )
             }
             currentServices.isNullOrEmpty() && componentPackageName.isNullOrEmpty() -> {
                 // No home app installed and we don't know which app we want to install.
-                return disabledPickerState()
+                return disabledPickerState(
+                    explanation =
+                        context.getString(
+                            R.string.home_quick_affordance_unavailable_install_the_app
+                        ),
+                )
             }
             !hasFavorites -> {
                 // Home app installed but no favorites selected.
                 val activityClass = component.getControlsUiController().get().resolveActivity()
                 return disabledPickerState(
+                    explanation =
+                        context.getString(
+                            R.string.home_quick_affordance_unavailable_configure_the_app
+                        ),
                     actionText = context.getString(R.string.controls_open_app),
                     actionIntent =
                         Intent().apply {
@@ -188,21 +201,14 @@
     }
 
     private fun disabledPickerState(
+        explanation: String,
         actionText: String? = null,
         actionIntent: Intent? = null,
     ): KeyguardQuickAffordanceConfig.PickerScreenState.Disabled {
         check(actionIntent == null || actionText != null)
 
         return KeyguardQuickAffordanceConfig.PickerScreenState.Disabled(
-            instructions =
-                listOf(
-                    context.getString(
-                        R.string.keyguard_affordance_enablement_dialog_home_instruction_1
-                    ),
-                    context.getString(
-                        R.string.keyguard_affordance_enablement_dialog_home_instruction_2
-                    ),
-                ),
+            explanation = explanation,
             actionText = actionText,
             actionIntent = actionIntent,
         )
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfig.kt
index 42fe9bc..320d158 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfig.kt
@@ -87,8 +87,8 @@
          * described in the instructions.
          */
         data class Disabled(
-            /** List of human-readable instructions for setting up the quick affordance. */
-            val instructions: List<String>,
+            /** Human-readable explanation as to why the quick affordance is current disabled. */
+            val explanation: String,
             /**
              * Optional text to display on a button that the user can click to start a flow to go
              * and set up the quick affordance and make it enabled.
@@ -101,7 +101,7 @@
             val actionIntent: Intent? = null,
         ) : PickerScreenState() {
             init {
-                check(instructions.isNotEmpty()) { "Instructions must not be empty!" }
+                check(explanation.isNotEmpty()) { "Explanation must not be empty!" }
                 check(
                     (actionText.isNullOrEmpty() && actionIntent == null) ||
                         (!actionText.isNullOrEmpty() && actionIntent != null)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
index 0d54ab9..20ed549 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
@@ -80,16 +80,14 @@
         return when {
             !controller.isAvailableOnDevice ->
                 KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice
-            !controller.isAbleToOpenCameraApp ->
+            !controller.isAbleToOpenCameraApp -> {
                 KeyguardQuickAffordanceConfig.PickerScreenState.Disabled(
-                    instructions =
-                        listOf(
-                            context.getString(
-                                R.string
-                                    .keyguard_affordance_enablement_dialog_qr_scanner_instruction
-                            ),
+                    explanation =
+                        context.getString(
+                            R.string.qr_scanner_quick_affordance_unavailable_explanation
                         ),
                 )
+            }
             else -> KeyguardQuickAffordanceConfig.PickerScreenState.Default()
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
index 9db3c22..c019d21 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
@@ -100,19 +100,20 @@
         return when {
             !walletController.walletClient.isWalletServiceAvailable ->
                 KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice
-            !isWalletAvailable() || queryCards().isEmpty() -> {
+            !isWalletAvailable() ->
                 KeyguardQuickAffordanceConfig.PickerScreenState.Disabled(
-                    instructions =
-                        listOf(
-                            context.getString(
-                                R.string.keyguard_affordance_enablement_dialog_wallet_instruction_1
-                            ),
-                            context.getString(
-                                R.string.keyguard_affordance_enablement_dialog_wallet_instruction_2
-                            ),
+                    explanation =
+                        context.getString(
+                            R.string.wallet_quick_affordance_unavailable_install_the_app
                         ),
                 )
-            }
+            queryCards().isEmpty() ->
+                KeyguardQuickAffordanceConfig.PickerScreenState.Disabled(
+                    explanation =
+                        context.getString(
+                            R.string.wallet_quick_affordance_unavailable_configure_the_app
+                        ),
+                )
             else -> KeyguardQuickAffordanceConfig.PickerScreenState.Default()
         }
     }
@@ -147,9 +148,7 @@
     }
 
     private fun isWalletAvailable() =
-        with(walletController.walletClient) {
-            isWalletServiceAvailable && isWalletFeatureAvailable
-        }
+        with(walletController.walletClient) { isWalletServiceAvailable && isWalletFeatureAvailable }
 
     private fun state(
         isFeatureEnabled: Boolean,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt
index bd3b83c..34f6b4d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt
@@ -175,7 +175,7 @@
                     iconResourceId = config.pickerIconResourceId,
                     isEnabled =
                         pickerState is KeyguardQuickAffordanceConfig.PickerScreenState.Default,
-                    instructions = disabledPickerState?.instructions,
+                    explanation = disabledPickerState?.explanation,
                     actionText = disabledPickerState?.actionText,
                     actionIntent =
                         disabledPickerState?.actionIntent?.apply {
@@ -191,6 +191,7 @@
                         },
                 )
             }
+            .sortedBy { it.name }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
index 2275337..ea9c2b2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
@@ -35,6 +35,7 @@
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
+import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
 import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
 import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordanceModel
 import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceRegistry
@@ -77,6 +78,7 @@
     private val logger: KeyguardQuickAffordancesMetricsLogger,
     private val devicePolicyManager: DevicePolicyManager,
     private val dockManager: DockManager,
+    private val biometricSettingsRepository: BiometricSettingsRepository,
     @Background private val backgroundDispatcher: CoroutineDispatcher,
     @Application private val appContext: Context,
 ) {
@@ -107,9 +109,10 @@
             quickAffordanceAlwaysVisible(position),
             keyguardInteractor.isDozing,
             keyguardInteractor.isKeyguardShowing,
-            keyguardInteractor.isQuickSettingsVisible
-        ) { affordance, isDozing, isKeyguardShowing, isQuickSettingsVisible ->
-            if (!isDozing && isKeyguardShowing && !isQuickSettingsVisible) {
+            keyguardInteractor.isQuickSettingsVisible,
+            biometricSettingsRepository.isCurrentUserInLockdown,
+        ) { affordance, isDozing, isKeyguardShowing, isQuickSettingsVisible, isUserInLockdown ->
+            if (!isDozing && isKeyguardShowing && !isQuickSettingsVisible && !isUserInLockdown) {
                 affordance
             } else {
                 KeyguardQuickAffordanceModel.Hidden
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardQuickAffordancePickerRepresentation.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardQuickAffordancePickerRepresentation.kt
index 3c96eaf..c6320de 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardQuickAffordancePickerRepresentation.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardQuickAffordancePickerRepresentation.kt
@@ -32,8 +32,8 @@
     /** Whether this quick affordance is enabled. */
     val isEnabled: Boolean = true,
 
-    /** If not enabled, the list of user-visible steps to re-enable it. */
-    val instructions: List<String>? = null,
+    /** If not enabled, a user-visible explanation as to why. */
+    val explanation: String? = null,
 
     /**
      * If not enabled, an optional label for a button that takes the user to a destination where
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt
index 8da7cec..f02d362 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt
@@ -122,17 +122,18 @@
             isEnabled && isDefaultNotesAppSet -> PickerScreenState.Default()
             isEnabled -> {
                 PickerScreenState.Disabled(
-                    listOf(
+                    explanation =
                         context.getString(
-                            R.string.keyguard_affordance_enablement_dialog_notes_app_instruction
-                        )
-                    ),
-                    context.getString(
-                        R.string.keyguard_affordance_enablement_dialog_notes_app_action
-                    ),
-                    Intent(ACTION_MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE).apply {
-                        setPackage(context.packageName)
-                    }
+                            R.string.notes_app_quick_affordance_unavailable_explanation
+                        ),
+                    actionText =
+                        context.getString(
+                            R.string.keyguard_affordance_enablement_dialog_notes_app_action
+                        ),
+                    actionIntent =
+                        Intent(ACTION_MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE).apply {
+                            setPackage(context.packageName)
+                        },
                 )
             }
             else -> PickerScreenState.UnavailableOnDevice
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index b848d2e..109c1cf 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -930,6 +930,7 @@
                 showRingerDrawer();
             }
         });
+        updateSelectedRingerContainerDescription(mIsRingerDrawerOpen);
 
         mRingerDrawerVibrate.setOnClickListener(
                 new RingerDrawerItemClickListener(RINGER_MODE_VIBRATE));
@@ -992,6 +993,18 @@
                         : 0;
     }
 
+    @VisibleForTesting String getSelectedRingerContainerDescription() {
+        return mSelectedRingerContainer.getContentDescription().toString();
+    }
+
+    @VisibleForTesting void toggleRingerDrawer(boolean show) {
+        if (show) {
+            showRingerDrawer();
+        } else {
+            hideRingerDrawer();
+        }
+    }
+
     /** Animates in the ringer drawer. */
     private void showRingerDrawer() {
         if (mIsRingerDrawerOpen) {
@@ -1069,12 +1082,7 @@
                     .start();
         }
 
-        // When the ringer drawer is open, tapping the currently selected ringer will set the ringer
-        // to the current ringer mode. Change the content description to that, instead of the 'tap
-        // to change ringer mode' default.
-        mSelectedRingerContainer.setContentDescription(
-                mContext.getString(getStringDescriptionResourceForRingerMode(
-                        mState.ringerModeInternal)));
+        updateSelectedRingerContainerDescription(true);
 
         mIsRingerDrawerOpen = true;
     }
@@ -1120,14 +1128,38 @@
                 .translationY(0f)
                 .start();
 
-        // When the drawer is closed, tapping the selected ringer drawer will open it, allowing the
-        // user to change the ringer.
-        mSelectedRingerContainer.setContentDescription(
-                mContext.getString(R.string.volume_ringer_change));
+        updateSelectedRingerContainerDescription(false);
 
         mIsRingerDrawerOpen = false;
     }
 
+
+    /**
+     * @param open false to set the description when drawer is closed
+     */
+    private void updateSelectedRingerContainerDescription(boolean open) {
+        if (mState == null) return;
+
+        String currentMode = mContext.getString(getStringDescriptionResourceForRingerMode(
+                mState.ringerModeInternal));
+        String tapToSelect;
+
+        if (open) {
+            // When the ringer drawer is open, tapping the currently selected ringer will set the
+            // ringer to the current ringer mode. Change the content description to that, instead of
+            // the 'tap to change ringer mode' default.
+            tapToSelect = "";
+
+        } else {
+            // When the drawer is closed, tapping the selected ringer drawer will open it, allowing
+            // the user to change the ringer. The user needs to know that, and also the current mode
+            currentMode += ", ";
+            tapToSelect = mContext.getString(R.string.volume_ringer_change);
+        }
+
+        mSelectedRingerContainer.setContentDescription(currentMode + tapToSelect);
+    }
+
     private void initSettingsH(int lockTaskModeState) {
         if (mSettingsView != null) {
             mSettingsView.setVisibility(
@@ -1703,7 +1735,7 @@
         });
     }
 
-    private int getStringDescriptionResourceForRingerMode(int mode) {
+    @VisibleForTesting int getStringDescriptionResourceForRingerMode(int mode) {
         switch (mode) {
             case RINGER_MODE_SILENT:
                 return R.string.volume_ringer_status_silent;
@@ -1785,6 +1817,7 @@
             updateVolumeRowH(row);
         }
         updateRingerH();
+        updateSelectedRingerContainerDescription(mIsRingerDrawerOpen);
         mWindow.setTitle(composeWindowTitle());
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
index 8ee7d3e..cdc99af3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
@@ -42,6 +42,7 @@
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
 import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
@@ -98,6 +99,7 @@
     @Mock private lateinit var logger: KeyguardQuickAffordancesMetricsLogger
 
     private lateinit var dockManager: DockManagerFake
+    private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
 
     private lateinit var underTest: CustomizationProvider
     private lateinit var testScope: TestScope
@@ -111,6 +113,7 @@
         whenever(backgroundHandler.looper).thenReturn(TestableLooper.get(this).looper)
 
         dockManager = DockManagerFake()
+        biometricSettingsRepository = FakeBiometricSettingsRepository()
 
         underTest = CustomizationProvider()
         val testDispatcher = UnconfinedTestDispatcher()
@@ -197,6 +200,7 @@
                 logger = logger,
                 devicePolicyManager = devicePolicyManager,
                 dockManager = dockManager,
+                biometricSettingsRepository = biometricSettingsRepository,
                 backgroundDispatcher = testDispatcher,
                 appContext = mContext,
             )
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
index 26c0ea4..7510373 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
@@ -53,7 +53,7 @@
         MockitoAnnotations.initMocks(this)
         whenever(controller.intent).thenReturn(INTENT_1)
 
-        underTest = QrCodeScannerKeyguardQuickAffordanceConfig(mock(), controller)
+        underTest = QrCodeScannerKeyguardQuickAffordanceConfig(context, controller)
     }
 
     @Test
@@ -77,22 +77,21 @@
     }
 
     @Test
-    fun affordance_scannerActivityChanged_deliversModelWithUpdatedIntent() =
-        runBlockingTest {
-            whenever(controller.isEnabledForLockScreenButton).thenReturn(true)
-            var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
-            val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
-            val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>()
-            verify(controller).addCallback(callbackCaptor.capture())
+    fun affordance_scannerActivityChanged_deliversModelWithUpdatedIntent() = runBlockingTest {
+        whenever(controller.isEnabledForLockScreenButton).thenReturn(true)
+        var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null
+        val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this)
+        val callbackCaptor = argumentCaptor<QRCodeScannerController.Callback>()
+        verify(controller).addCallback(callbackCaptor.capture())
 
-            whenever(controller.intent).thenReturn(INTENT_2)
-            callbackCaptor.value.onQRCodeScannerActivityChanged()
+        whenever(controller.intent).thenReturn(INTENT_2)
+        callbackCaptor.value.onQRCodeScannerActivityChanged()
 
-            assertVisibleState(latest)
+        assertVisibleState(latest)
 
-            job.cancel()
-            verify(controller).removeCallback(callbackCaptor.value)
-        }
+        job.cancel()
+        verify(controller).removeCallback(callbackCaptor.value)
+    }
 
     @Test
     fun affordance_scannerPreferenceChanged_deliversVisibleModel() = runBlockingTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
index fb21847..2c90d53 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
@@ -38,6 +38,7 @@
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
 import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
@@ -239,6 +240,7 @@
     @JvmField @Parameter(4) var startActivity: Boolean = false
     private lateinit var homeControls: FakeKeyguardQuickAffordanceConfig
     private lateinit var dockManager: DockManagerFake
+    private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
     private lateinit var userTracker: UserTracker
 
     @Before
@@ -250,6 +252,7 @@
         homeControls =
             FakeKeyguardQuickAffordanceConfig(BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS)
         dockManager = DockManagerFake()
+        biometricSettingsRepository = FakeBiometricSettingsRepository()
         val quickAccessWallet =
             FakeKeyguardQuickAffordanceConfig(
                 BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET
@@ -339,6 +342,7 @@
                 logger = logger,
                 devicePolicyManager = devicePolicyManager,
                 dockManager = dockManager,
+                biometricSettingsRepository = biometricSettingsRepository,
                 backgroundDispatcher = testDispatcher,
                 appContext = mContext,
             )
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
index 1d5971c..7cab680 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
@@ -40,6 +40,7 @@
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
 import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
@@ -97,6 +98,7 @@
     private lateinit var qrCodeScanner: FakeKeyguardQuickAffordanceConfig
     private lateinit var featureFlags: FakeFeatureFlags
     private lateinit var dockManager: DockManagerFake
+    private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
 
     @Before
     fun setUp() {
@@ -119,6 +121,7 @@
         testScope = TestScope(testDispatcher)
 
         dockManager = DockManagerFake()
+        biometricSettingsRepository = FakeBiometricSettingsRepository()
 
         val localUserSelectionManager =
             KeyguardQuickAffordanceLocalUserSelectionManager(
@@ -201,6 +204,7 @@
                 logger = logger,
                 devicePolicyManager = devicePolicyManager,
                 dockManager = dockManager,
+                biometricSettingsRepository = biometricSettingsRepository,
                 backgroundDispatcher = testDispatcher,
                 appContext = context,
             )
@@ -314,6 +318,24 @@
         }
 
     @Test
+    fun quickAffordance_hiddenWhenUserIsInLockdownMode() =
+        testScope.runTest {
+            biometricSettingsRepository.setIsUserInLockdown(true)
+            quickAccessWallet.setState(
+                KeyguardQuickAffordanceConfig.LockScreenState.Visible(
+                    icon = ICON,
+                )
+            )
+
+            val collectedValue by
+                collectLastValue(
+                    underTest.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_END)
+                )
+
+            assertThat(collectedValue).isEqualTo(KeyguardQuickAffordanceModel.Hidden)
+        }
+
+    @Test
     fun quickAffordance_bottomStartAffordanceHiddenWhileDozing() =
         testScope.runTest {
             repository.setIsDozing(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
index 8a36dbc..73fe380 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
@@ -39,6 +39,7 @@
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
 import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
@@ -110,6 +111,7 @@
     private lateinit var quickAccessWalletAffordanceConfig: FakeKeyguardQuickAffordanceConfig
     private lateinit var qrCodeScannerAffordanceConfig: FakeKeyguardQuickAffordanceConfig
     private lateinit var dockManager: DockManagerFake
+    private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
 
     @Before
     fun setUp() {
@@ -126,6 +128,7 @@
         qrCodeScannerAffordanceConfig =
             FakeKeyguardQuickAffordanceConfig(BuiltInKeyguardQuickAffordanceKeys.QR_CODE_SCANNER)
         dockManager = DockManagerFake()
+        biometricSettingsRepository = FakeBiometricSettingsRepository()
         registry =
             FakeKeyguardQuickAffordanceRegistry(
                 mapOf(
@@ -240,6 +243,7 @@
                         logger = logger,
                         devicePolicyManager = devicePolicyManager,
                         dockManager = dockManager,
+                        biometricSettingsRepository = biometricSettingsRepository,
                         backgroundDispatcher = testDispatcher,
                         appContext = mContext,
                     ),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt
index cc64cc2..58c762e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt
@@ -296,8 +296,8 @@
         assertThat(pickerScreenState is KeyguardQuickAffordanceConfig.PickerScreenState.Disabled)
             .isTrue()
         val disabled = pickerScreenState as KeyguardQuickAffordanceConfig.PickerScreenState.Disabled
-        assertThat(disabled.instructions)
-            .isEqualTo(listOf("Select a default notes app to use the notetaking shortcut"))
+        assertThat(disabled.explanation)
+            .isEqualTo("Select a default notes app to use the notetaking shortcut")
         assertThat(disabled.actionText).isEqualTo("Select app")
         assertThat(disabled.actionIntent?.action)
             .isEqualTo(ACTION_MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 85b1ec1..b0c1486 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -89,7 +89,6 @@
 
 import org.junit.Assert;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -103,7 +102,6 @@
 /**
  * Tests for {@link NotificationStackScrollLayout}.
  */
-@Ignore("b/255552856")
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
@@ -375,20 +373,6 @@
     }
 
     @Test
-    public void testAppearFractionCalculation() {
-        // appear start position
-        when(mNotificationShelf.getIntrinsicHeight()).thenReturn(100);
-        // because it's the same as shelf height, appear start position equals shelf height
-        mStackScroller.mStatusBarHeight = 100;
-        // appear end position
-        when(mEmptyShadeView.getHeight()).thenReturn(200);
-
-        assertEquals(0f, mStackScroller.calculateAppearFraction(100));
-        assertEquals(1f, mStackScroller.calculateAppearFraction(200));
-        assertEquals(0.5f, mStackScroller.calculateAppearFraction(150));
-    }
-
-    @Test
     public void testAppearFractionCalculationIsNotNegativeWhenShelfBecomesSmaller() {
         // this situation might occur if status bar height is defined in pixels while shelf height
         // in dp and screen density changes - appear start position
@@ -590,6 +574,7 @@
 
     @Test
     public void testReInflatesFooterViews() {
+        when(mEmptyShadeView.getTextResource()).thenReturn(R.string.empty_shade_text);
         clearInvocations(mStackScroller);
         mStackScroller.reinflateViews();
         verify(mStackScroller).setFooterView(any());
@@ -916,7 +901,7 @@
         mStackScroller.setHasFilteredOutSeenNotifications(true);
         mStackScroller.updateEmptyShadeView(true, false);
 
-        verify(mEmptyShadeView).setFooterText(not(0));
+        verify(mEmptyShadeView).setFooterText(not(eq(0)));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index 8f725be..2ea6368 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -16,11 +16,16 @@
 
 package com.android.systemui.volume;
 
+import static android.media.AudioManager.RINGER_MODE_NORMAL;
+import static android.media.AudioManager.RINGER_MODE_SILENT;
+import static android.media.AudioManager.RINGER_MODE_VIBRATE;
+
 import static com.android.systemui.volume.Events.DISMISS_REASON_UNKNOWN;
 import static com.android.systemui.volume.Events.SHOW_REASON_UNKNOWN;
 import static com.android.systemui.volume.VolumeDialogControllerImpl.STREAMS;
 
 import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotSame;
 import static junit.framework.Assert.assertTrue;
 
 import static org.mockito.ArgumentMatchers.any;
@@ -293,7 +298,7 @@
     @Test
     public void testSelectVibrateFromDrawer() {
         final State initialUnsetState = new State();
-        initialUnsetState.ringerModeInternal = AudioManager.RINGER_MODE_NORMAL;
+        initialUnsetState.ringerModeInternal = RINGER_MODE_NORMAL;
         mDialog.onStateChangedH(initialUnsetState);
 
         mActiveRinger.performClick();
@@ -307,7 +312,7 @@
     @Test
     public void testSelectMuteFromDrawer() {
         final State initialUnsetState = new State();
-        initialUnsetState.ringerModeInternal = AudioManager.RINGER_MODE_NORMAL;
+        initialUnsetState.ringerModeInternal = RINGER_MODE_NORMAL;
         mDialog.onStateChangedH(initialUnsetState);
 
         mActiveRinger.performClick();
@@ -329,7 +334,7 @@
 
         // Make sure we've actually changed the ringer mode.
         verify(mVolumeDialogController, times(1)).setRingerMode(
-                AudioManager.RINGER_MODE_NORMAL, false);
+                RINGER_MODE_NORMAL, false);
     }
 
     /**
@@ -511,6 +516,85 @@
         }
     }
 
+    private enum RingerDrawerState {INIT, OPEN, CLOSE}
+
+    @Test
+    public void ringerModeNormal_ringerContainerDescribesItsState() {
+        assertRingerContainerDescribesItsState(RINGER_MODE_NORMAL, RingerDrawerState.INIT);
+    }
+
+    @Test
+    public void ringerModeSilent_ringerContainerDescribesItsState() {
+        assertRingerContainerDescribesItsState(RINGER_MODE_SILENT, RingerDrawerState.INIT);
+    }
+
+    @Test
+    public void ringerModeVibrate_ringerContainerDescribesItsState() {
+        assertRingerContainerDescribesItsState(RINGER_MODE_VIBRATE, RingerDrawerState.INIT);
+    }
+
+    @Test
+    public void ringerModeNormal_openDrawer_ringerContainerDescribesItsState() {
+        assertRingerContainerDescribesItsState(RINGER_MODE_NORMAL, RingerDrawerState.OPEN);
+    }
+
+    @Test
+    public void ringerModeSilent_openDrawer_ringerContainerDescribesItsState() {
+        assertRingerContainerDescribesItsState(RINGER_MODE_SILENT, RingerDrawerState.OPEN);
+    }
+
+    @Test
+    public void ringerModeVibrate_openDrawer_ringerContainerDescribesItsState() {
+        assertRingerContainerDescribesItsState(RINGER_MODE_VIBRATE, RingerDrawerState.OPEN);
+    }
+
+    @Test
+    public void ringerModeNormal_closeDrawer_ringerContainerDescribesItsState() {
+        assertRingerContainerDescribesItsState(RINGER_MODE_NORMAL, RingerDrawerState.CLOSE);
+    }
+
+    @Test
+    public void ringerModeSilent_closeDrawer_ringerContainerDescribesItsState() {
+        assertRingerContainerDescribesItsState(RINGER_MODE_SILENT, RingerDrawerState.CLOSE);
+    }
+
+    @Test
+    public void ringerModeVibrate_closeDrawer_ringerContainerDescribesItsState() {
+        assertRingerContainerDescribesItsState(RINGER_MODE_VIBRATE, RingerDrawerState.CLOSE);
+    }
+
+    /**
+     * The content description should include ringer state, and the correct one.
+     */
+    private void assertRingerContainerDescribesItsState(int ringerMode,
+            RingerDrawerState drawerState) {
+        State state = createShellState();
+        state.ringerModeInternal = ringerMode;
+        mDialog.onStateChangedH(state);
+
+        mDialog.show(SHOW_REASON_UNKNOWN);
+
+        if (drawerState != RingerDrawerState.INIT) {
+            // in both cases we first open the drawer
+            mDialog.toggleRingerDrawer(true);
+
+            if (drawerState == RingerDrawerState.CLOSE) {
+                mDialog.toggleRingerDrawer(false);
+            }
+        }
+
+        String ringerContainerDescription = mDialog.getSelectedRingerContainerDescription();
+        String ringerDescription = mContext.getString(
+                mDialog.getStringDescriptionResourceForRingerMode(ringerMode));
+
+        if (drawerState == RingerDrawerState.OPEN) {
+            assertEquals(ringerDescription, ringerContainerDescription);
+        } else {
+            assertNotSame(ringerDescription, ringerContainerDescription);
+            assertTrue(ringerContainerDescription.startsWith(ringerDescription));
+        }
+    }
+
     @After
     public void teardown() {
         if (mDialog != null) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5c1dad9..92e73f5 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -13785,7 +13785,8 @@
                         if (action.startsWith("android.intent.action.USER_")
                                 || action.startsWith("android.intent.action.PACKAGE_")
                                 || action.startsWith("android.intent.action.UID_")
-                                || action.startsWith("android.intent.action.EXTERNAL_")) {
+                                || action.startsWith("android.intent.action.EXTERNAL_")
+                                || action.startsWith("android.bluetooth.")) {
                             if (DEBUG_BROADCAST) {
                                 Slog.wtf(TAG,
                                         "System internals registering for " + filter.toLongString()
diff --git a/services/core/java/com/android/server/notification/TEST_MAPPING b/services/core/java/com/android/server/notification/TEST_MAPPING
new file mode 100644
index 0000000..59b2bc1
--- /dev/null
+++ b/services/core/java/com/android/server/notification/TEST_MAPPING
@@ -0,0 +1,49 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsNotificationTestCases",
+      "options": [
+        {
+          "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        },
+        {
+          "exclude-annotation": "android.platform.test.annotations.LargeTest"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.LargeTest"
+        }
+      ]
+    },
+    {
+      "name": "FrameworksUiServicesTests",
+      "options": [
+        {
+          "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        },
+        {
+          "exclude-annotation": "android.platform.test.annotations.LargeTest"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.LargeTest"
+        }
+      ]
+    }
+  ],
+  "postsubmit": [
+    {
+      "name": "CtsNotificationTestCases"
+    }
+  ]
+}