Merge "Dont grant Phone and Calendar permissions to Assistant on non-Wear lowram devices" into main
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index bd80dc1..69b5222 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -499,32 +499,31 @@
 
     /**
      * Activity Action: Launch an Automatic Zen Rule configuration screen
-     * <p>
-     * Input: Optionally, {@link #EXTRA_AUTOMATIC_RULE_ID}, if the configuration screen for an
+     *
+     * <p> Input: Optionally, {@link #EXTRA_AUTOMATIC_RULE_ID}, if the configuration screen for an
      * existing rule should be displayed. If the rule id is missing or null, apps should display
      * a configuration screen where users can create a new instance of the rule.
-     * <p>
-     * Output: Nothing
-     * <p>
-     *     You can have multiple activities handling this intent, if you support multiple
-     *     {@link AutomaticZenRule rules}. In order for the system to properly display all of your
-     *     rule types so that users can create new instances or configure existing ones, you need
-     *     to add some extra metadata ({@link #META_DATA_AUTOMATIC_RULE_TYPE})
-     *     to your activity tag in your manifest. If you'd like to limit the number of rules a user
-     *     can create from this flow, you can additionally optionally include
-     *     {@link #META_DATA_RULE_INSTANCE_LIMIT}.
      *
-     *     For example,
-     *     &lt;meta-data
-     *         android:name="android.app.zen.automatic.ruleType"
-     *         android:value="@string/my_condition_rule">
-     *     &lt;/meta-data>
-     *     &lt;meta-data
-     *         android:name="android.app.zen.automatic.ruleInstanceLimit"
-     *         android:value="1">
-     *     &lt;/meta-data>
-     * </p>
-     * </p>
+     * <p> Output: Nothing
+     *
+     * <p> You can have multiple activities handling this intent, if you support multiple
+     * {@link AutomaticZenRule rules}. In order for the system to properly display all of your
+     * rule types so that users can create new instances or configure existing ones, you need
+     * to add some extra metadata ({@link #META_DATA_AUTOMATIC_RULE_TYPE})
+     * to your activity tag in your manifest. If you'd like to limit the number of rules a user
+     * can create from this flow, you can additionally optionally include
+     * {@link #META_DATA_RULE_INSTANCE_LIMIT}. For example,
+     *
+     * <pre>
+     *     {@code
+     *     <meta-data
+     *         android:name="android.service.zen.automatic.ruleType"
+     *         android:value="@string/my_condition_rule" />
+     *     <meta-data
+     *         android:name="android.service.zen.automatic.ruleInstanceLimit"
+     *         android:value="1" />
+     *     }
+     * </pre>
      *
      * @see #addAutomaticZenRule(AutomaticZenRule)
      */
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 065b3d6..b2f333a 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -9025,6 +9025,10 @@
 
             final int uid = consumer.getUid();
             final Uid u = uidStats.get(uid);
+            if (u == null) {
+                continue;
+            }
+
             final long rxPackets = u.getNetworkActivityPackets(
                     BatteryStats.NETWORK_MOBILE_RX_DATA, STATS_SINCE_CHARGED);
             final long txPackets = u.getNetworkActivityPackets(
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index a459aaa..2c7b9c0 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -159,6 +159,8 @@
     @UnsupportedAppUsage
     private static UserEnvironment sCurrentUser;
     private static boolean sUserRequired;
+    private static Boolean sLegacyStorageAppOp;
+    private static Boolean sNoIsolatedStorageAppOp;
 
     static {
         initForCurrentUser();
@@ -1459,15 +1461,23 @@
         final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
         final String opPackageName = context.getOpPackageName();
 
-        if (appOps.noteOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE, uid,
-                opPackageName) == AppOpsManager.MODE_ALLOWED) {
-            return true;
+        if (sLegacyStorageAppOp == null) {
+            sLegacyStorageAppOp =
+              appOps.checkOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE, uid, opPackageName) ==
+                              AppOpsManager.MODE_ALLOWED;
+        }
+        if (sLegacyStorageAppOp) {
+            return sLegacyStorageAppOp;
         }
 
         // Legacy external storage access is granted to instrumentations invoked with
         // "--no-isolated-storage" flag.
-        return appOps.noteOpNoThrow(AppOpsManager.OP_NO_ISOLATED_STORAGE, uid,
-                opPackageName) == AppOpsManager.MODE_ALLOWED;
+        if (sNoIsolatedStorageAppOp == null) {
+            sNoIsolatedStorageAppOp =
+              appOps.checkOpNoThrow(AppOpsManager.OP_NO_ISOLATED_STORAGE, uid,
+                                    opPackageName) == AppOpsManager.MODE_ALLOWED;
+        }
+        return sNoIsolatedStorageAppOp;
     }
 
     private static boolean isScopedStorageEnforced(boolean defaultScopedStorage,
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 57853e7..94c76929 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -13396,7 +13396,19 @@
                 = "enable_freeform_support";
 
         /**
-         * Whether to enable experimental desktop mode on secondary displays.
+         * Whether to override the availability of the desktop mode on the main display of the
+         * device. If on, users can make move an app to the desktop, allowing a freeform windowing
+         * experience.
+         * @hide
+         */
+        @Readable
+        public static final String DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES =
+                "override_desktop_mode_features";
+
+        /**
+         * Whether to enable the legacy freeform support on secondary displays. If enabled, the
+         * SECONDARY_HOME of the launcher is started on any secondary display, allowing for a
+         * desktop experience.
          * @hide
          */
         @Readable
diff --git a/core/java/android/tracing/flags.aconfig b/core/java/android/tracing/flags.aconfig
index d7389ba..be60c25 100644
--- a/core/java/android/tracing/flags.aconfig
+++ b/core/java/android/tracing/flags.aconfig
@@ -38,3 +38,11 @@
     is_fixed_read_only: true
     bug: "323166383"
 }
+
+flag {
+    name: "perfetto_wm_tracing"
+    namespace: "windowing_tools"
+    description: "Migrate WindowManager tracing to Perfetto"
+    is_fixed_read_only: true
+    bug: "323165543"
+}
diff --git a/core/java/android/view/autofill/AutofillFeatureFlags.java b/core/java/android/view/autofill/AutofillFeatureFlags.java
index 199a69a..5b1c7d5 100644
--- a/core/java/android/view/autofill/AutofillFeatureFlags.java
+++ b/core/java/android/view/autofill/AutofillFeatureFlags.java
@@ -256,6 +256,21 @@
             "ignore_relayout_auth_pending";
 
     /**
+     * Fixes to handle apps relaying out, and causing problems for autofill.
+     *
+     * @hide
+     */
+    public static final String DEVICE_CONFIG_ENABLE_RELAYOUT = "enable_relayout";
+
+    /**
+     * Enable relative location of views for fingerprinting for relayout.
+     *
+     * @hide
+     */
+    public static final String DEVICE_CONFIG_ENABLE_RELATIVE_LOCATION_FOR_RELAYOUT =
+            "enable_relative_location_for_relayout";
+
+    /**
      * Bugfix flag, Autofill should only fill in value from current session.
      *
      * See frameworks/base/services/autofill/bugfixes.aconfig#fill_fields_from_current_session_only
@@ -543,6 +558,22 @@
                 false);
     }
 
+    /** @hide */
+    public static boolean enableRelayoutFixes() {
+        return DeviceConfig.getBoolean(
+                DeviceConfig.NAMESPACE_AUTOFILL,
+                DEVICE_CONFIG_ENABLE_RELAYOUT,
+                true);
+    }
+
+    /** @hide */
+    public static boolean enableRelativeLocationForRelayout() {
+        return DeviceConfig.getBoolean(
+                DeviceConfig.NAMESPACE_AUTOFILL,
+                DEVICE_CONFIG_ENABLE_RELATIVE_LOCATION_FOR_RELAYOUT,
+                false);
+    }
+
     /** @hide **/
     public static boolean shouldFillFieldsFromCurrentSessionOnly() {
         return DeviceConfig.getBoolean(
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 0d4c556..515ed0e 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -748,7 +748,16 @@
 
     // Controls logic around apps changing some properties of their views when activity loses
     // focus due to autofill showing biometric activity, password manager, or password breach check.
-    private boolean mRelayoutFix;
+    // Deprecated. TODO: Remove it after ramp of new solution.
+    private boolean mRelayoutFixDeprecated;
+
+    // Controls logic around apps changing some properties of their views when activity loses
+    // focus due to autofill showing biometric activity, password manager, or password breach check.
+    private final boolean mRelayoutFix;
+
+    // Controls logic around apps changing some properties of their views when activity loses
+    // focus due to autofill showing biometric activity, password manager, or password breach check.
+    private final boolean mRelativePositionForRelayout;
 
     // Indicates whether the credman integration is enabled.
     private final boolean mIsCredmanIntegrationEnabled;
@@ -978,11 +987,31 @@
         mShouldIncludeInvisibleViewInAssistStructure =
                 AutofillFeatureFlags.shouldIncludeInvisibleViewInAssistStructure();
 
-        mRelayoutFix = AutofillFeatureFlags.shouldIgnoreRelayoutWhenAuthPending();
+        mRelayoutFixDeprecated = AutofillFeatureFlags.shouldIgnoreRelayoutWhenAuthPending();
+        mRelayoutFix = AutofillFeatureFlags.enableRelayoutFixes();
+        mRelativePositionForRelayout = AutofillFeatureFlags.enableRelativeLocationForRelayout();
         mIsCredmanIntegrationEnabled = Flags.autofillCredmanIntegration();
     }
 
     /**
+     * Whether to apply relayout fixes.
+     *
+     * @hide
+     */
+    public boolean isRelayoutFixEnabled() {
+        return mRelayoutFix;
+    }
+
+    /**
+     * Whether to use relative positions and locations of the views for disambiguation.
+     *
+     * @hide
+     */
+    public boolean isRelativePositionForRelayoutEnabled() {
+        return mRelativePositionForRelayout;
+    }
+
+    /**
      * Whether to apply heuristic check on important views before triggering fill request
      *
      * @hide
@@ -1779,7 +1808,7 @@
                 }
                 return;
             }
-            if (mRelayoutFix && mState == STATE_PENDING_AUTHENTICATION) {
+            if (mRelayoutFixDeprecated && mState == STATE_PENDING_AUTHENTICATION) {
                 if (sVerbose) {
                     Log.v(TAG, "notifyViewVisibilityChanged(): ignoring in auth pending mode");
                 }
@@ -2917,7 +2946,7 @@
             Intent fillInIntent, boolean authenticateInline) {
         synchronized (mLock) {
             if (sessionId == mSessionId) {
-                if (mRelayoutFix) {
+                if (mRelayoutFixDeprecated) {
                     mState = STATE_PENDING_AUTHENTICATION;
                 }
                 final AutofillClient client = getClient();
@@ -3778,7 +3807,7 @@
 
     @GuardedBy("mLock")
     private boolean isPendingAuthenticationLocked() {
-        return mRelayoutFix && mState == STATE_PENDING_AUTHENTICATION;
+        return mRelayoutFixDeprecated && mState == STATE_PENDING_AUTHENTICATION;
     }
 
     @GuardedBy("mLock")
@@ -4322,6 +4351,13 @@
                         addToSet(mInvisibleDialogTrackedIds, id);
                     }
                 }
+            } else {
+                if (sDebug) {
+                    // isClientVisibleForAutofillLocked() is checking whether
+                    // activity has stopped under the hood
+                    Log.d(TAG, "notifyViewVisibilityChangedLocked(): ignoring "
+                            + "view visibility change since activity has stopped");
+                }
             }
 
             if (mIsTrackedSaveView && mVisibleTrackedIds.isEmpty()) {
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index e44c727..565d584 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -62,7 +62,7 @@
         android:layout_height="match_parent"
         android:layout_alignParentStart="true"
         android:layout_centerVertical="true"
-        android:layout_toStartOf="@id/expand_button"
+        android:layout_toStartOf="@id/notification_buttons_column"
         android:layout_alignWithParentIfMissing="true"
         android:clipChildren="false"
         android:gravity="center_vertical"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index f696e872..6b71f97 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -722,9 +722,6 @@
     <!-- label for screenshot item in power menu [CHAR LIMIT=24]-->
     <string name="global_action_screenshot">Screenshot</string>
 
-    <!-- description for mandatory biometrics prompt -->
-    <string name="identity_check_biometric_prompt_description">This is needed since Identity Check is on</string>
-
     <!-- Take bug report menu title [CHAR LIMIT=30] -->
     <string name="bugreport_title">Bug report</string>
     <!-- Message in bugreport dialog describing what it does [CHAR LIMIT=NONE] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 7a51abc..7d50d22 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1927,7 +1927,6 @@
   <java-symbol type="string" name="global_action_voice_assist" />
   <java-symbol type="string" name="global_action_assist" />
   <java-symbol type="string" name="global_action_screenshot" />
-  <java-symbol type="string" name="identity_check_biometric_prompt_description" />
   <java-symbol type="string" name="invalidPuk" />
   <java-symbol type="string" name="lockscreen_carrier_default" />
   <java-symbol type="style" name="Animation.LockScreen" />
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index c573cf4a..66b47da 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -92,6 +92,5 @@
         <permission name="android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS" />
         <permission name="android.permission.CONTROL_UI_TRACING" />
         <permission name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND" />
-        <permission name="android.permission.SET_BIOMETRIC_DIALOG_ADVANCED" />
     </privapp-permissions>
 </permissions>
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/OWNERS b/libs/WindowManager/Shell/multivalentScreenshotTests/OWNERS
new file mode 100644
index 0000000..dc11241
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/OWNERS
@@ -0,0 +1,4 @@
+atsjenk@google.com
+liranb@google.com
+madym@google.com
+mpodolian@google.com
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/dark_portrait_bubbles_education.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/dark_portrait_bubbles_education.png
index eb28881..027b28e 100644
--- a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/dark_portrait_bubbles_education.png
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/dark_portrait_bubbles_education.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/light_portrait_bubbles_education.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/light_portrait_bubbles_education.png
index eb28881..027b28e 100644
--- a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/light_portrait_bubbles_education.png
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/light_portrait_bubbles_education.png
Binary files differ
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/DesktopModeStatus.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/DesktopModeStatus.java
index 4876f32..92084e4 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/DesktopModeStatus.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/DesktopModeStatus.java
@@ -16,9 +16,13 @@
 
 package com.android.wm.shell.shared;
 
+import static android.provider.Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES;
+
 import android.annotation.NonNull;
 import android.content.Context;
 import android.os.SystemProperties;
+import android.provider.Settings;
+import android.util.Log;
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
@@ -29,6 +33,8 @@
  */
 public class DesktopModeStatus {
 
+    private static final String TAG = "DesktopModeStatus";
+
     /**
      * Flag to indicate whether task resizing is veiled.
      */
@@ -98,11 +104,12 @@
             "persist.wm.debug.desktop_max_task_limit", DEFAULT_MAX_TASK_LIMIT);
 
     /**
-     * Return {@code true} if desktop windowing is enabled. Only to be used for testing. Callers
-     * should use {@link #canEnterDesktopMode(Context)} to query the state of desktop windowing.
+     * Return {@code true} if desktop windowing flag is enabled. Only to be used for testing.
+     * Callers should use {@link #canEnterDesktopMode(Context)} to query the state of desktop
+     * windowing.
      */
     @VisibleForTesting
-    public static boolean isEnabled() {
+    public static boolean isDesktopModeFlagEnabled() {
         return Flags.enableDesktopWindowingMode();
     }
 
@@ -120,7 +127,7 @@
      */
     public static boolean useWindowShadow(boolean isFocusedWindow) {
         return USE_WINDOW_SHADOWS
-            || (USE_WINDOW_SHADOWS_FOCUSED_WINDOW && isFocusedWindow);
+                || (USE_WINDOW_SHADOWS_FOCUSED_WINDOW && isFocusedWindow);
     }
 
     /**
@@ -154,10 +161,36 @@
     }
 
     /**
+     * Return {@code true} if desktop mode dev option should be shown on current device
+     */
+    public static boolean canShowDesktopModeDevOption(@NonNull Context context) {
+        return isDeviceEligibleForDesktopMode(context) && Flags.showDesktopWindowingDevOption();
+    }
+
+    /** Returns if desktop mode dev option should be enabled if there is no user override. */
+    public static boolean shouldDevOptionBeEnabledByDefault() {
+        return isDesktopModeFlagEnabled();
+    }
+
+    /**
      * Return {@code true} if desktop mode is enabled and can be entered on the current device.
      */
     public static boolean canEnterDesktopMode(@NonNull Context context) {
-        return (!enforceDeviceRestrictions() || isDesktopModeSupported(context)) && isEnabled();
+        if (!isDeviceEligibleForDesktopMode(context)) return false;
+
+        // If dev option has ever been manually toggled by the user, return its value
+        // TODO(b/348193756) : Move the logic for DW override based on toggle overides to a common
+        //  infrastructure and add caching for the computation
+        int defaultOverrideState = -1;
+        int toggleState = Settings.Global.getInt(context.getContentResolver(),
+                DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, defaultOverrideState);
+        if (toggleState != defaultOverrideState) {
+            Log.d(TAG, "Using Desktop mode dev option overridden state");
+            return toggleState != 0;
+        }
+
+        // Return Desktop windowing flag value
+        return isDesktopModeFlagEnabled();
     }
 
     /**
@@ -181,4 +214,11 @@
         return DESKTOP_DENSITY_OVERRIDE >= DESKTOP_DENSITY_MIN
                 && DESKTOP_DENSITY_OVERRIDE <= DESKTOP_DENSITY_MAX;
     }
+
+    /**
+     * Return {@code true} if desktop mode is unrestricted and is supported in the device.
+     */
+    private static boolean isDeviceEligibleForDesktopMode(@NonNull Context context) {
+        return !enforceDeviceRestrictions() || isDesktopModeSupported(context);
+    }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index 0e53e10..5f36e9a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -193,7 +193,7 @@
             .strictness(Strictness.LENIENT)
             .spyStatic(DesktopModeStatus::class.java)
             .startMocking()
-    whenever(DesktopModeStatus.isEnabled()).thenReturn(true)
+    whenever(DesktopModeStatus.isDesktopModeFlagEnabled()).thenReturn(true)
     doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
 
     shellInit = spy(ShellInit(testExecutor))
@@ -264,7 +264,7 @@
 
   @Test
   fun instantiate_flagOff_doNotAddInitCallback() {
-    whenever(DesktopModeStatus.isEnabled()).thenReturn(false)
+    whenever(DesktopModeStatus.isDesktopModeFlagEnabled()).thenReturn(false)
     clearInvocations(shellInit)
 
     createController()
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
index 86aded7..ac5aeec 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
@@ -27,6 +27,9 @@
 import android.testing.AndroidTestingRunner
 import android.view.Display
 import android.window.WindowContainerToken
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
 import com.android.window.flags.Flags
 import com.android.wm.shell.R
 import com.android.wm.shell.common.DisplayController
@@ -37,6 +40,7 @@
 import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_TOP
 import com.google.common.truth.Truth.assertThat
 import junit.framework.Assert.assertTrue
+import org.junit.After
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
@@ -45,6 +49,7 @@
 import org.mockito.Mockito.any
 import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
+import org.mockito.quality.Strictness
 
 /**
  * Tests for [DragPositioningCallbackUtility].
@@ -82,9 +87,13 @@
     @Rule
     val setFlagsRule = SetFlagsRule()
 
+    private lateinit var mockitoSession: StaticMockitoSession
+
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
+        mockitoSession = ExtendedMockito.mockitoSession().strictness(Strictness.LENIENT)
+                .spyStatic(DesktopModeStatus::class.java).startMocking()
 
         whenever(taskToken.asBinder()).thenReturn(taskBinder)
         whenever(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout)
@@ -105,6 +114,11 @@
         whenever(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
     }
 
+    @After
+    fun tearDown() {
+        mockitoSession.finishMocking()
+    }
+
     @Test
     fun testChangeBoundsDoesNotChangeHeightWhenLessThanMin() {
         val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat())
@@ -252,7 +266,7 @@
     @Test
     @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_SIZE_CONSTRAINTS)
     fun taskMinWidthHeightUndefined_changeBoundsInDesktopModeLessThanMin_shouldNotChangeBounds() {
-        whenever(DesktopModeStatus.canEnterDesktopMode(mockContext)).thenReturn(true)
+        doReturn(true).`when`{ DesktopModeStatus.canEnterDesktopMode(mockContext) }
         initializeTaskInfo(taskMinWidth = -1, taskMinHeight = -1)
         val startingPoint =
             PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.bottom.toFloat())
@@ -275,7 +289,7 @@
     @Test
     @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_SIZE_CONSTRAINTS)
     fun taskMinWidthHeightUndefined_changeBoundsInDesktopModeAllowedSize_shouldChangeBounds() {
-        whenever(DesktopModeStatus.canEnterDesktopMode(mockContext)).thenReturn(true)
+        doReturn(true).`when`{ DesktopModeStatus.canEnterDesktopMode(mockContext) }
         initializeTaskInfo(taskMinWidth = -1, taskMinHeight = -1)
         val startingPoint =
             PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.bottom.toFloat())
@@ -361,7 +375,7 @@
     @Test
     @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_SIZE_CONSTRAINTS)
     fun testChangeBoundsInDesktopMode_windowSizeExceedsStableBounds_shouldBeLimitedToDisplaySize() {
-        whenever(DesktopModeStatus.canEnterDesktopMode(mockContext)).thenReturn(true)
+        doReturn(true).`when`{ DesktopModeStatus.canEnterDesktopMode(mockContext) }
         val startingPoint =
             PointF(OFF_CENTER_STARTING_BOUNDS.right.toFloat(),
                 OFF_CENTER_STARTING_BOUNDS.bottom.toFloat())
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 27c386e..cfd74d4 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1010,10 +1010,10 @@
     <!-- UI debug setting: force allow on external summary [CHAR LIMIT=150] -->
     <string name="force_resizable_activities_summary">Make all activities resizable for multi-window, regardless of manifest values.</string>
 
-    <!-- UI debug setting: enable freeform window support [CHAR LIMIT=50] -->
-    <string name="enable_freeform_support">Enable freeform windows</string>
-    <!-- UI debug setting: enable freeform window support summary [CHAR LIMIT=150] -->
-    <string name="enable_freeform_support_summary">Enable support for experimental freeform windows.</string>
+    <!-- UI debug setting: enable legacy freeform window support [CHAR LIMIT=50] -->
+    <string name="enable_freeform_support">Enable freeform windows (legacy)</string>
+    <!-- UI debug setting: enable legacy freeform window support summary [CHAR LIMIT=150] -->
+    <string name="enable_freeform_support_summary">Enable support for experimental legacy freeform windows.</string>
 
     <!-- Local (desktop) backup password menu title [CHAR LIMIT=25] -->
     <string name="local_backup_password_title">Desktop backup password</string>
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 5f8e933..411decd 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -177,6 +177,7 @@
                     Settings.Global.DESK_UNDOCK_SOUND,
                     Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT,
                     Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS,
+                    Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES,
                     Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES,
                     Settings.Global.DEVELOPMENT_FORCE_RTL,
                     Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW,
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 1b9a09d..b37db16 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -373,8 +373,6 @@
     <!-- Listen to (dis-)connection of external displays and enable / disable them. -->
     <uses-permission android:name="android.permission.MANAGE_DISPLAYS" />
 
-    <uses-permission android:name="android.permission.SET_BIOMETRIC_DIALOG_ADVANCED" />
-
     <protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" />
     <protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" />
     <protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" />
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalDreamStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalDreamStartableTest.kt
index fe683e07..dcc9c7a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalDreamStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalDreamStartableTest.kt
@@ -47,6 +47,7 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
+@EnableFlags(Flags.FLAG_COMMUNAL_HUB)
 @RunWith(AndroidJUnit4::class)
 class CommunalDreamStartableTest : SysuiTestCase() {
     private val kosmos = testKosmos()
@@ -76,7 +77,7 @@
         testScope.runTest {
             keyguardRepository.setDreaming(false)
             powerRepository.setScreenPowerState(ScreenPowerState.SCREEN_ON)
-            whenever(dreamManager.canStartDreaming(/* isScreenOn = */ true)).thenReturn(true)
+            whenever(dreamManager.canStartDreaming(/* isScreenOn= */ true)).thenReturn(true)
             runCurrent()
 
             verify(dreamManager, never()).startDream()
@@ -92,7 +93,7 @@
         testScope.runTest {
             keyguardRepository.setDreaming(false)
             powerRepository.setScreenPowerState(ScreenPowerState.SCREEN_ON)
-            whenever(dreamManager.canStartDreaming(/* isScreenOn = */ true)).thenReturn(true)
+            whenever(dreamManager.canStartDreaming(/* isScreenOn= */ true)).thenReturn(true)
             runCurrent()
 
             verify(dreamManager, never()).startDream()
@@ -118,7 +119,7 @@
             keyguardRepository.setDreaming(false)
             powerRepository.setScreenPowerState(ScreenPowerState.SCREEN_ON)
             // Not eligible to dream
-            whenever(dreamManager.canStartDreaming(/* isScreenOn = */ true)).thenReturn(false)
+            whenever(dreamManager.canStartDreaming(/* isScreenOn= */ true)).thenReturn(false)
             transition(from = KeyguardState.DREAMING, to = KeyguardState.GLANCEABLE_HUB)
 
             verify(dreamManager, never()).startDream()
@@ -129,7 +130,7 @@
         testScope.runTest {
             keyguardRepository.setDreaming(true)
             powerRepository.setScreenPowerState(ScreenPowerState.SCREEN_ON)
-            whenever(dreamManager.canStartDreaming(/* isScreenOn = */ true)).thenReturn(true)
+            whenever(dreamManager.canStartDreaming(/* isScreenOn= */ true)).thenReturn(true)
             transition(from = KeyguardState.DREAMING, to = KeyguardState.GLANCEABLE_HUB)
 
             verify(dreamManager, never()).startDream()
@@ -140,7 +141,7 @@
         testScope.runTest {
             keyguardRepository.setDreaming(true)
             powerRepository.setScreenPowerState(ScreenPowerState.SCREEN_ON)
-            whenever(dreamManager.canStartDreaming(/* isScreenOn = */ true)).thenReturn(true)
+            whenever(dreamManager.canStartDreaming(/* isScreenOn= */ true)).thenReturn(true)
 
             // Verify we do not trigger dreaming for any other state besides glanceable hub
             for (state in KeyguardState.entries) {
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index c1de381..1e4fb4f 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -51,14 +51,10 @@
 import android.database.ContentObserver;
 import android.graphics.Color;
 import android.graphics.drawable.Drawable;
-import android.hardware.biometrics.BiometricManager;
-import android.hardware.biometrics.BiometricPrompt;
-import android.hardware.biometrics.Flags;
 import android.media.AudioManager;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
@@ -861,29 +857,6 @@
             if (ActivityManager.isUserAMonkey()) {
                 return;
             }
-            if (Flags.mandatoryBiometrics()
-                    && requestBiometricAuthenticationForMandatoryBiometrics()) {
-                launchBiometricPromptForMandatoryBiometrics(
-                        new BiometricPrompt.AuthenticationCallback() {
-                            @Override
-                            public void onAuthenticationError(int errorCode,
-                                    CharSequence errString) {
-                                super.onAuthenticationError(errorCode, errString);
-                            }
-
-                            @Override
-                            public void onAuthenticationSucceeded(
-                                    BiometricPrompt.AuthenticationResult result) {
-                                super.onAuthenticationSucceeded(result);
-                                shutDown();
-                            }
-                        });
-            } else {
-                shutDown();
-            }
-        }
-
-        private void shutDown() {
             mUiEventLogger.log(GlobalActionsEvent.GA_SHUTDOWN_PRESS);
             // shutdown by making sure radio and power are handled accordingly.
             mWindowManagerFuncs.shutdown();
@@ -2288,35 +2261,6 @@
     }
 
     @VisibleForTesting
-    void launchBiometricPromptForMandatoryBiometrics(
-            BiometricPrompt.AuthenticationCallback authenticationCallback) {
-        final CancellationSignal cancellationSignal = new CancellationSignal();
-        final BiometricPrompt biometricPrompt = new BiometricPrompt.Builder(mContext)
-                .setAllowedAuthenticators(BiometricManager.Authenticators.MANDATORY_BIOMETRICS)
-                .setUseDefaultTitle()
-                .setDescription(mContext.getString(
-                        R.string.identity_check_biometric_prompt_description))
-                .setNegativeButton(mContext.getString(R.string.cancel), mContext.getMainExecutor(),
-                        (dialog, which) -> cancellationSignal.cancel())
-                .setAllowBackgroundAuthentication(true)
-                .build();
-        biometricPrompt.authenticate(cancellationSignal, mContext.getMainExecutor(),
-                authenticationCallback);
-    }
-
-    private boolean requestBiometricAuthenticationForMandatoryBiometrics() {
-        final BiometricManager biometricManager =
-                (BiometricManager) mContext.getSystemService(Context.BIOMETRIC_SERVICE);
-        if (biometricManager == null) {
-            Log.e(TAG, "Biometric Manager is null.");
-            return false;
-        }
-        final int status = biometricManager.canAuthenticate(
-                BiometricManager.Authenticators.MANDATORY_BIOMETRICS);
-        return status == BiometricManager.BIOMETRIC_SUCCESS;
-    }
-
-    @VisibleForTesting
     static class ActionsDialogLite extends SystemUIDialog implements DialogInterface,
             ColorExtractor.OnColorsChangedListener {
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index 4f75e6f..22ab82b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -249,7 +249,7 @@
     val isKeyguardGoingAway: Flow<Boolean> = repository.isKeyguardGoingAway
 
     /** Keyguard can be clipped at the top as the shade is dragged */
-    val topClippingBounds: Flow<Int?> =
+    val topClippingBounds: Flow<Int?> by lazy {
         combineTransform(
                 keyguardTransitionInteractor
                     .transitionValue(scene = Scenes.Gone, stateWithoutSceneContainer = GONE)
@@ -263,6 +263,7 @@
                 }
             }
             .distinctUntilChanged()
+    }
 
     /** Last point that [KeyguardRootView] view was tapped */
     val lastRootViewTapPosition: Flow<Point?> = repository.lastRootViewTapPosition.asStateFlow()
diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
index e7c2a45..bda0069 100644
--- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
@@ -17,6 +17,7 @@
 package com.android.systemui.media;
 
 import android.annotation.Nullable;
+import android.content.ContentProvider;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -123,9 +124,13 @@
                 boolean looping, @Nullable VolumeShaper.Configuration volumeShaperConfig)
                 throws RemoteException {
             if (LOGD) {
-                Log.d(TAG, "play(token=" + token + ", uri=" + uri + ", uid="
-                        + Binder.getCallingUid() + ")");
+                Log.d(TAG, "play(token=" + token + ", uri=" + uri
+                        + ", uid=" + Binder.getCallingUid()
+                        + ") uriUserId=" + ContentProvider.getUserIdFromUri(uri)
+                        + " callingUserId=" + Binder.getCallingUserHandle().getIdentifier());
             }
+            enforceUriUserId(uri);
+
             Client client;
             synchronized (mClients) {
                 client = mClients.get(token);
@@ -207,6 +212,7 @@
 
         @Override
         public String getTitle(Uri uri) {
+            enforceUriUserId(uri);
             final UserHandle user = Binder.getCallingUserHandle();
             return Ringtone.getTitle(getContextForUser(user), uri,
                     false /*followSettingsUri*/, false /*allowRemote*/);
@@ -239,6 +245,25 @@
             }
             throw new SecurityException("Uri is not ringtone, alarm, or notification: " + uri);
         }
+
+        /**
+         * Must be called from the Binder calling thread.
+         * Ensures caller is from the same userId as the content they're trying to access.
+         * @param uri the URI to check
+         * @throws SecurityException when non-system call or userId in uri differs from the
+         *                           caller's userId
+         */
+        private void enforceUriUserId(Uri uri) throws SecurityException {
+            final int uriUserId = ContentProvider.getUserIdFromUri(uri);
+            final int callerUserId = Binder.getCallingUserHandle().getIdentifier();
+            // for a non-system call, verify the URI to play belongs to the same user as the caller
+            if (UserHandle.isApp(Binder.getCallingUid()) && uriUserId != callerUserId) {
+                throw new SecurityException("Illegal access to uri=" + uri
+                        + " content associated with user=" + uriUserId
+                        + ", request originates from user=" + callerUserId);
+            }
+        }
+
     };
 
     private Context getContextForUser(UserHandle user) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
index b58eb49..e2cca38 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
@@ -23,7 +23,6 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
@@ -34,20 +33,13 @@
 import android.app.IActivityManager;
 import android.app.admin.DevicePolicyManager;
 import android.app.trust.TrustManager;
-import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.graphics.Color;
-import android.hardware.biometrics.BiometricManager;
-import android.hardware.biometrics.BiometricPrompt;
-import android.hardware.biometrics.Flags;
 import android.media.AudioManager;
 import android.os.Handler;
 import android.os.UserManager;
-import android.platform.test.annotations.RequiresFlagsEnabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.provider.Settings;
 import android.service.dreams.IDreamManager;
 import android.testing.TestableLooper;
@@ -96,7 +88,6 @@
 import com.android.systemui.util.settings.SecureSettings;
 
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -111,9 +102,6 @@
 @RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 public class GlobalActionsDialogLiteTest extends SysuiTestCase {
-    @Rule
-    public final CheckFlagsRule mCheckFlagsRule =
-            DeviceFlagsValueProvider.createCheckFlagsRule();
     private GlobalActionsDialogLite mGlobalActionsDialogLite;
 
     @Mock private GlobalActions.GlobalActionsManager mWindowManagerFuncs;
@@ -153,7 +141,6 @@
     @Mock private DialogTransitionAnimator mDialogTransitionAnimator;
     @Mock private SelectedUserInteractor mSelectedUserInteractor;
     @Mock private OnBackInvokedDispatcher mOnBackInvokedDispatcher;
-    @Mock private BiometricManager mBiometricManager;
     @Captor private ArgumentCaptor<OnBackInvokedCallback> mOnBackInvokedCallback;
 
     private TestableLooper mTestableLooper;
@@ -170,13 +157,10 @@
         when(mUserContextProvider.getUserContext()).thenReturn(mContext);
         when(mResources.getConfiguration()).thenReturn(
                 getContext().getResources().getConfiguration());
-        when(mBiometricManager.canAuthenticate(anyInt())).thenReturn(
-                BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE);
 
         mGlobalSettings = new FakeGlobalSettings();
         mSecureSettings = new FakeSettings();
         mInteractor = mKosmos.getGlobalActionsInteractor();
-        mContext.addMockSystemService(Context.BIOMETRIC_SERVICE, mBiometricManager);
 
         mGlobalActionsDialogLite = new GlobalActionsDialogLite(mContext,
                 mWindowManagerFuncs,
@@ -567,35 +551,6 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(Flags.FLAG_MANDATORY_BIOMETRICS)
-    public void requestBiometricAuth_whenShutDownShortPressAndMandatoryBiometricsActive() {
-        mGlobalActionsDialogLite = spy(mGlobalActionsDialogLite);
-        ArgumentCaptor<BiometricPrompt.AuthenticationCallback>
-                authenticationCallbackArgumentCaptor = ArgumentCaptor.forClass(
-                        BiometricPrompt.AuthenticationCallback.class);
-
-        when(mBiometricManager.canAuthenticate(
-                BiometricManager.Authenticators.MANDATORY_BIOMETRICS)).thenReturn(
-                        BiometricManager.BIOMETRIC_SUCCESS);
-        doNothing().when(mGlobalActionsDialogLite).launchBiometricPromptForMandatoryBiometrics(
-                any());
-
-        GlobalActionsDialogLite.ShutDownAction shutDownAction =
-                mGlobalActionsDialogLite.new ShutDownAction();
-        shutDownAction.onPress();
-
-        verify(mGlobalActionsDialogLite).launchBiometricPromptForMandatoryBiometrics(
-                authenticationCallbackArgumentCaptor.capture());
-
-        BiometricPrompt.AuthenticationCallback authenticationCallback =
-                authenticationCallbackArgumentCaptor.getValue();
-        authenticationCallback.onAuthenticationSucceeded(null);
-
-        verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_SHUTDOWN_PRESS);
-        verify(mWindowManagerFuncs).shutdown();
-    }
-
-    @Test
     public void testShouldLogLockdownPress() {
         GlobalActionsDialogLite.LockDownAction lockDownAction =
                 mGlobalActionsDialogLite.new LockDownAction();
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 39cb5a9..9732621 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -461,6 +461,7 @@
     private static final int MSG_DISPATCH_PREFERRED_MIXER_ATTRIBUTES = 52;
     private static final int MSG_CONFIGURATION_CHANGED = 54;
     private static final int MSG_BROADCAST_MASTER_MUTE = 55;
+    private static final int MSG_UPDATE_CONTEXTUAL_VOLUMES = 56;
 
     /**
      * Messages handled by the {@link SoundDoseHelper}, do not exceed
@@ -4466,7 +4467,7 @@
             }
         }
         if (mVoicePlaybackActive.getAndSet(voiceActive) != voiceActive) {
-            updateHearingAidVolumeOnVoiceActivityUpdate();
+            postUpdateContextualVolumes();
         }
         if (mMediaPlaybackActive.getAndSet(mediaActive) != mediaActive && mediaActive) {
             mSoundDoseHelper.scheduleMusicActiveCheck();
@@ -4604,13 +4605,29 @@
         }
     }
 
-    private void updateHearingAidVolumeOnVoiceActivityUpdate() {
-        final int streamType = getBluetoothContextualVolumeStream();
-        final int index = getStreamVolume(streamType);
-        sVolumeLogger.enqueue(new VolumeEvent(VolumeEvent.VOL_VOICE_ACTIVITY_HEARING_AID,
-                mVoicePlaybackActive.get(), streamType, index));
-        mDeviceBroker.postSetHearingAidVolumeIndex(index * 10, streamType);
 
+    // delay between audio playback configuration update and checking
+    // actual stream activity to take async playback stop into account
+    private static final int UPDATE_CONTEXTUAL_VOLUME_DELAY_MS = 500;
+
+    /*package*/ void postUpdateContextualVolumes() {
+        sendMsg(mAudioHandler, MSG_UPDATE_CONTEXTUAL_VOLUMES, SENDMSG_REPLACE,
+                /*arg1*/ 0, /*arg2*/ 0, TAG, UPDATE_CONTEXTUAL_VOLUME_DELAY_MS);
+    }
+
+    private void onUpdateContextualVolumes() {
+        final int streamType = getBluetoothContextualVolumeStream();
+        final int device = getDeviceForStream(streamType);
+        final int index = getStreamVolume(streamType, device);
+
+        if (AudioSystem.isLeAudioDeviceType(device)) {
+            mDeviceBroker.postSetLeAudioVolumeIndex(index * 10,
+                    mStreamStates[streamType].getMaxIndex(), streamType);
+        } else if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
+            mDeviceBroker.postSetHearingAidVolumeIndex(index * 10, streamType);
+        }
+        sVolumeLogger.enqueue(new VolumeEvent(VolumeEvent.VOL_VOICE_ACTIVITY_CONTEXTUAL_VOLUME,
+                mVoicePlaybackActive.get(), streamType, index, device));
     }
 
     /**
@@ -9812,6 +9829,10 @@
                     onConfigurationChanged();
                     break;
 
+                case MSG_UPDATE_CONTEXTUAL_VOLUMES:
+                    onUpdateContextualVolumes();
+                    break;
+
                 case MusicFxHelper.MSG_EFFECT_CLIENT_GONE:
                     mMusicFxHelper.handleMessage(msg);
                     break;
diff --git a/services/core/java/com/android/server/audio/AudioServiceEvents.java b/services/core/java/com/android/server/audio/AudioServiceEvents.java
index 8ea28be..631d5d8 100644
--- a/services/core/java/com/android/server/audio/AudioServiceEvents.java
+++ b/services/core/java/com/android/server/audio/AudioServiceEvents.java
@@ -227,7 +227,7 @@
         static final int VOL_SET_HEARING_AID_VOL = 3;
         static final int VOL_SET_AVRCP_VOL = 4;
         static final int VOL_ADJUST_VOL_UID = 5;
-        static final int VOL_VOICE_ACTIVITY_HEARING_AID = 6;
+        static final int VOL_VOICE_ACTIVITY_CONTEXTUAL_VOLUME = 6;
         static final int VOL_MODE_CHANGE_HEARING_AID = 7;
         static final int VOL_SET_GROUP_VOL = 8;
         static final int VOL_MUTE_STREAM_INT = 9;
@@ -299,14 +299,14 @@
             logMetricEvent();
         }
 
-        /** used for VOL_VOICE_ACTIVITY_HEARING_AID */
-        VolumeEvent(int op, boolean voiceActive, int stream, int index) {
+        /** used for VOL_VOICE_ACTIVITY_CONTEXTUAL_VOLUME */
+        VolumeEvent(int op, boolean voiceActive, int stream, int index, int device) {
             mOp = op;
             mStream = stream;
             mVal1 = index;
             mVal2 = voiceActive ? 1 : 0;
             // unused
-            mVal3 = -1;
+            mVal3 = device;
             mCaller = null;
             mGroupName = null;
             logMetricEvent();
@@ -445,14 +445,16 @@
                             .set(MediaMetrics.Property.INDEX, mVal1)
                             .record();
                     return;
-                case VOL_VOICE_ACTIVITY_HEARING_AID:
+                case VOL_VOICE_ACTIVITY_CONTEXTUAL_VOLUME:
                     new MediaMetrics.Item(mMetricsId)
-                            .set(MediaMetrics.Property.EVENT, "voiceActivityHearingAid")
+                            .set(MediaMetrics.Property.EVENT, "voiceActivityContextualVolume")
                             .set(MediaMetrics.Property.INDEX, mVal1)
                             .set(MediaMetrics.Property.STATE,
                                     mVal2 == 1 ? "active" : "inactive")
                             .set(MediaMetrics.Property.STREAM_TYPE,
                                     AudioSystem.streamToString(mStream))
+                            .set(MediaMetrics.Property.DEVICE,
+                                    AudioSystem.getOutputDeviceName(mVal3))
                             .record();
                     return;
                 case VOL_MODE_CHANGE_HEARING_AID:
@@ -538,11 +540,12 @@
                             .append(" flags:0x").append(Integer.toHexString(mVal2))
                             .append(") from ").append(mCaller)
                             .toString();
-                case VOL_VOICE_ACTIVITY_HEARING_AID:
+                case VOL_VOICE_ACTIVITY_CONTEXTUAL_VOLUME:
                     return new StringBuilder("Voice activity change (")
                             .append(mVal2 == 1 ? "active" : "inactive")
-                            .append(") causes setting HEARING_AID volume to idx:").append(mVal1)
+                            .append(") causes setting volume to idx:").append(mVal1)
                             .append(" stream:").append(AudioSystem.streamToString(mStream))
+                            .append(" device:").append(AudioSystem.getOutputDeviceName(mVal3))
                             .toString();
                 case VOL_MODE_CHANGE_HEARING_AID:
                     return new StringBuilder("setMode(")
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index f5a2a21..2a16872 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -369,10 +369,6 @@
                 checkPermission();
             }
 
-            if ((authenticators & Authenticators.MANDATORY_BIOMETRICS) != 0) {
-                checkBiometricAdvancedPermission();
-            }
-
             final long identity = Binder.clearCallingIdentity();
             try {
                 final int result = mBiometricService.canAuthenticate(
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index 693a3e6..daaafcb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -418,7 +418,7 @@
     }
 
     protected int getRequestReason() {
-        if (isKeyguard() && !isBiometricPrompt()) {
+        if (isKeyguard()) {
             return BiometricRequestConstants.REASON_AUTH_KEYGUARD;
         } else if (isBiometricPrompt()) {
             // BP reason always takes precedent over settings, since callers from within
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 1e76324..78d501c 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -320,6 +320,19 @@
                 && Flags.concurrentInputMethods();
     }
 
+    /**
+     * Figures out the target IME user ID for a given {@link Binder} IPC.
+     *
+     * @param callingProcessUserId the user ID of the calling process
+     * @return User ID to be used for this {@link Binder} call.
+     */
+    @GuardedBy("ImfLock.class")
+    @UserIdInt
+    @BinderThread
+    private int resolveImeUserIdLocked(@UserIdInt int callingProcessUserId) {
+        return mExperimentalConcurrentMultiUserModeEnabled ? callingProcessUserId : mCurrentUserId;
+    }
+
     final Context mContext;
     final Resources mRes;
     private final Handler mHandler;
@@ -2916,6 +2929,9 @@
         final var userData = getUserData(userId);
         userData.mSwitchingController.resetCircularListLocked(mContext, settings);
         userData.mHardwareKeyboardShortcutController.update(settings);
+
+        final var bindingController = getInputMethodBindingController(userId);
+        bindingController.setSelectedMethodId(id);
     }
 
     @GuardedBy("ImfLock.class")
@@ -3101,19 +3117,19 @@
             int lastClickToolType, ResultReceiver resultReceiver,
             @SoftInputShowHideReason int reason) {
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.showSoftInput");
-        int uid = Binder.getCallingUid();
+        final int uid = Binder.getCallingUid();
+        final int callingUserId = UserHandle.getUserId(uid);
         ImeTracing.getInstance().triggerManagerServiceDump(
                 "InputMethodManagerService#showSoftInput", mDumper);
         synchronized (ImfLock.class) {
-            if (!canInteractWithImeLocked(uid, client, "showSoftInput", statsToken)) {
+            final int userId = resolveImeUserIdLocked(callingUserId);
+            if (!canInteractWithImeLocked(uid, client, "showSoftInput", statsToken,
+                    userId)) {
                 ImeTracker.forLogging().onFailed(
                         statsToken, ImeTracker.PHASE_SERVER_CLIENT_FOCUSED);
                 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
                 return false;
             }
-            // TODO(b/305849394): Create a utility method for the following policy.
-            final int userId = mExperimentalConcurrentMultiUserModeEnabled
-                    ? UserHandle.getCallingUserId() : mCurrentUserId;
             final long ident = Binder.clearCallingIdentity();
             final var userData = getUserData(userId);
             try {
@@ -3265,13 +3281,15 @@
         try {
             ImeTracing.getInstance().triggerManagerServiceDump(
                     "InputMethodManagerService#startStylusHandwriting", mDumper);
-            int uid = Binder.getCallingUid();
+            final int uid = Binder.getCallingUid();
+            final int callingUserId = UserHandle.getUserId(uid);
             synchronized (ImfLock.class) {
+                final int userId = resolveImeUserIdLocked(callingUserId);
                 if (!acceptingDelegation) {
                     mHwController.clearPendingHandwritingDelegation();
                 }
                 if (!canInteractWithImeLocked(uid, client, "startStylusHandwriting",
-                        null /* statsToken */)) {
+                        null /* statsToken */, userId)) {
                     return false;
                 }
                 if (!hasSupportedStylusLocked()) {
@@ -3281,7 +3299,7 @@
                 }
                 final long ident = Binder.clearCallingIdentity();
                 try {
-                    final var bindingController = getInputMethodBindingController(mCurrentUserId);
+                    final var bindingController = getInputMethodBindingController(userId);
                     if (!bindingController.supportsStylusHandwriting()) {
                         Slog.w(TAG,
                                 "Stylus HW unsupported by IME. Ignoring startStylusHandwriting()");
@@ -3531,11 +3549,13 @@
     public boolean hideSoftInput(IInputMethodClient client, IBinder windowToken,
             @NonNull ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags,
             ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
-        int uid = Binder.getCallingUid();
+        final int uid = Binder.getCallingUid();
+        final int callingUserId = UserHandle.getUserId(uid);
         ImeTracing.getInstance().triggerManagerServiceDump(
                 "InputMethodManagerService#hideSoftInput", mDumper);
         synchronized (ImfLock.class) {
-            if (!canInteractWithImeLocked(uid, client, "hideSoftInput", statsToken)) {
+            final int userId = resolveImeUserIdLocked(callingUserId);
+            if (!canInteractWithImeLocked(uid, client, "hideSoftInput", statsToken, userId)) {
                 if (isInputShownLocked()) {
                     ImeTracker.forLogging().onFailed(
                             statsToken, ImeTracker.PHASE_SERVER_CLIENT_FOCUSED);
@@ -3545,9 +3565,6 @@
                 }
                 return false;
             }
-            // TODO(b/305849394): Create a utility method for the following policy.
-            final int userId = mExperimentalConcurrentMultiUserModeEnabled
-                    ? UserHandle.getCallingUserId() : mCurrentUserId;
             final long ident = Binder.clearCallingIdentity();
             final var userData = getUserData(userId);
             try {
@@ -3582,9 +3599,9 @@
     @Override
     @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.TEST_INPUT_METHOD)
     public void hideSoftInputFromServerForTest() {
+        final int callingUserId = UserHandle.getCallingUserId();
         synchronized (ImfLock.class) {
-            // TODO(b/305849394): Get userId from caller.
-            final int userId = mCurrentUserId;
+            final int userId = resolveImeUserIdLocked(callingUserId);
             final var userData = getUserData(userId);
             hideCurrentInputLocked(userData.mImeBindingState.mFocusedWindow, 0 /* flags */,
                     SoftInputShowHideReason.HIDE_SOFT_INPUT, userId);
@@ -3945,9 +3962,7 @@
 
     @GuardedBy("ImfLock.class")
     private boolean canInteractWithImeLocked(int uid, IInputMethodClient client, String methodName,
-            @Nullable ImeTracker.Token statsToken) {
-        // TODO(b/305849394): Get userId from callers.
-        final int userId = mCurrentUserId;
+            @Nullable ImeTracker.Token statsToken, @UserIdInt int userId) {
         final var userData = getUserData(userId);
         if (userData.mCurClient == null || client == null
                 || userData.mCurClient.mClient.asBinder() != client.asBinder()) {
@@ -3994,15 +4009,14 @@
     @Override
     public void showInputMethodPickerFromClient(IInputMethodClient client,
             int auxiliarySubtypeMode) {
+        final int callingUserId = UserHandle.getCallingUserId();
         synchronized (ImfLock.class) {
             if (!canShowInputMethodPickerLocked(client)) {
                 Slog.w(TAG, "Ignoring showInputMethodPickerFromClient of uid "
                         + Binder.getCallingUid() + ": " + client);
                 return;
             }
-            // TODO(b/305849394): Create a utility method for the following policy.
-            final int userId = mExperimentalConcurrentMultiUserModeEnabled
-                    ? UserHandle.getCallingUserId() : mCurrentUserId;
+            final int userId = resolveImeUserIdLocked(callingUserId);
             final var userData = getUserData(userId);
             // Always call subtype picker, because subtype picker is a superset of input method
             // picker.
@@ -4318,13 +4332,11 @@
         return Binder.withCleanCallingIdentity(() -> {
             final int curTokenDisplayId;
             synchronized (ImfLock.class) {
+                final int userId = resolveImeUserIdLocked(callingUserId);
                 if (!canInteractWithImeLocked(callingUid, client,
-                        "getInputMethodWindowVisibleHeight", null /* statsToken */)) {
+                        "getInputMethodWindowVisibleHeight", null /* statsToken */, userId)) {
                     return 0;
                 }
-                // TODO(b/305849394): Create a utility method for the following policy.
-                final int userId = mExperimentalConcurrentMultiUserModeEnabled
-                        ? callingUserId : mCurrentUserId;
                 final var bindingController = getInputMethodBindingController(userId);
                 // This should probably use the caller's display id, but because this is unsupported
                 // and maintained only for compatibility, there's no point in fixing it.
@@ -4453,10 +4465,12 @@
     @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.TEST_INPUT_METHOD)
     @Override
     public void addVirtualStylusIdForTestSession(IInputMethodClient client) {
-        int uid = Binder.getCallingUid();
+        final int uid = Binder.getCallingUid();
+        final int callingUserId = UserHandle.getUserId(uid);
         synchronized (ImfLock.class) {
+            final int userId = resolveImeUserIdLocked(callingUserId);
             if (!canInteractWithImeLocked(uid, client, "addVirtualStylusIdForTestSession",
-                    null /* statsToken */)) {
+                    null /* statsToken */, userId)) {
                 return;
             }
             final long ident = Binder.clearCallingIdentity();
@@ -4480,10 +4494,12 @@
     @Override
     public void setStylusWindowIdleTimeoutForTest(
             IInputMethodClient client, @DurationMillisLong long timeout) {
-        int uid = Binder.getCallingUid();
+        final int uid = Binder.getCallingUid();
+        final int callingUserId = UserHandle.getUserId(uid);
         synchronized (ImfLock.class) {
+            final int userId = resolveImeUserIdLocked(callingUserId);
             if (!canInteractWithImeLocked(uid, client, "setStylusWindowIdleTimeoutForTest",
-                    null /* statsToken */)) {
+                    null /* statsToken */, userId)) {
                 return;
             }
             final long ident = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
index 3051379..1a449e0 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
@@ -618,12 +618,14 @@
 
     /**
      * Processes message transactions, starting and completing them as needed.
+     * <p>
      * This function is called when adding a message transaction or when a timer
      * expires for an existing message transaction's retry or timeout. The
      * internal processing loop will iterate at most twice as if one iteration
      * completes a transaction, the next iteration can only start new transactions.
      * If the first iteration does not complete any transaction, the loop will
      * only iterate once.
+     * <p>
      */
     private synchronized void processMessageTransactions() {
         if (!Flags.reliableMessageRetrySupportService()) {
diff --git a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
index c558aae..7ed23cd 100644
--- a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
@@ -230,18 +230,7 @@
         }
         val isSoftRestricted =
             if (permission.isSoftRestricted && !isExempt) {
-                val targetSdkVersion =
-                    reducePackageInAppId(appId, Build.VERSION_CODES.CUR_DEVELOPMENT) {
-                        targetSdkVersion,
-                        packageState ->
-                        if (permissionName in packageState.androidPackage!!.requestedPermissions) {
-                            targetSdkVersion.coerceAtMost(
-                                packageState.androidPackage!!.targetSdkVersion
-                            )
-                        } else {
-                            targetSdkVersion
-                        }
-                    }
+                val targetSdkVersion = getAppIdTargetSdkVersion(appId, permissionName)
                 !anyPackageInAppId(appId) {
                     permissionName in it.androidPackage!!.requestedPermissions &&
                         isSoftRestrictedPermissionExemptForPackage(
@@ -718,18 +707,8 @@
 
         // If the app is updated, and has scoped storage permissions, then it is possible that the
         // app updated in an attempt to get unscoped storage. If so, revoke all storage permissions.
-        val oldTargetSdkVersion =
-            reducePackageInAppId(appId, Build.VERSION_CODES.CUR_DEVELOPMENT, oldState) {
-                targetSdkVersion,
-                packageState ->
-                targetSdkVersion.coerceAtMost(packageState.androidPackage!!.targetSdkVersion)
-            }
-        val newTargetSdkVersion =
-            reducePackageInAppId(appId, Build.VERSION_CODES.CUR_DEVELOPMENT, newState) {
-                targetSdkVersion,
-                packageState ->
-                targetSdkVersion.coerceAtMost(packageState.androidPackage!!.targetSdkVersion)
-            }
+        val oldTargetSdkVersion = getAppIdTargetSdkVersion(appId, null, oldState)
+        val newTargetSdkVersion = getAppIdTargetSdkVersion(appId, null, newState)
         @Suppress("ConvertTwoComparisonsToRangeCheck")
         val isTargetSdkVersionDowngraded =
             oldTargetSdkVersion >= Build.VERSION_CODES.Q &&
@@ -1115,10 +1094,9 @@
     }
 
     private fun MutateStateScope.inheritImplicitPermissionStates(appId: Int, userId: Int) {
-        var targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT
+        val targetSdkVersion = getAppIdTargetSdkVersion(appId, null)
         val implicitPermissions = MutableIndexedSet<String>()
         forEachPackageInAppId(appId) {
-            targetSdkVersion = targetSdkVersion.coerceAtMost(it.androidPackage!!.targetSdkVersion)
             implicitPermissions += it.androidPackage!!.implicitPermissions
         }
         implicitPermissions.forEachIndexed implicitPermissions@{ _, implicitPermissionName ->
@@ -1418,6 +1396,22 @@
             else -> false
         }
 
+    private fun MutateStateScope.getAppIdTargetSdkVersion(
+        appId: Int,
+        permissionName: String?,
+        state: AccessState = newState
+    ): Int =
+        reducePackageInAppId(appId, Build.VERSION_CODES.CUR_DEVELOPMENT, state) {
+            targetSdkVersion,
+            packageState ->
+            val androidPackage = packageState.androidPackage!!
+            if (permissionName == null || permissionName in androidPackage.requestedPermissions) {
+                targetSdkVersion.coerceAtMost(androidPackage.targetSdkVersion)
+            } else {
+                targetSdkVersion
+            }
+        }
+
     private inline fun MutateStateScope.anyPackageInAppId(
         appId: Int,
         state: AccessState = newState,
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
index 36a5cda..9cd3186 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
@@ -393,18 +393,6 @@
         testAuthenticate_throwsSecurityException(promptInfo);
     }
 
-    @Test
-    public void testCanAuthenticate_throwsWhenUsingAdvancedApis() {
-        mAuthService = new AuthService(mContext, mInjector);
-        mAuthService.onStart();
-
-        assertThrows(SecurityException.class, () -> {
-            mAuthService.mImpl.canAuthenticate(TEST_OP_PACKAGE_NAME, 1 /* userId */,
-                    BiometricManager.Authenticators.MANDATORY_BIOMETRICS);
-            waitForIdle();
-        });
-    }
-
     private void testAuthenticate_throwsSecurityException(PromptInfo promptInfo) {
         mAuthService = new AuthService(mContext, mInjector);
         mAuthService.onStart();
diff --git a/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt b/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt
index 822118c..2a83677 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt
@@ -35,7 +35,7 @@
         val output = run(
                 srcs = mapOf("frameworks/base/org/example/Example.java" to """
                     package org.example;
-                    import com.android.internal.protolog.common.ProtoLog;
+                    import com.android.internal.protolog.ProtoLog;
                     import static com.android.internal.protolog.ProtoLogGroup.GROUP;
 
                     class Example {
@@ -48,7 +48,7 @@
                 """.trimIndent()),
                 logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"),
                 commandOptions = CommandOptions(arrayOf("transform-protolog-calls",
-                        "--protolog-class", "com.android.internal.protolog.common.ProtoLog",
+                        "--protolog-class", "com.android.internal.protolog.ProtoLog",
                         "--loggroups-class", "com.android.internal.protolog.ProtoLogGroup",
                         "--loggroups-jar", "not_required.jar",
                         "--viewer-config-file-path", "not_required.pb",
@@ -69,7 +69,7 @@
         val output = run(
                 srcs = mapOf("frameworks/base/org/example/Example.java" to """
                     package org.example;
-                    import com.android.internal.protolog.common.ProtoLog;
+                    import com.android.internal.protolog.ProtoLog;
                     import static com.android.internal.protolog.ProtoLogGroup.GROUP;
 
                     class Example {
@@ -82,7 +82,7 @@
                 """.trimIndent()),
                 logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"),
                 commandOptions = CommandOptions(arrayOf("generate-viewer-config",
-                        "--protolog-class", "com.android.internal.protolog.common.ProtoLog",
+                        "--protolog-class", "com.android.internal.protolog.ProtoLog",
                         "--loggroups-class", "com.android.internal.protolog.ProtoLogGroup",
                         "--loggroups-jar", "not_required.jar",
                         "--viewer-config-type", "json",