Merge "Add flag for APIs that use expected presentation time" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 08a09e1..b1f587e 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -334,7 +334,7 @@
 aconfig_declarations {
     name: "android.app.flags-aconfig",
     package: "android.app",
-    srcs: ["core/java/android/app/activity_manager.aconfig"],
+    srcs: ["core/java/android/app/*.aconfig"],
 }
 
 java_aconfig_library {
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 122e627..b215ee4 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -68,7 +68,6 @@
       "name": "FrameworksInputMethodSystemServerTests",
       "options": [
         {"include-filter": "com.android.server.inputmethod"},
-        {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
         {"exclude-annotation": "androidx.test.filters.FlakyTest"},
         {"exclude-annotation": "org.junit.Ignore"}
       ]
diff --git a/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING
index b8fef63..6924cb2 100644
--- a/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING
@@ -7,7 +7,6 @@
       ],
       "options": [
         {"include-filter": "com.android.server.DeviceIdleControllerTest"},
-        {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
         {"exclude-annotation": "androidx.test.filters.FlakyTest"}
       ]
     },
@@ -29,4 +28,4 @@
       ]
     }
   ]
-}
\ No newline at end of file
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/deviceidle/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/deviceidle/TEST_MAPPING
index b76c582..c0686116 100644
--- a/apex/jobscheduler/service/java/com/android/server/deviceidle/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/deviceidle/TEST_MAPPING
@@ -4,7 +4,6 @@
       "name": "FrameworksMockingServicesTests",
       "options": [
         {"include-filter": "com.android.server.DeviceIdleControllerTest"},
-        {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
         {"exclude-annotation": "androidx.test.filters.FlakyTest"}
       ]
     }
@@ -17,4 +16,4 @@
       ]
     }
   ]
-}
\ No newline at end of file
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
index 8504b1f..e649485 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
@@ -3,8 +3,6 @@
         {
             "name": "CtsJobSchedulerTestCases",
             "options": [
-                {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
-                {"exclude-annotation": "androidx.test.filters.LargeTest"},
                 {"exclude-annotation": "androidx.test.filters.FlakyTest"},
                 {"exclude-annotation": "androidx.test.filters.LargeTest"}
             ]
@@ -13,18 +11,16 @@
             "name": "FrameworksMockingServicesTests",
             "options": [
                 {"include-filter": "com.android.server.job"},
-                {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
-                {"exclude-annotation": "androidx.test.filters.LargeTest"},
-                {"exclude-annotation": "androidx.test.filters.FlakyTest"}
+                {"exclude-annotation": "androidx.test.filters.FlakyTest"},
+                {"exclude-annotation": "androidx.test.filters.LargeTest"}
             ]
         },
         {
             "name": "FrameworksServicesTests",
             "options": [
                 {"include-filter": "com.android.server.job"},
-                {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
-                {"exclude-annotation": "androidx.test.filters.LargeTest"},
-                {"exclude-annotation": "androidx.test.filters.FlakyTest"}
+                {"exclude-annotation": "androidx.test.filters.FlakyTest"},
+                {"exclude-annotation": "androidx.test.filters.LargeTest"}
             ]
         }
     ],
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/tare/TEST_MAPPING
index 73b00b6..e194b8d 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/tare/TEST_MAPPING
@@ -4,7 +4,6 @@
             "name": "FrameworksMockingServicesTests",
             "options": [
                 {"include-filter": "com.android.server.tare"},
-                {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
                 {"exclude-annotation": "androidx.test.filters.FlakyTest"}
             ]
         },
@@ -12,7 +11,6 @@
             "name": "FrameworksServicesTests",
             "options": [
                 {"include-filter": "com.android.server.tare"},
-                {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
                 {"exclude-annotation": "androidx.test.filters.FlakyTest"}
             ]
         }
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING
index 9ec799f..a75415e 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING
@@ -4,7 +4,6 @@
       "name": "CtsUsageStatsTestCases",
       "options": [
         {"include-filter": "android.app.usage.cts.UsageStatsTest"},
-        {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
         {"exclude-annotation": "androidx.test.filters.FlakyTest"},
         {"exclude-annotation": "androidx.test.filters.MediumTest"},
         {"exclude-annotation": "androidx.test.filters.LargeTest"}
@@ -21,7 +20,6 @@
       "name": "FrameworksServicesTests",
       "options": [
         {"include-filter": "com.android.server.usage"},
-        {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
         {"exclude-annotation": "androidx.test.filters.FlakyTest"}
       ]
     }
@@ -37,4 +35,4 @@
       ]
     }
   ]
-}
\ No newline at end of file
+}
diff --git a/boot/Android.bp b/boot/Android.bp
index 93d425e..b33fab6 100644
--- a/boot/Android.bp
+++ b/boot/Android.bp
@@ -208,6 +208,13 @@
     ],
 }
 
+genrule { // This module exists to make the srcjar output available to Make.
+    name: "platform-bootclasspath.srcjar",
+    srcs: [":platform-bootclasspath{.srcjar}"],
+    out: ["platform-bootclasspath.srcjar"],
+    cmd: "cp $(in) $(out)",
+}
+
 platform_systemserverclasspath {
     name: "platform-systemserverclasspath",
 }
diff --git a/cmds/uinput/README.md b/cmds/uinput/README.md
index 82df555..e7361fe 100644
--- a/cmds/uinput/README.md
+++ b/cmds/uinput/README.md
@@ -48,6 +48,7 @@
 | `vid`            | 16-bit integer | Vendor ID                  |
 | `pid`            | 16-bit integer | Product ID                 |
 | `bus`            | string         | Bus that device should use |
+| `port`           | string         | `phys` value to report     |
 | `configuration`  | object array   | uinput device configuration|
 | `ff_effects_max` | integer        | `ff_effects_max` value     |
 | `abs_info`       | array          | Absolute axes information  |
diff --git a/core/api/current.txt b/core/api/current.txt
index 43f7e2a..f340e16 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -5952,6 +5952,7 @@
 
   public class GrammaticalInflectionManager {
     method public int getApplicationGrammaticalGender();
+    method @FlaggedApi("android.app.system_terms_of_address_enabled") public int getSystemGrammaticalGender();
     method public void setRequestedApplicationGrammaticalGender(int);
   }
 
@@ -6749,7 +6750,6 @@
     method public android.app.Notification.WearableExtender clone();
     method public android.app.Notification.Builder extend(android.app.Notification.Builder);
     method public java.util.List<android.app.Notification.Action> getActions();
-    method @Deprecated public android.graphics.Bitmap getBackground();
     method public String getBridgeTag();
     method public int getContentAction();
     method @Deprecated public int getContentIcon();
@@ -6768,7 +6768,6 @@
     method @Deprecated public boolean getHintShowBackgroundOnly();
     method @Deprecated public java.util.List<android.app.Notification> getPages();
     method public boolean getStartScrollBottom();
-    method @Deprecated public android.app.Notification.WearableExtender setBackground(android.graphics.Bitmap);
     method public android.app.Notification.WearableExtender setBridgeTag(String);
     method public android.app.Notification.WearableExtender setContentAction(int);
     method @Deprecated public android.app.Notification.WearableExtender setContentIcon(int);
@@ -9682,6 +9681,7 @@
     method public int describeContents();
     method public int getDeviceId();
     method @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") @NonNull public int[] getDisplayIds();
+    method @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") @Nullable public CharSequence getDisplayName();
     method @Nullable public String getName();
     method @Nullable public String getPersistentDeviceId();
     method @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") public boolean hasCustomSensorSupport();
@@ -42904,7 +42904,7 @@
     field public static final String KEY_CARRIER_SERVICE_NUMBER_STRING_ARRAY = "carrier_service_number_array";
     field public static final String KEY_CARRIER_SETTINGS_ACTIVITY_COMPONENT_NAME_STRING = "carrier_settings_activity_component_name_string";
     field public static final String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
-    field public static final String KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE = "carrier_supported_satellite_services_per_provider_bundle";
+    field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE = "carrier_supported_satellite_services_per_provider_bundle";
     field public static final String KEY_CARRIER_SUPPORTS_OPP_DATA_AUTO_PROVISIONING_BOOL = "carrier_supports_opp_data_auto_provisioning_bool";
     field public static final String KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL = "carrier_supports_ss_over_ut_bool";
     field public static final String KEY_CARRIER_SUPPORTS_TETHERING_BOOL = "carrier_supports_tethering_bool";
@@ -43072,6 +43072,7 @@
     field public static final String KEY_RTT_SUPPORTED_WHILE_ROAMING_BOOL = "rtt_supported_while_roaming_bool";
     field public static final String KEY_RTT_UPGRADE_SUPPORTED_BOOL = "rtt_upgrade_supported_bool";
     field public static final String KEY_RTT_UPGRADE_SUPPORTED_FOR_DOWNGRADED_VT_CALL_BOOL = "rtt_upgrade_supported_for_downgraded_vt_call";
+    field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_SATELLITE_ATTACH_SUPPORTED_BOOL = "satellite_attach_supported_bool";
     field public static final String KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL = "show_4g_for_3g_data_icon_bool";
     field public static final String KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL = "show_4g_for_lte_data_icon_bool";
     field public static final String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool";
diff --git a/core/api/removed.txt b/core/api/removed.txt
index 8b3696a..57e2e73 100644
--- a/core/api/removed.txt
+++ b/core/api/removed.txt
@@ -23,6 +23,11 @@
     method @Deprecated public android.app.Notification.Builder setTimeout(long);
   }
 
+  public static final class Notification.WearableExtender implements android.app.Notification.Extender {
+    method @Deprecated public android.graphics.Bitmap getBackground();
+    method @Deprecated public android.app.Notification.WearableExtender setBackground(android.graphics.Bitmap);
+  }
+
 }
 
 package android.app.slice {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 1d88e00..98a454a 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -16731,17 +16731,22 @@
   }
 
   public final class SatelliteManager {
+    method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void addSatelliteAttachRestrictionForCarrier(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void deprovisionSatelliteService(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+    method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.Set<java.lang.Integer> getSatelliteAttachRestrictionReasonsForCarrier(int);
     method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void pollPendingSatelliteDatagrams(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void provisionSatelliteService(@NonNull String, @NonNull byte[], @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSatelliteDatagram(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteDatagramCallback);
     method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSatelliteModemStateChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteStateCallback);
     method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSatelliteProvisionStateChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteProvisionStateCallback);
+    method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void removeSatelliteAttachRestrictionForCarrier(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsDemoModeEnabled(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
+    method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsSatelliteAttachEnabledForCarrier(int, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
     method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsSatelliteCommunicationAllowedForCurrentLocation(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
     method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsSatelliteEnabled(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
     method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsSatelliteProvisioned(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
     method public void requestIsSatelliteSupported(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
+    method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestSatelliteAttachEnabledForCarrier(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestSatelliteCapabilities(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.satellite.SatelliteCapabilities,android.telephony.satellite.SatelliteManager.SatelliteException>);
     method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestSatelliteEnabled(boolean, boolean, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestTimeForNextSatelliteVisibility(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.time.Duration,android.telephony.satellite.SatelliteManager.SatelliteException>);
@@ -16768,6 +16773,7 @@
     field public static final int NT_RADIO_TECHNOLOGY_NR_NTN = 2; // 0x2
     field public static final int NT_RADIO_TECHNOLOGY_PROPRIETARY = 4; // 0x4
     field public static final int NT_RADIO_TECHNOLOGY_UNKNOWN = 0; // 0x0
+    field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final int SATELLITE_COMMUNICATION_RESTRICTION_REASON_GEOLOCATION = 1; // 0x1
     field public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE = 0; // 0x0
     field public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED = 7; // 0x7
     field public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE = 6; // 0x6
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 25c48e6..183783b 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -62,7 +62,7 @@
 import android.app.servertransaction.ActivityRelaunchItem;
 import android.app.servertransaction.ActivityResultItem;
 import android.app.servertransaction.ClientTransaction;
-import android.app.servertransaction.ClientTransactionItem;
+import android.app.servertransaction.DestroyActivityItem;
 import android.app.servertransaction.PauseActivityItem;
 import android.app.servertransaction.PendingTransactionActions;
 import android.app.servertransaction.PendingTransactionActions.StopInfo;
@@ -375,8 +375,8 @@
     @GuardedBy("mPendingOverrideConfigs")
     private final ArrayMap<IBinder, Configuration> mPendingOverrideConfigs = new ArrayMap<>();
     /** The activities to be truly destroyed (not include relaunch). */
-    final Map<IBinder, ClientTransactionItem> mActivitiesToBeDestroyed =
-            Collections.synchronizedMap(new ArrayMap<IBinder, ClientTransactionItem>());
+    final Map<IBinder, DestroyActivityItem> mActivitiesToBeDestroyed =
+            Collections.synchronizedMap(new ArrayMap<>());
     // List of new activities that should be reported when next we idle.
     final ArrayList<ActivityClientRecord> mNewActivities = new ArrayList<>();
     // Number of activities that are currently visible on-screen.
@@ -5799,7 +5799,7 @@
     }
 
     @Override
-    public Map<IBinder, ClientTransactionItem> getActivitiesToBeDestroyed() {
+    public Map<IBinder, DestroyActivityItem> getActivitiesToBeDestroyed() {
         return mActivitiesToBeDestroyed;
     }
 
diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java
index 98020ff..25075e9 100644
--- a/core/java/android/app/ClientTransactionHandler.java
+++ b/core/java/android/app/ClientTransactionHandler.java
@@ -19,7 +19,7 @@
 import android.annotation.Nullable;
 import android.app.ActivityThread.ActivityClientRecord;
 import android.app.servertransaction.ClientTransaction;
-import android.app.servertransaction.ClientTransactionItem;
+import android.app.servertransaction.DestroyActivityItem;
 import android.app.servertransaction.PendingTransactionActions;
 import android.app.servertransaction.TransactionExecutor;
 import android.content.Context;
@@ -108,7 +108,7 @@
     // and deliver callbacks.
 
     /** Get activity and its corresponding transaction item which are going to destroy. */
-    public abstract Map<IBinder, ClientTransactionItem> getActivitiesToBeDestroyed();
+    public abstract Map<IBinder, DestroyActivityItem> getActivitiesToBeDestroyed();
 
     /** Destroy the activity. */
     public abstract void handleDestroyActivity(@NonNull ActivityClientRecord r, boolean finishing,
diff --git a/core/java/android/app/GrammaticalInflectionManager.java b/core/java/android/app/GrammaticalInflectionManager.java
index 1905b6a..bc6fe61 100644
--- a/core/java/android/app/GrammaticalInflectionManager.java
+++ b/core/java/android/app/GrammaticalInflectionManager.java
@@ -16,12 +16,15 @@
 
 package android.app;
 
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
 import android.annotation.SystemService;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.os.RemoteException;
 
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -31,11 +34,15 @@
  */
 @SystemService(Context.GRAMMATICAL_INFLECTION_SERVICE)
 public class GrammaticalInflectionManager {
-    private static final Set<Integer> VALID_GENDER_VALUES = new HashSet<>(Arrays.asList(
+
+    /** @hide */
+    @NonNull
+    public static final Set<Integer> VALID_GRAMMATICAL_GENDER_VALUES =
+        Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
             Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED,
             Configuration.GRAMMATICAL_GENDER_NEUTRAL,
             Configuration.GRAMMATICAL_GENDER_FEMININE,
-            Configuration.GRAMMATICAL_GENDER_MASCULINE));
+            Configuration.GRAMMATICAL_GENDER_MASCULINE)));
 
     private final Context mContext;
     private final IGrammaticalInflectionManager mService;
@@ -79,7 +86,7 @@
      */
     public void setRequestedApplicationGrammaticalGender(
             @Configuration.GrammaticalGender int grammaticalGender) {
-        if (!VALID_GENDER_VALUES.contains(grammaticalGender)) {
+        if (!VALID_GRAMMATICAL_GENDER_VALUES.contains(grammaticalGender)) {
             throw new IllegalArgumentException("Unknown grammatical gender");
         }
 
@@ -90,4 +97,44 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Sets the current grammatical gender for all privileged applications. The value will be
+     * stored in an encrypted file at {@link android.os.Environment#getDataSystemCeDirectory(int)
+     *
+     * @param grammaticalGender the terms of address the user preferred in system.
+     *
+     * @see Configuration#getGrammaticalGender
+     * @hide
+     */
+    public void setSystemWideGrammaticalGender(
+            @Configuration.GrammaticalGender int grammaticalGender) {
+        if (!VALID_GRAMMATICAL_GENDER_VALUES.contains(grammaticalGender)) {
+            throw new IllegalArgumentException("Unknown grammatical gender");
+        }
+
+        try {
+            mService.setSystemWideGrammaticalGender(mContext.getUserId(), grammaticalGender);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Get the current grammatical gender of privileged application from the encrypted file,
+     * which is stored under {@link android.os.Environment#getDataSystemCeDirectory(int)}.
+     *
+     * @return the value of grammatical gender
+     *
+     * @see Configuration#getGrammaticalGender
+     */
+    @FlaggedApi(Flags.FLAG_SYSTEM_TERMS_OF_ADDRESS_ENABLED)
+    @Configuration.GrammaticalGender
+    public int getSystemGrammaticalGender() {
+        try {
+            return mService.getSystemGrammaticalGender(mContext.getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/app/IGrammaticalInflectionManager.aidl b/core/java/android/app/IGrammaticalInflectionManager.aidl
index 9366a45..48a4841 100644
--- a/core/java/android/app/IGrammaticalInflectionManager.aidl
+++ b/core/java/android/app/IGrammaticalInflectionManager.aidl
@@ -16,4 +16,14 @@
       * Sets a specified app’s app-specific grammatical gender.
       */
      void setRequestedApplicationGrammaticalGender(String appPackageName, int userId, int gender);
- }
\ No newline at end of file
+
+     /**
+      * Sets the grammatical gender to system.
+      */
+     void setSystemWideGrammaticalGender(int userId, int gender);
+
+     /**
+      * Gets the grammatical gender from system.
+      */
+     int getSystemGrammaticalGender(int userId);
+ }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 2c42df3..93c2b5a 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -44,6 +44,9 @@
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.app.admin.DevicePolicyManager;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
@@ -296,6 +299,15 @@
     public static final String EXTRA_REMOTE_INPUT_DRAFT = "android.remoteInputDraft";
 
     /**
+     * The call to WearableExtender#setBackground(Bitmap) will have no effect and the passed
+     * Bitmap will not be retained in memory.
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
+    @VisibleForTesting
+    static final long WEARABLE_EXTENDER_BACKGROUND_BLOCKED = 270551184L;
+
+    /**
      * A timestamp related to this notification, in milliseconds since the epoch.
      *
      * Default value: {@link System#currentTimeMillis() Now}.
@@ -11148,9 +11160,20 @@
                 wearableBundle.putParcelableArray(KEY_PAGES, mPages.toArray(
                         new Notification[mPages.size()]));
             }
+
             if (mBackground != null) {
-                wearableBundle.putParcelable(KEY_BACKGROUND, mBackground);
+                // Keeping WearableExtender backgrounds in memory despite them being deprecated has
+                // added noticeable increase in system server and system ui memory usage. After
+                // target VERSION_CODE#VANILLA_ICE_CREAM the background will not be populated
+                // anymore.
+                if (CompatChanges.isChangeEnabled(WEARABLE_EXTENDER_BACKGROUND_BLOCKED)) {
+                    Log.d(TAG, "Use of background in WearableExtenders has been deprecated and "
+                            + "will not be populated anymore.");
+                } else {
+                    wearableBundle.putParcelable(KEY_BACKGROUND, mBackground);
+                }
             }
+
             if (mContentIcon != 0) {
                 wearableBundle.putInt(KEY_CONTENT_ICON, mContentIcon);
             }
@@ -11369,12 +11392,21 @@
          *
          * @param background the background bitmap
          * @return this object for method chaining
-         * @see android.app.Notification.WearableExtender#getBackground
-         * @deprecated Background images are no longer supported.
+         * @removed Not functional since {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}.
+         *          The wearable background is not used by wearables anymore and uses up
+         *          unnecessary memory.
          */
         @Deprecated
         public WearableExtender setBackground(Bitmap background) {
-            mBackground = background;
+            // Keeping WearableExtender backgrounds in memory despite them being deprecated has
+            // added noticeable increase in system server and system ui memory usage. After
+            // target VERSION_CODE#VANILLA_ICE_CREAM the background will not be populated anymore.
+            if (CompatChanges.isChangeEnabled(WEARABLE_EXTENDER_BACKGROUND_BLOCKED)) {
+                Log.d(TAG, "Use of background in WearableExtenders has been deprecated and "
+                        + "will not be populated anymore.");
+            } else {
+                mBackground = background;
+            }
             return this;
         }
 
@@ -11384,11 +11416,13 @@
          * will work with any notification style.
          *
          * @return the background image
-         * @see android.app.Notification.WearableExtender#setBackground
-         * @deprecated Background images are no longer supported.
+         * @removed Not functional since {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}. The
+         *          wearable background is not used by wearables anymore and uses up
+         *          unnecessary memory.
          */
         @Deprecated
         public Bitmap getBackground() {
+            Log.w(TAG, "Use of background in WearableExtender has been removed, returning null.");
             return mBackground;
         }
 
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index e1c45d9..9cf54e3 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -54,6 +54,9 @@
 per-file Broadcast* = file:/BROADCASTS_OWNERS
 per-file ReceiverInfo* = file:/BROADCASTS_OWNERS
 
+# GrammaticalInflectionManager
+per-file *GrammaticalInflection* = file:/services/core/java/com/android/server/grammaticalinflection/OWNERS
+
 # KeyguardManager
 per-file KeyguardManager.java = file:/services/core/java/com/android/server/locksettings/OWNERS
 
diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING
index 315a055..a29c196 100644
--- a/core/java/android/app/TEST_MAPPING
+++ b/core/java/android/app/TEST_MAPPING
@@ -19,7 +19,7 @@
             "name": "CtsAppOpsTestCases",
             "options": [
                 {
-                    "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+                    "exclude-annotation": "androidx.test.filters.FlakyTest"
                 }
             ]
         },
diff --git a/core/java/android/app/grammatical_inflection_manager.aconfig b/core/java/android/app/grammatical_inflection_manager.aconfig
new file mode 100644
index 0000000..989ce61
--- /dev/null
+++ b/core/java/android/app/grammatical_inflection_manager.aconfig
@@ -0,0 +1,8 @@
+package: "android.app"
+
+flag {
+    name: "system_terms_of_address_enabled"
+    namespace: "grammatical_gender"
+    description: "Feature flag for System Terms of Address"
+    bug: "297798866"
+}
diff --git a/core/java/android/app/servertransaction/ClientTransaction.java b/core/java/android/app/servertransaction/ClientTransaction.java
index a5b0f18..8617386 100644
--- a/core/java/android/app/servertransaction/ClientTransaction.java
+++ b/core/java/android/app/servertransaction/ClientTransaction.java
@@ -23,7 +23,6 @@
 import android.app.ClientTransactionHandler;
 import android.app.IApplicationThread;
 import android.compat.annotation.UnsupportedAppUsage;
-import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.RemoteException;
@@ -83,23 +82,6 @@
         return mActivityCallbacks;
     }
 
-    /** Get the target activity. */
-    @Nullable
-    @UnsupportedAppUsage
-    public IBinder getActivityToken() {
-        // TODO(b/260873529): remove after we allow multiple activity items in one transaction.
-        if (mLifecycleStateRequest != null) {
-            return mLifecycleStateRequest.getActivityToken();
-        }
-        for (int i = mActivityCallbacks.size() - 1; i >= 0; i--) {
-            final IBinder token = mActivityCallbacks.get(i).getActivityToken();
-            if (token != null) {
-                return token;
-            }
-        }
-        return null;
-    }
-
     /** Get the target state lifecycle request. */
     @VisibleForTesting(visibility = PACKAGE)
     @UnsupportedAppUsage
diff --git a/core/java/android/app/servertransaction/DestroyActivityItem.java b/core/java/android/app/servertransaction/DestroyActivityItem.java
index ddb6df1..f9cf075 100644
--- a/core/java/android/app/servertransaction/DestroyActivityItem.java
+++ b/core/java/android/app/servertransaction/DestroyActivityItem.java
@@ -50,6 +50,13 @@
     }
 
     @Override
+    public void postExecute(@NonNull ClientTransactionHandler client,
+            @NonNull PendingTransactionActions pendingActions) {
+        // Cleanup after execution.
+        client.getActivitiesToBeDestroyed().remove(getActivityToken());
+    }
+
+    @Override
     public int getTargetState() {
         return ON_DESTROY;
     }
diff --git a/core/java/android/app/servertransaction/TransactionExecutor.java b/core/java/android/app/servertransaction/TransactionExecutor.java
index 4433673..066f9fe 100644
--- a/core/java/android/app/servertransaction/TransactionExecutor.java
+++ b/core/java/android/app/servertransaction/TransactionExecutor.java
@@ -47,7 +47,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.List;
-import java.util.Map;
 
 /**
  * Class that manages transaction execution in the correct order.
@@ -75,34 +74,14 @@
      * either remain in the initial state, or last state needed by a callback.
      */
     public void execute(@NonNull ClientTransaction transaction) {
-        if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "Start resolving transaction");
-
-        final IBinder token = transaction.getActivityToken();
-        if (token != null) {
-            final Map<IBinder, ClientTransactionItem> activitiesToBeDestroyed =
-                    mTransactionHandler.getActivitiesToBeDestroyed();
-            final ClientTransactionItem destroyItem = activitiesToBeDestroyed.get(token);
-            if (destroyItem != null) {
-                if (transaction.getLifecycleStateRequest() == destroyItem) {
-                    // It is going to execute the transaction that will destroy activity with the
-                    // token, so the corresponding to-be-destroyed record can be removed.
-                    activitiesToBeDestroyed.remove(token);
-                }
-                if (mTransactionHandler.getActivityClient(token) == null) {
-                    // The activity has not been created but has been requested to destroy, so all
-                    // transactions for the token are just like being cancelled.
-                    Slog.w(TAG, tId(transaction) + "Skip pre-destroyed transaction:\n"
-                            + transactionToString(transaction, mTransactionHandler));
-                    return;
-                }
-            }
+        if (DEBUG_RESOLVER) {
+            Slog.d(TAG, tId(transaction) + "Start resolving transaction");
+            Slog.d(TAG, transactionToString(transaction, mTransactionHandler));
         }
 
-        if (DEBUG_RESOLVER) Slog.d(TAG, transactionToString(transaction, mTransactionHandler));
-
         executeCallbacks(transaction);
-
         executeLifecycleState(transaction);
+
         mPendingActions.clear();
         if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "End resolving transaction");
     }
@@ -135,6 +114,14 @@
             final IBinder token = item.getActivityToken();
             ActivityClientRecord r = mTransactionHandler.getActivityClient(token);
 
+            if (token != null && r == null
+                    && mTransactionHandler.getActivitiesToBeDestroyed().containsKey(token)) {
+                // The activity has not been created but has been requested to destroy, so all
+                // transactions for the token are just like being cancelled.
+                Slog.w(TAG, "Skip pre-destroyed transaction item:\n" + item);
+                continue;
+            }
+
             if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "Resolving callback: " + item);
             final int postExecutionState = item.getPostExecutionState();
 
@@ -211,6 +198,10 @@
         }
 
         if (r == null) {
+            if (mTransactionHandler.getActivitiesToBeDestroyed().get(token) == lifecycleItem) {
+                // Always cleanup for destroy item.
+                lifecycleItem.postExecute(mTransactionHandler, mPendingActions);
+            }
             // Ignore requests for non-existent client records for now.
             return;
         }
diff --git a/core/java/android/companion/virtual/VirtualDevice.java b/core/java/android/companion/virtual/VirtualDevice.java
index 4692f92..ce883cd 100644
--- a/core/java/android/companion/virtual/VirtualDevice.java
+++ b/core/java/android/companion/virtual/VirtualDevice.java
@@ -44,6 +44,7 @@
     private final int mId;
     private final @Nullable String mPersistentId;
     private final @Nullable String mName;
+    private final @Nullable CharSequence mDisplayName;
 
     /**
      * Creates a new instance of {@link VirtualDevice}.
@@ -53,6 +54,18 @@
      */
     public VirtualDevice(@NonNull IVirtualDevice virtualDevice, int id,
             @Nullable String persistentId, @Nullable String name) {
+        this(virtualDevice, id, persistentId, name, null);
+    }
+
+    /**
+     * Creates a new instance of {@link VirtualDevice}. Only to be used by the
+     * VirtualDeviceManagerService.
+     *
+     * @hide
+     */
+    public VirtualDevice(@NonNull IVirtualDevice virtualDevice, int id,
+            @Nullable String persistentId, @Nullable String name,
+            @Nullable CharSequence displayName) {
         if (id <= Context.DEVICE_ID_DEFAULT) {
             throw new IllegalArgumentException("VirtualDevice ID must be greater than "
                     + Context.DEVICE_ID_DEFAULT);
@@ -61,6 +74,7 @@
         mId = id;
         mPersistentId = persistentId;
         mName = name;
+        mDisplayName = displayName;
     }
 
     private VirtualDevice(@NonNull Parcel parcel) {
@@ -68,6 +82,7 @@
         mId = parcel.readInt();
         mPersistentId = parcel.readString8();
         mName = parcel.readString8();
+        mDisplayName = parcel.readCharSequence();
     }
 
     /**
@@ -112,6 +127,15 @@
     }
 
     /**
+     * Returns the human-readable name of the virtual device, if defined, which is suitable to be
+     * shown in UI.
+     */
+    @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
+    public @Nullable CharSequence getDisplayName() {
+        return mDisplayName;
+    }
+
+    /**
      * Returns the IDs of all virtual displays that belong to this device, if any.
      *
      * <p>The actual {@link android.view.Display} objects can be obtained by passing the returned
@@ -156,6 +180,7 @@
         dest.writeInt(mId);
         dest.writeString8(mPersistentId);
         dest.writeString8(mName);
+        dest.writeCharSequence(mDisplayName);
     }
 
     @Override
@@ -165,6 +190,7 @@
                 + " mId=" + mId
                 + " mPersistentId=" + mPersistentId
                 + " mName=" + mName
+                + " mDisplayName=" + mDisplayName
                 + ")";
     }
 
diff --git a/core/java/android/companion/virtual/flags.aconfig b/core/java/android/companion/virtual/flags.aconfig
index 3e96c96..d0e13cd 100644
--- a/core/java/android/companion/virtual/flags.aconfig
+++ b/core/java/android/companion/virtual/flags.aconfig
@@ -34,3 +34,10 @@
     description: "Enable Virtual Camera"
     bug: "270352264"
 }
+
+flag {
+  name: "stream_permissions"
+  namespace: "virtual_devices"
+  description: "Enable streaming permission dialogs to Virtual Devices"
+  bug: "291737919"
+}
diff --git a/core/java/android/content/pm/TEST_MAPPING b/core/java/android/content/pm/TEST_MAPPING
index ab669cc..b0ab11f 100644
--- a/core/java/android/content/pm/TEST_MAPPING
+++ b/core/java/android/content/pm/TEST_MAPPING
@@ -45,7 +45,8 @@
             ]
         },
         {
-            "name":"CarrierAppIntegrationTestCases"
+            "name":"CarrierAppIntegrationTestCases",
+            "keywords": ["internal"]
         },
         {
             "name":"CtsSilentUpdateHostTestCases"
diff --git a/core/java/android/hardware/radio/ProgramSelector.java b/core/java/android/hardware/radio/ProgramSelector.java
index 727716e..12442ba 100644
--- a/core/java/android/hardware/radio/ProgramSelector.java
+++ b/core/java/android/hardware/radio/ProgramSelector.java
@@ -147,8 +147,8 @@
      *
      * <p>Consists of (from the LSB):
      * <li>
-     *     <ul>132bit: Station ID number.
-     *     <ul>14bit: HD_SUBCHANNEL.
+     *     <ul>32bit: Station ID number.
+     *     <ul>4bit: HD_SUBCHANNEL.
      *     <ul>18bit: AMFM_FREQUENCY.
      * </li>
      *
diff --git a/core/java/android/net/metrics/WakeupEvent.java b/core/java/android/net/metrics/WakeupEvent.java
index af9a73c..53a3ea5 100644
--- a/core/java/android/net/metrics/WakeupEvent.java
+++ b/core/java/android/net/metrics/WakeupEvent.java
@@ -29,7 +29,7 @@
     public String iface;
     public int uid;
     public int ethertype;
-    public MacAddress dstHwAddr;
+    public MacAddress dstHwAddr;  // actually used to store a src mac address
     public String srcIp;
     public String dstIp;
     public int ipNextHeader;
@@ -44,7 +44,7 @@
         j.add(iface);
         j.add("uid: " + Integer.toString(uid));
         j.add("eth=0x" + Integer.toHexString(ethertype));
-        j.add("dstHw=" + dstHwAddr);
+        j.add("srcMac=" + dstHwAddr);  // really!! http://b/292404319#comment11
         if (ipNextHeader > 0) {
             j.add("ipNxtHdr=" + ipNextHeader);
             j.add("srcIp=" + srcIp);
diff --git a/core/java/android/os/TEST_MAPPING b/core/java/android/os/TEST_MAPPING
index ad3abd9..2d6e09a 100644
--- a/core/java/android/os/TEST_MAPPING
+++ b/core/java/android/os/TEST_MAPPING
@@ -8,7 +8,6 @@
       "name": "FrameworksVibratorCoreTests",
       "options": [
         {"exclude-annotation": "androidx.test.filters.LargeTest"},
-        {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
         {"exclude-annotation": "androidx.test.filters.FlakyTest"},
         {"exclude-annotation": "org.junit.Ignore"}
       ]
@@ -21,7 +20,6 @@
       "name": "FrameworksVibratorServicesTests",
       "options": [
         {"exclude-annotation": "androidx.test.filters.LargeTest"},
-        {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
         {"exclude-annotation": "androidx.test.filters.FlakyTest"},
         {"exclude-annotation": "org.junit.Ignore"}
       ]
@@ -34,7 +32,6 @@
       "name": "CtsVibratorTestCases",
       "options": [
         {"exclude-annotation": "androidx.test.filters.LargeTest"},
-        {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
         {"exclude-annotation": "androidx.test.filters.FlakyTest"},
         {"exclude-annotation": "org.junit.Ignore"}
       ]
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 80b7d40..4c8ef97 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -2940,6 +2940,12 @@
      * Used to check if the context user is a restricted profile. Restricted profiles
      * may have a reduced number of available apps, app restrictions, and account restrictions.
      *
+     * <p>The caller must be in the same profile group as the context user or else hold
+     * <li>{@link android.Manifest.permission#MANAGE_USERS},
+     * <li>or {@link android.Manifest.permission#CREATE_USERS},
+     * <li>or, for devices after {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE},
+     * {@link android.Manifest.permission#QUERY_USERS}.
+     *
      * @return whether the context user is a restricted profile.
      * @hide
      */
@@ -2963,6 +2969,12 @@
      * Check if a user is a restricted profile. Restricted profiles may have a reduced number of
      * available apps, app restrictions, and account restrictions.
      *
+     * <p>Requires
+     * <li>{@link android.Manifest.permission#MANAGE_USERS},
+     * <li>or {@link android.Manifest.permission#CREATE_USERS},
+     * <li>or, for devices after {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE},
+     * {@link android.Manifest.permission#QUERY_USERS}.
+     *
      * @param user the user to check
      * @return whether the user is a restricted profile.
      * @hide
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index 77be5d4..1294f98 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -6,3 +6,10 @@
   description: "enable device aware permission APIs"
   bug: "274852670"
 }
+
+flag {
+  name: "voice_activation_permission_apis"
+  namespace: "permissions"
+  description: "enable voice activation permission APIs"
+  bug: "287264308"
+}
\ No newline at end of file
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e829ca2..f40232b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9908,6 +9908,48 @@
          */
         public static final String DOCK_SETUP_STATE = "dock_setup_state";
 
+
+        /**
+         * Default, indicates that the user has not yet started the hub mode tutorial.
+         *
+         * @hide
+         */
+        public static final int HUB_MODE_TUTORIAL_NOT_STARTED = 0;
+
+        /**
+         * Indicates that the user has started but not yet completed the hub mode tutorial.
+         * One of the possible states for {@link #HUB_MODE_TUTORIAL_STATE}.
+         *
+         * @hide
+         */
+        public static final int HUB_MODE_TUTORIAL_STARTED = 1;
+
+        /**
+         * Indicates that the user has completed the hub mode tutorial.
+         * One of the possible states for {@link #HUB_MODE_TUTORIAL_STATE}.
+         *
+         * @hide
+         */
+        public static final int HUB_MODE_TUTORIAL_COMPLETED = 10;
+
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef({
+                HUB_MODE_TUTORIAL_NOT_STARTED,
+                HUB_MODE_TUTORIAL_STARTED,
+                HUB_MODE_TUTORIAL_COMPLETED
+        })
+        public @interface HubModeTutorialState {
+        }
+
+        /**
+         * Defines the user's current state of navigating through the hub mode tutorial.
+         * The possible states are defined in {@link HubModeTutorialState}.
+         *
+         * @hide
+         */
+        public static final String HUB_MODE_TUTORIAL_STATE = "hub_mode_tutorial_state";
+
         /**
          * The default NFC payment component
          * @hide
@@ -11105,6 +11147,12 @@
         public static final String BLUETOOTH_ON_WHILE_DRIVING = "bluetooth_on_while_driving";
 
         /**
+         * Volume dialog timeout in ms.
+         * @hide
+         */
+        public static final String VOLUME_DIALOG_DISMISS_TIMEOUT = "volume_dialog_dismiss_timeout";
+
+        /**
          * What behavior should be invoked when the volume hush gesture is triggered
          * One of VOLUME_HUSH_OFF, VOLUME_HUSH_VIBRATE, VOLUME_HUSH_MUTE.
          *
diff --git a/core/java/android/service/notification/TEST_MAPPING b/core/java/android/service/notification/TEST_MAPPING
index 7b8d52f..468c451 100644
--- a/core/java/android/service/notification/TEST_MAPPING
+++ b/core/java/android/service/notification/TEST_MAPPING
@@ -4,9 +4,6 @@
       "name": "CtsNotificationTestCases",
       "options": [
         {
-          "exclude-annotation": "android.platform.test.annotations.FlakyTest"
-        },
-        {
           "exclude-annotation": "androidx.test.filters.FlakyTest"
         },
         {
@@ -21,9 +18,6 @@
       "name": "FrameworksUiServicesTests",
       "options": [
         {
-          "exclude-annotation": "android.platform.test.annotations.FlakyTest"
-        },
-        {
           "exclude-annotation": "androidx.test.filters.FlakyTest"
         },
         {
diff --git a/core/java/android/text/TEST_MAPPING b/core/java/android/text/TEST_MAPPING
index 0fe974a..c9bd2ca 100644
--- a/core/java/android/text/TEST_MAPPING
+++ b/core/java/android/text/TEST_MAPPING
@@ -4,7 +4,7 @@
       "name": "CtsTextTestCases",
       "options": [
           {
-              "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+              "exclude-annotation": "androidx.test.filters.FlakyTest"
           },
           {
               "exclude-annotation": "androidx.test.filters.LargeTest"
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index bdd0a9c..e4e8b7b5b 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.annotation.FloatRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -30,8 +31,10 @@
 import android.graphics.TextureLayer;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
+import android.os.Trace;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.flags.Flags;
 
 /**
  * <p>A TextureView can be used to display a content stream, such as that
@@ -51,9 +54,9 @@
  *       <th style="text-align: center;">SurfaceView</th>
  *     </tr>
  *     <tr>
- *       <td>Supports alpha</td>
+ *       <td>Supports View alpha</td>
  *       <td style="text-align: center;">X</td>
- *       <td style="text-align: center;">&nbsp;</td>
+ *       <td style="text-align: center;">U+</td>
  *     </tr>
  *     <tr>
  *       <td>Supports rotations</td>
@@ -194,6 +197,9 @@
     private Canvas mCanvas;
     private int mSaveCount;
 
+    @FloatRange(from = 0.0) float mFrameRate;
+    @Surface.FrameRateCompatibility int mFrameRateCompatibility;
+
     private final Object[] mNativeWindowLock = new Object[0];
     // Set by native code, do not write!
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -465,6 +471,16 @@
             mLayer.setSurfaceTexture(mSurface);
             mSurface.setDefaultBufferSize(getWidth(), getHeight());
             mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler);
+            if (Flags.toolkitSetFrameRate()) {
+                mSurface.setOnSetFrameRateListener(
+                        (surfaceTexture, frameRate, compatibility, strategy) -> {
+                            if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+                                Trace.instant(Trace.TRACE_TAG_VIEW, "setFrameRate: " + frameRate);
+                            }
+                            mFrameRate = frameRate;
+                            mFrameRateCompatibility = compatibility;
+                        }, mAttachInfo.mHandler);
+            }
 
             if (mListener != null && createNewSurface) {
                 mListener.onSurfaceTextureAvailable(mSurface, getWidth(), getHeight());
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 55374b9..552263a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1328,6 +1328,14 @@
     public static final String AUTOFILL_HINT_PASSWORD_AUTO = "passwordAuto";
 
     /**
+     * Hint indicating that the developer intends to fill this view with output from
+     * CredentialManager.
+     *
+     * @hide
+     */
+    public static final String AUTOFILL_HINT_CREDENTIAL_MANAGER = "credential";
+
+    /**
      * Hints for the autofill services that describes the content of the view.
      */
     private @Nullable String[] mAutofillHints;
@@ -8562,6 +8570,15 @@
      * announcements every time a View is updated.
      *
      * <p>
+     * For notifying users about errors, such as in a login screen with text that displays an
+     * "incorrect password" notification, that view should send an AccessibilityEvent of type
+     * {@link AccessibilityEvent#CONTENT_CHANGE_TYPE_ERROR} and set
+     * {@link AccessibilityNodeInfo#setError(CharSequence)} instead. Custom widgets should expose
+     * error-setting methods that support accessibility automatically. For example, instead of
+     * explicitly sending this event when using a TextView, use
+     * {@link android.widget.TextView#setError(CharSequence)}.
+     *
+     * <p>
      * Use {@link #setStateDescription(CharSequence)} to convey state changes to views within the
      * user interface. While a live region may send different types of events generated by the view,
      * state description will send {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} events of
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 4cb8788..6cf185a 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -1464,7 +1464,7 @@
         if (infos.size() == 0) {
             throw new IllegalArgumentException("No VirtualViewInfo found");
         }
-        if (view.isCredential() && mIsFillAndSaveDialogDisabledForCredentialManager) {
+        if (isCredmanRequested(view) && mIsFillAndSaveDialogDisabledForCredentialManager) {
             if (sDebug) {
                 Log.d(TAG, "Ignoring Fill Dialog request since important for credMan:"
                         + view.getAutofillId().toString());
@@ -1488,7 +1488,7 @@
      * @hide
      */
     public void notifyViewEnteredForFillDialog(View v) {
-        if (v.isCredential()
+        if (isCredmanRequested(v)
                 && mIsFillAndSaveDialogDisabledForCredentialManager) {
             if (sDebug) {
                 Log.d(TAG, "Ignoring Fill Dialog request since important for credMan:"
@@ -3434,6 +3434,22 @@
         }
     }
 
+    private boolean isCredmanRequested(View view) {
+        if (view.isCredential()) {
+            return true;
+        }
+        String[] hints = view.getAutofillHints();
+        if (hints == null) {
+            return false;
+        }
+        for (String hint : hints) {
+            if (hint.equals(View.AUTOFILL_HINT_CREDENTIAL_MANAGER)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Find a single view by its id.
      *
diff --git a/core/java/android/window/ITaskFragmentOrganizerController.aidl b/core/java/android/window/ITaskFragmentOrganizerController.aidl
index d25c8a8..7b7e341 100644
--- a/core/java/android/window/ITaskFragmentOrganizerController.aidl
+++ b/core/java/android/window/ITaskFragmentOrganizerController.aidl
@@ -25,9 +25,12 @@
 interface ITaskFragmentOrganizerController {
 
     /**
-     * Registers a TaskFragmentOrganizer to manage TaskFragments.
+     * Registers a TaskFragmentOrganizer to manage TaskFragments. Registering a system
+     * organizer requires MANAGE_ACTIVITY_TASKS permission, and the organizer will have additional
+     * system capabilities.
      */
-    void registerOrganizer(in ITaskFragmentOrganizer organizer);
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value=android.Manifest.permission.MANAGE_ACTIVITY_TASKS, conditional=true)")
+    void registerOrganizer(in ITaskFragmentOrganizer organizer, in boolean isSystemOrganizer);
 
     /**
      * Unregisters a previously registered TaskFragmentOrganizer.
diff --git a/core/java/android/window/StartingWindowInfo.java b/core/java/android/window/StartingWindowInfo.java
index a88e394..451acbe 100644
--- a/core/java/android/window/StartingWindowInfo.java
+++ b/core/java/android/window/StartingWindowInfo.java
@@ -122,7 +122,7 @@
             TYPE_PARAMETER_PROCESS_RUNNING,
             TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT,
             TYPE_PARAMETER_ACTIVITY_CREATED,
-            TYPE_PARAMETER_ALLOW_ICON,
+            TYPE_PARAMETER_USE_SOLID_COLOR_SPLASH_SCREEN,
             TYPE_PARAMETER_ALLOW_HANDLE_SOLID_COLOR_SCREEN,
             TYPE_PARAMETER_WINDOWLESS,
             TYPE_PARAMETER_LEGACY_SPLASH_SCREEN
@@ -143,7 +143,7 @@
     /** @hide */
     public static final int TYPE_PARAMETER_ACTIVITY_CREATED = 0x00000010;
     /** @hide */
-    public static final int TYPE_PARAMETER_ALLOW_ICON = 0x00000020;
+    public static final int TYPE_PARAMETER_USE_SOLID_COLOR_SPLASH_SCREEN = 0x00000020;
     /**
      * The parameter which indicates if the activity has finished drawing.
      * @hide
diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java
index f785a3d..a6c9cec 100644
--- a/core/java/android/window/TaskFragmentOrganizer.java
+++ b/core/java/android/window/TaskFragmentOrganizer.java
@@ -22,9 +22,11 @@
 import static android.view.WindowManager.TRANSIT_OPEN;
 
 import android.annotation.CallSuper;
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.TestApi;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -32,6 +34,8 @@
 import android.view.RemoteAnimationDefinition;
 import android.view.WindowManager;
 
+import com.android.window.flags.Flags;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.concurrent.Executor;
@@ -140,12 +144,34 @@
     }
 
     /**
-     * Registers a TaskFragmentOrganizer to manage TaskFragments.
+     * Registers a {@link TaskFragmentOrganizer} to manage TaskFragments.
      */
     @CallSuper
     public void registerOrganizer() {
+        // TODO(b/302420256) point to registerOrganizer(boolean) when flag is removed.
         try {
-            getController().registerOrganizer(mInterface);
+            getController().registerOrganizer(mInterface, false /* isSystemOrganizer */);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Registers a {@link TaskFragmentOrganizer} to manage TaskFragments.
+     *
+     * Registering a system organizer requires MANAGE_ACTIVITY_TASKS permission, and the organizer
+     * will have additional system capabilities, including: (1) it will receive SurfaceControl for
+     * the organized TaskFragment, and (2) it needs to update the
+     * {@link android.view.SurfaceControl} following the window change accordingly.
+     *
+     * @hide
+     */
+    @CallSuper
+    @RequiresPermission(value = "android.permission.MANAGE_ACTIVITY_TASKS", conditional = true)
+    @FlaggedApi(Flags.FLAG_TASK_FRAGMENT_SYSTEM_ORGANIZER_FLAG)
+    public void registerOrganizer(boolean isSystemOrganizer) {
+        try {
+            getController().registerOrganizer(mInterface, isSystemOrganizer);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/window/TaskFragmentTransaction.java b/core/java/android/window/TaskFragmentTransaction.java
index 3c5d60d..4dada10 100644
--- a/core/java/android/window/TaskFragmentTransaction.java
+++ b/core/java/android/window/TaskFragmentTransaction.java
@@ -30,6 +30,7 @@
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.view.SurfaceControl;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -192,6 +193,9 @@
         @Nullable
         private TaskFragmentParentInfo mTaskFragmentParentInfo;
 
+        @Nullable
+        private SurfaceControl mSurfaceControl;
+
         public Change(@ChangeType int type) {
             mType = type;
         }
@@ -206,6 +210,7 @@
             mActivityIntent = in.readTypedObject(Intent.CREATOR);
             mActivityToken = in.readStrongBinder();
             mTaskFragmentParentInfo = in.readTypedObject(TaskFragmentParentInfo.CREATOR);
+            mSurfaceControl = in.readTypedObject(SurfaceControl.CREATOR);
         }
 
         @Override
@@ -219,6 +224,7 @@
             dest.writeTypedObject(mActivityIntent, flags);
             dest.writeStrongBinder(mActivityToken);
             dest.writeTypedObject(mTaskFragmentParentInfo, flags);
+            dest.writeTypedObject(mSurfaceControl, flags);
         }
 
         /** The change is related to the TaskFragment created with this unique token. */
@@ -306,6 +312,13 @@
             return this;
         }
 
+        /** @hide */
+        @NonNull
+        public Change setTaskFragmentSurfaceControl(@Nullable SurfaceControl sc) {
+            mSurfaceControl = sc;
+            return this;
+        }
+
         @ChangeType
         public int getType() {
             return mType;
@@ -359,6 +372,21 @@
             return mTaskFragmentParentInfo;
         }
 
+        /**
+         * Gets the {@link SurfaceControl} of the TaskFragment. This field is {@code null} for
+         * a regular {@link TaskFragmentOrganizer} and is only available for a system
+         * {@link TaskFragmentOrganizer} in the
+         * {@link TaskFragmentTransaction#TYPE_TASK_FRAGMENT_APPEARED} event. See
+         * {@link ITaskFragmentOrganizerController#registerOrganizer(ITaskFragmentOrganizer,
+         * boolean)}
+         *
+         * @hide
+         */
+        @Nullable
+        public SurfaceControl getTaskFragmentSurfaceControl() {
+            return mSurfaceControl;
+        }
+
         @Override
         public String toString() {
             return "Change{ type=" + mType + " }";
diff --git a/core/java/com/android/internal/display/BrightnessSynchronizer.java b/core/java/com/android/internal/display/BrightnessSynchronizer.java
index 7a87c3a..d503904 100644
--- a/core/java/com/android/internal/display/BrightnessSynchronizer.java
+++ b/core/java/com/android/internal/display/BrightnessSynchronizer.java
@@ -16,11 +16,9 @@
 
 package com.android.internal.display;
 
-import android.annotation.SuppressLint;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.database.ContentObserver;
-import android.hardware.display.BrightnessInfo;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManager.DisplayListener;
 import android.net.Uri;
@@ -56,7 +54,8 @@
     private static final int MSG_RUN_UPDATE = 1;
 
     // The tolerance within which we consider brightness values approximately equal to eachother.
-    public static final float EPSILON = 0.0001f;
+    // This value is approximately 1/3 of the smallest possible brightness value.
+    public static final float EPSILON = 0.001f;
 
     private static int sBrightnessUpdateCount = 1;
 
@@ -285,74 +284,6 @@
     }
 
     /**
-     * Converts between the int brightness setting and the float brightness system. The int
-     * brightness setting is between 0-255 and matches the brightness slider - e.g. 128 is 50% on
-     * the slider. Accounts for special values such as OFF and invalid values. Accounts for
-     * brightness limits; the maximum value here represents the max value allowed on the slider.
-     */
-    @VisibleForTesting
-    @SuppressLint("AndroidFrameworkRequiresPermission")
-    public float brightnessIntSettingToFloat(int brightnessInt) {
-        if (brightnessInt == PowerManager.BRIGHTNESS_OFF) {
-            return PowerManager.BRIGHTNESS_OFF_FLOAT;
-        } else if (brightnessInt == PowerManager.BRIGHTNESS_INVALID) {
-            return PowerManager.BRIGHTNESS_INVALID_FLOAT;
-        } else {
-            final float minInt = PowerManager.BRIGHTNESS_OFF + 1;
-            final float maxInt = PowerManager.BRIGHTNESS_ON;
-
-            // Normalize to the range [0, 1]
-            float userPerceptionBrightness = MathUtils.norm(minInt, maxInt, brightnessInt);
-
-            // Convert from user-perception to linear scale
-            float linearBrightness = BrightnessUtils.convertGammaToLinear(userPerceptionBrightness);
-
-            // Interpolate to the range [0, currentlyAllowedMax]
-            final Display display = mContext.getDisplay();
-            if (display == null) {
-                return PowerManager.BRIGHTNESS_INVALID_FLOAT;
-            }
-            final BrightnessInfo info = display.getBrightnessInfo();
-            return MathUtils.lerp(info.brightnessMinimum, info.brightnessMaximum, linearBrightness);
-        }
-    }
-
-    /**
-     * Translates specified value from the float brightness system to the setting int brightness
-     * system. The value returned is between 0-255 and matches the brightness slider - e.g. 128 is
-     * 50% on the slider. Accounts for special values such as OFF and invalid values. Accounts for
-     * brightness limits; the maximum value here represents the max value currently allowed on
-     * the slider.
-     */
-    @VisibleForTesting
-    @SuppressLint("AndroidFrameworkRequiresPermission")
-    public int brightnessFloatToIntSetting(float brightnessFloat) {
-        if (floatEquals(brightnessFloat, PowerManager.BRIGHTNESS_OFF_FLOAT)) {
-            return PowerManager.BRIGHTNESS_OFF;
-        } else if (Float.isNaN(brightnessFloat)) {
-            return PowerManager.BRIGHTNESS_INVALID;
-        } else {
-            // Normalize to the range [0, 1]
-            final Display display = mContext.getDisplay();
-            if (display == null) {
-                return PowerManager.BRIGHTNESS_INVALID;
-            }
-            final BrightnessInfo info = display.getBrightnessInfo();
-            float linearBrightness =
-                    MathUtils.norm(info.brightnessMinimum, info.brightnessMaximum, brightnessFloat);
-
-            // Convert from linear to user-perception scale
-            float userPerceptionBrightness = BrightnessUtils.convertLinearToGamma(linearBrightness);
-
-            // Interpolate to the range [0, 255]
-            final float minInt = PowerManager.BRIGHTNESS_OFF + 1;
-            final float maxInt = PowerManager.BRIGHTNESS_ON;
-            float intBrightness = MathUtils.lerp(minInt, maxInt, userPerceptionBrightness);
-            return Math.round(intBrightness);
-        }
-    }
-
-    /**
      * Encapsulates a brightness change event and contains logic for synchronizing the appropriate
      * settings for the specified brightness change.
      */
@@ -490,14 +421,14 @@
             if (mSourceType == TYPE_INT) {
                 return (int) mBrightness;
             }
-            return brightnessFloatToIntSetting(mBrightness);
+            return brightnessFloatToInt(mBrightness);
         }
 
         private float getBrightnessAsFloat() {
             if (mSourceType == TYPE_FLOAT) {
                 return mBrightness;
             }
-            return brightnessIntSettingToFloat((int) mBrightness);
+            return brightnessIntToFloat((int) mBrightness);
         }
 
         private String toStringLabel(int type, float brightness) {
diff --git a/core/java/com/android/internal/infra/TEST_MAPPING b/core/java/com/android/internal/infra/TEST_MAPPING
index ddfd0ed..c09181f 100644
--- a/core/java/com/android/internal/infra/TEST_MAPPING
+++ b/core/java/com/android/internal/infra/TEST_MAPPING
@@ -4,7 +4,7 @@
       "name": "CtsRoleTestCases",
       "options": [
           {
-              "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+              "exclude-annotation": "androidx.test.filters.FlakyTest"
           }
       ]
     },
@@ -15,7 +15,7 @@
             "include-filter": "android.permission.cts.PermissionControllerTest"
           },
           {
-            "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+            "exclude-annotation": "androidx.test.filters.FlakyTest"
           }
       ]
     },
diff --git a/core/java/com/android/internal/net/OWNERS b/core/java/com/android/internal/net/OWNERS
index 71f997b..7157683 100644
--- a/core/java/com/android/internal/net/OWNERS
+++ b/core/java/com/android/internal/net/OWNERS
@@ -1,4 +1,4 @@
 set noparent
-file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking
+file:platform/packages/modules/Connectivity:main:/OWNERS_core_networking
 
 jsharkey@android.com
diff --git a/core/java/com/android/server/net/OWNERS b/core/java/com/android/server/net/OWNERS
index 62c5737..c24680e9 100644
--- a/core/java/com/android/server/net/OWNERS
+++ b/core/java/com/android/server/net/OWNERS
@@ -1,2 +1,2 @@
 set noparent
-file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking
+file:platform/packages/modules/Connectivity:main:/OWNERS_core_networking
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 9ed4155..3795fc8 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -102,6 +102,7 @@
     static_libs: [
         "libnativehelper_lazy",
         "libziparchive_for_incfs",
+        "libguiflags",
     ],
 
     export_include_dirs: [
diff --git a/core/jni/android_graphics_SurfaceTexture.cpp b/core/jni/android_graphics_SurfaceTexture.cpp
index 21487ab..50832a5 100644
--- a/core/jni/android_graphics_SurfaceTexture.cpp
+++ b/core/jni/android_graphics_SurfaceTexture.cpp
@@ -17,27 +17,24 @@
 #undef LOG_TAG
 #define LOG_TAG "SurfaceTexture"
 
-#include <stdio.h>
-
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
-
+#include <com_android_graphics_libgui_flags.h>
+#include <cutils/atomic.h>
 #include <gui/BufferQueue.h>
 #include <gui/Surface.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedLocalRef.h>
+#include <stdio.h>
 #include <surfacetexture/SurfaceTexture.h>
 #include <surfacetexture/surface_texture_platform.h>
-
-#include "core_jni_helpers.h"
-
-#include <cutils/atomic.h>
 #include <utils/Log.h>
 #include <utils/misc.h>
 
+#include "core_jni_helpers.h"
 #include "jni.h"
-#include <nativehelper/JNIHelp.h>
-#include <nativehelper/ScopedLocalRef.h>
 
 // ----------------------------------------------------------------------------
 
@@ -55,6 +52,7 @@
     jfieldID  producer;
     jfieldID  frameAvailableListener;
     jmethodID postEvent;
+    jmethodID postOnSetFrameRateEvent;
 };
 static fields_t fields;
 
@@ -139,61 +137,81 @@
 
 // ----------------------------------------------------------------------------
 
-class JNISurfaceTextureContext : public SurfaceTexture::FrameAvailableListener
-{
+class JNISurfaceTextureContextCommon {
 public:
-    JNISurfaceTextureContext(JNIEnv* env, jobject weakThiz, jclass clazz);
-    virtual ~JNISurfaceTextureContext();
-    virtual void onFrameAvailable(const BufferItem& item);
+    JNISurfaceTextureContextCommon(JNIEnv* env, jobject weakThiz, jclass clazz)
+          : mWeakThiz(env->NewGlobalRef(weakThiz)), mClazz((jclass)env->NewGlobalRef(clazz)) {}
 
-private:
-    static JNIEnv* getJNIEnv();
+    virtual ~JNISurfaceTextureContextCommon() {
+        JNIEnv* env = getJNIEnv();
+        if (env != NULL) {
+            env->DeleteGlobalRef(mWeakThiz);
+            env->DeleteGlobalRef(mClazz);
+        } else {
+            ALOGW("leaking JNI object references");
+        }
+    }
+
+    void onFrameAvailable(const BufferItem& item) {
+        JNIEnv* env = getJNIEnv();
+        if (env != NULL) {
+            env->CallStaticVoidMethod(mClazz, fields.postEvent, mWeakThiz);
+        } else {
+            ALOGW("onFrameAvailable event will not posted");
+        }
+    }
+
+protected:
+    static JNIEnv* getJNIEnv() {
+        JNIEnv* env = AndroidRuntime::getJNIEnv();
+        if (env == NULL) {
+            JavaVMAttachArgs args = {JNI_VERSION_1_4, "JNISurfaceTextureContext", NULL};
+            JavaVM* vm = AndroidRuntime::getJavaVM();
+            int result = vm->AttachCurrentThreadAsDaemon(&env, (void*)&args);
+            if (result != JNI_OK) {
+                ALOGE("thread attach failed: %#x", result);
+                return NULL;
+            }
+        }
+        return env;
+    }
 
     jobject mWeakThiz;
     jclass mClazz;
 };
 
-JNISurfaceTextureContext::JNISurfaceTextureContext(JNIEnv* env,
-        jobject weakThiz, jclass clazz) :
-    mWeakThiz(env->NewGlobalRef(weakThiz)),
-    mClazz((jclass)env->NewGlobalRef(clazz))
-{}
+class JNISurfaceTextureContextFrameAvailableListener
+      : public JNISurfaceTextureContextCommon,
+        public SurfaceTexture::FrameAvailableListener {
+public:
+    JNISurfaceTextureContextFrameAvailableListener(JNIEnv* env, jobject weakThiz, jclass clazz)
+          : JNISurfaceTextureContextCommon(env, weakThiz, clazz) {}
+    void onFrameAvailable(const BufferItem& item) override {
+        JNISurfaceTextureContextCommon::onFrameAvailable(item);
+    }
+};
 
-JNIEnv* JNISurfaceTextureContext::getJNIEnv() {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    if (env == NULL) {
-        JavaVMAttachArgs args = {
-            JNI_VERSION_1_4, "JNISurfaceTextureContext", NULL };
-        JavaVM* vm = AndroidRuntime::getJavaVM();
-        int result = vm->AttachCurrentThreadAsDaemon(&env, (void*)&args);
-        if (result != JNI_OK) {
-            ALOGE("thread attach failed: %#x", result);
-            return NULL;
+class JNISurfaceTextureContextListener : public JNISurfaceTextureContextCommon,
+                                         public SurfaceTexture::SurfaceTextureListener {
+public:
+    JNISurfaceTextureContextListener(JNIEnv* env, jobject weakThiz, jclass clazz)
+          : JNISurfaceTextureContextCommon(env, weakThiz, clazz) {}
+
+    void onFrameAvailable(const BufferItem& item) override {
+        JNISurfaceTextureContextCommon::onFrameAvailable(item);
+    }
+
+    void onSetFrameRate(float frameRate, int8_t compatibility,
+                        int8_t changeFrameRateStrategy) override {
+        JNIEnv* env = getJNIEnv();
+        if (env != NULL) {
+            env->CallStaticVoidMethod(mClazz, fields.postOnSetFrameRateEvent, mWeakThiz, frameRate,
+                                      compatibility, changeFrameRateStrategy);
+        } else {
+            ALOGW("onSetFrameRate event will not posted");
         }
     }
-    return env;
-}
-
-JNISurfaceTextureContext::~JNISurfaceTextureContext()
-{
-    JNIEnv* env = getJNIEnv();
-    if (env != NULL) {
-        env->DeleteGlobalRef(mWeakThiz);
-        env->DeleteGlobalRef(mClazz);
-    } else {
-        ALOGW("leaking JNI object references");
-    }
-}
-
-void JNISurfaceTextureContext::onFrameAvailable(const BufferItem& /* item */)
-{
-    JNIEnv* env = getJNIEnv();
-    if (env != NULL) {
-        env->CallStaticVoidMethod(mClazz, fields.postEvent, mWeakThiz);
-    } else {
-        ALOGW("onFrameAvailable event will not posted");
-    }
-}
+};
 
 // ----------------------------------------------------------------------------
 
@@ -229,6 +247,13 @@
     if (fields.postEvent == NULL) {
         ALOGE("can't find android/graphics/SurfaceTexture.postEventFromNative");
     }
+
+    fields.postOnSetFrameRateEvent =
+            env->GetStaticMethodID(clazz, "postOnSetFrameRateEventFromNative",
+                                   "(Ljava/lang/ref/WeakReference;FII)V");
+    if (fields.postOnSetFrameRateEvent == NULL) {
+        ALOGE("can't find android/graphics/SurfaceTexture.postOnSetFrameRateEventFromNative");
+    }
 }
 
 static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jboolean isDetached,
@@ -274,17 +299,27 @@
         return;
     }
 
-    sp<JNISurfaceTextureContext> ctx(new JNISurfaceTextureContext(env, weakThiz,
-            clazz));
-    surfaceTexture->setFrameAvailableListener(ctx);
-    SurfaceTexture_setFrameAvailableListener(env, thiz, ctx);
+    if (com::android::graphics::libgui::flags::bq_setframerate()) {
+        sp<JNISurfaceTextureContextListener> ctx(
+                new JNISurfaceTextureContextListener(env, weakThiz, clazz));
+        surfaceTexture->setSurfaceTextureListener(ctx);
+    } else {
+        sp<JNISurfaceTextureContextFrameAvailableListener> ctx(
+                new JNISurfaceTextureContextFrameAvailableListener(env, weakThiz, clazz));
+        surfaceTexture->setFrameAvailableListener(ctx);
+        SurfaceTexture_setFrameAvailableListener(env, thiz, ctx);
+    }
 }
 
 static void SurfaceTexture_finalize(JNIEnv* env, jobject thiz)
 {
     sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
-    surfaceTexture->setFrameAvailableListener(0);
-    SurfaceTexture_setFrameAvailableListener(env, thiz, 0);
+    if (com::android::graphics::libgui::flags::bq_setframerate()) {
+        surfaceTexture->setSurfaceTextureListener(0);
+    } else {
+        surfaceTexture->setFrameAvailableListener(0);
+        SurfaceTexture_setFrameAvailableListener(env, thiz, 0);
+    }
     SurfaceTexture_setSurfaceTexture(env, thiz, 0);
     SurfaceTexture_setProducer(env, thiz, 0);
 }
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index c00a776f..4e073ca 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4830,7 +4830,7 @@
     <string translatable="false" name="config_deviceSpecificInputMethodManagerService"></string>
 
     <!-- Component name of media projection permission dialog -->
-    <string name="config_mediaProjectionPermissionDialogComponent" translatable="false">com.android.systemui/com.android.systemui.media.MediaProjectionPermissionActivity</string>
+    <string name="config_mediaProjectionPermissionDialogComponent" translatable="false">com.android.systemui/com.android.systemui.mediaprojection.permission.MediaProjectionPermissionActivity</string>
 
     <!-- Corner radius of system dialogs -->
     <dimen name="config_dialogCornerRadius">28dp</dimen>
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index 878e6b3..71d696e 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -172,28 +172,17 @@
     <integer name="config_satellite_nb_iot_inactivity_timeout_millis">180000</integer>
     <java-symbol type="integer" name="config_satellite_nb_iot_inactivity_timeout_millis" />
 
-    <!-- Telephony config for services supported by satellite providers. The format of each config
-         string in the array is as follows: "PLMN_1:service_1,service_2,..."
-         where PLMN is the satellite PLMN of a provider and service is an integer with the
-         following value:
-            1 = {@link android.telephony.NetworkRegistrationInfo#SERVICE_TYPE_VOICE}
-            2 = {@link android.telephony.NetworkRegistrationInfo#SERVICE_TYPE_DATA}
-            3 = {@link android.telephony.NetworkRegistrationInfo#SERVICE_TYPE_SMS}
-            4 = {@link android.telephony.NetworkRegistrationInfo#SERVICE_TYPE_VIDEO}
-            5 = {@link android.telephony.NetworkRegistrationInfo#SERVICE_TYPE_EMERGENCY}
-            6 = {@link android.telephony.NetworkRegistrationInfo#SERVICE_TYPE_MMS}
-         Example of a config string: "10011:2,3"
+    <!-- Telephony config for the PLMNs of all satellite providers. This is used by satellite modem
+         to identify providers that should be ignored if the carrier config
+         carrier_supported_satellite_services_per_provider_bundle does not support them.
+         -->
+    <string-array name="config_satellite_providers" translatable="false"></string-array>
+    <java-symbol type="array" name="config_satellite_providers" />
 
-         The PLMNs not configured in this array will be ignored and will not be used for satellite
-         scanning. -->
-    <string-array name="config_satellite_services_supported_by_providers" translatable="false">
-    </string-array>
-    <java-symbol type="array" name="config_satellite_services_supported_by_providers" />
-
-    <!-- The identifier of the satellite's eSIM profile preloaded on the device. The identifier is
-    composed of MCC and MNC of the satellite PLMN with the format "mccmnc". -->
-    <string name="config_satellite_esim_identifier" translatable="false"></string>
-    <java-symbol type="string" name="config_satellite_esim_identifier" />
+    <!-- The identifier of the satellite's SIM profile. The identifier is composed of MCC and MNC
+         of the satellite PLMN with the format "mccmnc". -->
+    <string name="config_satellite_sim_identifier" translatable="false"></string>
+    <java-symbol type="string" name="config_satellite_sim_identifier" />
 
     <!-- Whether enhanced IWLAN handover check is enabled. If enabled, telephony frameworks
          will not perform handover if the target transport is out of service, or VoPS not
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index 48dc167..7f3e014 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -69,6 +69,7 @@
 import static org.mockito.Mockito.when;
 
 import android.annotation.Nullable;
+import android.compat.testing.PlatformCompatChangeRule;
 import android.content.Context;
 import android.content.Intent;
 import android.content.LocusId;
@@ -95,16 +96,20 @@
 import android.widget.RemoteViews;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.R;
 import com.android.internal.util.ContrastColorUtil;
 
 import junit.framework.Assert;
 
+import libcore.junit.util.compat.CoreCompatChangeRule;
+
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestRule;
 import org.junit.runner.RunWith;
 
 import java.util.List;
@@ -116,6 +121,9 @@
 
     private Context mContext;
 
+    @Rule
+    public TestRule compatChangeRule = new PlatformCompatChangeRule();
+
     @Before
     public void setUp() {
         mContext = InstrumentationRegistry.getContext();
@@ -1777,6 +1785,42 @@
         assertThat(recoveredExtender.getColor()).isEqualTo(1234);
     }
 
+    @Test
+    @CoreCompatChangeRule.EnableCompatChanges({Notification.WEARABLE_EXTENDER_BACKGROUND_BLOCKED})
+    public void wearableBackgroundBlockEnabled_wearableBackgroundSet_valueRemainsNull() {
+        Notification.WearableExtender extender = new Notification.WearableExtender();
+        Bitmap bitmap = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888);
+        extender.setBackground(bitmap);
+        Notification notif =
+                new Notification.Builder(mContext, "test id")
+                        .setSmallIcon(1)
+                        .setContentTitle("test_title")
+                        .extend(extender)
+                        .build();
+
+        Notification.WearableExtender result = new Notification.WearableExtender(notif);
+        Assert.assertNull(result.getBackground());
+    }
+
+    @Test
+    @CoreCompatChangeRule.DisableCompatChanges({Notification.WEARABLE_EXTENDER_BACKGROUND_BLOCKED})
+    public void wearableBackgroundBlockDisabled_wearableBackgroundSet_valueKeepsBitmap() {
+        Notification.WearableExtender extender = new Notification.WearableExtender();
+        Bitmap bitmap = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888);
+        extender.setBackground(bitmap);
+        Notification notif =
+                new Notification.Builder(mContext, "test id")
+                        .setSmallIcon(1)
+                        .setContentTitle("test_title")
+                        .extend(extender)
+                        .build();
+
+        Notification.WearableExtender result = new Notification.WearableExtender(notif);
+        Bitmap resultBitmap = result.getBackground();
+        assertNotNull(resultBitmap);
+        Assert.assertEquals(bitmap, resultBitmap);
+    }
+
     private void assertValid(Notification.Colors c) {
         // Assert that all colors are populated
         assertThat(c.getBackgroundColor()).isNotEqualTo(Notification.COLOR_INVALID);
diff --git a/core/tests/coretests/src/android/app/servertransaction/DestroyActivityItemTest.java b/core/tests/coretests/src/android/app/servertransaction/DestroyActivityItemTest.java
new file mode 100644
index 0000000..ecd75a8
--- /dev/null
+++ b/core/tests/coretests/src/android/app/servertransaction/DestroyActivityItemTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.servertransaction;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+
+import android.app.ActivityThread.ActivityClientRecord;
+import android.app.ClientTransactionHandler;
+import android.os.IBinder;
+import android.platform.test.annotations.Presubmit;
+import android.util.ArrayMap;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for {@link DestroyActivityItem}.
+ *
+ * Build/Install/Run:
+ *  atest FrameworksCoreTests:DestroyActivityItemTest
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class DestroyActivityItemTest {
+
+    @Mock
+    private ClientTransactionHandler mHandler;
+    @Mock
+    private PendingTransactionActions mPendingActions;
+    @Mock
+    private IBinder mActivityToken;
+
+    // Can't mock final class.
+    private ActivityClientRecord mActivityClientRecord;
+
+    private ArrayMap<IBinder, DestroyActivityItem> mActivitiesToBeDestroyed;
+    private DestroyActivityItem mItem;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mItem = DestroyActivityItem.obtain(
+                mActivityToken, false /* finished */, 123 /* configChanges */);
+        mActivityClientRecord = new ActivityClientRecord();
+        mActivitiesToBeDestroyed = new ArrayMap<>();
+
+        doReturn(mActivitiesToBeDestroyed).when(mHandler).getActivitiesToBeDestroyed();
+    }
+
+    @Test
+    public void testPreExecute() {
+        mItem.preExecute(mHandler);
+
+        assertEquals(1, mActivitiesToBeDestroyed.size());
+        assertEquals(mItem, mActivitiesToBeDestroyed.get(mActivityToken));
+    }
+
+    @Test
+    public void testPostExecute() {
+        mItem.preExecute(mHandler);
+        mItem.postExecute(mHandler, mPendingActions);
+
+        assertTrue(mActivitiesToBeDestroyed.isEmpty());
+    }
+
+    @Test
+    public void testExecute() {
+        mItem.execute(mHandler, mActivityClientRecord, mPendingActions);
+
+        verify(mHandler).handleDestroyActivity(eq(mActivityClientRecord), eq(false) /* finishing */,
+                eq(123) /* configChanges */, eq(false) /* getNonConfigInstance */, any());
+    }
+}
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
index a1a2bdb..44a4d58 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
@@ -28,6 +28,7 @@
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.inOrder;
@@ -247,7 +248,7 @@
 
     @Test
     public void testDoNotLaunchDestroyedActivity() {
-        final Map<IBinder, ClientTransactionItem> activitiesToBeDestroyed = new ArrayMap<>();
+        final Map<IBinder, DestroyActivityItem> activitiesToBeDestroyed = new ArrayMap<>();
         when(mTransactionHandler.getActivitiesToBeDestroyed()).thenReturn(activitiesToBeDestroyed);
         // Assume launch transaction is still in queue, so there is no client record.
         when(mTransactionHandler.getActivityClient(any())).thenReturn(null);
@@ -259,7 +260,7 @@
                 DestroyActivityItem.obtain(token, false /* finished */, 0 /* configChanges */));
         destroyTransaction.preExecute(mTransactionHandler);
         // The activity should be added to to-be-destroyed container.
-        assertEquals(1, mTransactionHandler.getActivitiesToBeDestroyed().size());
+        assertEquals(1, activitiesToBeDestroyed.size());
 
         // A previous queued launch transaction runs on main thread (execute).
         final ClientTransaction launchTransaction = ClientTransaction.obtain(null /* client */);
@@ -274,7 +275,7 @@
 
         // After the destroy transaction has been executed, the token should be removed.
         mExecutor.execute(destroyTransaction);
-        assertEquals(0, mTransactionHandler.getActivitiesToBeDestroyed().size());
+        assertTrue(activitiesToBeDestroyed.isEmpty());
     }
 
     @Test
diff --git a/core/tests/coretests/src/android/window/flags/WindowFlagsTest.java b/core/tests/coretests/src/android/window/flags/WindowFlagsTest.java
index a8b4032..a5bbeb5 100644
--- a/core/tests/coretests/src/android/window/flags/WindowFlagsTest.java
+++ b/core/tests/coretests/src/android/window/flags/WindowFlagsTest.java
@@ -17,6 +17,7 @@
 package android.window.flags;
 
 import static com.android.window.flags.Flags.syncWindowConfigUpdateFlag;
+import static com.android.window.flags.Flags.taskFragmentSystemOrganizerFlag;
 
 import android.platform.test.annotations.Presubmit;
 
@@ -42,4 +43,10 @@
         // No crash when accessing the flag.
         syncWindowConfigUpdateFlag();
     }
+
+    @Test
+    public void testTaskFragmentSystemOrganizerFlag() {
+        // No crash when accessing the flag.
+        taskFragmentSystemOrganizerFlag();
+    }
 }
diff --git a/core/tests/vibrator/TEST_MAPPING b/core/tests/vibrator/TEST_MAPPING
index 2f3afa6..54a5ff1 100644
--- a/core/tests/vibrator/TEST_MAPPING
+++ b/core/tests/vibrator/TEST_MAPPING
@@ -4,7 +4,6 @@
       "name": "FrameworksVibratorCoreTests",
       "options": [
         {"exclude-annotation": "androidx.test.filters.LargeTest"},
-        {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
         {"exclude-annotation": "androidx.test.filters.FlakyTest"},
         {"exclude-annotation": "org.junit.Ignore"}
       ]
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index dfe5012..dd82fed 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -16,6 +16,7 @@
 
 package android.graphics;
 
+import android.annotation.FloatRange;
 import android.annotation.Nullable;
 import android.annotation.SuppressLint;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -24,8 +25,10 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Trace;
 import android.view.Surface;
 import android.view.TextureView;
+import android.view.flags.Flags;
 
 import java.lang.ref.WeakReference;
 
@@ -79,6 +82,7 @@
     private final Looper mCreatorLooper;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     private Handler mOnFrameAvailableHandler;
+    private Handler mOnSetFrameRateHandler;
 
     /**
      * These fields are used by native code, do not access or modify.
@@ -100,6 +104,21 @@
     }
 
     /**
+     * Callback interface for being notified that a producer set a frame rate
+     * @hide
+     */
+    public interface OnSetFrameRateListener {
+        /**
+         * Called when the producer sets a frame rate
+         * @hide
+         */
+        void onSetFrameRate(SurfaceTexture surfaceTexture,
+                            @FloatRange(from = 0.0) float frameRate,
+                                 @Surface.FrameRateCompatibility int compatibility,
+                                 @Surface.ChangeFrameRateStrategy int changeFrameRateStrategy);
+    }
+
+    /**
      * Exception thrown when a SurfaceTexture couldn't be created or resized.
      *
      * @deprecated No longer thrown. {@link android.view.Surface.OutOfResourcesException}
@@ -224,6 +243,48 @@
         }
     }
 
+    private static class SetFrameRateArgs {
+        SetFrameRateArgs(@FloatRange(from = 0.0) float frameRate,
+                                @Surface.FrameRateCompatibility int compatibility,
+                   @Surface.ChangeFrameRateStrategy int changeFrameRateStrategy) {
+            this.mFrameRate = frameRate;
+            this.mCompatibility = compatibility;
+            this.mChangeFrameRateStrategy = changeFrameRateStrategy;
+        }
+        final float mFrameRate;
+        final int mCompatibility;
+        final int mChangeFrameRateStrategy;
+    }
+
+    /**
+     * Register a callback to be invoked when the producer sets a frame rate using
+     * Surface.setFrameRate.
+     * @hide
+     */
+    public void setOnSetFrameRateListener(@Nullable final OnSetFrameRateListener listener,
+                                            @Nullable Handler handler) {
+        if (listener != null) {
+            Looper looper = handler != null ? handler.getLooper() :
+                    mCreatorLooper != null ? mCreatorLooper : Looper.getMainLooper();
+            mOnSetFrameRateHandler = new Handler(looper, null, true /*async*/) {
+                @Override
+                public void handleMessage(Message msg) {
+                    Trace.traceBegin(Trace.TRACE_TAG_VIEW, "onSetFrameRateHandler");
+                    try {
+                        SetFrameRateArgs args = (SetFrameRateArgs) msg.obj;
+                        listener.onSetFrameRate(SurfaceTexture.this,
+                                args.mFrameRate, args.mCompatibility,
+                                args.mChangeFrameRateStrategy);
+                    } finally {
+                        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+                    }
+                }
+            };
+        } else {
+            mOnSetFrameRateHandler = null;
+        }
+    }
+
     /**
      * Set the default size of the image buffers.  The image producer may override the buffer size,
      * in which case the producer-set buffer size will be used, not the default size set by this
@@ -418,6 +479,35 @@
     }
 
     /**
+     * This method is invoked from native code only.
+     * @hide
+     */
+    @SuppressWarnings({"UnusedDeclaration"})
+    private static void postOnSetFrameRateEventFromNative(WeakReference<SurfaceTexture> weakSelf,
+            @FloatRange(from = 0.0) float frameRate,
+            @Surface.FrameRateCompatibility int compatibility,
+            @Surface.ChangeFrameRateStrategy int changeFrameRateStrategy) {
+        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "postOnSetFrameRateEventFromNative");
+        try {
+            if (Flags.toolkitSetFrameRate()) {
+                SurfaceTexture st = weakSelf.get();
+                if (st != null) {
+                    Handler handler = st.mOnSetFrameRateHandler;
+                    if (handler != null) {
+                        Message msg = new Message();
+                        msg.obj = new SetFrameRateArgs(frameRate, compatibility,
+                                changeFrameRateStrategy);
+                        handler.sendMessage(msg);
+                    }
+                }
+            }
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+        }
+
+    }
+
+    /**
      * Returns {@code true} if the SurfaceTexture is single-buffered.
      * @hide
      */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 3d825f0..4ea14f4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -720,6 +720,8 @@
         mSplitLayout.setDivideRatio(snapPosition);
         updateWindowBounds(mSplitLayout, wct);
         wct.reorder(mRootTaskInfo.token, true);
+        wct.setReparentLeafTaskIfRelaunch(mRootTaskInfo.token,
+                false /* reparentLeafTaskIfRelaunch */);
         setRootForceTranslucent(false, wct);
 
         // Make sure the launch options will put tasks in the corresponding split roots
@@ -767,6 +769,8 @@
         mSplitLayout.setDivideRatio(snapPosition);
         updateWindowBounds(mSplitLayout, wct);
         wct.reorder(mRootTaskInfo.token, true);
+        wct.setReparentLeafTaskIfRelaunch(mRootTaskInfo.token,
+                false /* reparentLeafTaskIfRelaunch */);
         setRootForceTranslucent(false, wct);
 
         options1 = options1 != null ? options1 : new Bundle();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java
index 6ea6516..72fc8686 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java
@@ -30,7 +30,7 @@
 import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK;
 import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING;
 import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH;
-import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_ICON;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_USE_SOLID_COLOR_SPLASH_SCREEN;
 import static android.window.StartingWindowInfo.TYPE_PARAMETER_WINDOWLESS;
 
 import android.window.StartingWindowInfo;
@@ -52,7 +52,8 @@
         final boolean processRunning = (parameter & TYPE_PARAMETER_PROCESS_RUNNING) != 0;
         final boolean allowTaskSnapshot = (parameter & TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT) != 0;
         final boolean activityCreated = (parameter & TYPE_PARAMETER_ACTIVITY_CREATED) != 0;
-        final boolean allowIcon = (parameter & TYPE_PARAMETER_ALLOW_ICON) != 0;
+        final boolean isSolidColorSplashScreen =
+                (parameter & TYPE_PARAMETER_USE_SOLID_COLOR_SPLASH_SCREEN) != 0;
         final boolean legacySplashScreen =
                 ((parameter & TYPE_PARAMETER_LEGACY_SPLASH_SCREEN) != 0);
         final boolean activityDrawn = (parameter & TYPE_PARAMETER_ACTIVITY_DRAWN) != 0;
@@ -66,13 +67,13 @@
                         + "processRunning=%b, "
                         + "allowTaskSnapshot=%b, "
                         + "activityCreated=%b, "
-                        + "allowIcon=%b, "
+                        + "isSolidColorSplashScreen=%b, "
                         + "legacySplashScreen=%b, "
                         + "activityDrawn=%b, "
                         + "windowless=%b, "
                         + "topIsHome=%b",
                 newTask, taskSwitch, processRunning, allowTaskSnapshot, activityCreated,
-                allowIcon, legacySplashScreen, activityDrawn, windowlessSurface,
+                isSolidColorSplashScreen, legacySplashScreen, activityDrawn, windowlessSurface,
                 topIsHome);
 
         if (windowlessSurface) {
@@ -80,7 +81,7 @@
         }
         if (!topIsHome) {
             if (!processRunning || newTask || (taskSwitch && !activityCreated)) {
-                return getSplashscreenType(allowIcon, legacySplashScreen);
+                return getSplashscreenType(isSolidColorSplashScreen, legacySplashScreen);
             }
         }
 
@@ -94,18 +95,18 @@
                 }
             }
             if (!activityDrawn && !topIsHome) {
-                return getSplashscreenType(allowIcon, legacySplashScreen);
+                return getSplashscreenType(isSolidColorSplashScreen, legacySplashScreen);
             }
         }
         return STARTING_WINDOW_TYPE_NONE;
     }
 
-    private static int getSplashscreenType(boolean allowIcon, boolean legacySplashScreen) {
-        if (allowIcon) {
-            return legacySplashScreen ? STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN
+    private static int getSplashscreenType(boolean solidColorSplashScreen,
+            boolean legacySplashScreen) {
+        return solidColorSplashScreen
+                ? STARTING_WINDOW_TYPE_SOLID_COLOR_SPLASH_SCREEN
+                : legacySplashScreen
+                        ? STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN
                         : STARTING_WINDOW_TYPE_SPLASH_SCREEN;
-        } else {
-            return STARTING_WINDOW_TYPE_SOLID_COLOR_SPLASH_SCREEN;
-        }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt
index b444bad..b0e847f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt
@@ -26,7 +26,7 @@
 
 open class CopyContentInSplitGesturalNavLandscape : CopyContentInSplit(Rotation.ROTATION_90) {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt
index e2ab989..f847e40 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt
@@ -26,7 +26,7 @@
 
 open class CopyContentInSplitGesturalNavPortrait : CopyContentInSplit(Rotation.ROTATION_0) {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt
index 22b8102..31e52e2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt
@@ -27,7 +27,7 @@
 open class DismissSplitScreenByDividerGesturalNavLandscape :
     DismissSplitScreenByDivider(Rotation.ROTATION_90) {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt
index 3fb014f..0870073 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt
@@ -27,7 +27,7 @@
 open class DismissSplitScreenByDividerGesturalNavPortrait :
     DismissSplitScreenByDivider(Rotation.ROTATION_0) {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt
index ea1f942..1bb6c45 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt
@@ -27,7 +27,7 @@
 open class DismissSplitScreenByGoHomeGesturalNavLandscape :
     DismissSplitScreenByGoHome(Rotation.ROTATION_90) {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt
index 8f23a79..bb084d6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt
@@ -27,7 +27,7 @@
 open class DismissSplitScreenByGoHomeGesturalNavPortrait :
     DismissSplitScreenByGoHome(Rotation.ROTATION_0) {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt
index b0f39e5..bc5857f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt
@@ -26,7 +26,7 @@
 
 open class DragDividerToResizeGesturalNavLandscape : DragDividerToResize(Rotation.ROTATION_90) {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt
index 6ce8746..e4faa4a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt
@@ -26,7 +26,7 @@
 
 open class DragDividerToResizeGesturalNavPortrait : DragDividerToResize(Rotation.ROTATION_0) {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt
index 9f74edf..7431974 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt
@@ -27,7 +27,7 @@
 open class EnterSplitScreenByDragFromAllAppsGesturalNavLandscape :
     EnterSplitScreenByDragFromAllApps(Rotation.ROTATION_90) {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt
index 1e4055e..c2b0609 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt
@@ -27,7 +27,7 @@
 open class EnterSplitScreenByDragFromAllAppsGesturalNavPortrait :
     EnterSplitScreenByDragFromAllApps(Rotation.ROTATION_0) {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt
index c3b8132..7d1072d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt
@@ -27,7 +27,7 @@
 open class EnterSplitScreenByDragFromNotificationGesturalNavLandscape :
     EnterSplitScreenByDragFromNotification(Rotation.ROTATION_90) {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt
index 7756d04..79760d1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt
@@ -27,7 +27,7 @@
 open class EnterSplitScreenByDragFromNotificationGesturalNavPortrait :
     EnterSplitScreenByDragFromNotification(Rotation.ROTATION_0) {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt
index c72aa5a..ff3729a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt
@@ -27,7 +27,7 @@
 open class EnterSplitScreenByDragFromShortcutGesturalNavLandscape :
     EnterSplitScreenByDragFromShortcut(Rotation.ROTATION_90) {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt
index cc88f27..ffbcfe4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt
@@ -27,7 +27,7 @@
 open class EnterSplitScreenByDragFromShortcutGesturalNavPortrait :
     EnterSplitScreenByDragFromShortcut(Rotation.ROTATION_0) {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt
index 87b38b1..5e937c0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt
@@ -27,7 +27,7 @@
 open class EnterSplitScreenByDragFromTaskbarGesturalNavLandscape :
     EnterSplitScreenByDragFromTaskbar(Rotation.ROTATION_90) {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt
index ca347ed..89db8a0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt
@@ -27,7 +27,7 @@
 open class EnterSplitScreenByDragFromTaskbarGesturalNavPortrait :
     EnterSplitScreenByDragFromTaskbar(Rotation.ROTATION_0) {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt
index 6597819..bf4ee7a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt
@@ -27,7 +27,7 @@
 open class EnterSplitScreenFromOverviewGesturalNavLandscape :
     EnterSplitScreenFromOverview(Rotation.ROTATION_90) {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt
index 6df31fc..7e96f06 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt
@@ -27,7 +27,7 @@
 open class EnterSplitScreenFromOverviewGesturalNavPortrait :
     EnterSplitScreenFromOverview(Rotation.ROTATION_0) {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt
index 02596c5..a84deac 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt
@@ -27,7 +27,7 @@
 open class SwitchAppByDoubleTapDividerGesturalNavLandscape :
     SwitchAppByDoubleTapDivider(Rotation.ROTATION_90) {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt
index 9d579f6..afcc743 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt
@@ -27,7 +27,7 @@
 open class SwitchAppByDoubleTapDividerGesturalNavPortrait :
     SwitchAppByDoubleTapDivider(Rotation.ROTATION_0) {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt
index da85342..2f96f5f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt
@@ -27,7 +27,7 @@
 open class SwitchBackToSplitFromAnotherAppGesturalNavLandscape :
     SwitchBackToSplitFromAnotherApp(Rotation.ROTATION_90) {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt
index 1ae2c9e..efbeb76 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt
@@ -27,7 +27,7 @@
 open class SwitchBackToSplitFromAnotherAppGesturalNavPortrait :
     SwitchBackToSplitFromAnotherApp(Rotation.ROTATION_0) {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt
index b1b56257..232fccc 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt
@@ -27,7 +27,7 @@
 open class SwitchBackToSplitFromHomeGesturalNavLandscape :
     SwitchBackToSplitFromHome(Rotation.ROTATION_90) {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt
index 08c437e..d7f2845 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt
@@ -27,7 +27,7 @@
 open class SwitchBackToSplitFromHomeGesturalNavPortrait :
     SwitchBackToSplitFromHome(Rotation.ROTATION_0) {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt
index efbf86d..019c946 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt
@@ -27,7 +27,7 @@
 open class SwitchBackToSplitFromRecentGesturalNavLandscape :
     SwitchBackToSplitFromRecent(Rotation.ROTATION_90) {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt
index f7072fa..5678861 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt
@@ -27,7 +27,7 @@
 open class SwitchBackToSplitFromRecentGesturalNavPortrait :
     SwitchBackToSplitFromRecent(Rotation.ROTATION_0) {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt
index d80d112..b3c4ea2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt
@@ -27,7 +27,7 @@
 open class SwitchBetweenSplitPairsGesturalNavLandscape :
     SwitchBetweenSplitPairs(Rotation.ROTATION_90) {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt
index 30ec37a..f88180f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt
@@ -27,7 +27,7 @@
 open class SwitchBetweenSplitPairsGesturalNavPortrait :
     SwitchBetweenSplitPairs(Rotation.ROTATION_0) {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt
index 1e086d2..391cb9b7 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt
@@ -28,7 +28,7 @@
 @RunWith(BlockJUnit4ClassRunner::class)
 open class UnlockKeyguardToSplitScreenGesturalNavLandscape : UnlockKeyguardToSplitScreen() {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt
index 932f892..4af133d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/platinum/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt
@@ -28,7 +28,7 @@
 @RunWith(BlockJUnit4ClassRunner::class)
 open class UnlockKeyguardToSplitScreenGesturalNavPortrait : UnlockKeyguardToSplitScreen() {
     @get:Rule
-    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFaasFailure = false)
+    val flickerServiceRule = FlickerServiceRule(enabled = true, failTestOnFlicker = false)
 
     @PlatinumTest(focusArea = "sysui")
     @Presubmit
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 664fbb2..f2c29f4 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
@@ -180,7 +180,8 @@
 
         controller.showDesktopApps(DEFAULT_DISPLAY, RemoteTransition(TestRemoteTransition()))
 
-        val wct = getLatestWct(type = TRANSIT_OPEN, handlerClass = OneShotRemoteHandler::class.java)
+        val wct =
+            getLatestWct(type = TRANSIT_TO_FRONT, handlerClass = OneShotRemoteHandler::class.java)
         assertThat(wct.hierarchyOps).hasSize(3)
         // Expect order to be from bottom: home, task1, task2
         wct.assertReorderAt(index = 0, homeTask)
@@ -198,7 +199,8 @@
 
         controller.showDesktopApps(DEFAULT_DISPLAY, RemoteTransition(TestRemoteTransition()))
 
-        val wct = getLatestWct(type = TRANSIT_OPEN, handlerClass = OneShotRemoteHandler::class.java)
+        val wct =
+            getLatestWct(type = TRANSIT_TO_FRONT, handlerClass = OneShotRemoteHandler::class.java)
         assertThat(wct.hierarchyOps).hasSize(3)
         // Expect order to be from bottom: home, task1, task2
         wct.assertReorderAt(index = 0, homeTask)
@@ -216,7 +218,8 @@
 
         controller.showDesktopApps(DEFAULT_DISPLAY, RemoteTransition(TestRemoteTransition()))
 
-        val wct = getLatestWct(type = TRANSIT_OPEN, handlerClass = OneShotRemoteHandler::class.java)
+        val wct =
+            getLatestWct(type = TRANSIT_TO_FRONT, handlerClass = OneShotRemoteHandler::class.java)
         assertThat(wct.hierarchyOps).hasSize(3)
         // Expect order to be from bottom: home, task1, task2
         wct.assertReorderAt(index = 0, homeTask)
@@ -230,7 +233,8 @@
 
         controller.showDesktopApps(DEFAULT_DISPLAY, RemoteTransition(TestRemoteTransition()))
 
-        val wct = getLatestWct(type = TRANSIT_OPEN, handlerClass = OneShotRemoteHandler::class.java)
+        val wct =
+            getLatestWct(type = TRANSIT_TO_FRONT, handlerClass = OneShotRemoteHandler::class.java)
         assertThat(wct.hierarchyOps).hasSize(1)
         wct.assertReorderAt(index = 0, homeTask)
     }
@@ -246,7 +250,8 @@
 
         controller.showDesktopApps(DEFAULT_DISPLAY, RemoteTransition(TestRemoteTransition()))
 
-        val wct = getLatestWct(type = TRANSIT_OPEN, handlerClass = OneShotRemoteHandler::class.java)
+        val wct =
+            getLatestWct(type = TRANSIT_TO_FRONT, handlerClass = OneShotRemoteHandler::class.java)
         assertThat(wct.hierarchyOps).hasSize(2)
         // Expect order to be from bottom: home, task
         wct.assertReorderAt(index = 0, homeTaskDefaultDisplay)
diff --git a/libs/hwui/jni/Gainmap.cpp b/libs/hwui/jni/Gainmap.cpp
index cec0ee7..0fffee7 100644
--- a/libs/hwui/jni/Gainmap.cpp
+++ b/libs/hwui/jni/Gainmap.cpp
@@ -208,8 +208,6 @@
     p.writeFloat(info.fDisplayRatioHdr);
     // base image type
     p.writeInt32(static_cast<int32_t>(info.fBaseImageType));
-    // type
-    p.writeInt32(static_cast<int32_t>(info.fType));
 #else
     doThrowRE(env, "Cannot use parcels outside of Android!");
 #endif
@@ -232,7 +230,6 @@
     info.fDisplayRatioSdr = p.readFloat();
     info.fDisplayRatioHdr = p.readFloat();
     info.fBaseImageType = static_cast<SkGainmapInfo::BaseImageType>(p.readInt32());
-    info.fType = static_cast<SkGainmapInfo::Type>(p.readInt32());
 
     fromJava(nativeObject)->info = info;
 #else
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 94ed06c..f76ea06 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -17,6 +17,7 @@
 #include "RenderThread.h"
 
 #include <GrContextOptions.h>
+#include <include/gpu/ganesh/gl/GrGLDirectContext.h>
 #include <android-base/properties.h>
 #include <dlfcn.h>
 #include <gl/GrGLInterface.h>
@@ -286,7 +287,7 @@
     auto glesVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));
     auto size = glesVersion ? strlen(glesVersion) : -1;
     cacheManager().configureContext(&options, glesVersion, size);
-    sk_sp<GrDirectContext> grContext(GrDirectContext::MakeGL(std::move(glInterface), options));
+    sk_sp<GrDirectContext> grContext(GrDirectContexts::MakeGL(std::move(glInterface), options));
     LOG_ALWAYS_FATAL_IF(!grContext.get());
     setGrContext(grContext);
 }
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index b0cdb05..230fb07 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -1167,7 +1167,10 @@
                                 streamType);
                 if (attributes != null) {
                     mUsage = attributes.mUsage;
-                    mContentType = attributes.mContentType;
+                    // on purpose ignoring the content type: stream types are deprecated for
+                    // playback, making assumptions about the content type is prone to
+                    // interpretation errors for ambiguous types such as STREAM_TTS and STREAM_MUSIC
+                    //mContentType = attributes.mContentType;
                     mFlags = attributes.getAllFlags();
                     mMuteHapticChannels = attributes.areHapticChannelsMuted();
                     mIsContentSpatialized = attributes.isContentSpatialized();
@@ -1177,49 +1180,47 @@
                     mSource = attributes.mSource;
                 }
             }
-            if (mContentType == CONTENT_TYPE_UNKNOWN) {
-                switch (streamType) {
-                    case AudioSystem.STREAM_VOICE_CALL:
-                        mContentType = CONTENT_TYPE_SPEECH;
-                        break;
-                    case AudioSystem.STREAM_SYSTEM_ENFORCED:
-                        mFlags |= FLAG_AUDIBILITY_ENFORCED;
-                        // intended fall through, attributes in common with STREAM_SYSTEM
-                    case AudioSystem.STREAM_SYSTEM:
-                        mContentType = CONTENT_TYPE_SONIFICATION;
-                        break;
-                    case AudioSystem.STREAM_RING:
-                        mContentType = CONTENT_TYPE_SONIFICATION;
-                        break;
-                    case AudioSystem.STREAM_MUSIC:
-                        mContentType = CONTENT_TYPE_MUSIC;
-                        break;
-                    case AudioSystem.STREAM_ALARM:
-                        mContentType = CONTENT_TYPE_SONIFICATION;
-                        break;
-                    case AudioSystem.STREAM_NOTIFICATION:
-                        mContentType = CONTENT_TYPE_SONIFICATION;
-                        break;
-                    case AudioSystem.STREAM_BLUETOOTH_SCO:
-                        mContentType = CONTENT_TYPE_SPEECH;
-                        mFlags |= FLAG_SCO;
-                        break;
-                    case AudioSystem.STREAM_DTMF:
-                        mContentType = CONTENT_TYPE_SONIFICATION;
-                        break;
-                    case AudioSystem.STREAM_TTS:
-                        mContentType = CONTENT_TYPE_SONIFICATION;
-                        mFlags |= FLAG_BEACON;
-                        break;
-                    case AudioSystem.STREAM_ACCESSIBILITY:
-                        mContentType = CONTENT_TYPE_SPEECH;
-                        break;
-                    case AudioSystem.STREAM_ASSISTANT:
-                        mContentType = CONTENT_TYPE_SPEECH;
-                        break;
-                    default:
-                        Log.e(TAG, "Invalid stream type " + streamType + " for AudioAttributes");
-                }
+            switch (streamType) {
+                case AudioSystem.STREAM_VOICE_CALL:
+                    mContentType = CONTENT_TYPE_SPEECH;
+                    break;
+                case AudioSystem.STREAM_SYSTEM_ENFORCED:
+                    mFlags |= FLAG_AUDIBILITY_ENFORCED;
+                    // intended fall through, attributes in common with STREAM_SYSTEM
+                case AudioSystem.STREAM_SYSTEM:
+                    mContentType = CONTENT_TYPE_SONIFICATION;
+                    break;
+                case AudioSystem.STREAM_RING:
+                    mContentType = CONTENT_TYPE_SONIFICATION;
+                    break;
+                case AudioSystem.STREAM_ALARM:
+                    mContentType = CONTENT_TYPE_SONIFICATION;
+                    break;
+                case AudioSystem.STREAM_NOTIFICATION:
+                    mContentType = CONTENT_TYPE_SONIFICATION;
+                    break;
+                case AudioSystem.STREAM_BLUETOOTH_SCO:
+                    mContentType = CONTENT_TYPE_SPEECH;
+                    mFlags |= FLAG_SCO;
+                    break;
+                case AudioSystem.STREAM_DTMF:
+                    mContentType = CONTENT_TYPE_SONIFICATION;
+                    break;
+                case AudioSystem.STREAM_TTS:
+                    mContentType = CONTENT_TYPE_SONIFICATION;
+                    mFlags |= FLAG_BEACON;
+                    break;
+                case AudioSystem.STREAM_ACCESSIBILITY:
+                    mContentType = CONTENT_TYPE_SPEECH;
+                    break;
+                case AudioSystem.STREAM_ASSISTANT:
+                    mContentType = CONTENT_TYPE_SPEECH;
+                    break;
+                case AudioSystem.STREAM_MUSIC:
+                    // leaving as CONTENT_TYPE_UNKNOWN
+                    break;
+                default:
+                    Log.e(TAG, "Invalid stream type " + streamType + " for AudioAttributes");
             }
             if (mUsage == USAGE_UNKNOWN) {
                 mUsage = usageForStreamType(streamType);
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index f9ea773..49bd9d9 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -345,6 +345,8 @@
     <string name="accessibility_wifi_three_bars">Wifi three bars.</string>
     <!-- Content description of the WIFI signal when it is full for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_wifi_signal_full">Wifi signal full.</string>
+    <!-- Content description of the WIFI signal when the WIFI is connected using the signal from a different device owned by the user. For accessibility (not shown on the screen) [CHAR LIMIT=NONE] -->
+    <string name="accessibility_wifi_other_device">Connected to your device.</string>
 
     <!-- Content description of the Wi-Fi security type. This message indicates this is an open Wi-Fi (no password needed) [CHAR LIMIT=NONE] -->
     <string name="accessibility_wifi_security_type_none">Open network</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/AccessibilityContentDescriptions.java b/packages/SettingsLib/src/com/android/settingslib/AccessibilityContentDescriptions.java
index ee65ef4..ce466df 100644
--- a/packages/SettingsLib/src/com/android/settingslib/AccessibilityContentDescriptions.java
+++ b/packages/SettingsLib/src/com/android/settingslib/AccessibilityContentDescriptions.java
@@ -50,6 +50,7 @@
     };
 
     public static final int WIFI_NO_CONNECTION = R.string.accessibility_no_wifi;
+    public static final int WIFI_OTHER_DEVICE_CONNECTION = R.string.accessibility_wifi_other_device;
 
     public static final int NO_CALLING = R.string.accessibility_no_calling;
 
diff --git a/packages/SettingsLib/tests/integ/AndroidManifest.xml b/packages/SettingsLib/tests/integ/AndroidManifest.xml
index a95da303..32048ca 100644
--- a/packages/SettingsLib/tests/integ/AndroidManifest.xml
+++ b/packages/SettingsLib/tests/integ/AndroidManifest.xml
@@ -41,7 +41,7 @@
     </application>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
-        android:targetPackage="com.android.settingslib"
+        android:targetPackage="com.android.settingslib.tests.integ"
         android:label="Tests for SettingsLib">
     </instrumentation>
 </manifest>
diff --git a/packages/SettingsLib/tests/integ/AndroidTest.xml b/packages/SettingsLib/tests/integ/AndroidTest.xml
index b5d0947..d0aee88 100644
--- a/packages/SettingsLib/tests/integ/AndroidTest.xml
+++ b/packages/SettingsLib/tests/integ/AndroidTest.xml
@@ -21,7 +21,7 @@
     <option name="test-suite-tag" value="apct" />
     <option name="test-tag" value="SettingsLibTests" />
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
-        <option name="package" value="com.android.settingslib" />
+        <option name="package" value="com.android.settingslib.tests.integ" />
         <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
         <option name="hidden-api-checks" value="false"/>
     </test>
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 1c33544..f6f75de 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -143,6 +143,7 @@
         Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
         Settings.Secure.SCREENSAVER_HOME_CONTROLS_ENABLED,
         Settings.Secure.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
+        Settings.Secure.VOLUME_DIALOG_DISMISS_TIMEOUT,
         Settings.Secure.VOLUME_HUSH_GESTURE,
         Settings.Secure.MANUAL_RINGER_TOGGLE_COUNT,
         Settings.Secure.LOW_POWER_WARNING_ACKNOWLEDGED,
@@ -243,6 +244,7 @@
         Settings.Secure.HEARING_AID_SYSTEM_SOUNDS_ROUTING,
         Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED,
         Settings.Secure.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED,
-        Settings.Secure.SEARCH_LONG_PRESS_HOME_ENABLED
+        Settings.Secure.SEARCH_LONG_PRESS_HOME_ENABLED,
+        Settings.Secure.HUB_MODE_TUTORIAL_STATE
     };
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 301fd6f..8d13f01 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -212,6 +212,7 @@
         VALIDATORS.put(Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.SCREENSAVER_HOME_CONTROLS_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.VOLUME_DIALOG_DISMISS_TIMEOUT, NON_NEGATIVE_INTEGER_VALIDATOR);
         VALIDATORS.put(Secure.VOLUME_HUSH_GESTURE, NON_NEGATIVE_INTEGER_VALIDATOR);
         VALIDATORS.put(
                 Secure.ENABLED_NOTIFICATION_LISTENERS,
@@ -389,5 +390,6 @@
         VALIDATORS.put(Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_EDGE_HAPTIC_ENABLED,
                 BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.DND_CONFIGS_MIGRATED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.HUB_MODE_TUTORIAL_STATE, NON_NEGATIVE_INTEGER_VALIDATOR);
     }
 }
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index b5b873c..9bfc4be 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -634,7 +634,7 @@
 
         <!-- started from MediaProjectionManager -->
         <activity
-            android:name=".media.MediaProjectionPermissionActivity"
+            android:name=".mediaprojection.permission.MediaProjectionPermissionActivity"
             android:exported="true"
             android:theme="@style/Theme.SystemUI.MediaProjectionAlertDialog"
             android:finishOnCloseSystemDialogs="true"
@@ -643,7 +643,7 @@
             android:visibleToInstantApps="true"/>
 
         <activity
-            android:name=".media.MediaProjectionAppSelectorActivity"
+            android:name=".mediaprojection.appselector.MediaProjectionAppSelectorActivity"
             android:theme="@style/Theme.SystemUI.MediaProjectionAppSelector"
             android:finishOnCloseSystemDialogs="true"
             android:excludeFromRecents="true"
diff --git a/packages/SystemUI/compose/core/Android.bp b/packages/SystemUI/compose/core/Android.bp
index 510fa1e..42d088f 100644
--- a/packages/SystemUI/compose/core/Android.bp
+++ b/packages/SystemUI/compose/core/Android.bp
@@ -34,7 +34,9 @@
 
         "androidx.compose.runtime_runtime",
         "androidx.compose.material3_material3",
+        "androidx.compose.material3_material3-window-size-class",
         "androidx.savedstate_savedstate",
+        "androidx.window_window",
     ],
 
     kotlincflags: ["-Xjvm-default=all"],
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Element.kt
index 0cc259a..a62c984 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Element.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Element.kt
@@ -151,7 +151,7 @@
                 element.lastAlpha = alpha
             }
         }
-        .testTag(key.name)
+        .testTag(key.testTag)
 }
 
 private fun shouldDrawElement(
@@ -167,7 +167,8 @@
             state.fromScene == state.toScene ||
             !layoutImpl.isTransitionReady(state) ||
             state.fromScene !in element.sceneValues ||
-            state.toScene !in element.sceneValues
+            state.toScene !in element.sceneValues ||
+            !isSharedElementEnabled(layoutImpl, state, element.key)
     ) {
         return true
     }
@@ -191,6 +192,26 @@
     }
 }
 
+private fun isSharedElementEnabled(
+    layoutImpl: SceneTransitionLayoutImpl,
+    transition: TransitionState.Transition,
+    element: ElementKey,
+): Boolean {
+    val spec = layoutImpl.transitions.transitionSpec(transition.fromScene, transition.toScene)
+    val sharedInFromScene = spec.transformations(element, transition.fromScene).shared
+    val sharedInToScene = spec.transformations(element, transition.toScene).shared
+
+    // The sharedElement() transformation must either be null or be the same in both scenes.
+    if (sharedInFromScene != sharedInToScene) {
+        error(
+            "Different sharedElement() transformations matched $element (from=$sharedInFromScene " +
+                "to=$sharedInToScene)"
+        )
+    }
+
+    return sharedInFromScene?.enabled ?: true
+}
+
 /**
  * Chain the [com.android.compose.animation.scene.transformation.ModifierTransformation] applied
  * throughout the current transition, if any.
@@ -213,7 +234,7 @@
 
             return layoutImpl.transitions
                 .transitionSpec(fromScene, state.toScene)
-                .transformations(element.key)
+                .transformations(element.key, scene.key)
                 .modifier
                 .fold(this) { modifier, transformation ->
                     with(transformation) {
@@ -407,17 +428,20 @@
     // The element is shared: interpolate between the value in fromScene and the value in toScene.
     // TODO(b/290184746): Support non linear shared paths as well as a way to make sure that shared
     // elements follow the finger direction.
-    if (fromValues != null && toValues != null) {
+    val isSharedElement = fromValues != null && toValues != null
+    if (isSharedElement && isSharedElementEnabled(layoutImpl, state, element.key)) {
         return lerp(
-            sceneValue(fromValues),
-            sceneValue(toValues),
+            sceneValue(fromValues!!),
+            sceneValue(toValues!!),
             transitionProgress,
         )
     }
 
     val transformation =
         transformation(
-            layoutImpl.transitions.transitionSpec(fromScene, toScene).transformations(element.key)
+            layoutImpl.transitions
+                .transitionSpec(fromScene, toScene)
+                .transformations(element.key, scene.key)
         )
         // If there is no transformation explicitly associated to this element value, let's use
         // the value given by the system (like the current position and size given by the layout
@@ -426,12 +450,21 @@
 
     // Get the transformed value, i.e. the target value at the beginning (for entering elements) or
     // end (for leaving elements) of the transition.
+    val sceneValues =
+        checkNotNull(
+            when {
+                isSharedElement && scene.key == fromScene -> fromValues
+                isSharedElement -> toValues
+                else -> fromValues ?: toValues
+            }
+        )
+
     val targetValue =
         transformation.transform(
             layoutImpl,
             scene,
             element,
-            fromValues ?: toValues!!,
+            sceneValues,
             state,
             idleValue,
         )
@@ -440,7 +473,7 @@
     val rangeProgress = transformation.range?.progress(transitionProgress) ?: transitionProgress
 
     // Interpolate between the value at rest and the value before entering/after leaving.
-    val isEntering = fromValues == null
+    val isEntering = scene.key == toScene
     return if (isEntering) {
         lerp(targetValue, idleValue, rangeProgress)
     } else {
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/ElementMatcher.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/ElementMatcher.kt
new file mode 100644
index 0000000..98dbb67
--- /dev/null
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/ElementMatcher.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compose.animation.scene
+
+/** An interface to match one or more elements. */
+interface ElementMatcher {
+    /** Whether the element with key [key] in scene [scene] matches this matcher. */
+    fun matches(key: ElementKey, scene: SceneKey): Boolean
+}
+
+/**
+ * Returns an [ElementMatcher] that matches elements in [scene] also matching [this]
+ * [ElementMatcher].
+ */
+fun ElementMatcher.inScene(scene: SceneKey): ElementMatcher {
+    val delegate = this
+    val matcherScene = scene
+    return object : ElementMatcher {
+        override fun matches(key: ElementKey, scene: SceneKey): Boolean {
+            return scene == matcherScene && delegate.matches(key, scene)
+        }
+    }
+}
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Key.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Key.kt
index f7ebe2f..b7acc48 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Key.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Key.kt
@@ -16,6 +16,8 @@
 
 package com.android.compose.animation.scene
 
+import androidx.annotation.VisibleForTesting
+
 /**
  * A base class to create unique keys, associated to an [identity] that is used to check the
  * equality of two key instances.
@@ -41,6 +43,7 @@
     name: String,
     identity: Any = Object(),
 ) : Key(name, identity) {
+    @VisibleForTesting val testTag: String = "scene:$name"
 
     /** The unique [ElementKey] identifying this scene's root element. */
     val rootElementKey = ElementKey(name, identity)
@@ -61,7 +64,9 @@
      */
     val isBackground: Boolean = false,
 ) : Key(name, identity), ElementMatcher {
-    override fun matches(key: ElementKey): Boolean {
+    @VisibleForTesting val testTag: String = "element:$name"
+
+    override fun matches(key: ElementKey, scene: SceneKey): Boolean {
         return key == this
     }
 
@@ -73,7 +78,9 @@
         /** Matches any element whose [key identity][ElementKey.identity] matches [predicate]. */
         fun withIdentity(predicate: (Any) -> Boolean): ElementMatcher {
             return object : ElementMatcher {
-                override fun matches(key: ElementKey): Boolean = predicate(key.identity)
+                override fun matches(key: ElementKey, scene: SceneKey): Boolean {
+                    return predicate(key.identity)
+                }
             }
         }
     }
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Scene.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Scene.kt
index b44c8ef..3985233 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Scene.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Scene.kt
@@ -25,6 +25,7 @@
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.layout.onPlaced
+import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.zIndex
 
@@ -45,7 +46,9 @@
 
     @Composable
     fun Content(modifier: Modifier = Modifier) {
-        Box(modifier.zIndex(zIndex).onPlaced { size = it.size }) { scope.content() }
+        Box(modifier.zIndex(zIndex).onPlaced { size = it.size }.testTag(key.testTag)) {
+            scope.content()
+        }
     }
 
     override fun toString(): String {
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitions.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitions.kt
index f4e3902..75dcb2e 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitions.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitions.kt
@@ -16,6 +16,7 @@
 
 package com.android.compose.animation.scene
 
+import androidx.annotation.VisibleForTesting
 import androidx.compose.animation.core.AnimationSpec
 import androidx.compose.animation.core.snap
 import androidx.compose.ui.geometry.Offset
@@ -28,6 +29,7 @@
 import com.android.compose.animation.scene.transformation.PropertyTransformation
 import com.android.compose.animation.scene.transformation.RangedPropertyTransformation
 import com.android.compose.animation.scene.transformation.ScaleSize
+import com.android.compose.animation.scene.transformation.SharedElementTransformation
 import com.android.compose.animation.scene.transformation.Transformation
 import com.android.compose.animation.scene.transformation.Translate
 import com.android.compose.ui.util.fastForEach
@@ -35,11 +37,12 @@
 
 /** The transitions configuration of a [SceneTransitionLayout]. */
 class SceneTransitions(
-    private val transitionSpecs: List<TransitionSpec>,
+    @get:VisibleForTesting val transitionSpecs: List<TransitionSpec>,
 ) {
     private val cache = mutableMapOf<SceneKey, MutableMap<SceneKey, TransitionSpec>>()
 
-    internal fun transitionSpec(from: SceneKey, to: SceneKey): TransitionSpec {
+    @VisibleForTesting
+    fun transitionSpec(from: SceneKey, to: SceneKey): TransitionSpec {
         return cache.getOrPut(from) { mutableMapOf() }.getOrPut(to) { findSpec(from, to) }
     }
 
@@ -97,7 +100,8 @@
     val transformations: List<Transformation>,
     val spec: AnimationSpec<Float>,
 ) {
-    private val cache = mutableMapOf<ElementKey, ElementTransformations>()
+    // TODO(b/302300957): Make sure this cache does not infinitely grow.
+    private val cache = mutableMapOf<ElementKey, MutableMap<SceneKey, ElementTransformations>>()
 
     internal fun reverse(): TransitionSpec {
         return copy(
@@ -107,12 +111,18 @@
         )
     }
 
-    internal fun transformations(element: ElementKey): ElementTransformations {
-        return cache.getOrPut(element) { computeTransformations(element) }
+    internal fun transformations(element: ElementKey, scene: SceneKey): ElementTransformations {
+        return cache
+            .getOrPut(element) { mutableMapOf() }
+            .getOrPut(scene) { computeTransformations(element, scene) }
     }
 
     /** Filter [transformations] to compute the [ElementTransformations] of [element]. */
-    private fun computeTransformations(element: ElementKey): ElementTransformations {
+    private fun computeTransformations(
+        element: ElementKey,
+        scene: SceneKey,
+    ): ElementTransformations {
+        var shared: SharedElementTransformation? = null
         val modifier = mutableListOf<ModifierTransformation>()
         var offset: PropertyTransformation<Offset>? = null
         var size: PropertyTransformation<IntSize>? = null
@@ -126,16 +136,16 @@
                 is Translate,
                 is EdgeTranslate,
                 is AnchoredTranslate -> {
-                    throwIfNotNull(offset, element, property = "offset")
+                    throwIfNotNull(offset, element, name = "offset")
                     offset = root as PropertyTransformation<Offset>
                 }
                 is ScaleSize,
                 is AnchoredSize -> {
-                    throwIfNotNull(size, element, property = "size")
+                    throwIfNotNull(size, element, name = "size")
                     size = root as PropertyTransformation<IntSize>
                 }
                 is Fade -> {
-                    throwIfNotNull(alpha, element, property = "alpha")
+                    throwIfNotNull(alpha, element, name = "alpha")
                     alpha = root as PropertyTransformation<Float>
                 }
                 is RangedPropertyTransformation -> onPropertyTransformation(root, current.delegate)
@@ -143,32 +153,37 @@
         }
 
         transformations.fastForEach { transformation ->
-            if (!transformation.matcher.matches(element)) {
+            if (!transformation.matcher.matches(element, scene)) {
                 return@fastForEach
             }
 
             when (transformation) {
+                is SharedElementTransformation -> {
+                    throwIfNotNull(shared, element, name = "shared")
+                    shared = transformation
+                }
                 is ModifierTransformation -> modifier.add(transformation)
                 is PropertyTransformation<*> -> onPropertyTransformation(transformation)
             }
         }
 
-        return ElementTransformations(modifier, offset, size, alpha)
+        return ElementTransformations(shared, modifier, offset, size, alpha)
     }
 
     private fun throwIfNotNull(
-        previous: PropertyTransformation<*>?,
+        previous: Transformation?,
         element: ElementKey,
-        property: String,
+        name: String,
     ) {
         if (previous != null) {
-            error("$element has multiple transformations for its $property property")
+            error("$element has multiple $name transformations")
         }
     }
 }
 
 /** The transformations of an element during a transition. */
 internal class ElementTransformations(
+    val shared: SharedElementTransformation?,
     val modifier: List<ModifierTransformation>,
     val offset: PropertyTransformation<Offset>?,
     val size: PropertyTransformation<IntSize>?,
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/TransitionDsl.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/TransitionDsl.kt
index fb12b90..4966977 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/TransitionDsl.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/TransitionDsl.kt
@@ -116,6 +116,14 @@
     )
 
     /**
+     * Configure the shared transition when [matcher] is shared between two scenes.
+     *
+     * @param enabled whether the matched element(s) should actually be shared in this transition.
+     *   Defaults to true.
+     */
+    fun sharedElement(matcher: ElementMatcher, enabled: Boolean = true)
+
+    /**
      * Punch a hole in the element(s) matching [matcher] that has the same bounds as [bounds] and
      * using the given [shape].
      *
@@ -127,6 +135,13 @@
      * the result.
      */
     fun punchHole(matcher: ElementMatcher, bounds: ElementKey, shape: Shape = RectangleShape)
+
+    /**
+     * Adds the transformations in [builder] but in reversed order. This allows you to partially
+     * reuse the definition of the transition from scene `Foo` to scene `Bar` inside the definition
+     * of the transition from scene `Bar` to scene `Foo`.
+     */
+    fun reversed(builder: TransitionBuilder.() -> Unit)
 }
 
 @TransitionDsl
@@ -179,12 +194,6 @@
     fun anchoredSize(matcher: ElementMatcher, anchor: ElementKey)
 }
 
-/** An interface to match one or more elements. */
-interface ElementMatcher {
-    /** Whether the element with key [key] matches this matcher. */
-    fun matches(key: ElementKey): Boolean
-}
-
 /** The edge of a [SceneTransitionLayout]. */
 enum class Edge {
     Left,
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/TransitionDslImpl.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/TransitionDslImpl.kt
index 48d5638e8b..f1c2717 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/TransitionDslImpl.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/TransitionDslImpl.kt
@@ -31,6 +31,7 @@
 import com.android.compose.animation.scene.transformation.PunchHole
 import com.android.compose.animation.scene.transformation.RangedPropertyTransformation
 import com.android.compose.animation.scene.transformation.ScaleSize
+import com.android.compose.animation.scene.transformation.SharedElementTransformation
 import com.android.compose.animation.scene.transformation.Transformation
 import com.android.compose.animation.scene.transformation.TransformationRange
 import com.android.compose.animation.scene.transformation.Translate
@@ -80,6 +81,7 @@
     override var spec: AnimationSpec<Float> = spring(stiffness = Spring.StiffnessLow)
 
     private var range: TransformationRange? = null
+    private var reversed = false
     private val durationMillis: Int by lazy {
         val spec = spec
         if (spec !is DurationBasedAnimationSpec) {
@@ -93,6 +95,12 @@
         transformations.add(PunchHole(matcher, bounds, shape))
     }
 
+    override fun reversed(builder: TransitionBuilder.() -> Unit) {
+        reversed = true
+        builder()
+        reversed = false
+    }
+
     override fun fractionRange(
         start: Float?,
         end: Float?,
@@ -103,6 +111,10 @@
         range = null
     }
 
+    override fun sharedElement(matcher: ElementMatcher, enabled: Boolean) {
+        transformations.add(SharedElementTransformation(matcher, enabled))
+    }
+
     override fun timestampRange(
         startMillis: Int?,
         endMillis: Int?,
@@ -122,11 +134,20 @@
     }
 
     private fun transformation(transformation: PropertyTransformation<*>) {
-        if (range != null) {
-            transformations.add(RangedPropertyTransformation(transformation, range!!))
-        } else {
-            transformations.add(transformation)
-        }
+        val transformation =
+            if (range != null) {
+                RangedPropertyTransformation(transformation, range!!)
+            } else {
+                transformation
+            }
+
+        transformations.add(
+            if (reversed) {
+                transformation.reverse()
+            } else {
+                transformation
+            }
+        )
     }
 
     override fun fade(matcher: ElementMatcher) {
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/Transformation.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/Transformation.kt
index ce6749d..a650254 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/Transformation.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/transformation/Transformation.kt
@@ -30,6 +30,14 @@
      */
     val matcher: ElementMatcher
 
+    /**
+     * The range during which the transformation is applied. If it is `null`, then the
+     * transformation will be applied throughout the whole scene transition.
+     */
+    // TODO(b/240432457): Move this back to PropertyTransformation.
+    val range: TransformationRange?
+        get() = null
+
     /*
      * Reverse this transformation. This is called when we use Transition(from = A, to = B) when
      * animating from B to A and there is no Transition(from = B, to = A) defined.
@@ -37,6 +45,11 @@
     fun reverse(): Transformation = this
 }
 
+internal class SharedElementTransformation(
+    override val matcher: ElementMatcher,
+    internal val enabled: Boolean,
+) : Transformation
+
 /** A transformation that is applied on the element during the whole transition. */
 internal interface ModifierTransformation : Transformation {
     /** Apply the transformation to [element]. */
@@ -53,13 +66,6 @@
 /** A transformation that changes the value of an element property, like its size or offset. */
 internal sealed interface PropertyTransformation<T> : Transformation {
     /**
-     * The range during which the transformation is applied. If it is `null`, then the
-     * transformation will be applied throughout the whole scene transition.
-     */
-    val range: TransformationRange?
-        get() = null
-
-    /**
      * Transform [value], i.e. the value of the transformed property without this transformation.
      */
     // TODO(b/290184746): Figure out a public API for custom transformations that don't have access
@@ -92,8 +98,7 @@
 }
 
 /** The progress-based range of a [PropertyTransformation]. */
-data class TransformationRange
-private constructor(
+data class TransformationRange(
     val start: Float,
     val end: Float,
 ) {
@@ -133,6 +138,6 @@
     }
 
     companion object {
-        private const val BoundUnspecified = Float.MIN_VALUE
+        const val BoundUnspecified = Float.MIN_VALUE
     }
 }
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/theme/PlatformTheme.kt b/packages/SystemUI/compose/core/src/com/android/compose/theme/PlatformTheme.kt
index b4e90d6..0661870 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/theme/PlatformTheme.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/theme/PlatformTheme.kt
@@ -29,6 +29,8 @@
 import com.android.compose.theme.typography.TypefaceTokens
 import com.android.compose.theme.typography.TypographyTokens
 import com.android.compose.theme.typography.platformTypography
+import com.android.compose.windowsizeclass.LocalWindowSizeClass
+import com.android.compose.windowsizeclass.calculateWindowSizeClass
 
 /** The Material 3 theme that should wrap all Platform Composables. */
 @Composable
@@ -51,10 +53,12 @@
         remember(typefaceNames) {
             platformTypography(TypographyTokens(TypeScaleTokens(TypefaceTokens(typefaceNames))))
         }
+    val windowSizeClass = calculateWindowSizeClass()
 
     MaterialTheme(colorScheme, typography = typography) {
         CompositionLocalProvider(
             LocalAndroidColorScheme provides androidColorScheme,
+            LocalWindowSizeClass provides windowSizeClass,
         ) {
             content()
         }
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/windowsizeclass/WindowSizeClass.kt b/packages/SystemUI/compose/core/src/com/android/compose/windowsizeclass/WindowSizeClass.kt
new file mode 100644
index 0000000..4674d6e
--- /dev/null
+++ b/packages/SystemUI/compose/core/src/com/android/compose/windowsizeclass/WindowSizeClass.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compose.windowsizeclass
+
+import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
+import androidx.compose.material3.windowsizeclass.WindowSizeClass
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.staticCompositionLocalOf
+import androidx.compose.ui.graphics.toComposeRect
+import androidx.compose.ui.platform.LocalConfiguration
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalDensity
+import androidx.window.layout.WindowMetricsCalculator
+
+val LocalWindowSizeClass =
+    staticCompositionLocalOf<WindowSizeClass> {
+        throw IllegalStateException(
+            "No WindowSizeClass configured. Make sure to use LocalWindowSizeClass in a Composable" +
+                " surrounded by a PlatformTheme {}."
+        )
+    }
+
+@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
+@Composable
+fun calculateWindowSizeClass(): WindowSizeClass {
+    // Observe view configuration changes and recalculate the size class on each change.
+    LocalConfiguration.current
+    val density = LocalDensity.current
+    val context = LocalContext.current
+    val metrics = WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(context)
+    val size = with(density) { metrics.bounds.toComposeRect().size.toDpSize() }
+    return WindowSizeClass.calculateFromSize(size)
+}
diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
index 8bd6545..328866e 100644
--- a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
+++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
@@ -224,7 +224,7 @@
 
         // In scene A, the shared element SharedFoo() is at the top end of the layout and has a size
         // of 50.dp.
-        var sharedFoo = rule.onNodeWithTag(TestElements.Foo.name, useUnmergedTree = true)
+        var sharedFoo = rule.onNodeWithTag(TestElements.Foo.testTag, useUnmergedTree = true)
         sharedFoo.assertWidthIsEqualTo(50.dp)
         sharedFoo.assertHeightIsEqualTo(50.dp)
         sharedFoo.assertPositionInRootIsEqualTo(
@@ -250,7 +250,7 @@
 
         // We need to use onAllNodesWithTag().onFirst() here given that shared elements are
         // composed and laid out in both scenes (but drawn only in one).
-        sharedFoo = rule.onAllNodesWithTag(TestElements.Foo.name).onFirst()
+        sharedFoo = rule.onAllNodesWithTag(TestElements.Foo.testTag).onFirst()
 
         // In scene B, foo is at the top start (x = 0, y = 0) of the layout and has a size of
         // 100.dp. We pause at the middle of the transition, so it should now be 75.dp given that we
@@ -284,7 +284,7 @@
         val expectedLeft = 0.dp
         val expectedSize = 100.dp + (150.dp - 100.dp) * interpolatedProgress
 
-        sharedFoo = rule.onAllNodesWithTag(TestElements.Foo.name).onFirst()
+        sharedFoo = rule.onAllNodesWithTag(TestElements.Foo.testTag).onFirst()
         assertThat((layoutState.transitionState as TransitionState.Transition).progress)
             .isEqualTo(interpolatedProgress)
         sharedFoo.assertWidthIsEqualTo(expectedSize)
diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/TestTransition.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/TestTransition.kt
index 275149a0..268057f 100644
--- a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/TestTransition.kt
+++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/TestTransition.kt
@@ -23,7 +23,11 @@
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.test.SemanticsNodeInteraction
+import androidx.compose.ui.test.SemanticsNodeInteractionCollection
+import androidx.compose.ui.test.hasParent
+import androidx.compose.ui.test.hasTestTag
 import androidx.compose.ui.test.junit4.ComposeContentTestRule
+import androidx.compose.ui.test.onAllNodesWithTag
 import androidx.compose.ui.test.onNodeWithTag
 
 @DslMarker annotation class TransitionTestDsl
@@ -59,8 +63,21 @@
 
 @TransitionTestDsl
 interface TransitionTestAssertionScope {
-    /** Assert on [element]. */
-    fun onElement(element: ElementKey): SemanticsNodeInteraction
+    /**
+     * Assert on [element].
+     *
+     * Note that presence/value assertions on the returned [SemanticsNodeInteraction] will fail if 0
+     * or more than 1 elements matched [element]. If you need to assert on a shared element that
+     * will be present multiple times in the layout during transitions, either specify the [scene]
+     * in which you are matching or use [onSharedElement] instead.
+     */
+    fun onElement(element: ElementKey, scene: SceneKey? = null): SemanticsNodeInteraction
+
+    /**
+     * Assert on a shared [element]. This will throw if [element] is not shared and present only in
+     * one scene during a transition.
+     */
+    fun onSharedElement(element: ElementKey): SemanticsNodeInteractionCollection
 }
 
 /**
@@ -73,20 +90,22 @@
     toSceneContent: @Composable SceneScope.() -> Unit,
     transition: TransitionBuilder.() -> Unit,
     layoutModifier: Modifier = Modifier,
+    fromScene: SceneKey = TestScenes.SceneA,
+    toScene: SceneKey = TestScenes.SceneB,
     builder: TransitionTestBuilder.() -> Unit,
 ) {
     testTransition(
-        from = TestScenes.SceneA,
-        to = TestScenes.SceneB,
+        from = fromScene,
+        to = toScene,
         transitionLayout = { currentScene, onChangeScene ->
             SceneTransitionLayout(
                 currentScene,
                 onChangeScene,
-                transitions { from(TestScenes.SceneA, to = TestScenes.SceneB, transition) },
+                transitions { from(fromScene, to = toScene, transition) },
                 layoutModifier.fillMaxSize(),
             ) {
-                scene(TestScenes.SceneA, content = fromSceneContent)
-                scene(TestScenes.SceneB, content = toSceneContent)
+                scene(fromScene, content = fromSceneContent)
+                scene(toScene, content = toSceneContent)
             }
         },
         builder,
@@ -111,8 +130,24 @@
     val test = transitionTest(builder)
     val assertionScope =
         object : TransitionTestAssertionScope {
-            override fun onElement(element: ElementKey): SemanticsNodeInteraction {
-                return this@testTransition.onNodeWithTag(element.name)
+            override fun onElement(
+                element: ElementKey,
+                scene: SceneKey?
+            ): SemanticsNodeInteraction {
+                return if (scene == null) {
+                    onNodeWithTag(element.testTag)
+                } else {
+                    onNode(hasTestTag(element.testTag) and hasParent(hasTestTag(scene.testTag)))
+                }
+            }
+
+            override fun onSharedElement(element: ElementKey): SemanticsNodeInteractionCollection {
+                val interaction = onAllNodesWithTag(element.testTag)
+                val matches = interaction.fetchSemanticsNodes(atLeastOneRootRequired = false).size
+                if (matches < 2) {
+                    error("Element $element is not shared ($matches matches)")
+                }
+                return interaction
             }
         }
 
diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
new file mode 100644
index 0000000..fa94b250
--- /dev/null
+++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compose.animation.scene
+
+import androidx.compose.animation.core.SpringSpec
+import androidx.compose.animation.core.TweenSpec
+import androidx.compose.animation.core.tween
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compose.animation.scene.transformation.Transformation
+import com.android.compose.animation.scene.transformation.TransformationRange
+import com.google.common.truth.Correspondence
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class TransitionDslTest {
+    @Test
+    fun emptyTransitions() {
+        val transitions = transitions {}
+        assertThat(transitions.transitionSpecs).isEmpty()
+    }
+
+    @Test
+    fun manyTransitions() {
+        val transitions = transitions {
+            from(TestScenes.SceneA, to = TestScenes.SceneB)
+            from(TestScenes.SceneB, to = TestScenes.SceneC)
+            from(TestScenes.SceneC, to = TestScenes.SceneA)
+        }
+        assertThat(transitions.transitionSpecs).hasSize(3)
+    }
+
+    @Test
+    fun toFromBuilders() {
+        val transitions = transitions {
+            from(TestScenes.SceneA, to = TestScenes.SceneB)
+            from(TestScenes.SceneB)
+            to(TestScenes.SceneC)
+        }
+
+        assertThat(transitions.transitionSpecs)
+            .comparingElementsUsing(
+                Correspondence.transforming<TransitionSpec, Pair<SceneKey?, SceneKey?>>(
+                    { it?.from to it?.to },
+                    "has (from, to) equal to"
+                )
+            )
+            .containsExactly(
+                TestScenes.SceneA to TestScenes.SceneB,
+                TestScenes.SceneB to null,
+                null to TestScenes.SceneC,
+            )
+    }
+
+    @Test
+    fun defaultTransitionSpec() {
+        val transitions = transitions { from(TestScenes.SceneA, to = TestScenes.SceneB) }
+        val transition = transitions.transitionSpecs.single()
+        assertThat(transition.spec).isInstanceOf(SpringSpec::class.java)
+    }
+
+    @Test
+    fun customTransitionSpec() {
+        val transitions = transitions {
+            from(TestScenes.SceneA, to = TestScenes.SceneB) { spec = tween(durationMillis = 42) }
+        }
+        val transition = transitions.transitionSpecs.single()
+        assertThat(transition.spec).isInstanceOf(TweenSpec::class.java)
+        assertThat((transition.spec as TweenSpec).durationMillis).isEqualTo(42)
+    }
+
+    @Test
+    fun defaultRange() {
+        val transitions = transitions {
+            from(TestScenes.SceneA, to = TestScenes.SceneB) { fade(TestElements.Foo) }
+        }
+
+        val transition = transitions.transitionSpecs.single()
+        assertThat(transition.transformations.size).isEqualTo(1)
+        assertThat(transition.transformations.single().range).isEqualTo(null)
+    }
+
+    @Test
+    fun fractionRange() {
+        val transitions = transitions {
+            from(TestScenes.SceneA, to = TestScenes.SceneB) {
+                fractionRange(start = 0.1f, end = 0.8f) { fade(TestElements.Foo) }
+                fractionRange(start = 0.2f) { fade(TestElements.Foo) }
+                fractionRange(end = 0.9f) { fade(TestElements.Foo) }
+            }
+        }
+
+        val transition = transitions.transitionSpecs.single()
+        assertThat(transition.transformations)
+            .comparingElementsUsing(TRANSFORMATION_RANGE)
+            .containsExactly(
+                TransformationRange(start = 0.1f, end = 0.8f),
+                TransformationRange(start = 0.2f, end = TransformationRange.BoundUnspecified),
+                TransformationRange(start = TransformationRange.BoundUnspecified, end = 0.9f),
+            )
+    }
+
+    @Test
+    fun timestampRange() {
+        val transitions = transitions {
+            from(TestScenes.SceneA, to = TestScenes.SceneB) {
+                spec = tween(500)
+
+                timestampRange(startMillis = 100, endMillis = 300) { fade(TestElements.Foo) }
+                timestampRange(startMillis = 200) { fade(TestElements.Foo) }
+                timestampRange(endMillis = 400) { fade(TestElements.Foo) }
+            }
+        }
+
+        val transition = transitions.transitionSpecs.single()
+        assertThat(transition.transformations)
+            .comparingElementsUsing(TRANSFORMATION_RANGE)
+            .containsExactly(
+                TransformationRange(start = 100 / 500f, end = 300 / 500f),
+                TransformationRange(start = 200 / 500f, end = TransformationRange.BoundUnspecified),
+                TransformationRange(start = TransformationRange.BoundUnspecified, end = 400 / 500f),
+            )
+    }
+
+    @Test
+    fun reversed() {
+        val transitions = transitions {
+            from(TestScenes.SceneA, to = TestScenes.SceneB) {
+                spec = tween(500)
+                reversed {
+                    fractionRange(start = 0.1f, end = 0.8f) { fade(TestElements.Foo) }
+                    timestampRange(startMillis = 100, endMillis = 300) { fade(TestElements.Foo) }
+                }
+            }
+        }
+
+        val transition = transitions.transitionSpecs.single()
+        assertThat(transition.transformations)
+            .comparingElementsUsing(TRANSFORMATION_RANGE)
+            .containsExactly(
+                TransformationRange(start = 1f - 0.8f, end = 1f - 0.1f),
+                TransformationRange(start = 1f - 300 / 500f, end = 1f - 100 / 500f),
+            )
+    }
+
+    @Test
+    fun defaultReversed() {
+        val transitions = transitions {
+            from(TestScenes.SceneA, to = TestScenes.SceneB) {
+                spec = tween(500)
+                fractionRange(start = 0.1f, end = 0.8f) { fade(TestElements.Foo) }
+                timestampRange(startMillis = 100, endMillis = 300) { fade(TestElements.Foo) }
+            }
+        }
+
+        // Fetch the transition from B to A, which will automatically reverse the transition from A
+        // to B we defined.
+        val transition =
+            transitions.transitionSpec(from = TestScenes.SceneB, to = TestScenes.SceneA)
+        assertThat(transition.transformations)
+            .comparingElementsUsing(TRANSFORMATION_RANGE)
+            .containsExactly(
+                TransformationRange(start = 1f - 0.8f, end = 1f - 0.1f),
+                TransformationRange(start = 1f - 300 / 500f, end = 1f - 100 / 500f),
+            )
+    }
+
+    companion object {
+        private val TRANSFORMATION_RANGE =
+            Correspondence.transforming<Transformation, TransformationRange?>(
+                { it?.range },
+                "has range equal to"
+            )
+    }
+}
diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/transformation/SharedElementTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/transformation/SharedElementTest.kt
new file mode 100644
index 0000000..2af3638
--- /dev/null
+++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/transformation/SharedElementTest.kt
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compose.animation.scene.transformation
+
+import androidx.compose.animation.core.LinearEasing
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.offset
+import androidx.compose.foundation.layout.size
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.test.assertPositionInRootIsEqualTo
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compose.animation.scene.Edge
+import com.android.compose.animation.scene.TestElements
+import com.android.compose.animation.scene.TestScenes
+import com.android.compose.animation.scene.inScene
+import com.android.compose.animation.scene.testTransition
+import com.android.compose.modifiers.size
+import com.android.compose.test.assertSizeIsEqualTo
+import com.android.compose.test.onEach
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class SharedElementTest {
+    @get:Rule val rule = createComposeRule()
+
+    @Test
+    fun testSharedElement() {
+        rule.testTransition(
+            fromSceneContent = {
+                // Foo is at (10, 50) with a size of (20, 80).
+                Box(Modifier.offset(10.dp, 50.dp).element(TestElements.Foo).size(20.dp, 80.dp))
+            },
+            toSceneContent = {
+                // Foo is at (50, 70) with a size of (10, 40).
+                Box(Modifier.offset(50.dp, 70.dp).element(TestElements.Foo).size(10.dp, 40.dp))
+            },
+            transition = {
+                spec = tween(16 * 4, easing = LinearEasing)
+                // Elements should be shared by default.
+            }
+        ) {
+            before {
+                onElement(TestElements.Foo).assertPositionInRootIsEqualTo(10.dp, 50.dp)
+                onElement(TestElements.Foo).assertSizeIsEqualTo(20.dp, 80.dp)
+            }
+            at(0) {
+                onSharedElement(TestElements.Foo).onEach {
+                    assertPositionInRootIsEqualTo(10.dp, 50.dp)
+                    assertSizeIsEqualTo(20.dp, 80.dp)
+                }
+            }
+            at(16) {
+                onSharedElement(TestElements.Foo).onEach {
+                    assertPositionInRootIsEqualTo(20.dp, 55.dp)
+                    assertSizeIsEqualTo(17.5.dp, 70.dp)
+                }
+            }
+            at(32) {
+                onSharedElement(TestElements.Foo).onEach {
+                    assertPositionInRootIsEqualTo(30.dp, 60.dp)
+                    assertSizeIsEqualTo(15.dp, 60.dp)
+                }
+            }
+            at(48) {
+                onSharedElement(TestElements.Foo).onEach {
+                    assertPositionInRootIsEqualTo(40.dp, 65.dp)
+                    assertSizeIsEqualTo(12.5.dp, 50.dp)
+                }
+            }
+            after {
+                onElement(TestElements.Foo).assertPositionInRootIsEqualTo(50.dp, 70.dp)
+                onElement(TestElements.Foo).assertSizeIsEqualTo(10.dp, 40.dp)
+            }
+        }
+    }
+
+    @Test
+    fun testSharedElementDisabled() {
+        rule.testTransition(
+            fromScene = TestScenes.SceneA,
+            toScene = TestScenes.SceneB,
+            // The full layout is 100x100.
+            layoutModifier = Modifier.size(100.dp),
+            fromSceneContent = {
+                Box(Modifier.fillMaxSize()) {
+                    // Foo is at (10, 50).
+                    Box(Modifier.offset(10.dp, 50.dp).element(TestElements.Foo))
+                }
+            },
+            toSceneContent = {
+                Box(Modifier.fillMaxSize()) {
+                    // Foo is at (50, 60).
+                    Box(Modifier.offset(50.dp, 60.dp).element(TestElements.Foo))
+                }
+            },
+            transition = {
+                spec = tween(16 * 4, easing = LinearEasing)
+
+                // Disable the shared element animation.
+                sharedElement(TestElements.Foo, enabled = false)
+
+                // In SceneA, Foo leaves to the left edge.
+                translate(TestElements.Foo.inScene(TestScenes.SceneA), Edge.Left)
+
+                // In SceneB, Foo comes from the bottom edge.
+                translate(TestElements.Foo.inScene(TestScenes.SceneB), Edge.Bottom)
+            },
+        ) {
+            before { onElement(TestElements.Foo).assertPositionInRootIsEqualTo(10.dp, 50.dp) }
+            at(0) {
+                onElement(TestElements.Foo, scene = TestScenes.SceneA)
+                    .assertPositionInRootIsEqualTo(10.dp, 50.dp)
+                onElement(TestElements.Foo, scene = TestScenes.SceneB)
+                    .assertPositionInRootIsEqualTo(50.dp, 100.dp)
+            }
+            at(16) {
+                onElement(TestElements.Foo, scene = TestScenes.SceneA)
+                    .assertPositionInRootIsEqualTo(7.5.dp, 50.dp)
+                onElement(TestElements.Foo, scene = TestScenes.SceneB)
+                    .assertPositionInRootIsEqualTo(50.dp, 90.dp)
+            }
+            at(32) {
+                onElement(TestElements.Foo, scene = TestScenes.SceneA)
+                    .assertPositionInRootIsEqualTo(5.dp, 50.dp)
+                onElement(TestElements.Foo, scene = TestScenes.SceneB)
+                    .assertPositionInRootIsEqualTo(50.dp, 80.dp)
+            }
+            at(48) {
+                onElement(TestElements.Foo, scene = TestScenes.SceneA)
+                    .assertPositionInRootIsEqualTo(2.5.dp, 50.dp)
+                onElement(TestElements.Foo, scene = TestScenes.SceneB)
+                    .assertPositionInRootIsEqualTo(50.dp, 70.dp)
+            }
+            after { onElement(TestElements.Foo).assertPositionInRootIsEqualTo(50.dp, 60.dp) }
+        }
+    }
+}
diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/test/Selectors.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/test/Selectors.kt
new file mode 100644
index 0000000..d6f64bf
--- /dev/null
+++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/test/Selectors.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compose.test
+
+import androidx.compose.ui.test.SemanticsNodeInteraction
+import androidx.compose.ui.test.SemanticsNodeInteractionCollection
+
+/** Assert [assert] on each element of [this] [SemanticsNodeInteractionCollection]. */
+fun SemanticsNodeInteractionCollection.onEach(assert: SemanticsNodeInteraction.() -> Unit) {
+    for (i in 0 until this.fetchSemanticsNodes().size) {
+        get(i).assert()
+    }
+}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
index c41dc53..cb76ad7 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
@@ -507,9 +507,10 @@
         }
     }
 
-    private var isVerifying = AtomicBoolean(false)
+    private var isQueued = AtomicBoolean(false)
     fun verifyLoadedProviders() {
-        val shouldSchedule = isVerifying.compareAndSet(false, true)
+        Log.i(TAG, Thread.currentThread().getStackTrace().toString())
+        val shouldSchedule = isQueued.compareAndSet(false, true)
         if (!shouldSchedule) {
             logger.tryLog(
                 TAG,
@@ -521,48 +522,54 @@
         }
 
         scope.launch(bgDispatcher) {
-            if (keepAllLoaded) {
+            // TODO(b/267372164): Use better threading approach when converting to flows
+            synchronized(availableClocks) {
+                isQueued.set(false)
+                if (keepAllLoaded) {
+                    logger.tryLog(
+                        TAG,
+                        LogLevel.INFO,
+                        {},
+                        { "verifyLoadedProviders: keepAllLoaded=true" }
+                    )
+                    // Enforce that all plugins are loaded if requested
+                    for ((_, info) in availableClocks) {
+                        info.manager?.loadPlugin()
+                    }
+                    return@launch
+                }
+
+                val currentClock = availableClocks[currentClockId]
+                if (currentClock == null) {
+                    logger.tryLog(
+                        TAG,
+                        LogLevel.INFO,
+                        {},
+                        { "verifyLoadedProviders: currentClock=null" }
+                    )
+                    // Current Clock missing, load no plugins and use default
+                    for ((_, info) in availableClocks) {
+                        info.manager?.unloadPlugin()
+                    }
+                    return@launch
+                }
+
                 logger.tryLog(
                     TAG,
                     LogLevel.INFO,
                     {},
-                    { "verifyLoadedProviders: keepAllLoaded=true" }
+                    { "verifyLoadedProviders: load currentClock" }
                 )
-                // Enforce that all plugins are loaded if requested
+                val currentManager = currentClock.manager
+                currentManager?.loadPlugin()
+
                 for ((_, info) in availableClocks) {
-                    info.manager?.loadPlugin()
-                }
-                isVerifying.set(false)
-                return@launch
-            }
-
-            val currentClock = availableClocks[currentClockId]
-            if (currentClock == null) {
-                logger.tryLog(
-                    TAG,
-                    LogLevel.INFO,
-                    {},
-                    { "verifyLoadedProviders: currentClock=null" }
-                )
-                // Current Clock missing, load no plugins and use default
-                for ((_, info) in availableClocks) {
-                    info.manager?.unloadPlugin()
-                }
-                isVerifying.set(false)
-                return@launch
-            }
-
-            logger.tryLog(TAG, LogLevel.INFO, {}, { "verifyLoadedProviders: load currentClock" })
-            val currentManager = currentClock.manager
-            currentManager?.loadPlugin()
-
-            for ((_, info) in availableClocks) {
-                val manager = info.manager
-                if (manager != null && currentManager != manager) {
-                    manager.unloadPlugin()
+                    val manager = info.manager
+                    if (manager != null && currentManager != manager) {
+                        manager.unloadPlugin()
+                    }
                 }
             }
-            isVerifying.set(false)
         }
     }
 
diff --git a/packages/SystemUI/res/layout/connected_display_dialog.xml b/packages/SystemUI/res/layout/connected_display_dialog.xml
index 569dd4c..a51c55e 100644
--- a/packages/SystemUI/res/layout/connected_display_dialog.xml
+++ b/packages/SystemUI/res/layout/connected_display_dialog.xml
@@ -52,7 +52,7 @@
             style="@style/Widget.Dialog.Button.BorderButton"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:text="@string/cancel" />
+            android:text="@string/dismiss_dialog" />
 
         <Space
             android:layout_width="0dp"
@@ -64,6 +64,6 @@
             style="@style/Widget.Dialog.Button"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:text="@string/enable_display" />
+            android:text="@string/mirror_display" />
     </LinearLayout>
 </LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml
index 85fb3ac..587caaf 100644
--- a/packages/SystemUI/res/values-land/config.xml
+++ b/packages/SystemUI/res/values-land/config.xml
@@ -44,6 +44,6 @@
 
     <!-- Whether to force split shade.
      For now, this value has effect only when flag lockscreen.enable_landscape is enabled.
-     TODO (b/293290851) - change this comment/resource when flag is enabled -->
+     TODO (b/293252410) - change this comment/resource when flag is enabled -->
     <bool name="force_config_use_split_notification_shade">true</bool>
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp-land/config.xml b/packages/SystemUI/res/values-sw600dp-land/config.xml
index e63229a..fc6d20e 100644
--- a/packages/SystemUI/res/values-sw600dp-land/config.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/config.xml
@@ -38,6 +38,6 @@
 
     <!-- Whether to force split shade.
     For now, this value has effect only when flag lockscreen.enable_landscape is enabled.
-    TODO (b/293290851) - change this comment/resource when flag is enabled -->
+    TODO (b/293252410) - change this comment/resource when flag is enabled -->
     <bool name="force_config_use_split_notification_shade">false</bool>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index b6bca65..3bdc0af 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -604,7 +604,7 @@
 
     <!-- Whether to force split shade.
     For now, this value has effect only when flag lockscreen.enable_landscape is enabled.
-    TODO (b/293290851) - change this comment/resource when flag is enabled -->
+    TODO (b/293252410) - change this comment/resource when flag is enabled -->
     <bool name="force_config_use_split_notification_shade">false</bool>
 
     <!-- Whether we use large screen shade header which takes only one row compared to QS header -->
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 21696fe..6cdd15e 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -233,6 +233,11 @@
     <item type="id" name="pin_pad"/>
 
     <!--
+    Tag used to store pending intent registration listeners in NotificationTemplateViewWrapper
+    -->
+    <item type="id" name="pending_intent_listener_tag" />
+
+    <!--
     Used to tag views programmatically added to the smartspace area so they can be more easily
     removed later.
     -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 5860806..a2637d5 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -3214,9 +3214,10 @@
 
     <!--- Title of the dialog appearing when an external display is connected, asking whether to start mirroring [CHAR LIMIT=NONE]-->
     <string name="connected_display_dialog_start_mirroring">Mirror to external display?</string>
-
     <!--- Label of the "enable display" button of the dialog appearing when an external display is connected [CHAR LIMIT=NONE]-->
-    <string name="enable_display">Enable display</string>
+    <string name="mirror_display">Mirror display</string>
+    <!--- Label of the dismiss button of the dialog appearing when an external display is connected [CHAR LIMIT=NONE]-->
+    <string name="dismiss_dialog">Dismiss</string>
 
     <!-- Title of the privacy dialog, shown for active / recent app usage of some phone sensors [CHAR LIMIT=30] -->
     <string name="privacy_dialog_title">Microphone &amp; Camera</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index ba8e427..f6a0563 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -184,6 +184,10 @@
         }
     }
 
+    public boolean getSplitShadeCentered() {
+        return mSplitShadeCentered;
+    }
+
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 29414ea..5646abe 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -234,6 +234,10 @@
         }
     }
 
+    public KeyguardClockSwitch getView() {
+        return mView;
+    }
+
     private void hideSliceViewAndNotificationIconContainer() {
         View ksv = mView.findViewById(R.id.keyguard_slice_view);
         ksv.setVisibility(View.GONE);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 625c1de..b2287d87 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -163,7 +163,10 @@
             }
             mCurrentUser = KeyguardUpdateMonitor.getCurrentUser();
             showPrimarySecurityScreen(false);
-            reinflateViewFlipper((l) -> {});
+            if (mCurrentSecurityMode != SecurityMode.SimPin
+                    && mCurrentSecurityMode != SecurityMode.SimPuk) {
+                reinflateViewFlipper((l) -> {});
+            }
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index d848602..f9cc03ee 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -18,6 +18,7 @@
 
 import static java.util.Collections.emptySet;
 
+import android.animation.LayoutTransition;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.os.Build;
@@ -78,6 +79,14 @@
         mKeyguardSlice = findViewById(R.id.keyguard_slice_view);
 
         mMediaHostContainer = findViewById(R.id.status_view_media_container);
+        if (mMediaHostContainer != null) {
+            LayoutTransition mediaLayoutTransition = new LayoutTransition();
+            ((ViewGroup) mMediaHostContainer).setLayoutTransition(mediaLayoutTransition);
+            mediaLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_APPEARING);
+            mediaLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
+            mediaLayoutTransition.disableTransitionType(LayoutTransition.APPEARING);
+            mediaLayoutTransition.disableTransitionType(LayoutTransition.DISAPPEARING);
+        }
 
         updateDark();
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 8d0d299..931ba6d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -23,6 +23,7 @@
 import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
 
 import android.animation.Animator;
+import android.animation.LayoutTransition;
 import android.animation.ValueAnimator;
 import android.annotation.Nullable;
 import android.content.res.Configuration;
@@ -101,6 +102,7 @@
     private final Rect mClipBounds = new Rect();
     private final KeyguardInteractor mKeyguardInteractor;
 
+    private Boolean mSplitShadeEnabled = false;
     private Boolean mStatusViewCentered = true;
 
     private DumpManager mDumpManager;
@@ -150,6 +152,48 @@
     @Override
     public void onInit() {
         mKeyguardClockSwitchController.init();
+        final View mediaHostContainer = mView.findViewById(R.id.status_view_media_container);
+        if (mediaHostContainer != null) {
+            mKeyguardClockSwitchController.getView().addOnLayoutChangeListener(
+                    (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+                        if (!mSplitShadeEnabled
+                                || mKeyguardClockSwitchController.getView().getSplitShadeCentered()
+                                // Note: isKeyguardVisible() returns false after Launcher -> AOD.
+                                || !mKeyguardUpdateMonitor.isKeyguardVisible()) {
+                            return;
+                        }
+
+                        int oldHeight = oldBottom - oldTop;
+                        if (v.getHeight() == oldHeight) return;
+
+                        if (mediaHostContainer.getVisibility() != View.VISIBLE
+                                // If the media is appearing, also don't do the transition.
+                                || mediaHostContainer.getHeight() == 0) {
+                            return;
+                        }
+
+                        final LayoutTransition mediaLayoutTransition =
+                                ((ViewGroup) mediaHostContainer).getLayoutTransition();
+                        if (mediaLayoutTransition == null) return;
+
+                        mediaLayoutTransition.enableTransitionType(LayoutTransition.CHANGING);
+                    });
+
+            mediaHostContainer.addOnLayoutChangeListener(
+                    (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+                        final LayoutTransition mediaLayoutTransition =
+                                ((ViewGroup) mediaHostContainer).getLayoutTransition();
+                        if (mediaLayoutTransition == null) return;
+                        if (!mediaLayoutTransition.isTransitionTypeEnabled(
+                                LayoutTransition.CHANGING)) {
+                            return;
+                        }
+                        // Note: when this is called, the LayoutTransition is already been set up.
+                        // Disables the LayoutTransition until it's explicitly enabled again.
+                        mediaLayoutTransition.disableTransitionType(LayoutTransition.CHANGING);
+                    }
+            );
+        }
 
         mDumpManager.registerDumpable(getInstanceName(), this);
         if (mFeatureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
@@ -385,6 +429,7 @@
      */
     public void setSplitShadeEnabled(boolean enabled) {
         mKeyguardClockSwitchController.setSplitShadeEnabled(enabled);
+        mSplitShadeEnabled = enabled;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 165c4bb..a81069a 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -424,11 +424,11 @@
     private void updateConfiguration() {
         WindowManager windowManager = mContext.getSystemService(WindowManager.class);
         Rect bounds = windowManager.getCurrentWindowMetrics().getBounds();
-        WindowInsets insets = windowManager.getCurrentWindowMetrics().getWindowInsets();
         mWidthPixels = bounds.right;
         if (mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ENABLE_LANDSCAPE)) {
             // Assumed to be initially neglected as there are no left or right insets in portrait
             // However, on landscape, these insets need to included when calculating the midpoint
+            WindowInsets insets = windowManager.getCurrentWindowMetrics().getWindowInsets();
             mWidthPixels -= insets.getSystemWindowInsetLeft() + insets.getSystemWindowInsetRight();
         }
         mHeightPixels = bounds.bottom;
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 954129e..22bd207 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -18,8 +18,8 @@
 
 import static androidx.dynamicanimation.animation.DynamicAnimation.TRANSLATION_X;
 import static androidx.dynamicanimation.animation.FloatPropertyCompat.createFloatPropertyCompat;
-
 import static com.android.systemui.classifier.Classifier.NOTIFICATION_DISMISS;
+import static com.android.systemui.flags.Flags.SWIPE_UNCLEARED_TRANSIENT_VIEW_FIX;
 import static com.android.systemui.statusbar.notification.NotificationUtils.logKey;
 
 import android.animation.Animator;
@@ -482,7 +482,14 @@
                 boolean wasRemoved = false;
                 if (animView instanceof ExpandableNotificationRow) {
                     ExpandableNotificationRow row = (ExpandableNotificationRow) animView;
-                    wasRemoved = row.isRemoved();
+                    if (mFeatureFlags.isEnabled(SWIPE_UNCLEARED_TRANSIENT_VIEW_FIX)) {
+                        // If the view is already removed from its parent and added as Transient,
+                        // we need to clean the transient view upon animation end
+                        wasRemoved = row.getTransientContainer() != null
+                            || row.getParent() == null || row.isRemoved();
+                    } else {
+                        wasRemoved = row.isRemoved();
+                    }
                 }
                 if (!mCancelled || wasRemoved) {
                     mCallback.onChildDismissed(animView);
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 3b70555..871257e 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -303,6 +303,11 @@
     @JvmField val MIGRATE_CLOCKS_TO_BLUEPRINT =
             unreleasedFlag("migrate_clocks_to_blueprint")
 
+    /** Migrate KeyguardRootView to use composables. */
+    // TODO(b/301969856): Tracking Bug.
+    @JvmField val KEYGUARD_ROOT_VIEW_USE_COMPOSE =
+        unreleasedFlag("keyguard_root_view_use_compose")
+
     /** Enables preview loading animation in the wallpaper picker. */
     // TODO(b/274443705): Tracking Bug
     @JvmField
@@ -771,6 +776,10 @@
     // TODO(b/302087895): Tracking Bug
     @JvmField val CALL_LAYOUT_ASYNC_SET_DATA = unreleasedFlag("call_layout_async_set_data")
 
+    // TODO(b/302144438): Tracking Bug
+    @JvmField val DECOUPLE_REMOTE_INPUT_DELEGATE_AND_CALLBACK_UPDATE =
+            unreleasedFlag("decouple_remote_input_delegate_and_callback_update")
+
     // 2900 - CentralSurfaces-related flags
 
     // TODO(b/285174336): Tracking Bug
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
index fb02c7d..1761ca8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
@@ -26,7 +26,6 @@
 import com.android.keyguard.LockIconViewController
 import com.android.keyguard.dagger.KeyguardStatusViewComponent
 import com.android.systemui.CoreStartable
-import com.android.systemui.res.R
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
@@ -40,7 +39,9 @@
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
 import com.android.systemui.keyguard.ui.viewmodel.OccludingAppDeviceEntryMessageViewModel
+import com.android.systemui.res.R
 import com.android.systemui.shade.NotificationShadeWindowView
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.statusbar.KeyguardIndicationController
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator
@@ -69,6 +70,7 @@
     private val context: Context,
     private val keyguardIndicationController: KeyguardIndicationController,
     private val lockIconViewController: LockIconViewController,
+    private val shadeInteractor: ShadeInteractor,
 ) : CoreStartable {
 
     private var rootViewHandle: DisposableHandle? = null
@@ -135,6 +137,7 @@
                 occludingAppDeviceEntryMessageViewModel,
                 chipbarCoordinator,
                 keyguardStateController,
+                shadeInteractor
             )
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
index f564d00..053727a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
@@ -32,6 +32,7 @@
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
 import com.android.systemui.keyguard.ui.viewmodel.OccludingAppDeviceEntryMessageViewModel
 import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.temporarydisplay.ViewPriority
@@ -55,6 +56,7 @@
         occludingAppDeviceEntryMessageViewModel: OccludingAppDeviceEntryMessageViewModel,
         chipbarCoordinator: ChipbarCoordinator,
         keyguardStateController: KeyguardStateController,
+        shadeInteractor: ShadeInteractor,
     ): DisposableHandle {
         val disposableHandle =
             view.repeatWhenAttached {
@@ -88,6 +90,17 @@
                             }
                         }
                     }
+
+                    launch {
+                        shadeInteractor.isAnyFullyExpanded.collect { isFullyAnyExpanded ->
+                            view.visibility =
+                                if (isFullyAnyExpanded) {
+                                    View.INVISIBLE
+                                } else {
+                                    View.VISIBLE
+                                }
+                        }
+                    }
                 }
 
                 repeatOnLifecycle(Lifecycle.State.STARTED) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
index 2ad74fb..864e345 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
@@ -62,6 +62,7 @@
 import com.android.systemui.monet.ColorScheme
 import com.android.systemui.plugins.ClockController
 import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.shared.clocks.ClockRegistry
 import com.android.systemui.shared.clocks.DefaultClockController
 import com.android.systemui.shared.clocks.shared.model.ClockPreviewConstants
@@ -109,6 +110,7 @@
     private val occludingAppDeviceEntryMessageViewModel: OccludingAppDeviceEntryMessageViewModel,
     private val chipbarCoordinator: ChipbarCoordinator,
     private val keyguardStateController: KeyguardStateController,
+    private val shadeInteractor: ShadeInteractor,
 ) {
 
     val hostToken: IBinder? = bundle.getBinder(KEY_HOST_TOKEN)
@@ -317,6 +319,7 @@
                 occludingAppDeviceEntryMessageViewModel,
                 chipbarCoordinator,
                 keyguardStateController,
+                shadeInteractor,
             )
         )
         rootView.addView(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSection.kt
index 9409036..f4bc713 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSection.kt
@@ -29,11 +29,11 @@
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.keyguard.LockIconView
 import com.android.keyguard.LockIconViewController
-import com.android.systemui.res.R
 import com.android.systemui.biometrics.AuthController
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.shared.model.KeyguardSection
+import com.android.systemui.res.R
 import com.android.systemui.shade.NotificationPanelView
 import javax.inject.Inject
 
@@ -73,11 +73,11 @@
         val mBottomPaddingPx =
             context.resources.getDimensionPixelSize(R.dimen.lock_icon_margin_bottom)
         val bounds = windowManager.currentWindowMetrics.bounds
-        val insets = windowManager.currentWindowMetrics.windowInsets
         var widthPixels = bounds.right.toFloat()
         if (featureFlags.isEnabled(Flags.LOCKSCREEN_ENABLE_LANDSCAPE)) {
             // Assumed to be initially neglected as there are no left or right insets in portrait.
             // However, on landscape, these insets need to included when calculating the midpoint.
+            val insets = windowManager.currentWindowMetrics.windowInsets
             widthPixels -= (insets.systemWindowInsetLeft + insets.systemWindowInsetRight).toFloat()
         }
         val heightPixels = bounds.bottom.toFloat()
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
index ae3c912..ed6d41e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
@@ -101,7 +101,8 @@
     panelEventsEvents: ShadeStateEvents,
     private val secureSettings: SecureSettings,
     @Main private val handler: Handler,
-    private val splitShadeStateController: SplitShadeStateController
+    private val splitShadeStateController: SplitShadeStateController,
+    private val logger: MediaViewLogger,
 ) {
 
     /** Track the media player setting status on lock screen. */
@@ -1057,6 +1058,7 @@
                     // that and directly set the mediaFrame's bounds within the premeasured host.
                     targetHost.addView(mediaFrame)
                 }
+                logger.logMediaHostAttachment(currentAttachmentLocation)
                 if (isCrossFadeAnimatorRunning) {
                     // When cross-fading with an animation, we only notify the media carousel of the
                     // location change, once the view is reattached to the new place and not
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewLogger.kt
index 8f1595d..3ff23159 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewLogger.kt
@@ -52,4 +52,8 @@
             { "location ($str1): $int1 -> $int2" }
         )
     }
+
+    fun logMediaHostAttachment(host: Int) {
+        buffer.log(TAG, LogLevel.DEBUG, { int1 = host }, { "Host (updateHostAttachment): $int1" })
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionCaptureTarget.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionCaptureTarget.kt
similarity index 80%
rename from packages/SystemUI/src/com/android/systemui/media/MediaProjectionCaptureTarget.kt
rename to packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionCaptureTarget.kt
index fbf9294..11d0be5 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionCaptureTarget.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionCaptureTarget.kt
@@ -14,20 +14,17 @@
  * limitations under the License.
  */
 
-package com.android.systemui.media
+package com.android.systemui.mediaprojection
 
 import android.os.IBinder
 import android.os.Parcel
 import android.os.Parcelable
 
 /**
- * Class that represents an area that should be captured.
- * Currently it has only a launch cookie that represents a task but
- * we potentially could add more identifiers e.g. for a pair of tasks.
+ * Class that represents an area that should be captured. Currently it has only a launch cookie that
+ * represents a task but we potentially could add more identifiers e.g. for a pair of tasks.
  */
-data class MediaProjectionCaptureTarget(
-    val launchCookie: IBinder?
-): Parcelable {
+data class MediaProjectionCaptureTarget(val launchCookie: IBinder?) : Parcelable {
 
     constructor(parcel: Parcel) : this(parcel.readStrongBinder())
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionServiceHelper.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionServiceHelper.kt
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/media/MediaProjectionServiceHelper.kt
rename to packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionServiceHelper.kt
index 9e616e2..f1cade7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionServiceHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionServiceHelper.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.media
+package com.android.systemui.mediaprojection
 
 import android.content.Context
 import android.media.projection.IMediaProjection
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
rename to packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt
index 88bc064..b5d3e91 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.systemui.media
+package com.android.systemui.mediaprojection.appselector
 
 import android.app.ActivityOptions
 import android.content.Intent
@@ -46,13 +46,11 @@
 import com.android.internal.widget.RecyclerView
 import com.android.internal.widget.RecyclerViewAccessibilityDelegate
 import com.android.internal.widget.ResolverDrawerLayout
-import com.android.systemui.res.R
-import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorComponent
-import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorController
-import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorResultHandler
-import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorView
+import com.android.systemui.mediaprojection.MediaProjectionCaptureTarget
+import com.android.systemui.mediaprojection.MediaProjectionServiceHelper
 import com.android.systemui.mediaprojection.appselector.data.RecentTask
 import com.android.systemui.mediaprojection.appselector.view.MediaProjectionRecentsViewController
+import com.android.systemui.res.R
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.util.AsyncActivityLauncher
 import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt
index 33d9cc3..72aea04 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt
@@ -23,8 +23,6 @@
 import androidx.lifecycle.DefaultLifecycleObserver
 import com.android.launcher3.icons.IconFactory
 import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.media.MediaProjectionAppSelectorActivity
-import com.android.systemui.media.MediaProjectionPermissionActivity
 import com.android.systemui.mediaprojection.appselector.data.ActivityTaskManagerLabelLoader
 import com.android.systemui.mediaprojection.appselector.data.ActivityTaskManagerThumbnailLoader
 import com.android.systemui.mediaprojection.appselector.data.AppIconLoader
@@ -37,6 +35,7 @@
 import com.android.systemui.mediaprojection.appselector.view.TaskPreviewSizeProvider
 import com.android.systemui.mediaprojection.devicepolicy.MediaProjectionDevicePolicyModule
 import com.android.systemui.mediaprojection.devicepolicy.PersonalProfile
+import com.android.systemui.mediaprojection.permission.MediaProjectionPermissionActivity
 import com.android.systemui.statusbar.phone.ConfigurationControllerImpl
 import com.android.systemui.statusbar.policy.ConfigurationController
 import dagger.Binds
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/BaseScreenSharePermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseScreenSharePermissionDialog.kt
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/screenrecord/BaseScreenSharePermissionDialog.kt
rename to packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseScreenSharePermissionDialog.kt
index 64006fe..8b437c3 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/BaseScreenSharePermissionDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseScreenSharePermissionDialog.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.systemui.screenrecord
+package com.android.systemui.mediaprojection.permission
 
 import android.content.Context
 import android.os.Bundle
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
rename to packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
index 4de6278..2b56d0c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.media;
+package com.android.systemui.mediaprojection.permission;
 
 import static android.media.projection.IMediaProjectionManager.EXTRA_PACKAGE_REUSING_GRANTED_CONSENT;
 import static android.media.projection.IMediaProjectionManager.EXTRA_USER_REVIEW_GRANTED_CONSENT;
@@ -22,8 +22,8 @@
 import static android.media.projection.ReviewGrantedConsentResult.RECORD_CONTENT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
 
-import static com.android.systemui.screenrecord.ScreenShareOptionKt.ENTIRE_SCREEN;
-import static com.android.systemui.screenrecord.ScreenShareOptionKt.SINGLE_APP;
+import static com.android.systemui.mediaprojection.permission.ScreenShareOptionKt.ENTIRE_SCREEN;
+import static com.android.systemui.mediaprojection.permission.ScreenShareOptionKt.SINGLE_APP;
 
 import android.annotation.Nullable;
 import android.app.Activity;
@@ -51,13 +51,13 @@
 import android.util.Log;
 import android.view.Window;
 
-import com.android.systemui.res.R;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
+import com.android.systemui.mediaprojection.MediaProjectionServiceHelper;
+import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorActivity;
 import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDevicePolicyResolver;
 import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDisabledDialog;
-import com.android.systemui.screenrecord.MediaProjectionPermissionDialog;
-import com.android.systemui.screenrecord.ScreenShareOption;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.util.Utils;
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/MediaProjectionPermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialog.kt
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/screenrecord/MediaProjectionPermissionDialog.kt
rename to packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialog.kt
index 47e28d8..2f10ad3 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/MediaProjectionPermissionDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialog.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.systemui.screenrecord
+package com.android.systemui.mediaprojection.permission
 
 import android.content.Context
 import android.media.projection.MediaProjectionConfig
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenShareOption.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/ScreenShareOption.kt
similarity index 94%
rename from packages/SystemUI/src/com/android/systemui/screenrecord/ScreenShareOption.kt
rename to packages/SystemUI/src/com/android/systemui/mediaprojection/permission/ScreenShareOption.kt
index ebf0dd2..37e8d9f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenShareOption.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/ScreenShareOption.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.systemui.screenrecord
+package com.android.systemui.mediaprojection.permission
 
 import androidx.annotation.IntDef
 import androidx.annotation.StringRes
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index 9a9626d..10f95e0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -48,6 +48,7 @@
 import com.android.systemui.qs.pipeline.data.repository.CustomTileAddedRepository;
 import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor;
 import com.android.systemui.qs.pipeline.shared.QSPipelineFlagsRepository;
+import com.android.systemui.qs.tiles.di.NewQSTileFactory;
 import com.android.systemui.settings.UserFileManager;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.shade.ShadeController;
@@ -56,6 +57,8 @@
 import com.android.systemui.tuner.TunerService.Tunable;
 import com.android.systemui.util.settings.SecureSettings;
 
+import dagger.Lazy;
+
 import org.jetbrains.annotations.NotNull;
 
 import java.io.PrintWriter;
@@ -121,6 +124,7 @@
 
     @Inject
     public QSTileHost(Context context,
+            Lazy<NewQSTileFactory> newQsTileFactoryProvider,
             QSFactory defaultFactory,
             @Main Executor mainExecutor,
             PluginManager pluginManager,
@@ -147,6 +151,9 @@
 
         mShadeController = shadeController;
 
+        if (featureFlags.getPipelineTilesEnabled()) {
+            mQsFactories.add(newQsTileFactoryProvider.get());
+        }
         mQsFactories.add(defaultFactory);
         pluginManager.addPluginListener(this, QSFactory.class, true);
         mUserTracker = userTracker;
@@ -326,7 +333,6 @@
                 try {
                     tile = createTile(tileSpec);
                     if (tile != null) {
-                        tile.setTileSpec(tileSpec);
                         if (tile.isAvailable()) {
                             newTiles.put(tileSpec, tile);
                             mQSLogger.logTileAdded(tileSpec);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index a6226b3..2af7ae0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -130,11 +130,9 @@
             if (tile == null) {
                 continue;
             } else if (!tile.isAvailable()) {
-                tile.setTileSpec(spec);
                 tile.destroy();
                 continue;
             }
-            tile.setTileSpec(spec);
             tilesToAdd.add(tile);
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
index 92490e8..a65967a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
@@ -31,6 +31,7 @@
 import com.android.systemui.qs.external.QSExternalModule;
 import com.android.systemui.qs.pipeline.dagger.QSPipelineModule;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.qs.tiles.viewmodel.QSTileViewModel;
 import com.android.systemui.statusbar.phone.AutoTileManager;
 import com.android.systemui.statusbar.phone.ManagedProfileController;
 import com.android.systemui.statusbar.policy.CastController;
@@ -41,14 +42,14 @@
 import com.android.systemui.statusbar.policy.WalletController;
 import com.android.systemui.util.settings.SecureSettings;
 
-import java.util.Map;
-
-import javax.inject.Named;
-
 import dagger.Module;
 import dagger.Provides;
 import dagger.multibindings.Multibinds;
 
+import java.util.Map;
+
+import javax.inject.Named;
+
 /**
  * Module for QS dependencies
  */
@@ -68,6 +69,11 @@
     @Multibinds
     Map<String, QSTileImpl<?>> tileMap();
 
+    /** A map of internal QS tile ViewModels. Ensures that this can be injected even if
+     * it is empty */
+    @Multibinds
+    Map<String, QSTileViewModel> tileViewModelMap();
+
     @Provides
     @SysUISingleton
     static AutoTileManager provideAutoTileManager(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt
index 00c2358..c5512c1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt
@@ -41,10 +41,12 @@
 import com.android.systemui.qs.pipeline.shared.QSPipelineFlagsRepository
 import com.android.systemui.qs.pipeline.shared.TileSpec
 import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger
+import com.android.systemui.qs.tiles.di.NewQSTileFactory
 import com.android.systemui.qs.toProto
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.user.data.repository.UserRepository
 import com.android.systemui.util.kotlin.pairwise
+import dagger.Lazy
 import java.io.PrintWriter
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
@@ -131,6 +133,7 @@
     private val installedTilesComponentRepository: InstalledTilesComponentRepository,
     private val userRepository: UserRepository,
     private val customTileStatePersister: CustomTileStatePersister,
+    private val newQSTileFactory: Lazy<NewQSTileFactory>,
     private val tileFactory: QSFactory,
     private val customTileAddedRepository: CustomTileAddedRepository,
     private val tileLifecycleManagerFactory: TileLifecycleManager.Factory,
@@ -139,7 +142,7 @@
     @Background private val backgroundDispatcher: CoroutineDispatcher,
     @Application private val scope: CoroutineScope,
     private val logger: QSPipelineLogger,
-    featureFlags: QSPipelineFlagsRepository,
+    private val featureFlags: QSPipelineFlagsRepository,
 ) : CurrentTilesInteractor {
 
     private val _currentSpecsAndTiles: MutableStateFlow<List<TileModel>> =
@@ -333,12 +336,19 @@
     }
 
     private suspend fun createTile(spec: TileSpec): QSTile? {
-        val tile = withContext(mainDispatcher) { tileFactory.createTile(spec.spec) }
+        val tile =
+            withContext(mainDispatcher) {
+                if (featureFlags.pipelineTilesEnabled) {
+                    newQSTileFactory.get().createTile(spec.spec)
+                } else {
+                    null
+                }
+                    ?: tileFactory.createTile(spec.spec)
+            }
         if (tile == null) {
             logger.logTileNotFoundInFactory(spec)
             return null
         } else {
-            tile.tileSpec = spec.spec
             return if (!tile.isAvailable) {
                 logger.logTileDestroyed(
                     spec,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepository.kt
index 551b0f4..1a71b71 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepository.kt
@@ -1,7 +1,7 @@
 package com.android.systemui.qs.pipeline.shared
 
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.FeatureFlagsClassic
 import com.android.systemui.flags.Flags
 import javax.inject.Inject
 
@@ -10,7 +10,7 @@
 class QSPipelineFlagsRepository
 @Inject
 constructor(
-    private val featureFlags: FeatureFlags,
+    private val featureFlags: FeatureFlagsClassic,
 ) {
 
     /** @see Flags.QS_PIPELINE_NEW_HOST */
@@ -20,4 +20,8 @@
     /** @see Flags.QS_PIPELINE_AUTO_ADD */
     val pipelineAutoAddEnabled: Boolean
         get() = pipelineHostEnabled && featureFlags.isEnabled(Flags.QS_PIPELINE_AUTO_ADD)
+
+    /** @see Flags.QS_PIPELINE_NEW_TILES */
+    val pipelineTilesEnabled: Boolean
+        get() = featureFlags.isEnabled(Flags.QS_PIPELINE_NEW_TILES)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt
index 11b5dd7..aed08f8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt
@@ -31,11 +31,7 @@
 sealed class TileSpec private constructor(open val spec: String) {
 
     /** Represents a spec that couldn't be parsed into a valid type of tile. */
-    object Invalid : TileSpec("") {
-        override fun toString(): String {
-            return "TileSpec.INVALID"
-        }
-    }
+    data object Invalid : TileSpec("")
 
     /** Container for the spec of a tile provided by SystemUI. */
     data class PlatformTileSpec
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index 9c7a734..632aa63 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -70,6 +70,7 @@
         if (tile != null) {
             tile.initialize();
             tile.postStale(); // Tile was just created, must be stale.
+            tile.setTileSpec(tileSpec);
         }
         return tile;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserActionHandler.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserActionHandler.kt
index e9f907c..dc9e115 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserActionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserActionHandler.kt
@@ -1,11 +1,11 @@
 package com.android.systemui.qs.tiles.base.actions
 
 import android.content.Intent
+import android.view.View
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.systemui.animation.ActivityLaunchAnimator
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
 import javax.inject.Inject
 
 /**
@@ -17,9 +17,9 @@
 @Inject
 constructor(private val activityStarter: ActivityStarter) {
 
-    fun handle(userAction: QSTileUserAction, intent: Intent) {
+    fun handle(view: View?, intent: Intent) {
         val animationController: ActivityLaunchAnimator.Controller? =
-            userAction.view?.let {
+            view?.let {
                 ActivityLaunchAnimator.Controller.fromView(
                     it,
                     InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/BaseQSTileViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/BaseQSTileViewModel.kt
index c2a75fa..bb4de80 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/BaseQSTileViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/BaseQSTileViewModel.kt
@@ -92,7 +92,7 @@
             .stateIn(
                 tileScope,
                 SharingStarted.WhileSubscribed(),
-                false,
+                true,
             )
 
     private var currentLifeState: QSTileLifecycle = QSTileLifecycle.DEAD
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/di/NewQSTileFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/di/NewQSTileFactory.kt
new file mode 100644
index 0000000..3fedbfc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/di/NewQSTileFactory.kt
@@ -0,0 +1,28 @@
+package com.android.systemui.qs.tiles.di
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.plugins.qs.QSFactory
+import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.qs.tiles.viewmodel.QSTileLifecycle
+import com.android.systemui.qs.tiles.viewmodel.QSTileViewModel
+import com.android.systemui.qs.tiles.viewmodel.QSTileViewModelAdapter
+import javax.inject.Inject
+import javax.inject.Provider
+
+// TODO(b/http://b/299909989): Rename the factory after rollout
+@SysUISingleton
+class NewQSTileFactory
+@Inject
+constructor(
+    private val adapterFactory: QSTileViewModelAdapter.Factory,
+    private val tileMap:
+        Map<String, @JvmSuppressWildcards Provider<@JvmSuppressWildcards QSTileViewModel>>,
+) : QSFactory {
+
+    override fun createTile(tileSpec: String): QSTile? =
+        tileMap[tileSpec]?.let {
+            val tile = it.get()
+            tile.onLifecycle(QSTileLifecycle.ALIVE)
+            adapterFactory.create(tile)
+        }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfig.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfig.kt
index a5eaac1..019d3c0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfig.kt
@@ -1,14 +1,13 @@
 package com.android.systemui.qs.tiles.viewmodel
 
-import android.graphics.drawable.Icon
+import androidx.annotation.StringRes
+import com.android.internal.logging.InstanceId
+import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.qs.pipeline.shared.TileSpec
 
 data class QSTileConfig(
     val tileSpec: TileSpec,
     val tileIcon: Icon,
-    val tileLabel: CharSequence,
-// TODO(b/299908705): Fill necessary params
-/*
-val instanceId: InstanceId,
- */
+    @StringRes val tileLabelRes: Int,
+    val instanceId: InstanceId,
 )
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt
index 53f9edf..dc5c690 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt
@@ -1,18 +1,96 @@
 package com.android.systemui.qs.tiles.viewmodel
 
-import android.graphics.drawable.Icon
+import android.service.quicksettings.Tile
+import com.android.systemui.common.shared.model.Icon
 
+/**
+ * Represents current a state of the tile to be displayed in on the view. Consider using
+ * [QSTileState.build] for better state creation experience and preset default values for certain
+ * fields.
+ *
+ * // TODO(b/http://b/299909989): Clean up legacy mappings after the transition
+ */
 data class QSTileState(
-    val icon: Icon,
+    val icon: () -> Icon,
     val label: CharSequence,
-// TODO(b/299908705): Fill necessary params
-/*
-   val subtitle: CharSequence = "",
-   val activeState: ActivationState = Active,
-   val enabledState: Enabled = Enabled,
-   val loopIconAnimation: Boolean = false,
-   val secondaryIcon: Icon? = null,
-   val slashState: SlashState? = null,
-   val supportedActions: Collection<UserAction> = listOf(Click), clicks should be a default action
-*/
-)
+    val activationState: ActivationState,
+    val secondaryLabel: CharSequence?,
+    val supportedActions: Set<UserAction>,
+    val contentDescription: CharSequence?,
+    val stateDescription: CharSequence?,
+    val sideViewIcon: SideViewIcon,
+    val enabledState: EnabledState,
+    val expandedAccessibilityClassName: String?,
+) {
+
+    companion object {
+
+        fun build(icon: () -> Icon, label: CharSequence, build: Builder.() -> Unit): QSTileState =
+            Builder(icon, label).apply(build).build()
+
+        fun build(icon: Icon, label: CharSequence, build: Builder.() -> Unit): QSTileState =
+            build({ icon }, label, build)
+    }
+
+    enum class ActivationState(val legacyState: Int) {
+        // An unavailable state indicates that for some reason this tile is not currently available
+        // to the user, and will have no click action. The tile's icon will be tinted differently to
+        // reflect this state.
+        UNAVAILABLE(Tile.STATE_UNAVAILABLE),
+        // This represents a tile that is currently active. (e.g. wifi is connected, bluetooth is
+        // on, cast is casting). This is the default state.
+        ACTIVE(Tile.STATE_ACTIVE),
+        // This represents a tile that is currently in a disabled state but is still interactable. A
+        // disabled state indicates that the tile is not currently active (e.g. wifi disconnected or
+        // bluetooth disabled), but is still interactable by the user to modify this state.
+        INACTIVE(Tile.STATE_INACTIVE),
+    }
+
+    /**
+     * Enabled tile behaves as usual where is disabled one is frozen and inactive in its current
+     * [ActivationState].
+     */
+    enum class EnabledState {
+        ENABLED,
+        DISABLED,
+    }
+
+    enum class UserAction {
+        CLICK,
+        LONG_CLICK,
+    }
+
+    sealed interface SideViewIcon {
+        data class Custom(val icon: Icon) : SideViewIcon
+        data object Chevron : SideViewIcon
+        data object None : SideViewIcon
+    }
+
+    class Builder(
+        var icon: () -> Icon,
+        var label: CharSequence,
+    ) {
+        var activationState: ActivationState = ActivationState.INACTIVE
+        var secondaryLabel: CharSequence? = null
+        var supportedActions: Set<UserAction> = setOf(UserAction.CLICK)
+        var contentDescription: CharSequence? = null
+        var stateDescription: CharSequence? = null
+        var sideViewIcon: SideViewIcon = SideViewIcon.None
+        var enabledState: EnabledState = EnabledState.ENABLED
+        var expandedAccessibilityClassName: String? = null
+
+        fun build(): QSTileState =
+            QSTileState(
+                icon,
+                label,
+                activationState,
+                secondaryLabel,
+                supportedActions,
+                contentDescription,
+                stateDescription,
+                sideViewIcon,
+                enabledState,
+                expandedAccessibilityClassName,
+            )
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileUserAction.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileUserAction.kt
index f1f8f01..0b232c2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileUserAction.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileUserAction.kt
@@ -1,13 +1,11 @@
 package com.android.systemui.qs.tiles.viewmodel
 
-import android.content.Context
 import android.view.View
 
 sealed interface QSTileUserAction {
 
-    val context: Context
     val view: View?
 
-    class Click(override val context: Context, override val view: View?) : QSTileUserAction
-    class LongClick(override val context: Context, override val view: View?) : QSTileUserAction
+    class Click(override val view: View?) : QSTileUserAction
+    class LongClick(override val view: View?) : QSTileUserAction
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt
new file mode 100644
index 0000000..d4bdb77
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt
@@ -0,0 +1,232 @@
+package com.android.systemui.qs.tiles.viewmodel
+
+import android.content.Context
+import android.util.Log
+import android.view.View
+import androidx.annotation.GuardedBy
+import com.android.internal.logging.InstanceId
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.qs.QSHost
+import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon
+import com.android.systemui.qs.tileimpl.QSTileImpl.ResourceIcon
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import java.util.function.Supplier
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.cancelChildren
+import kotlinx.coroutines.flow.collectIndexed
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
+
+// TODO(b/http://b/299909989): Use QSTileViewModel directly after the rollout
+class QSTileViewModelAdapter
+@AssistedInject
+constructor(
+    private val qsHost: QSHost,
+    @Assisted private val qsTileViewModel: QSTileViewModel,
+) : QSTile {
+
+    private val context
+        get() = qsHost.context
+
+    @GuardedBy("callbacks")
+    private val callbacks: MutableCollection<QSTile.Callback> = mutableSetOf()
+    @GuardedBy("listeningClients")
+    private val listeningClients: MutableCollection<Any> = mutableSetOf()
+
+    // Cancels the jobs when the adapter is no longer alive
+    private val adapterScope = CoroutineScope(SupervisorJob())
+    // Cancels the jobs when clients stop listening
+    private val listeningScope = CoroutineScope(SupervisorJob())
+
+    init {
+        adapterScope.launch {
+            qsTileViewModel.isAvailable.collectIndexed { index, isAvailable ->
+                if (!isAvailable) {
+                    qsHost.removeTile(tileSpec)
+                }
+                // qsTileViewModel.isAvailable flow often starts with isAvailable == true. That's
+                // why we only allow isAvailable == true once and throw an exception afterwards.
+                if (index > 0 && isAvailable) {
+                    // See com.android.systemui.qs.pipeline.domain.model.AutoAddable for additional
+                    // guidance on how to auto add your tile
+                    throw UnsupportedOperationException("Turning on tile is not supported now")
+                }
+            }
+        }
+
+        // QSTileHost doesn't call this when userId is initialized
+        userSwitch(qsHost.userId)
+
+        if (DEBUG) {
+            Log.d(TAG, "Using new tiles for: $tileSpec")
+        }
+    }
+
+    override fun isAvailable(): Boolean = qsTileViewModel.isAvailable.value
+
+    override fun setTileSpec(tileSpec: String?) {
+        throw UnsupportedOperationException("Tile spec is immutable in new tiles")
+    }
+
+    override fun refreshState() {
+        qsTileViewModel.forceUpdate()
+    }
+
+    override fun addCallback(callback: QSTile.Callback?) {
+        callback ?: return
+        synchronized(callbacks) { callbacks.add(callback) }
+    }
+
+    override fun removeCallback(callback: QSTile.Callback?) {
+        callback ?: return
+        synchronized(callbacks) { callbacks.remove(callback) }
+    }
+
+    override fun removeCallbacks() {
+        synchronized(callbacks) { callbacks.clear() }
+    }
+
+    override fun click(view: View?) {
+        if (isActionSupported(QSTileState.UserAction.CLICK)) {
+            qsTileViewModel.onActionPerformed(QSTileUserAction.Click(view))
+        }
+    }
+
+    override fun secondaryClick(view: View?) {
+        if (isActionSupported(QSTileState.UserAction.CLICK)) {
+            qsTileViewModel.onActionPerformed(QSTileUserAction.Click(view))
+        }
+    }
+
+    override fun longClick(view: View?) {
+        if (isActionSupported(QSTileState.UserAction.LONG_CLICK)) {
+            qsTileViewModel.onActionPerformed(QSTileUserAction.LongClick(view))
+        }
+    }
+
+    private fun isActionSupported(action: QSTileState.UserAction): Boolean =
+        qsTileViewModel.currentState?.supportedActions?.contains(action) == true
+
+    override fun userSwitch(currentUser: Int) {
+        qsTileViewModel.onUserIdChanged(currentUser)
+    }
+
+    @Deprecated(
+        "Not needed as {@link com.android.internal.logging.UiEvent} will use #getMetricsSpec",
+        replaceWith = ReplaceWith("getMetricsSpec"),
+    )
+    override fun getMetricsCategory(): Int = 0
+
+    override fun setListening(client: Any?, listening: Boolean) {
+        client ?: return
+        synchronized(listeningClients) {
+            if (listening) {
+                listeningClients.add(client)
+                if (listeningClients.size == 1) {
+                    qsTileViewModel.state
+                        .map { mapState(context, it, qsTileViewModel.config) }
+                        .onEach { legacyState ->
+                            synchronized(callbacks) {
+                                callbacks.forEach { it.onStateChanged(legacyState) }
+                            }
+                        }
+                        .launchIn(listeningScope)
+                }
+            } else {
+                listeningClients.remove(client)
+                if (listeningClients.isEmpty()) {
+                    listeningScope.coroutineContext.cancelChildren()
+                }
+            }
+        }
+    }
+
+    override fun isListening(): Boolean =
+        synchronized(listeningClients) { listeningClients.isNotEmpty() }
+
+    override fun setDetailListening(show: Boolean) {
+        // do nothing like QSTileImpl
+    }
+
+    override fun destroy() {
+        adapterScope.cancel()
+        listeningScope.cancel()
+        qsTileViewModel.onLifecycle(QSTileLifecycle.DEAD)
+    }
+
+    override fun getState(): QSTile.State? =
+        qsTileViewModel.currentState?.let { mapState(context, it, qsTileViewModel.config) }
+
+    override fun getInstanceId(): InstanceId = qsTileViewModel.config.instanceId
+    override fun getTileLabel(): CharSequence =
+        context.getString(qsTileViewModel.config.tileLabelRes)
+    override fun getTileSpec(): String = qsTileViewModel.config.tileSpec.spec
+
+    private companion object {
+
+        const val DEBUG = false
+        const val TAG = "QSTileVMAdapter"
+
+        fun mapState(
+            context: Context,
+            viewModelState: QSTileState,
+            config: QSTileConfig
+        ): QSTile.State =
+            // we have to use QSTile.BooleanState to support different side icons
+            // which are bound to instanceof QSTile.BooleanState in QSTileView.
+            QSTile.BooleanState().apply {
+                spec = config.tileSpec.spec
+                label = viewModelState.label
+                // This value is synthetic and doesn't have any meaning
+                value = false
+
+                secondaryLabel = viewModelState.secondaryLabel
+                handlesLongClick =
+                    viewModelState.supportedActions.contains(QSTileState.UserAction.LONG_CLICK)
+
+                iconSupplier = Supplier {
+                    when (val stateIcon = viewModelState.icon()) {
+                        is Icon.Loaded -> DrawableIcon(stateIcon.drawable)
+                        is Icon.Resource -> ResourceIcon.get(stateIcon.res)
+                    }
+                }
+                state = viewModelState.activationState.legacyState
+
+                contentDescription = viewModelState.contentDescription
+                stateDescription = viewModelState.stateDescription
+
+                disabledByPolicy = viewModelState.enabledState == QSTileState.EnabledState.DISABLED
+                expandedAccessibilityClassName = viewModelState.expandedAccessibilityClassName
+
+                when (viewModelState.sideViewIcon) {
+                    is QSTileState.SideViewIcon.Custom -> {
+                        sideViewCustomDrawable =
+                            when (viewModelState.sideViewIcon.icon) {
+                                is Icon.Loaded -> viewModelState.sideViewIcon.icon.drawable
+                                is Icon.Resource ->
+                                    context.getDrawable(viewModelState.sideViewIcon.icon.res)
+                            }
+                    }
+                    is QSTileState.SideViewIcon.Chevron -> {
+                        forceExpandIcon = true
+                    }
+                    is QSTileState.SideViewIcon.None -> {
+                        forceExpandIcon = false
+                    }
+                }
+            }
+    }
+
+    @AssistedFactory
+    interface Factory {
+
+        fun create(qsTileViewModel: QSTileViewModel): QSTileViewModelAdapter
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index 7cdb655..3501b6b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -41,10 +41,10 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.UiEventLogger;
-import com.android.systemui.res.R;
 import com.android.systemui.dagger.qualifiers.LongRunning;
 import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.media.MediaProjectionCaptureTarget;
+import com.android.systemui.mediaprojection.MediaProjectionCaptureTarget;
+import com.android.systemui.res.R;
 import com.android.systemui.screenrecord.ScreenMediaRecorder.ScreenMediaRecorderListener;
 import com.android.systemui.settings.UserContextProvider;
 import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
index b80a01212..3aab3bf 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
@@ -51,7 +51,7 @@
 import android.view.Surface;
 import android.view.WindowManager;
 
-import com.android.systemui.media.MediaProjectionCaptureTarget;
+import com.android.systemui.mediaprojection.MediaProjectionCaptureTarget;
 
 import java.io.Closeable;
 import java.io.File;
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
index f0ce8a4..f2e94e9 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
@@ -18,7 +18,7 @@
 
 import static android.app.Activity.RESULT_OK;
 
-import static com.android.systemui.media.MediaProjectionAppSelectorActivity.KEY_CAPTURE_TARGET;
+import static com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorActivity.KEY_CAPTURE_TARGET;
 import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.INTERNAL;
 import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.MIC;
 import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.MIC_AND_INTERNAL;
@@ -41,8 +41,8 @@
 
 import androidx.annotation.Nullable;
 
+import com.android.systemui.mediaprojection.MediaProjectionCaptureTarget;
 import com.android.systemui.res.R;
-import com.android.systemui.media.MediaProjectionCaptureTarget;
 import com.android.systemui.settings.UserContextProvider;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
index b5b7043..a1d5d98 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
@@ -32,10 +32,14 @@
 import android.widget.Spinner
 import android.widget.Switch
 import androidx.annotation.LayoutRes
-import com.android.systemui.res.R
-import com.android.systemui.media.MediaProjectionAppSelectorActivity
-import com.android.systemui.media.MediaProjectionCaptureTarget
+import com.android.systemui.mediaprojection.MediaProjectionCaptureTarget
+import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorActivity
+import com.android.systemui.mediaprojection.permission.BaseScreenSharePermissionDialog
+import com.android.systemui.mediaprojection.permission.ENTIRE_SCREEN
+import com.android.systemui.mediaprojection.permission.SINGLE_APP
+import com.android.systemui.mediaprojection.permission.ScreenShareOption
 import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.res.R
 import com.android.systemui.settings.UserContextProvider
 
 /** Dialog to select screen recording options */
@@ -58,6 +62,7 @@
     private lateinit var tapsView: View
     private lateinit var audioSwitch: Switch
     private lateinit var options: Spinner
+
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         setDialogTitle(R.string.screenrecord_permission_dialog_title)
@@ -177,6 +182,7 @@
             )
         private const val DELAY_MS: Long = 3000
         private const val INTERVAL_MS: Long = 1000
+
         private fun createOptionList(): List<ScreenShareOption> {
             return listOf(
                 ScreenShareOption(
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
index b715237..6fa592c 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
@@ -30,12 +30,13 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.systemui.Gefingerpoken;
-import com.android.systemui.res.R;
 import com.android.systemui.classifier.Classifier;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.flags.FeatureFlagsClassic;
 import com.android.systemui.haptics.slider.SeekableSliderEventProducer;
+import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.policy.BrightnessMirrorController;
 import com.android.systemui.util.ViewController;
@@ -283,6 +284,7 @@
         private final VibratorHelper mVibratorHelper;
         private final SystemClock mSystemClock;
         private final CoroutineDispatcher mMainDispatcher;
+        private final ActivityStarter mActivityStarter;
 
         @Inject
         public Factory(
@@ -291,14 +293,15 @@
                 VibratorHelper vibratorHelper,
                 SystemClock clock,
                 FeatureFlagsClassic featureFlags,
-                @Main CoroutineDispatcher mainDispatcher
-        ) {
+                @Main CoroutineDispatcher mainDispatcher,
+                ActivityStarter activityStarter) {
             mFalsingManager = falsingManager;
             mUiEventLogger = uiEventLogger;
             mFeatureFlags = featureFlags;
             mVibratorHelper = vibratorHelper;
             mSystemClock = clock;
             mMainDispatcher = mainDispatcher;
+            mActivityStarter = activityStarter;
         }
 
         /**
@@ -314,6 +317,8 @@
             int layout = getLayout();
             BrightnessSliderView root = (BrightnessSliderView) LayoutInflater.from(context)
                     .inflate(layout, viewRoot, false);
+            root.setActivityStarter(mActivityStarter);
+
             BrightnessSliderHapticPlugin plugin;
             if (mFeatureFlags.isEnabled(HAPTIC_BRIGHTNESS_SLIDER)) {
                 plugin = new BrightnessSliderHapticPluginImpl(
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java
index c885492..5ecf07f 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java
@@ -33,6 +33,7 @@
 
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.systemui.Gefingerpoken;
+import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.res.R;
 
 /**
@@ -41,6 +42,7 @@
  */
 public class BrightnessSliderView extends FrameLayout {
 
+    private ActivityStarter mActivityStarter;
     @NonNull
     private ToggleSeekBar mSlider;
     private DispatchTouchEventListener mListener;
@@ -57,6 +59,10 @@
         super(context, attrs);
     }
 
+    public void setActivityStarter(@NonNull ActivityStarter activityStarter) {
+        mActivityStarter = activityStarter;
+    }
+
     // Inflated from quick_settings_brightness_dialog
     @Override
     protected void onFinishInflate() {
@@ -65,6 +71,7 @@
 
         mSlider = requireViewById(R.id.slider);
         mSlider.setAccessibilityLabel(getContentDescription().toString());
+        mSlider.setActivityStarter(mActivityStarter);
 
         // Finds the progress drawable. Assumes brightness_progress_drawable.xml
         try {
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSeekBar.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSeekBar.java
index a5a0ae7..6ec10da 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSeekBar.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSeekBar.java
@@ -23,8 +23,9 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.SeekBar;
 
+import androidx.annotation.NonNull;
+
 import com.android.settingslib.RestrictedLockUtils;
-import com.android.systemui.Dependency;
 import com.android.systemui.plugins.ActivityStarter;
 
 public class ToggleSeekBar extends SeekBar {
@@ -32,6 +33,8 @@
 
     private RestrictedLockUtils.EnforcedAdmin mEnforcedAdmin = null;
 
+    private ActivityStarter mActivityStarter;
+
     public ToggleSeekBar(Context context) {
         super(context);
     }
@@ -49,7 +52,7 @@
         if (mEnforcedAdmin != null) {
             Intent intent = RestrictedLockUtils.getShowAdminSupportDetailsIntent(
                     mContext, mEnforcedAdmin);
-            Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(intent, 0);
+            mActivityStarter.postStartActivityDismissingKeyguard(intent, 0);
             return true;
         }
         if (!isEnabled()) {
@@ -74,4 +77,8 @@
     public void setEnforcedAdmin(RestrictedLockUtils.EnforcedAdmin admin) {
         mEnforcedAdmin = admin;
     }
+
+    public void setActivityStarter(@NonNull ActivityStarter activityStarter) {
+        mActivityStarter = activityStarter;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
index 251cc16..ac8333a 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
@@ -129,6 +129,9 @@
         combine(shadeExpansion, qsExpansion) { shadeExp, qsExp -> maxOf(shadeExp, qsExp) }
             .stateIn(scope, SharingStarted.Eagerly, 0f)
 
+    /** Whether either the shade or QS is fully expanded. */
+    val isAnyFullyExpanded: Flow<Boolean> = anyExpansion.map { it >= 1f }.distinctUntilChanged()
+
     /** Whether either the shade or QS is expanding from a fully collapsed state. */
     val isAnyExpanding: Flow<Boolean> =
         anyExpansion
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 8baab25..f616b91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -244,12 +244,16 @@
             }
             final float scaledImageWidth = drawableWidth * scaleToFitIconView;
             final float scaledImageHeight = drawableHeight * scaleToFitIconView;
-            // if the scaled image size <= mOriginalStatusBarIconSize, we don't need to enlarge it
             scaleToOriginalDrawingSize = Math.min(
                     (float) mOriginalStatusBarIconSize / scaledImageWidth,
                     (float) mOriginalStatusBarIconSize / scaledImageHeight);
             if (scaleToOriginalDrawingSize > 1.0f) {
-                scaleToOriginalDrawingSize = 1.0f;
+                // per b/296026932, if the scaled image size <= mOriginalStatusBarIconSize, we need
+                // to scale up the scaled image to fit in mOriginalStatusBarIconSize. But if both
+                // the raw drawable intrinsic width/height are less than mOriginalStatusBarIconSize,
+                // then we just scale up the scaled image back to the raw drawable size.
+                scaleToOriginalDrawingSize = Math.min(
+                        scaleToOriginalDrawingSize, 1f / scaleToFitIconView);
             }
         }
         iconScale = scaleToOriginalDrawingSize;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/CallLayoutSetDataAsyncFactory.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/CallLayoutSetDataAsyncFactory.kt
new file mode 100644
index 0000000..4deebdb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/CallLayoutSetDataAsyncFactory.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.row
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.View
+import com.android.internal.widget.CallLayout
+import javax.inject.Inject
+
+class CallLayoutSetDataAsyncFactory @Inject constructor() : NotifRemoteViewsFactory {
+    override fun instantiate(
+        row: ExpandableNotificationRow,
+        @NotificationRowContentBinder.InflationFlag layoutType: Int,
+        parent: View?,
+        name: String,
+        context: Context,
+        attrs: AttributeSet
+    ): View? =
+        if (name == CallLayout::class.java.name)
+            CallLayout(context, attrs).apply { setSetDataAsyncEnabled(true) }
+        else null
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java
index 0239afc..3a59978 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java
@@ -61,7 +61,8 @@
     static Set<NotifRemoteViewsFactory> provideNotifRemoteViewsFactories(
             FeatureFlags featureFlags,
             PrecomputedTextViewFactory precomputedTextViewFactory,
-            BigPictureLayoutInflaterFactory bigPictureLayoutInflaterFactory
+            BigPictureLayoutInflaterFactory bigPictureLayoutInflaterFactory,
+            CallLayoutSetDataAsyncFactory callLayoutSetDataAsyncFactory
     ) {
         final Set<NotifRemoteViewsFactory> replacementFactories = new HashSet<>();
         if (featureFlags.isEnabled(Flags.PRECOMPUTED_TEXT)) {
@@ -70,6 +71,9 @@
         if (featureFlags.isEnabled(Flags.BIGPICTURE_NOTIFICATION_LAZY_LOADING)) {
             replacementFactories.add(bigPictureLayoutInflaterFactory);
         }
+        if (featureFlags.isEnabled(Flags.CALL_LAYOUT_ASYNC_SET_DATA)) {
+            replacementFactories.add(callLayoutSetDataAsyncFactory);
+        }
         return replacementFactories;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
index 875a409..91b12cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
@@ -20,6 +20,9 @@
 
 import static com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.DEFAULT_HEADER_VISIBLE_AMOUNT;
 
+import android.annotation.MainThread;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -34,8 +37,7 @@
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
-import androidx.annotation.Nullable;
-
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ContrastColorUtil;
 import com.android.internal.widget.NotificationActionListLayout;
 import com.android.systemui.Dependency;
@@ -49,6 +51,8 @@
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.HybridNotificationView;
 
+import java.util.function.Consumer;
+
 /**
  * Wraps a notification view inflated from a template.
  */
@@ -66,9 +70,13 @@
 
     private int mContentHeight;
     private int mMinHeightHint;
+    @Nullable
     private NotificationActionListLayout mActions;
-    private ArraySet<PendingIntent> mCancelledPendingIntents = new ArraySet<>();
-    private UiOffloadThread mUiOffloadThread;
+    // Holds list of pending intents that have been cancelled by now - we only keep hash codes
+    // to avoid holding full binder proxies for intents that may have been removed by now.
+    @NonNull
+    @VisibleForTesting
+    final ArraySet<Integer> mCancelledPendingIntents = new ArraySet<>();
     private View mRemoteInputHistory;
     private boolean mCanHideHeader;
     private float mHeaderTranslation;
@@ -147,6 +155,7 @@
                 com.android.internal.R.dimen.notification_content_margin_top);
     }
 
+    @MainThread
     private void resolveTemplateViews(StatusBarNotification sbn) {
         mRightIcon = mView.findViewById(com.android.internal.R.id.right_icon);
         if (mRightIcon != null) {
@@ -195,34 +204,57 @@
         return getLargeIcon(n);
     }
 
+    @MainThread
     private void updatePendingIntentCancellations() {
         if (mActions != null) {
             int numActions = mActions.getChildCount();
+            final ArraySet<Integer> currentlyActivePendingIntents = new ArraySet<>(numActions);
             for (int i = 0; i < numActions; i++) {
                 Button action = (Button) mActions.getChildAt(i);
-                performOnPendingIntentCancellation(action, () -> {
-                    if (action.isEnabled()) {
-                        action.setEnabled(false);
-                        // The visual appearance doesn't look disabled enough yet, let's add the
-                        // alpha as well. Since Alpha doesn't play nicely right now with the
-                        // transformation, we rather blend it manually with the background color.
-                        ColorStateList textColors = action.getTextColors();
-                        int[] colors = textColors.getColors();
-                        int[] newColors = new int[colors.length];
-                        float disabledAlpha = mView.getResources().getFloat(
-                                com.android.internal.R.dimen.notification_action_disabled_alpha);
-                        for (int j = 0; j < colors.length; j++) {
-                            int color = colors[j];
-                            color = blendColorWithBackground(color, disabledAlpha);
-                            newColors[j] = color;
-                        }
-                        ColorStateList newColorStateList = new ColorStateList(
-                                textColors.getStates(), newColors);
-                        action.setTextColor(newColorStateList);
+                PendingIntent pendingIntent = getPendingIntentForAction(action);
+                // Check if passed intent has already been cancelled in this class and immediately
+                // disable the action to avoid temporary race with enable/disable.
+                if (pendingIntent != null) {
+                    int pendingIntentHashCode = getHashCodeForPendingIntent(pendingIntent);
+                    currentlyActivePendingIntents.add(pendingIntentHashCode);
+                    if (mCancelledPendingIntents.contains(pendingIntentHashCode)) {
+                        disableActionView(action);
                     }
-                });
+                }
+                updatePendingIntentCancellationListener(action, pendingIntent);
+            }
+
+            // This cleanup ensures that the size of this set doesn't grow into unreasonable sizes.
+            // There are scenarios where applications updated notifications with different
+            // PendingIntents which could cause this Set to grow to 1000+ elements.
+            mCancelledPendingIntents.retainAll(currentlyActivePendingIntents);
+        }
+    }
+
+    @MainThread
+    private void updatePendingIntentCancellationListener(Button action,
+            @Nullable PendingIntent pendingIntent) {
+        ActionPendingIntentCancellationHandler cancellationHandler = null;
+        if (pendingIntent != null) {
+            // Attach listeners to handle intent cancellation to this view.
+            cancellationHandler = new ActionPendingIntentCancellationHandler(pendingIntent, action,
+                    this::disableActionViewWithIntent);
+            action.addOnAttachStateChangeListener(cancellationHandler);
+            // Immediately fire the event if the view is already attached to register
+            // pending intent cancellation listener.
+            if (action.isAttachedToWindow()) {
+                cancellationHandler.onViewAttachedToWindow(action);
             }
         }
+
+        // If the view has an old attached listener, remove it to avoid leaking intents.
+        ActionPendingIntentCancellationHandler previousHandler =
+                (ActionPendingIntentCancellationHandler) action.getTag(
+                        R.id.pending_intent_listener_tag);
+        if (previousHandler != null) {
+            previousHandler.remove();
+        }
+        action.setTag(R.id.pending_intent_listener_tag, cancellationHandler);
     }
 
     private int blendColorWithBackground(int color, float alpha) {
@@ -231,42 +263,6 @@
                 Color.red(color), Color.green(color), Color.blue(color)), resolveBackgroundColor());
     }
 
-    private void performOnPendingIntentCancellation(View view, Runnable cancellationRunnable) {
-        PendingIntent pendingIntent = (PendingIntent) view.getTag(
-                com.android.internal.R.id.pending_intent_tag);
-        if (pendingIntent == null) {
-            return;
-        }
-        if (mCancelledPendingIntents.contains(pendingIntent)) {
-            cancellationRunnable.run();
-        } else {
-            PendingIntent.CancelListener listener = (PendingIntent intent) -> {
-                mView.post(() -> {
-                    mCancelledPendingIntents.add(pendingIntent);
-                    cancellationRunnable.run();
-                });
-            };
-            if (mUiOffloadThread == null) {
-                mUiOffloadThread = Dependency.get(UiOffloadThread.class);
-            }
-            if (view.isAttachedToWindow()) {
-                mUiOffloadThread.execute(() -> pendingIntent.registerCancelListener(listener));
-            }
-            view.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
-                @Override
-                public void onViewAttachedToWindow(View v) {
-                    mUiOffloadThread.execute(() -> pendingIntent.registerCancelListener(listener));
-                }
-
-                @Override
-                public void onViewDetachedFromWindow(View v) {
-                    mUiOffloadThread.execute(
-                            () -> pendingIntent.unregisterCancelListener(listener));
-                }
-            });
-        }
-    }
-
     @Override
     public void onContentUpdated(ExpandableNotificationRow row) {
         // Reinspect the notification. Before the super call, because the super call also updates
@@ -364,4 +360,141 @@
         }
         return extra + super.getExtraMeasureHeight();
     }
+
+    /**
+     * This finds Action view with a given intent and disables it.
+     * With maximum of 3 views, this is sufficiently fast to iterate on main thread every time.
+     */
+    @MainThread
+    private void disableActionViewWithIntent(PendingIntent intent) {
+        mCancelledPendingIntents.add(getHashCodeForPendingIntent(intent));
+        if (mActions != null) {
+            int numActions = mActions.getChildCount();
+            for (int i = 0; i < numActions; i++) {
+                Button action = (Button) mActions.getChildAt(i);
+                PendingIntent pendingIntent = getPendingIntentForAction(action);
+                if (intent.equals(pendingIntent)) {
+                    disableActionView(action);
+                }
+            }
+        }
+    }
+
+    /**
+     * Disables Action view when, e.g., its PendingIntent is disabled.
+     */
+    @MainThread
+    private void disableActionView(Button action) {
+        if (action.isEnabled()) {
+            action.setEnabled(false);
+            // The visual appearance doesn't look disabled enough yet, let's add the
+            // alpha as well. Since Alpha doesn't play nicely right now with the
+            // transformation, we rather blend it manually with the background color.
+            ColorStateList textColors = action.getTextColors();
+            int[] colors = textColors.getColors();
+            int[] newColors = new int[colors.length];
+            float disabledAlpha = mView.getResources().getFloat(
+                    com.android.internal.R.dimen.notification_action_disabled_alpha);
+            for (int j = 0; j < colors.length; j++) {
+                int color = colors[j];
+                color = blendColorWithBackground(color, disabledAlpha);
+                newColors[j] = color;
+            }
+            ColorStateList newColorStateList = new ColorStateList(
+                    textColors.getStates(), newColors);
+            action.setTextColor(newColorStateList);
+        }
+    }
+
+    /**
+     * Returns the hashcode of underlying target of PendingIntent. We can get multiple
+     * Java PendingIntent wrapper objects pointing to the same cancelled PI in system_server.
+     * This makes sure we treat them equally.
+     */
+    private static int getHashCodeForPendingIntent(PendingIntent pendingIntent) {
+        return System.identityHashCode(pendingIntent.getTarget().asBinder());
+    }
+
+    /**
+     * Returns PendingIntent contained in the action tag. May be null.
+     */
+    @Nullable
+    private static PendingIntent getPendingIntentForAction(View action) {
+        return (PendingIntent) action.getTag(com.android.internal.R.id.pending_intent_tag);
+    }
+
+    /**
+     * Registers listeners for pending intent cancellation when Action views are attached
+     * to window.
+     * It calls onCancelPendingIntentForActionView when a PendingIntent is cancelled.
+     */
+    @VisibleForTesting
+    static final class ActionPendingIntentCancellationHandler
+            implements View.OnAttachStateChangeListener {
+
+        @Nullable
+        private static UiOffloadThread sUiOffloadThread = null;
+
+        @NonNull
+        private static UiOffloadThread getUiOffloadThread() {
+            if (sUiOffloadThread == null) {
+                sUiOffloadThread = Dependency.get(UiOffloadThread.class);
+            }
+            return sUiOffloadThread;
+        }
+
+        private final View mView;
+        private final Consumer<PendingIntent> mOnCancelledCallback;
+
+        private final PendingIntent mPendingIntent;
+
+        ActionPendingIntentCancellationHandler(PendingIntent pendingIntent, View actionView,
+                Consumer<PendingIntent> onCancelled) {
+            this.mPendingIntent = pendingIntent;
+            this.mView = actionView;
+            this.mOnCancelledCallback = onCancelled;
+        }
+
+        private final PendingIntent.CancelListener mCancelListener =
+                new PendingIntent.CancelListener() {
+            @Override
+            public void onCanceled(PendingIntent pendingIntent) {
+                mView.post(() -> {
+                    mOnCancelledCallback.accept(pendingIntent);
+                    // We don't need this listener anymore once the intent was cancelled.
+                    remove();
+                });
+            }
+        };
+
+        @MainThread
+        @Override
+        public void onViewAttachedToWindow(View view) {
+            // This is safe to call multiple times with the same listener instance.
+            getUiOffloadThread().execute(() -> {
+                mPendingIntent.registerCancelListener(mCancelListener);
+            });
+        }
+
+        @MainThread
+        @Override
+        public void onViewDetachedFromWindow(View view) {
+            // This is safe to call multiple times with the same listener instance.
+            getUiOffloadThread().execute(() ->
+                    mPendingIntent.unregisterCancelListener(mCancelListener));
+        }
+
+        /**
+         * Removes this listener from callbacks and releases the held PendingIntent.
+         */
+        @MainThread
+        public void remove() {
+            mView.removeOnAttachStateChangeListener(this);
+            if (mView.getTag(R.id.pending_intent_listener_tag) == this) {
+                mView.setTag(R.id.pending_intent_listener_tag, null);
+            }
+            getUiOffloadThread().execute(() ->
+                    mPendingIntent.unregisterCancelListener(mCancelListener));
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/model/WifiIcon.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/model/WifiIcon.kt
index efa092b..250fe53 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/model/WifiIcon.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/model/WifiIcon.kt
@@ -22,11 +22,12 @@
 import androidx.annotation.VisibleForTesting
 import com.android.settingslib.AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH
 import com.android.settingslib.AccessibilityContentDescriptions.WIFI_NO_CONNECTION
-import com.android.systemui.res.R
+import com.android.settingslib.AccessibilityContentDescriptions.WIFI_OTHER_DEVICE_CONNECTION
 import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.log.table.Diffable
 import com.android.systemui.log.table.TableRowLogger
+import com.android.systemui.res.R
 import com.android.systemui.statusbar.connectivity.WifiIcons
 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
 
@@ -90,50 +91,56 @@
                             )}"
                         )
                     )
-                is WifiNetworkModel.Active -> {
-                    val levelDesc = context.getString(WIFI_CONNECTION_STRENGTH[model.level])
-                    val contentDescription =
-                        ContentDescription.Loaded(
-                            if (model.isValidated) {
-                                (levelDesc)
-                            } else {
-                                "$levelDesc,${context.getString(NO_INTERNET)}"
-                            }
-                        )
-                    Visible(model.toIcon(showHotspotInfo), contentDescription)
-                }
+                is WifiNetworkModel.Active -> model.toIcon(showHotspotInfo, context)
             }
 
-        @DrawableRes
-        private fun WifiNetworkModel.Active.toIcon(showHotspotInfo: Boolean): Int {
-            return if (!showHotspotInfo) {
-                this.toBasicIcon()
+        private fun WifiNetworkModel.Active.toIcon(
+            showHotspotInfo: Boolean,
+            context: Context,
+        ): Visible {
+            return if (
+                !showHotspotInfo ||
+                    this.hotspotDeviceType == WifiNetworkModel.HotspotDeviceType.NONE
+            ) {
+                this.toBasicIcon(context)
             } else {
-                when (this.hotspotDeviceType) {
-                    WifiNetworkModel.HotspotDeviceType.NONE -> this.toBasicIcon()
-                    WifiNetworkModel.HotspotDeviceType.TABLET ->
-                        com.android.settingslib.R.drawable.ic_hotspot_tablet
-                    WifiNetworkModel.HotspotDeviceType.LAPTOP ->
-                        com.android.settingslib.R.drawable.ic_hotspot_laptop
-                    WifiNetworkModel.HotspotDeviceType.WATCH ->
-                        com.android.settingslib.R.drawable.ic_hotspot_watch
-                    WifiNetworkModel.HotspotDeviceType.AUTO ->
-                        com.android.settingslib.R.drawable.ic_hotspot_auto
-                    // Use phone as the default drawable
-                    WifiNetworkModel.HotspotDeviceType.PHONE,
-                    WifiNetworkModel.HotspotDeviceType.UNKNOWN,
-                    WifiNetworkModel.HotspotDeviceType.INVALID ->
-                        com.android.settingslib.R.drawable.ic_hotspot_phone
-                }
+                val icon =
+                    when (this.hotspotDeviceType) {
+                        WifiNetworkModel.HotspotDeviceType.TABLET ->
+                            com.android.settingslib.R.drawable.ic_hotspot_tablet
+                        WifiNetworkModel.HotspotDeviceType.LAPTOP ->
+                            com.android.settingslib.R.drawable.ic_hotspot_laptop
+                        WifiNetworkModel.HotspotDeviceType.WATCH ->
+                            com.android.settingslib.R.drawable.ic_hotspot_watch
+                        WifiNetworkModel.HotspotDeviceType.AUTO ->
+                            com.android.settingslib.R.drawable.ic_hotspot_auto
+                        // Use phone as the default drawable
+                        WifiNetworkModel.HotspotDeviceType.PHONE,
+                        WifiNetworkModel.HotspotDeviceType.UNKNOWN,
+                        WifiNetworkModel.HotspotDeviceType.INVALID ->
+                            com.android.settingslib.R.drawable.ic_hotspot_phone
+                        WifiNetworkModel.HotspotDeviceType.NONE ->
+                            throw IllegalStateException("NONE checked earlier")
+                    }
+                Visible(
+                    icon,
+                    ContentDescription.Loaded(context.getString(WIFI_OTHER_DEVICE_CONNECTION)),
+                )
             }
         }
 
-        @DrawableRes
-        private fun WifiNetworkModel.Active.toBasicIcon(): Int {
+        private fun WifiNetworkModel.Active.toBasicIcon(context: Context): Visible {
+            val levelDesc = context.getString(WIFI_CONNECTION_STRENGTH[this.level])
             return if (this.isValidated) {
-                WifiIcons.WIFI_FULL_ICONS[this.level]
+                Visible(
+                    WifiIcons.WIFI_FULL_ICONS[this.level],
+                    ContentDescription.Loaded(levelDesc),
+                )
             } else {
-                WifiIcons.WIFI_NO_INTERNET_ICONS[this.level]
+                Visible(
+                    WifiIcons.WIFI_NO_INTERNET_ICONS[this.level],
+                    ContentDescription.Loaded("$levelDesc,${context.getString(NO_INTERNET)}"),
+                )
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 727d649..3c6d90d 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -135,6 +135,7 @@
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.util.AlphaTintDrawableWrapper;
 import com.android.systemui.util.RoundedCornerProgressDrawable;
+import com.android.systemui.util.settings.SecureSettings;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -304,6 +305,8 @@
     private @DevicePostureController.DevicePostureInt int mDevicePosture;
     private int mOrientation;
     private final FeatureFlags mFeatureFlags;
+    private final SecureSettings mSecureSettings;
+    private int mDialogTimeoutMillis;
 
     public VolumeDialogImpl(
             Context context,
@@ -320,7 +323,8 @@
             DevicePostureController devicePostureController,
             Looper looper,
             DumpManager dumpManager,
-            FeatureFlags featureFlags) {
+            FeatureFlags featureFlags,
+            SecureSettings secureSettings) {
         mFeatureFlags = featureFlags;
         mContext =
                 new ContextThemeWrapper(context, R.style.volume_dialog_theme);
@@ -351,6 +355,8 @@
         mUseBackgroundBlur =
             mContext.getResources().getBoolean(R.bool.config_volumeDialogUseBackgroundBlur);
         mInteractionJankMonitor = interactionJankMonitor;
+        mSecureSettings = secureSettings;
+        mDialogTimeoutMillis = DIALOG_TIMEOUT_MILLIS;
 
         dumpManager.registerDumpable("VolumeDialogImpl", this);
 
@@ -515,6 +521,8 @@
         mDialog.setContentView(R.layout.volume_dialog);
         mDialogView = mDialog.findViewById(R.id.volume_dialog);
         mDialogView.setAlpha(0);
+        mDialogTimeoutMillis = mSecureSettings.getInt(Settings.Secure.VOLUME_DIALOG_DISMISS_TIMEOUT,
+                DIALOG_TIMEOUT_MILLIS);
         mDialog.setCanceledOnTouchOutside(true);
         mDialog.setOnShowListener(dialog -> {
             mDialogView.getViewTreeObserver().addOnComputeInternalInsetsListener(this);
@@ -527,7 +535,7 @@
                     .alpha(1)
                     .translationX(0)
                     .setDuration(mDialogShowAnimationDurationMs)
-                    .setListener(getJankListener(getDialogView(), TYPE_SHOW, DIALOG_TIMEOUT_MILLIS))
+                    .setListener(getJankListener(getDialogView(), TYPE_SHOW, mDialogTimeoutMillis))
                     .setInterpolator(new SystemUIInterpolators.LogDecelerateInterpolator())
                     .withEndAction(() -> {
                         if (!Prefs.getBoolean(mContext, Prefs.Key.TOUCHED_RINGER_TOGGLE, false)) {
@@ -1514,7 +1522,7 @@
                     AccessibilityManager.FLAG_CONTENT_TEXT
                             | AccessibilityManager.FLAG_CONTENT_CONTROLS);
         }
-        return mAccessibilityMgr.getRecommendedTimeoutMillis(DIALOG_TIMEOUT_MILLIS,
+        return mAccessibilityMgr.getRecommendedTimeoutMillis(mDialogTimeoutMillis,
                 AccessibilityManager.FLAG_CONTENT_CONTROLS);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
index cc9f3e1..624691b 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
@@ -31,6 +31,7 @@
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.DevicePostureController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.util.settings.SecureSettings;
 import com.android.systemui.volume.CsdWarningDialog;
 import com.android.systemui.volume.VolumeComponent;
 import com.android.systemui.volume.VolumeDialogComponent;
@@ -63,7 +64,8 @@
             CsdWarningDialog.Factory csdFactory,
             DevicePostureController devicePostureController,
             DumpManager dumpManager,
-            FeatureFlags featureFlags) {
+            FeatureFlags featureFlags,
+            SecureSettings secureSettings) {
         VolumeDialogImpl impl = new VolumeDialogImpl(
                 context,
                 volumeDialogController,
@@ -79,7 +81,8 @@
                 devicePostureController,
                 Looper.getMainLooper(),
                 dumpManager,
-                featureFlags);
+                featureFlags,
+                secureSettings);
         impl.setStreamImportant(AudioManager.STREAM_SYSTEM, false);
         impl.setAutomute(true);
         impl.setSilentMode(false);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java
index ba3dbf0..484b119 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerBaseTest.java
@@ -20,8 +20,10 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.animation.LayoutTransition;
 import android.view.View;
 import android.view.ViewTreeObserver;
+import android.widget.FrameLayout;
 
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.keyguard.logging.KeyguardLogger;
@@ -44,6 +46,7 @@
 public class KeyguardStatusViewControllerBaseTest extends SysuiTestCase {
 
     @Mock protected KeyguardStatusView mKeyguardStatusView;
+
     @Mock protected KeyguardSliceViewController mKeyguardSliceViewController;
     @Mock protected KeyguardClockSwitchController mKeyguardClockSwitchController;
     @Mock protected KeyguardStateController mKeyguardStateController;
@@ -61,6 +64,10 @@
 
     protected KeyguardStatusViewController mController;
 
+    @Mock protected KeyguardClockSwitch mKeyguardClockSwitch;
+    @Mock protected FrameLayout mMediaHostContainer;
+    @Mock protected LayoutTransition mMediaLayoutTransition;
+
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
@@ -93,6 +100,8 @@
                 };
 
         when(mKeyguardStatusView.getViewTreeObserver()).thenReturn(mViewTreeObserver);
+
+        when(mKeyguardClockSwitchController.getView()).thenReturn(mKeyguardClockSwitch);
     }
 
     protected void givenViewAttached() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
index b8b0198..e4e2b0a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
@@ -18,14 +18,18 @@
 
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.animation.LayoutTransition;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
+import android.view.View;
 
+import com.android.systemui.res.R;
 import com.android.systemui.plugins.ClockConfig;
 import com.android.systemui.plugins.ClockController;
 import com.android.systemui.statusbar.notification.AnimatableProperty;
@@ -124,4 +128,112 @@
         mController.onDestroy();
         verify(mDumpManager, times(1)).unregisterDumpable(eq(mController.getInstanceName()));
     }
+
+    @Test
+    public void onInit_addsOnLayoutChangeListenerToClockSwitch() {
+        when(mKeyguardStatusView.findViewById(R.id.status_view_media_container)).thenReturn(
+                mMediaHostContainer);
+
+        mController.onInit();
+
+        ArgumentCaptor<View.OnLayoutChangeListener> captor =
+                ArgumentCaptor.forClass(View.OnLayoutChangeListener.class);
+        verify(mKeyguardClockSwitch).addOnLayoutChangeListener(captor.capture());
+    }
+
+    @Test
+    public void onInit_addsOnLayoutChangeListenerToMediaHostContainer() {
+        when(mKeyguardStatusView.findViewById(R.id.status_view_media_container)).thenReturn(
+                mMediaHostContainer);
+
+        mController.onInit();
+
+        ArgumentCaptor<View.OnLayoutChangeListener> captor =
+                ArgumentCaptor.forClass(View.OnLayoutChangeListener.class);
+        verify(mMediaHostContainer).addOnLayoutChangeListener(captor.capture());
+    }
+
+    @Test
+    public void clockSwitchHeightChanged_mediaChangingLayoutTransitionEnabled() {
+        when(mKeyguardStatusView.findViewById(R.id.status_view_media_container)).thenReturn(
+                mMediaHostContainer);
+
+        mController.onInit();
+
+        ArgumentCaptor<View.OnLayoutChangeListener> captor =
+                ArgumentCaptor.forClass(View.OnLayoutChangeListener.class);
+        verify(mKeyguardClockSwitch).addOnLayoutChangeListener(captor.capture());
+
+        // Above here is the same as `onInit_addsOnLayoutChangeListenerToClockSwitch`.
+        // Below here is the actual test.
+
+        View.OnLayoutChangeListener listener = captor.getValue();
+
+        mController.setSplitShadeEnabled(true);
+        when(mKeyguardClockSwitch.getSplitShadeCentered()).thenReturn(false);
+        when(mKeyguardUpdateMonitor.isKeyguardVisible()).thenReturn(true);
+        when(mMediaHostContainer.getVisibility()).thenReturn(View.VISIBLE);
+        when(mMediaHostContainer.getHeight()).thenReturn(200);
+        when(mMediaHostContainer.getLayoutTransition()).thenReturn(mMediaLayoutTransition);
+
+        when(mKeyguardClockSwitch.getHeight()).thenReturn(0);
+        listener.onLayoutChange(mKeyguardClockSwitch, /* left= */ 0, /* top= */ 0, /* right= */
+                0, /* bottom= */ 0, /* oldLeft= */ 0, /* oldTop= */ 0, /* oldRight= */
+                0, /* oldBottom = */ 200);
+        verify(mMediaLayoutTransition).enableTransitionType(LayoutTransition.CHANGING);
+    }
+
+    @Test
+    public void clockSwitchHeightNotChanged_mediaChangingLayoutTransitionNotEnabled() {
+        when(mKeyguardStatusView.findViewById(R.id.status_view_media_container)).thenReturn(
+                mMediaHostContainer);
+
+        mController.onInit();
+
+        ArgumentCaptor<View.OnLayoutChangeListener> captor =
+                ArgumentCaptor.forClass(View.OnLayoutChangeListener.class);
+        verify(mKeyguardClockSwitch).addOnLayoutChangeListener(captor.capture());
+
+        // Above here is the same as `onInit_addsOnLayoutChangeListenerToClockSwitch`.
+        // Below here is the actual test.
+
+        View.OnLayoutChangeListener listener = captor.getValue();
+
+        mController.setSplitShadeEnabled(true);
+        when(mKeyguardClockSwitch.getSplitShadeCentered()).thenReturn(false);
+        when(mKeyguardUpdateMonitor.isKeyguardVisible()).thenReturn(true);
+        when(mMediaHostContainer.getVisibility()).thenReturn(View.VISIBLE);
+        when(mMediaHostContainer.getHeight()).thenReturn(200);
+        when(mMediaHostContainer.getLayoutTransition()).thenReturn(mMediaLayoutTransition);
+
+        when(mKeyguardClockSwitch.getHeight()).thenReturn(200);
+        listener.onLayoutChange(mKeyguardClockSwitch, /* left= */ 0, /* top= */ 0, /* right= */
+                0, /* bottom= */ 0, /* oldLeft= */ 0, /* oldTop= */ 0, /* oldRight= */
+                0, /* oldBottom = */ 200);
+        verify(mMediaLayoutTransition, never()).enableTransitionType(LayoutTransition.CHANGING);
+    }
+
+    @Test
+    public void onMediaHostContainerLayout_disablesChangingLayoutTransition() {
+        when(mKeyguardStatusView.findViewById(R.id.status_view_media_container)).thenReturn(
+                mMediaHostContainer);
+
+        mController.onInit();
+
+        ArgumentCaptor<View.OnLayoutChangeListener> captor =
+                ArgumentCaptor.forClass(View.OnLayoutChangeListener.class);
+        verify(mMediaHostContainer).addOnLayoutChangeListener(captor.capture());
+
+        // Above here is the same as `onInit_addsOnLayoutChangeListenerToMediaHostContainer`.
+        // Below here is the actual test.
+
+        View.OnLayoutChangeListener listener = captor.getValue();
+
+        when(mMediaHostContainer.getLayoutTransition()).thenReturn(mMediaLayoutTransition);
+
+        when(mMediaLayoutTransition.isTransitionTypeEnabled(LayoutTransition.CHANGING)).thenReturn(
+                true);
+        listener.onLayoutChange(mMediaHostContainer, 1, 2, 3, 4, 1, 2, 3, 4);
+        verify(mMediaLayoutTransition).disableTransitionType(LayoutTransition.CHANGING);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt
index 86439e5..58d372c 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt
@@ -1,5 +1,6 @@
 package com.android.keyguard
 
+import android.animation.LayoutTransition
 import android.test.suitebuilder.annotation.SmallTest
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
@@ -35,6 +36,20 @@
     }
 
     @Test
+    fun mediaViewHasLayoutTransitionInDisabledState() {
+        val layoutTransition = (mediaView as ViewGroup).layoutTransition
+        assertThat(layoutTransition).isNotNull()
+        assertThat(layoutTransition.isTransitionTypeEnabled(LayoutTransition.CHANGE_APPEARING))
+            .isFalse()
+        assertThat(layoutTransition.isTransitionTypeEnabled(LayoutTransition.CHANGE_DISAPPEARING))
+            .isFalse()
+        assertThat(layoutTransition.isTransitionTypeEnabled(LayoutTransition.APPEARING)).isFalse()
+        assertThat(layoutTransition.isTransitionTypeEnabled(LayoutTransition.DISAPPEARING))
+            .isFalse()
+        assertThat(layoutTransition.isTransitionTypeEnabled(LayoutTransition.CHANGING)).isFalse()
+    }
+
+    @Test
     fun setChildrenTranslationYExcludingMediaView_mediaViewIsNotTranslated() {
         val translationY = 1234f
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt
index 25faeef..de57b60 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt
@@ -81,6 +81,7 @@
     @Mock private lateinit var mediaDataManager: MediaDataManager
     @Mock private lateinit var uniqueObjectHostView: UniqueObjectHostView
     @Mock private lateinit var dreamOverlayStateController: DreamOverlayStateController
+    @Mock lateinit var logger: MediaViewLogger
     @Captor
     private lateinit var wakefullnessObserver: ArgumentCaptor<(WakefulnessLifecycle.Observer)>
     @Captor
@@ -121,7 +122,8 @@
                 notifPanelEvents,
                 settings,
                 fakeHandler,
-                ResourcesSplitShadeStateController()
+                ResourcesSplitShadeStateController(),
+                logger,
             )
         verify(wakefulnessLifecycle).addObserver(wakefullnessObserver.capture())
         verify(statusBarStateController).addCallback(statusBarCallback.capture())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
index b595e8d..79411f42 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -66,6 +66,7 @@
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.pipeline.shared.QSPipelineFlagsRepository;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.qs.tiles.di.NewQSTileFactory;
 import com.android.systemui.settings.UserFileManager;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.shade.ShadeController;
@@ -77,6 +78,8 @@
 import com.android.systemui.util.settings.SecureSettings;
 import com.android.systemui.util.time.FakeSystemClock;
 
+import dagger.Lazy;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -102,8 +105,6 @@
     private static final String SETTING = QSHost.TILES_SETTING;
 
     @Mock
-    private QSFactory mDefaultFactory;
-    @Mock
     private PluginManager mPluginManager;
     @Mock
     private TunerService mTunerService;
@@ -117,7 +118,6 @@
     private CustomTile mCustomTile;
     @Mock
     private UserTracker mUserTracker;
-    private SecureSettings mSecureSettings;
     @Mock
     private CustomTileStatePersister mCustomTileStatePersister;
     @Mock
@@ -127,6 +127,10 @@
     @Mock
     private UserFileManager mUserFileManager;
 
+    private SecureSettings mSecureSettings;
+
+    private QSFactory mDefaultFactory;
+
     private SparseArray<SharedPreferences> mSharedPreferencesByUser;
 
     private FakeFeatureFlags mFeatureFlags;
@@ -144,6 +148,8 @@
 
         mFeatureFlags.set(Flags.QS_PIPELINE_NEW_HOST, false);
         mFeatureFlags.set(Flags.QS_PIPELINE_AUTO_ADD, false);
+        // TODO(b/299909337): Add test checking the new factory is used when the flag is on
+        mFeatureFlags.set(Flags.QS_PIPELINE_NEW_TILES, false);
         mQSPipelineFlagsRepository = new QSPipelineFlagsRepository(mFeatureFlags);
 
         mMainExecutor = new FakeExecutor(new FakeSystemClock());
@@ -164,7 +170,8 @@
 
         mSecureSettings = new FakeSettings();
         saveSetting("");
-        mQSTileHost = new TestQSTileHost(mContext, mDefaultFactory, mMainExecutor,
+        setUpTileFactory();
+        mQSTileHost = new TestQSTileHost(mContext, () -> null, mDefaultFactory, mMainExecutor,
                 mPluginManager, mTunerService, () -> mAutoTiles, mShadeController,
                 mQSLogger, mUserTracker, mSecureSettings, mCustomTileStatePersister,
                 mTileLifecycleManagerFactory, mUserFileManager, mQSPipelineFlagsRepository);
@@ -178,7 +185,6 @@
                 mMainExecutor.runAllReady();
             }
         }, mUserTracker.getUserId());
-        setUpTileFactory();
     }
 
     private void saveSetting(String value) {
@@ -191,32 +197,29 @@
     }
 
     private void setUpTileFactory() {
-        // Only create this kind of tiles
-        when(mDefaultFactory.createTile(anyString())).thenAnswer(
-                invocation -> {
-                    String spec = invocation.getArgument(0);
-                    if ("spec1".equals(spec)) {
-                        return new TestTile1(mQSTileHost);
-                    } else if ("spec2".equals(spec)) {
-                        return new TestTile2(mQSTileHost);
-                    } else if ("spec3".equals(spec)) {
-                        return new TestTile3(mQSTileHost);
-                    } else if ("na".equals(spec)) {
-                        return new NotAvailableTile(mQSTileHost);
-                    } else if (CUSTOM_TILE_SPEC.equals(spec)) {
-                        QSTile tile = mCustomTile;
-                        QSTile.State s = mock(QSTile.State.class);
-                        s.spec = spec;
-                        when(mCustomTile.getState()).thenReturn(s);
-                        return tile;
-                    } else if ("internet".equals(spec)
-                            || "wifi".equals(spec)
-                            || "cell".equals(spec)) {
-                        return new TestTile1(mQSTileHost);
-                    } else {
-                        return null;
-                    }
-                });
+        mDefaultFactory = new FakeQSFactory(spec -> {
+            if ("spec1".equals(spec)) {
+                return new TestTile1(mQSTileHost);
+            } else if ("spec2".equals(spec)) {
+                return new TestTile2(mQSTileHost);
+            } else if ("spec3".equals(spec)) {
+                return new TestTile3(mQSTileHost);
+            } else if ("na".equals(spec)) {
+                return new NotAvailableTile(mQSTileHost);
+            } else if (CUSTOM_TILE_SPEC.equals(spec)) {
+                QSTile tile = mCustomTile;
+                QSTile.State s = mock(QSTile.State.class);
+                s.spec = spec;
+                when(mCustomTile.getState()).thenReturn(s);
+                return tile;
+            } else if ("internet".equals(spec)
+                    || "wifi".equals(spec)
+                    || "cell".equals(spec)) {
+                return new TestTile1(mQSTileHost);
+            } else {
+                return null;
+            }
+        });
         when(mCustomTile.isAvailable()).thenReturn(true);
     }
 
@@ -703,7 +706,7 @@
     }
 
     private class TestQSTileHost extends QSTileHost {
-        TestQSTileHost(Context context,
+        TestQSTileHost(Context context, Lazy<NewQSTileFactory> newQSTileFactoryProvider,
                 QSFactory defaultFactory, Executor mainExecutor,
                 PluginManager pluginManager, TunerService tunerService,
                 Provider<AutoTileManager> autoTiles,
@@ -712,7 +715,7 @@
                 CustomTileStatePersister customTileStatePersister,
                 TileLifecycleManager.Factory tileLifecycleManagerFactory,
                 UserFileManager userFileManager, QSPipelineFlagsRepository featureFlags) {
-            super(context, defaultFactory, mainExecutor, pluginManager,
+            super(context, newQSTileFactoryProvider, defaultFactory, mainExecutor, pluginManager,
                     tunerService, autoTiles,  shadeController, qsLogger,
                     userTracker, secureSettings, customTileStatePersister,
                     tileLifecycleManagerFactory, userFileManager, featureFlags);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
index bde3038..d3cd26b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
@@ -124,6 +124,7 @@
                     if (FACTORY_TILES.contains(spec)) {
                         FakeQSTile tile = new FakeQSTile(mBgExecutor, mMainExecutor);
                         tile.setState(mState);
+                        tile.setTileSpec(spec);
                         return tile;
                     } else {
                         return null;
@@ -284,7 +285,10 @@
         Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.QS_TILES, null);
 
         QSTile t = mock(QSTile.class);
-        when(mQSHost.createTile("hotspot")).thenReturn(t);
+        when(mQSHost.createTile("hotspot")).thenAnswer(invocation -> {
+            t.setTileSpec("hotspot");
+            return t;
+        });
 
         mContext.getOrCreateTestableResources().addOverride(R.string.quick_settings_tiles_stock,
                 "hotspot");
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt
index dc1b9c4..a750524 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt
@@ -46,6 +46,7 @@
 import com.android.systemui.qs.pipeline.shared.QSPipelineFlagsRepository
 import com.android.systemui.qs.pipeline.shared.TileSpec
 import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger
+import com.android.systemui.qs.tiles.di.NewQSTileFactory
 import com.android.systemui.qs.toProto
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.user.data.repository.FakeUserRepository
@@ -91,6 +92,8 @@
 
     @Mock private lateinit var logger: QSPipelineLogger
 
+    @Mock private lateinit var newQSTileFactory: NewQSTileFactory
+
     private val testDispatcher = StandardTestDispatcher()
     private val testScope = TestScope(testDispatcher)
 
@@ -105,6 +108,8 @@
 
         featureFlags.set(Flags.QS_PIPELINE_NEW_HOST, true)
         featureFlags.set(Flags.QS_PIPELINE_AUTO_ADD, true)
+        // TODO(b/299909337): Add test checking the new factory is used when the flag is on
+        featureFlags.set(Flags.QS_PIPELINE_NEW_TILES, true)
 
         userRepository.setUserInfos(listOf(USER_INFO_0, USER_INFO_1))
 
@@ -117,6 +122,7 @@
                 userRepository = userRepository,
                 customTileStatePersister = customTileStatePersister,
                 tileFactory = tileFactory,
+                newQSTileFactory = { newQSTileFactory },
                 customTileAddedRepository = customTileAddedRepository,
                 tileLifecycleManagerFactory = tileLifecycleManagerFactory,
                 userTracker = userTracker,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt
index 5630b9d..2e6b50b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt
@@ -1,6 +1,6 @@
 package com.android.systemui.qs.pipeline.domain.interactor
 
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
@@ -21,7 +21,7 @@
 import org.mockito.MockitoAnnotations
 
 @RoboPilotTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @SmallTest
 class RestoreReconciliationInteractorTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/QSTileIntentUserActionHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/QSTileIntentUserActionHandlerTest.kt
index 47b4244..077c813 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/QSTileIntentUserActionHandlerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/QSTileIntentUserActionHandlerTest.kt
@@ -6,7 +6,6 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserActionHandler
-import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -34,7 +33,7 @@
     fun testPassesIntentToStarter() {
         val intent = Intent("test.ACTION")
 
-        underTest.handle(QSTileUserAction.Click(context, null), intent)
+        underTest.handle(null, intent)
 
         verify(activityStarted).postStartActivityDismissingKeyguard(eq(intent), eq(0), any())
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelInterfaceComplianceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelInterfaceComplianceTest.kt
index 643866e..eacb080 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelInterfaceComplianceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelInterfaceComplianceTest.kt
@@ -1,11 +1,14 @@
 package com.android.systemui.qs.tiles.viewmodel
 
-import android.graphics.drawable.Icon
+import android.graphics.drawable.ShapeDrawable
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import androidx.test.filters.MediumTest
+import com.android.internal.logging.InstanceId
 import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.qs.pipeline.shared.TileSpec
 import com.android.systemui.qs.tiles.base.interactor.FakeQSTileDataInteractor
 import com.android.systemui.qs.tiles.base.interactor.FakeQSTileUserActionInteractor
@@ -71,20 +74,21 @@
                 fakeQSTileUserActionInteractor,
                 fakeQSTileDataInteractor,
                 object : QSTileDataToStateMapper<Any> {
-                    override fun map(config: QSTileConfig, data: Any): QSTileState {
-                        return QSTileState(config.tileIcon, config.tileLabel)
-                    }
+                    override fun map(config: QSTileConfig, data: Any): QSTileState =
+                        QSTileState.build(Icon.Resource(0, ContentDescription.Resource(0)), "") {}
                 },
                 testCoroutineDispatcher,
                 tileScope = scope.backgroundScope,
             ) {}
 
     private companion object {
+
         val TEST_QS_TILE_CONFIG =
             QSTileConfig(
                 TileSpec.create("default"),
-                Icon.createWithContentUri(""),
-                "",
+                Icon.Loaded(ShapeDrawable(), null),
+                0,
+                InstanceId.fakeInstanceId(0),
             )
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
index 59b5953..a2aed98 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
@@ -41,7 +41,7 @@
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.media.MediaProjectionCaptureTarget;
+import com.android.systemui.mediaprojection.MediaProjectionCaptureTarget;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.settings.UserContextProvider;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogTest.kt
index d470d24..3ae1f35 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogTest.kt
@@ -22,11 +22,13 @@
 import android.view.View
 import android.widget.Spinner
 import androidx.test.filters.SmallTest
-import com.android.systemui.res.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
+import com.android.systemui.mediaprojection.permission.ENTIRE_SCREEN
+import com.android.systemui.mediaprojection.permission.SINGLE_APP
 import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.res.R
 import com.android.systemui.settings.UserContextProvider
 import com.android.systemui.util.mockito.mock
 import com.google.common.truth.Truth.assertThat
@@ -35,8 +37,8 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mock
-import org.mockito.MockitoAnnotations
 import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
index 48665fe..e714736 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
@@ -15,6 +15,7 @@
  */
 package com.android.systemui.shared.clocks
 
+import android.content.ComponentName
 import android.content.ContentResolver
 import android.content.Context
 import android.graphics.drawable.Drawable
@@ -28,12 +29,11 @@
 import com.android.systemui.plugins.ClockMetadata
 import com.android.systemui.plugins.ClockProviderPlugin
 import com.android.systemui.plugins.ClockSettings
-import com.android.systemui.plugins.PluginListener
 import com.android.systemui.plugins.PluginLifecycleManager
+import com.android.systemui.plugins.PluginListener
 import com.android.systemui.plugins.PluginManager
 import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.eq
-import com.android.systemui.util.mockito.mock
 import junit.framework.Assert.assertEquals
 import junit.framework.Assert.fail
 import kotlinx.coroutines.CoroutineDispatcher
@@ -46,6 +46,7 @@
 import org.junit.runner.RunWith
 import org.mockito.Mock
 import org.mockito.Mockito.never
+import org.mockito.Mockito.spy
 import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when` as whenever
@@ -66,7 +67,6 @@
     @Mock private lateinit var mockDefaultClock: ClockController
     @Mock private lateinit var mockThumbnail: Drawable
     @Mock private lateinit var mockContentResolver: ContentResolver
-    @Mock private lateinit var mockPluginLifecycle: PluginLifecycleManager<ClockProviderPlugin>
     private lateinit var fakeDefaultProvider: FakeClockPlugin
     private lateinit var pluginListener: PluginListener<ClockProviderPlugin>
     private lateinit var registry: ClockRegistry
@@ -84,6 +84,41 @@
         }
     }
 
+    private class FakeLifecycle(
+        private val tag: String,
+        private val plugin: ClockProviderPlugin?,
+    ) : PluginLifecycleManager<ClockProviderPlugin> {
+        var onLoad: (() -> Unit)? = null
+        var onUnload: (() -> Unit)? = null
+
+        private var mIsLoaded: Boolean = true
+        override fun isLoaded() = mIsLoaded
+        override fun getPlugin(): ClockProviderPlugin? = if (isLoaded) plugin else null
+
+        var mComponentName = ComponentName("Package[$tag]", "Class[$tag]")
+        override fun toString() = "Manager[$tag]"
+        override fun getPackage(): String = mComponentName.getPackageName()
+        override fun getComponentName(): ComponentName = mComponentName
+
+        private var isDebug: Boolean = false
+        override fun getIsDebug(): Boolean = isDebug
+        override fun setIsDebug(value: Boolean) { isDebug = value }
+
+        override fun loadPlugin() {
+            if (!mIsLoaded) {
+                mIsLoaded = true
+                onLoad?.invoke()
+            }
+        }
+
+        override fun unloadPlugin() {
+            if (mIsLoaded) {
+                mIsLoaded = false
+                onUnload?.invoke()
+            }
+        }
+    }
+
     private class FakeClockPlugin : ClockProviderPlugin {
         private val metadata = mutableListOf<ClockMetadata>()
         private val createCallbacks = mutableMapOf<ClockId, (ClockId) -> ClockController>()
@@ -150,13 +185,15 @@
         val plugin1 = FakeClockPlugin()
             .addClock("clock_1", "clock 1")
             .addClock("clock_2", "clock 2")
+        val lifecycle1 = FakeLifecycle("1", plugin1)
 
         val plugin2 = FakeClockPlugin()
             .addClock("clock_3", "clock 3")
             .addClock("clock_4", "clock 4")
+        val lifecycle2 = FakeLifecycle("2", plugin2)
 
-        pluginListener.onPluginLoaded(plugin1, mockContext, mockPluginLifecycle)
-        pluginListener.onPluginLoaded(plugin2, mockContext, mockPluginLifecycle)
+        pluginListener.onPluginLoaded(plugin1, mockContext, lifecycle1)
+        pluginListener.onPluginLoaded(plugin2, mockContext, lifecycle2)
         val list = registry.getClocks()
         assertEquals(
             list.toSet(),
@@ -178,18 +215,18 @@
 
     @Test
     fun clockIdConflict_ErrorWithoutCrash_unloadDuplicate() {
-        val mockPluginLifecycle1 = mock<PluginLifecycleManager<ClockProviderPlugin>>()
         val plugin1 = FakeClockPlugin()
             .addClock("clock_1", "clock 1", { mockClock }, { mockThumbnail })
             .addClock("clock_2", "clock 2", { mockClock }, { mockThumbnail })
+        val lifecycle1 = spy(FakeLifecycle("1", plugin1))
 
-        val mockPluginLifecycle2 = mock<PluginLifecycleManager<ClockProviderPlugin>>()
         val plugin2 = FakeClockPlugin()
             .addClock("clock_1", "clock 1")
             .addClock("clock_2", "clock 2")
+        val lifecycle2 = spy(FakeLifecycle("2", plugin2))
 
-        pluginListener.onPluginLoaded(plugin1, mockContext, mockPluginLifecycle1)
-        pluginListener.onPluginLoaded(plugin2, mockContext, mockPluginLifecycle2)
+        pluginListener.onPluginLoaded(plugin1, mockContext, lifecycle1)
+        pluginListener.onPluginLoaded(plugin2, mockContext, lifecycle2)
         val list = registry.getClocks()
         assertEquals(
             list.toSet(),
@@ -204,8 +241,8 @@
         assertEquals(registry.createExampleClock("clock_2"), mockClock)
         assertEquals(registry.getClockThumbnail("clock_1"), mockThumbnail)
         assertEquals(registry.getClockThumbnail("clock_2"), mockThumbnail)
-        verify(mockPluginLifecycle1, never()).unloadPlugin()
-        verify(mockPluginLifecycle2, times(2)).unloadPlugin()
+        verify(lifecycle1, never()).unloadPlugin()
+        verify(lifecycle2, times(2)).unloadPlugin()
     }
 
     @Test
@@ -213,14 +250,16 @@
         val plugin1 = FakeClockPlugin()
             .addClock("clock_1", "clock 1")
             .addClock("clock_2", "clock 2")
+        val lifecycle1 = spy(FakeLifecycle("1", plugin1))
 
         val plugin2 = FakeClockPlugin()
             .addClock("clock_3", "clock 3", { mockClock })
             .addClock("clock_4", "clock 4")
+        val lifecycle2 = spy(FakeLifecycle("2", plugin2))
 
         registry.applySettings(ClockSettings("clock_3", null))
-        pluginListener.onPluginLoaded(plugin1, mockContext, mockPluginLifecycle)
-        pluginListener.onPluginLoaded(plugin2, mockContext, mockPluginLifecycle)
+        pluginListener.onPluginLoaded(plugin1, mockContext, lifecycle1)
+        pluginListener.onPluginLoaded(plugin2, mockContext, lifecycle2)
 
         val clock = registry.createCurrentClock()
         assertEquals(mockClock, clock)
@@ -231,17 +270,19 @@
         val plugin1 = FakeClockPlugin()
             .addClock("clock_1", "clock 1")
             .addClock("clock_2", "clock 2")
+        val lifecycle1 = spy(FakeLifecycle("1", plugin1))
 
         val plugin2 = FakeClockPlugin()
             .addClock("clock_3", "clock 3", { mockClock })
             .addClock("clock_4", "clock 4")
+        val lifecycle2 = spy(FakeLifecycle("2", plugin2))
 
         registry.applySettings(ClockSettings("clock_3", null))
 
-        pluginListener.onPluginLoaded(plugin1, mockContext, mockPluginLifecycle)
+        pluginListener.onPluginLoaded(plugin1, mockContext, lifecycle1)
         assertEquals(DEFAULT_CLOCK_ID, registry.activeClockId)
 
-        pluginListener.onPluginLoaded(plugin2, mockContext, mockPluginLifecycle)
+        pluginListener.onPluginLoaded(plugin2, mockContext, lifecycle2)
         assertEquals("clock_3", registry.activeClockId)
     }
 
@@ -250,15 +291,17 @@
         val plugin1 = FakeClockPlugin()
             .addClock("clock_1", "clock 1")
             .addClock("clock_2", "clock 2")
+        val lifecycle1 = spy(FakeLifecycle("1", plugin1))
 
         val plugin2 = FakeClockPlugin()
             .addClock("clock_3", "clock 3")
             .addClock("clock_4", "clock 4")
+        val lifecycle2 = spy(FakeLifecycle("2", plugin2))
 
         registry.applySettings(ClockSettings("clock_3", null))
-        pluginListener.onPluginLoaded(plugin1, mockContext, mockPluginLifecycle)
-        pluginListener.onPluginLoaded(plugin2, mockContext, mockPluginLifecycle)
-        pluginListener.onPluginUnloaded(plugin2, mockPluginLifecycle)
+        pluginListener.onPluginLoaded(plugin1, mockContext, lifecycle1)
+        pluginListener.onPluginLoaded(plugin2, mockContext, lifecycle2)
+        pluginListener.onPluginUnloaded(plugin2, lifecycle2)
 
         val clock = registry.createCurrentClock()
         assertEquals(clock, mockDefaultClock)
@@ -266,15 +309,15 @@
 
     @Test
     fun pluginRemoved_clockAndListChanged() {
-        val mockPluginLifecycle1 = mock<PluginLifecycleManager<ClockProviderPlugin>>()
         val plugin1 = FakeClockPlugin()
             .addClock("clock_1", "clock 1")
             .addClock("clock_2", "clock 2")
+        val lifecycle1 = spy(FakeLifecycle("1", plugin1))
 
-        val mockPluginLifecycle2 = mock<PluginLifecycleManager<ClockProviderPlugin>>()
         val plugin2 = FakeClockPlugin()
             .addClock("clock_3", "clock 3", { mockClock })
             .addClock("clock_4", "clock 4")
+        val lifecycle2 = spy(FakeLifecycle("2", plugin2))
 
         var changeCallCount = 0
         var listChangeCallCount = 0
@@ -288,32 +331,32 @@
         assertEquals(1, changeCallCount)
         assertEquals(0, listChangeCallCount)
 
-        pluginListener.onPluginLoaded(plugin1, mockContext, mockPluginLifecycle1)
+        pluginListener.onPluginLoaded(plugin1, mockContext, lifecycle1)
         scheduler.runCurrent()
         assertEquals(1, changeCallCount)
         assertEquals(1, listChangeCallCount)
 
-        pluginListener.onPluginLoaded(plugin2, mockContext, mockPluginLifecycle2)
+        pluginListener.onPluginLoaded(plugin2, mockContext, lifecycle2)
         scheduler.runCurrent()
         assertEquals(2, changeCallCount)
         assertEquals(2, listChangeCallCount)
 
-        pluginListener.onPluginUnloaded(plugin1, mockPluginLifecycle1)
+        pluginListener.onPluginUnloaded(plugin1, lifecycle1)
         scheduler.runCurrent()
         assertEquals(2, changeCallCount)
         assertEquals(2, listChangeCallCount)
 
-        pluginListener.onPluginUnloaded(plugin2, mockPluginLifecycle2)
+        pluginListener.onPluginUnloaded(plugin2, lifecycle2)
         scheduler.runCurrent()
         assertEquals(3, changeCallCount)
         assertEquals(2, listChangeCallCount)
 
-        pluginListener.onPluginDetached(mockPluginLifecycle1)
+        pluginListener.onPluginDetached(lifecycle1)
         scheduler.runCurrent()
         assertEquals(3, changeCallCount)
         assertEquals(3, listChangeCallCount)
 
-        pluginListener.onPluginDetached(mockPluginLifecycle2)
+        pluginListener.onPluginDetached(lifecycle2)
         scheduler.runCurrent()
         assertEquals(3, changeCallCount)
         assertEquals(4, listChangeCallCount)
@@ -321,8 +364,9 @@
 
     @Test
     fun unknownPluginAttached_clockAndListUnchanged_loadRequested() {
-        val mockPluginLifecycle = mock<PluginLifecycleManager<ClockProviderPlugin>>()
-        whenever(mockPluginLifecycle.getPackage()).thenReturn("some.other.package")
+        val lifecycle = FakeLifecycle("", null).apply {
+            mComponentName = ComponentName("some.other.package", "SomeClass")
+        }
 
         var changeCallCount = 0
         var listChangeCallCount = 0
@@ -331,7 +375,7 @@
             override fun onAvailableClocksChanged() { listChangeCallCount++ }
         })
 
-        assertEquals(true, pluginListener.onPluginAttached(mockPluginLifecycle))
+        assertEquals(true, pluginListener.onPluginAttached(lifecycle))
         scheduler.runCurrent()
         assertEquals(0, changeCallCount)
         assertEquals(0, listChangeCallCount)
@@ -339,10 +383,12 @@
 
     @Test
     fun knownPluginAttached_clockAndListChanged_notLoaded() {
-        val mockPluginLifecycle1 = mock<PluginLifecycleManager<ClockProviderPlugin>>()
-        whenever(mockPluginLifecycle1.getPackage()).thenReturn("com.android.systemui.clocks.metro")
-        val mockPluginLifecycle2 = mock<PluginLifecycleManager<ClockProviderPlugin>>()
-        whenever(mockPluginLifecycle2.getPackage()).thenReturn("com.android.systemui.clocks.bignum")
+        val lifecycle1 = FakeLifecycle("Metro", null).apply {
+            mComponentName = ComponentName("com.android.systemui.clocks.metro", "MetroClock")
+        }
+        val lifecycle2 = FakeLifecycle("BigNum", null).apply {
+            mComponentName = ComponentName("com.android.systemui.clocks.bignum", "BigNumClock")
+        }
 
         var changeCallCount = 0
         var listChangeCallCount = 0
@@ -356,12 +402,12 @@
         assertEquals(1, changeCallCount)
         assertEquals(0, listChangeCallCount)
 
-        assertEquals(false, pluginListener.onPluginAttached(mockPluginLifecycle1))
+        assertEquals(false, pluginListener.onPluginAttached(lifecycle1))
         scheduler.runCurrent()
         assertEquals(1, changeCallCount)
         assertEquals(1, listChangeCallCount)
 
-        assertEquals(false, pluginListener.onPluginAttached(mockPluginLifecycle2))
+        assertEquals(false, pluginListener.onPluginAttached(lifecycle2))
         scheduler.runCurrent()
         assertEquals(1, changeCallCount)
         assertEquals(2, listChangeCallCount)
@@ -369,18 +415,14 @@
 
     @Test
     fun pluginAddRemove_concurrentModification() {
-        val mockPluginLifecycle1 = mock<PluginLifecycleManager<ClockProviderPlugin>>()
-        val mockPluginLifecycle2 = mock<PluginLifecycleManager<ClockProviderPlugin>>()
-        val mockPluginLifecycle3 = mock<PluginLifecycleManager<ClockProviderPlugin>>()
-        val mockPluginLifecycle4 = mock<PluginLifecycleManager<ClockProviderPlugin>>()
         val plugin1 = FakeClockPlugin().addClock("clock_1", "clock 1")
+        val lifecycle1 = FakeLifecycle("1", plugin1)
         val plugin2 = FakeClockPlugin().addClock("clock_2", "clock 2")
+        val lifecycle2 = FakeLifecycle("2", plugin2)
         val plugin3 = FakeClockPlugin().addClock("clock_3", "clock 3")
+        val lifecycle3 = FakeLifecycle("3", plugin3)
         val plugin4 = FakeClockPlugin().addClock("clock_4", "clock 4")
-        whenever(mockPluginLifecycle1.isLoaded).thenReturn(true)
-        whenever(mockPluginLifecycle2.isLoaded).thenReturn(true)
-        whenever(mockPluginLifecycle3.isLoaded).thenReturn(true)
-        whenever(mockPluginLifecycle4.isLoaded).thenReturn(true)
+        val lifecycle4 = FakeLifecycle("4", plugin4)
 
         // Set the current clock to the final clock to load
         registry.applySettings(ClockSettings("clock_4", null))
@@ -390,15 +432,15 @@
         // unload other plugins. This causes ClockRegistry to modify the list of available clock
         // plugins while it is being iterated over. In production this happens as a result of a
         // thread race, instead of synchronously like it does here.
-        whenever(mockPluginLifecycle2.unloadPlugin()).then {
-            pluginListener.onPluginDetached(mockPluginLifecycle1)
-            pluginListener.onPluginLoaded(plugin4, mockContext, mockPluginLifecycle4)
+        lifecycle2.onUnload = {
+            pluginListener.onPluginDetached(lifecycle1)
+            pluginListener.onPluginLoaded(plugin4, mockContext, lifecycle4)
         }
 
         // Load initial plugins
-        pluginListener.onPluginLoaded(plugin1, mockContext, mockPluginLifecycle1)
-        pluginListener.onPluginLoaded(plugin2, mockContext, mockPluginLifecycle2)
-        pluginListener.onPluginLoaded(plugin3, mockContext, mockPluginLifecycle3)
+        pluginListener.onPluginLoaded(plugin1, mockContext, lifecycle1)
+        pluginListener.onPluginLoaded(plugin2, mockContext, lifecycle2)
+        pluginListener.onPluginLoaded(plugin3, mockContext, lifecycle3)
 
         // Repeatedly verify the loaded providers to get final state
         registry.verifyLoadedProviders()
@@ -484,11 +526,11 @@
     private fun testTransitClockFlag(flag: Boolean) {
         featureFlags.set(TRANSIT_CLOCK, flag)
         registry.isTransitClockEnabled = featureFlags.isEnabled(TRANSIT_CLOCK)
-        val mockPluginLifecycle = mock<PluginLifecycleManager<ClockProviderPlugin>>()
         val plugin = FakeClockPlugin()
                 .addClock("clock_1", "clock 1")
                 .addClock("DIGITAL_CLOCK_METRO", "metro clock")
-        pluginListener.onPluginLoaded(plugin, mockContext, mockPluginLifecycle)
+        val lifecycle = FakeLifecycle("metro", plugin)
+        pluginListener.onPluginLoaded(plugin, mockContext, lifecycle)
 
         val list = registry.getClocks()
         if (flag) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
index 1592c30..a6180ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
@@ -248,7 +248,7 @@
     }
 
     @Test
-    public void testUpdateIconScale_smallerFontAndConstrainedDrawableSizeLessThanDpIconSize() {
+    public void testUpdateIconScale_smallerFontAndRawDrawableSizeLessThanDpIconSize() {
         int dpIconSize = 60;
         int dpDrawingSize = 30;
         // smaller font scaling causes the spIconSize < dpIconSize
@@ -262,12 +262,42 @@
         setIconDrawableWithSize(/* width= */ 50, /* height= */ 50);
         mIconView.maybeUpdateIconScaleDimens();
 
-        // WHEN both the constrained drawable width/height are less than dpIconSize,
+        // WHEN both the raw/constrained drawable width/height are less than dpIconSize,
+        // THEN the icon is scaled up from constrained drawable size to the raw drawable size
+        float scaleToBackRawDrawableSize = (float) 50 / 40;
         // THEN the icon is scaled down from dpIconSize to fit the dpDrawingSize
         float scaleToFitDrawingSize = (float) dpDrawingSize / dpIconSize;
         // THEN the scaled icon should be scaled down further to fit spIconSize
         float scaleToFitSpIconSize = (float) spIconSize / dpIconSize;
-        assertEquals(scaleToFitDrawingSize * scaleToFitSpIconSize, mIconView.getIconScale(), 0.01f);
+        assertEquals(scaleToBackRawDrawableSize * scaleToFitDrawingSize * scaleToFitSpIconSize,
+                mIconView.getIconScale(), 0.01f);
+    }
+
+    @Test
+    public void testUpdateIconScale_smallerFontAndConstrainedDrawableSizeLessThanDpIconSize() {
+        int dpIconSize = 60;
+        int dpDrawingSize = 30;
+        // smaller font scaling causes the spIconSize < dpIconSize
+        int spIconSize = 40;
+        // the icon view layout size would be 40x150
+        //   (the height is always 150 due to TEST_STATUS_BAR_HEIGHT)
+        setUpIconView(dpIconSize, dpDrawingSize, spIconSize);
+        mIconView.setNotification(mock(StatusBarNotification.class));
+        // the raw drawable size is 70x70. When put the drawable into iconView whose
+        // layout size is 40x150, the drawable size would be constrained to 40x40
+        setIconDrawableWithSize(/* width= */ 70, /* height= */ 70);
+        mIconView.maybeUpdateIconScaleDimens();
+
+        // WHEN the raw drawable width/height are larger than dpIconSize,
+        //      but the constrained drawable width/height are less than dpIconSize,
+        // THEN the icon is scaled up from constrained drawable size to fit dpIconSize
+        float scaleToFitDpIconSize = (float) dpIconSize / 40;
+        // THEN the icon is scaled down from dpIconSize to fit the dpDrawingSize
+        float scaleToFitDrawingSize = (float) dpDrawingSize / dpIconSize;
+        // THEN the scaled icon should be scaled down further to fit spIconSize
+        float scaleToFitSpIconSize = (float) spIconSize / dpIconSize;
+        assertEquals(scaleToFitDpIconSize * scaleToFitDrawingSize * scaleToFitSpIconSize,
+                mIconView.getIconScale(), 0.01f);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt
new file mode 100644
index 0000000..8c3bfd5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.row.wrapper
+
+import android.app.PendingIntent
+import android.app.PendingIntent.CancelListener
+import android.content.Intent
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.testing.TestableLooper.RunWithLooper
+import android.testing.ViewUtils
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.FrameLayout
+import androidx.test.filters.SmallTest
+import com.android.internal.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.row.NotificationTestHelper
+import com.android.systemui.statusbar.notification.row.wrapper.NotificationTemplateViewWrapper.ActionPendingIntentCancellationHandler
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Mockito
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper
+class NotificationTemplateViewWrapperTest : SysuiTestCase() {
+
+    private lateinit var helper: NotificationTestHelper
+
+    private lateinit var root: ViewGroup
+    private lateinit var view: ViewGroup
+    private lateinit var row: ExpandableNotificationRow
+    private lateinit var actions: ViewGroup
+
+    private lateinit var looper: TestableLooper
+
+    @Before
+    fun setUp() {
+        looper = TestableLooper.get(this)
+        allowTestableLooperAsMainThread()
+        helper = NotificationTestHelper(mContext, mDependency, looper)
+        row = helper.createRow()
+        // Some code in the view iterates through parents so we need some extra containers around
+        // it.
+        root = FrameLayout(mContext)
+        val root2 = FrameLayout(mContext)
+        root.addView(root2)
+        view =
+            (LayoutInflater.from(mContext)
+                .inflate(R.layout.notification_template_material_big_text, root2) as ViewGroup)
+        actions = view.findViewById(R.id.actions)!!
+        ViewUtils.attachView(root)
+    }
+
+    @Test
+    fun noActionsPresent_noCrash() {
+        view.removeView(actions)
+        val wrapper = NotificationTemplateViewWrapper(mContext, view, row)
+        wrapper.onContentUpdated(row)
+    }
+
+    @Test
+    fun actionPendingIntentCancelled_actionDisabled() {
+        val wrapper = NotificationTemplateViewWrapper(mContext, view, row)
+        val action1 = createActionWithPendingIntent()
+        val action2 = createActionWithPendingIntent()
+        val action3 = createActionWithPendingIntent()
+        wrapper.onContentUpdated(row)
+        waitForUiOffloadThread() // Wait for cancellation registration to execute.
+
+        val pi3 = getPendingIntent(action3)
+        pi3.cancel()
+        looper.processAllMessages() // Wait for listener callbacks to execute
+
+        assertThat(action1.isEnabled).isTrue()
+        assertThat(action2.isEnabled).isTrue()
+        assertThat(action3.isEnabled).isFalse()
+        assertThat(wrapper.mCancelledPendingIntents)
+            .doesNotContain(getPendingIntent(action1).hashCode())
+        assertThat(wrapper.mCancelledPendingIntents)
+            .doesNotContain(getPendingIntent(action2).hashCode())
+        assertThat(wrapper.mCancelledPendingIntents).contains(pi3.hashCode())
+    }
+
+    @Test
+    fun newActionWithSamePendingIntentPosted_actionDisabled() {
+        val wrapper = NotificationTemplateViewWrapper(mContext, view, row)
+        val action = createActionWithPendingIntent()
+        wrapper.onContentUpdated(row)
+        waitForUiOffloadThread() // Wait for cancellation registration to execute.
+
+        // Cancel the intent and check action is now false.
+        val pi = getPendingIntent(action)
+        pi.cancel()
+        looper.processAllMessages() // Wait for listener callbacks to execute
+        assertThat(action.isEnabled).isFalse()
+
+        // Create a NEW action and make sure that one will also be cancelled with same PI.
+        actions.removeView(action)
+        val newAction = createActionWithPendingIntent(pi)
+        wrapper.onContentUpdated(row)
+        looper.processAllMessages() // Wait for listener callbacks to execute
+
+        assertThat(newAction.isEnabled).isFalse()
+        assertThat(wrapper.mCancelledPendingIntents).containsExactly(pi.hashCode())
+    }
+
+    @Test
+    fun twoActionsWithSameCancelledIntent_bothActionsDisabled() {
+        val wrapper = NotificationTemplateViewWrapper(mContext, view, row)
+        val action1 = createActionWithPendingIntent()
+        val action2 = createActionWithPendingIntent()
+        val action3 = createActionWithPendingIntent(getPendingIntent(action2))
+        wrapper.onContentUpdated(row)
+        waitForUiOffloadThread() // Wait for cancellation registration to execute.
+
+        val pi = getPendingIntent(action2)
+        pi.cancel()
+        looper.processAllMessages() // Wait for listener callbacks to execute
+
+        assertThat(action1.isEnabled).isTrue()
+        assertThat(action2.isEnabled).isFalse()
+        assertThat(action3.isEnabled).isFalse()
+    }
+
+    @Test
+    fun actionPendingIntentCancelled_whileDetached_actionDisabled() {
+        ViewUtils.detachView(root)
+        val wrapper = NotificationTemplateViewWrapper(mContext, view, row)
+        val action = createActionWithPendingIntent()
+        wrapper.onContentUpdated(row)
+        getPendingIntent(action).cancel()
+        ViewUtils.attachView(root)
+        waitForUiOffloadThread()
+        looper.processAllMessages()
+
+        assertThat(action.isEnabled).isFalse()
+    }
+
+    @Test
+    fun actionViewDetached_pendingIntentListenersDeregistered() {
+        val pi =
+            PendingIntent.getActivity(
+                mContext,
+                System.currentTimeMillis().toInt(),
+                Intent(Intent.ACTION_VIEW),
+                PendingIntent.FLAG_IMMUTABLE
+            )
+        val spy = Mockito.spy(pi)
+        createActionWithPendingIntent(spy)
+        val wrapper = NotificationTemplateViewWrapper(mContext, view, row)
+        wrapper.onContentUpdated(row)
+        ViewUtils.detachView(root)
+        waitForUiOffloadThread()
+        looper.processAllMessages()
+
+        val captor = ArgumentCaptor.forClass(CancelListener::class.java)
+        verify(spy, times(1)).registerCancelListener(captor.capture())
+        verify(spy, times(1)).unregisterCancelListener(captor.value)
+    }
+
+    @Test
+    fun actionViewUpdated_oldPendingIntentListenersRemoved() {
+        val pi =
+            PendingIntent.getActivity(
+                mContext,
+                System.currentTimeMillis().toInt(),
+                Intent(Intent.ACTION_VIEW),
+                PendingIntent.FLAG_IMMUTABLE
+            )
+        val spy = Mockito.spy(pi)
+        val action = createActionWithPendingIntent(spy)
+        val wrapper = NotificationTemplateViewWrapper(mContext, view, row)
+        wrapper.onContentUpdated(row)
+        waitForUiOffloadThread()
+        looper.processAllMessages()
+
+        // Grab set attach listener
+        val attachListener =
+            Mockito.spy(action.getTag(com.android.systemui.res.R.id.pending_intent_listener_tag))
+                as ActionPendingIntentCancellationHandler
+        action.setTag(com.android.systemui.res.R.id.pending_intent_listener_tag, attachListener)
+
+        // Update pending intent in the existing action
+        val newPi =
+            PendingIntent.getActivity(
+                mContext,
+                System.currentTimeMillis().toInt(),
+                Intent(Intent.ACTION_ALARM_CHANGED),
+                PendingIntent.FLAG_IMMUTABLE
+            )
+        action.setTagInternal(R.id.pending_intent_tag, newPi)
+        wrapper.onContentUpdated(row)
+        waitForUiOffloadThread()
+        looper.processAllMessages()
+
+        // Listeners for original pending intent need to be cleaned up now.
+        val captor = ArgumentCaptor.forClass(CancelListener::class.java)
+        verify(spy, times(1)).registerCancelListener(captor.capture())
+        verify(spy, times(1)).unregisterCancelListener(captor.value)
+        // Attach listener has to be replaced with a new one.
+        assertThat(action.getTag(com.android.systemui.res.R.id.pending_intent_listener_tag))
+            .isNotEqualTo(attachListener)
+        verify(attachListener).remove()
+    }
+
+    private fun createActionWithPendingIntent(): View {
+        val pi =
+            PendingIntent.getActivity(
+                mContext,
+                System.currentTimeMillis().toInt(),
+                Intent(Intent.ACTION_VIEW),
+                PendingIntent.FLAG_IMMUTABLE
+            )
+        return createActionWithPendingIntent(pi)
+    }
+
+    private fun createActionWithPendingIntent(pi: PendingIntent): View {
+        val view =
+            LayoutInflater.from(mContext)
+                .inflate(R.layout.notification_material_action, null, false)
+        view.setTagInternal(R.id.pending_intent_tag, pi)
+        actions.addView(view)
+        return view
+    }
+
+    private fun getPendingIntent(action: View): PendingIntent {
+        val pendingIntent = action.getTag(R.id.pending_intent_tag) as PendingIntent
+        assertThat(pendingIntent).isNotNull()
+        return pendingIntent
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt
index 15b9d61..c935dbb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt
@@ -17,13 +17,14 @@
 package com.android.systemui.statusbar.pipeline.shared.ui.viewmodel
 
 import androidx.test.filters.SmallTest
-import com.android.systemui.res.R
+import com.android.settingslib.AccessibilityContentDescriptions.WIFI_OTHER_DEVICE_CONNECTION
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.common.shared.model.ContentDescription.Companion.loadContentDescription
 import com.android.systemui.common.shared.model.Text
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.qs.tileimpl.QSTileImpl.ResourceIcon
+import com.android.systemui.res.R
 import com.android.systemui.statusbar.connectivity.WifiIcons
 import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
 import com.android.systemui.statusbar.pipeline.ethernet.domain.EthernetInteractor
@@ -181,6 +182,8 @@
 
             assertThat(latest?.icon)
                 .isEqualTo(ResourceIcon.get(WifiIcons.WIFI_NO_INTERNET_ICONS[4]))
+            assertThat(latest?.stateDescription.loadContentDescription(context))
+                .doesNotContain(context.getString(WIFI_OTHER_DEVICE_CONNECTION))
         }
 
     @Test
@@ -192,6 +195,8 @@
 
             assertThat(latest?.icon)
                 .isEqualTo(ResourceIcon.get(com.android.settingslib.R.drawable.ic_hotspot_tablet))
+            assertThat(latest?.stateDescription.loadContentDescription(context))
+                .isEqualTo(context.getString(WIFI_OTHER_DEVICE_CONNECTION))
         }
 
     @Test
@@ -203,6 +208,8 @@
 
             assertThat(latest?.icon)
                 .isEqualTo(ResourceIcon.get(com.android.settingslib.R.drawable.ic_hotspot_laptop))
+            assertThat(latest?.stateDescription.loadContentDescription(context))
+                .isEqualTo(context.getString(WIFI_OTHER_DEVICE_CONNECTION))
         }
 
     @Test
@@ -214,6 +221,8 @@
 
             assertThat(latest?.icon)
                 .isEqualTo(ResourceIcon.get(com.android.settingslib.R.drawable.ic_hotspot_watch))
+            assertThat(latest?.stateDescription.loadContentDescription(context))
+                .isEqualTo(context.getString(WIFI_OTHER_DEVICE_CONNECTION))
         }
 
     @Test
@@ -225,6 +234,8 @@
 
             assertThat(latest?.icon)
                 .isEqualTo(ResourceIcon.get(com.android.settingslib.R.drawable.ic_hotspot_auto))
+            assertThat(latest?.stateDescription.loadContentDescription(context))
+                .isEqualTo(context.getString(WIFI_OTHER_DEVICE_CONNECTION))
         }
 
     @Test
@@ -236,6 +247,8 @@
 
             assertThat(latest?.icon)
                 .isEqualTo(ResourceIcon.get(com.android.settingslib.R.drawable.ic_hotspot_phone))
+            assertThat(latest?.stateDescription.loadContentDescription(context))
+                .isEqualTo(context.getString(WIFI_OTHER_DEVICE_CONNECTION))
         }
 
     @Test
@@ -247,6 +260,8 @@
 
             assertThat(latest?.icon)
                 .isEqualTo(ResourceIcon.get(com.android.settingslib.R.drawable.ic_hotspot_phone))
+            assertThat(latest?.stateDescription.loadContentDescription(context))
+                .isEqualTo(context.getString(WIFI_OTHER_DEVICE_CONNECTION))
         }
 
     @Test
@@ -258,6 +273,8 @@
 
             assertThat(latest?.icon)
                 .isEqualTo(ResourceIcon.get(com.android.settingslib.R.drawable.ic_hotspot_phone))
+            assertThat(latest?.stateDescription.loadContentDescription(context))
+                .isEqualTo(context.getString(WIFI_OTHER_DEVICE_CONNECTION))
         }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
index a520f6c..49a2648 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
@@ -18,8 +18,10 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.settingslib.AccessibilityContentDescriptions.WIFI_OTHER_DEVICE_CONNECTION
 import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.ContentDescription.Companion.loadContentDescription
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.statusbar.connectivity.WifiIcons
@@ -136,6 +138,10 @@
             // is used instead
             assertThat(latest).isInstanceOf(WifiIcon.Visible::class.java)
             assertThat((latest as WifiIcon.Visible).res).isEqualTo(WifiIcons.WIFI_FULL_ICONS[1])
+            assertThat(
+                    (latest as WifiIcon.Visible).contentDescription.loadContentDescription(context)
+                )
+                .doesNotContain(context.getString(WIFI_OTHER_DEVICE_CONNECTION))
         }
 
     @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 8e57dc1..daf8877 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -41,8 +41,8 @@
 import android.app.KeyguardManager;
 import android.content.res.Configuration;
 import android.media.AudioManager;
-import android.os.Handler;
 import android.os.SystemClock;
+import android.provider.Settings;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.util.Log;
@@ -71,6 +71,7 @@
 import com.android.systemui.statusbar.policy.DevicePostureController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.FakeConfigurationController;
+import com.android.systemui.util.settings.FakeSettings;
 
 import org.junit.After;
 import org.junit.Before;
@@ -135,6 +136,8 @@
     private FakeFeatureFlags mFeatureFlags;
     private int mLongestHideShowAnimationDuration = 250;
 
+    private FakeSettings mSecureSettings;
+
     @Rule
     public final AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule();
 
@@ -147,10 +150,6 @@
         mTestableLooper = TestableLooper.get(this);
         allowTestableLooperAsMainThread();
 
-        // Ensure previous tests have not left messages on main looper
-        Handler localHandler = new Handler(mTestableLooper.getLooper());
-        localHandler.removeCallbacksAndMessages(null);
-
         when(mPostureController.getDevicePosture())
                 .thenReturn(DevicePostureController.DEVICE_POSTURE_CLOSED);
 
@@ -167,6 +166,8 @@
 
         mFeatureFlags = new FakeFeatureFlags();
 
+        mSecureSettings = new FakeSettings();
+
         mDialog = new VolumeDialogImpl(
                 getContext(),
                 mVolumeDialogController,
@@ -182,7 +183,8 @@
                 mPostureController,
                 mTestableLooper.getLooper(),
                 mDumpManager,
-                mFeatureFlags);
+                mFeatureFlags,
+                mSecureSettings);
         mDialog.init(0, null);
         State state = createShellState();
         mDialog.onStateChangedH(state);
@@ -247,6 +249,18 @@
     }
 
     @Test
+    public void testSetTimeoutValue_ComputeTimeout() {
+        mSecureSettings.putInt(Settings.Secure.VOLUME_DIALOG_DISMISS_TIMEOUT, 7000);
+        Mockito.reset(mAccessibilityMgr);
+        mDialog.init(0, null);
+        mDialog.rescheduleTimeoutH();
+        verify(mAccessibilityMgr).getRecommendedTimeoutMillis(
+                7000,
+                AccessibilityManager.FLAG_CONTENT_CONTROLS);
+    }
+
+
+    @Test
     public void testComputeTimeout_tooltip() {
         Mockito.reset(mAccessibilityMgr);
         mDialog.showCaptionsTooltip();
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeQSFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeQSFactory.kt
index bf26e71..cbf4ae5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeQSFactory.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeQSFactory.kt
@@ -21,6 +21,6 @@
 
 class FakeQSFactory(private val tileCreator: (String) -> QSTile?) : QSFactory {
     override fun createTile(tileSpec: String): QSTile? {
-        return tileCreator(tileSpec)
+        return tileCreator(tileSpec)?.also { it.tileSpec = tileSpec }
     }
 }
diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
index a3ccb16..9dd0dca 100644
--- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
+++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
@@ -113,13 +113,15 @@
     private final boolean mCrossTaskNavigationAllowedByDefault;
     @NonNull
     private final ArraySet<ComponentName> mCrossTaskNavigationExemptions;
+    @Nullable
+    private final ComponentName mPermissionDialogComponent;
     private final Object mGenericWindowPolicyControllerLock = new Object();
     @Nullable private final ActivityBlockedCallback mActivityBlockedCallback;
     private int mDisplayId = Display.INVALID_DISPLAY;
 
     @NonNull
     @GuardedBy("mGenericWindowPolicyControllerLock")
-    final ArraySet<Integer> mRunningUids = new ArraySet<>();
+    private final ArraySet<Integer> mRunningUids = new ArraySet<>();
     @Nullable private final ActivityListener mActivityListener;
     @Nullable private final PipBlockedCallback mPipBlockedCallback;
     @Nullable private final IntentListenerCallback mIntentListenerCallback;
@@ -171,6 +173,7 @@
             @NonNull Set<ComponentName> activityPolicyExemptions,
             boolean crossTaskNavigationAllowedByDefault,
             @NonNull Set<ComponentName> crossTaskNavigationExemptions,
+            @Nullable ComponentName permissionDialogComponent,
             @Nullable ActivityListener activityListener,
             @Nullable PipBlockedCallback pipBlockedCallback,
             @Nullable ActivityBlockedCallback activityBlockedCallback,
@@ -185,6 +188,7 @@
         mActivityPolicyExemptions = activityPolicyExemptions;
         mCrossTaskNavigationAllowedByDefault = crossTaskNavigationAllowedByDefault;
         mCrossTaskNavigationExemptions = new ArraySet<>(crossTaskNavigationExemptions);
+        mPermissionDialogComponent = permissionDialogComponent;
         mActivityBlockedCallback = activityBlockedCallback;
         setInterestedWindowFlags(windowFlags, systemWindowFlags);
         mActivityListener = activityListener;
@@ -309,6 +313,13 @@
             return false;
         }
 
+        // mPermissionDialogComponent being null means we don't want to block permission Dialogs
+        // based on FLAG_STREAM_PERMISSIONS
+        if (mPermissionDialogComponent != null
+                && mPermissionDialogComponent.equals(activityComponent)) {
+            return false;
+        }
+
         return true;
     }
 
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 203a152..a2e4d2c 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -24,6 +24,7 @@
 import static android.companion.virtual.VirtualDeviceParams.NAVIGATION_POLICY_DEFAULT_ALLOWED;
 import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_ACTIVITY;
 import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_RECENTS;
+import static android.content.pm.PackageManager.ACTION_REQUEST_PERMISSIONS;
 import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
 
@@ -204,6 +205,7 @@
     @GuardedBy("mVirtualDeviceLock")
     @NonNull
     private final Set<ComponentName> mActivityPolicyExemptions;
+    private final ComponentName mPermissionDialogComponent;
 
     private ActivityListener createListenerAdapter() {
         return new ActivityListener() {
@@ -317,6 +319,11 @@
                 mParams.getVirtualSensorCallback(), mParams.getVirtualSensorConfigs());
         mCameraAccessController = cameraAccessController;
         mCameraAccessController.startObservingIfNeeded();
+        if (!Flags.streamPermissions()) {
+            mPermissionDialogComponent = getPermissionDialogComponent();
+        } else {
+            mPermissionDialogComponent = null;
+        }
         try {
             token.linkToDeath(this, 0);
         } catch (RemoteException e) {
@@ -324,8 +331,14 @@
         }
         mVirtualDeviceLog.logCreated(deviceId, mOwnerUid);
 
-        mPublicVirtualDeviceObject = new VirtualDevice(
-                this, getDeviceId(), getPersistentDeviceId(), mParams.getName());
+        if (Flags.vdmPublicApis()) {
+            mPublicVirtualDeviceObject = new VirtualDevice(
+                    this, getDeviceId(), getPersistentDeviceId(), mParams.getName(),
+                    getDisplayName());
+        } else {
+            mPublicVirtualDeviceObject = new VirtualDevice(
+                    this, getDeviceId(), getPersistentDeviceId(), mParams.getName());
+        }
 
         if (Flags.dynamicPolicy()) {
             mActivityPolicyExemptions = new ArraySet<>(
@@ -951,6 +964,7 @@
                 /*crossTaskNavigationExemptions=*/crossTaskNavigationAllowedByDefault
                         ? mParams.getBlockedCrossTaskNavigations()
                         : mParams.getAllowedCrossTaskNavigations(),
+                mPermissionDialogComponent,
                 createListenerAdapter(),
                 this::onEnteringPipBlocked,
                 this::onActivityBlocked,
@@ -963,6 +977,13 @@
         return gwpc;
     }
 
+    private ComponentName getPermissionDialogComponent() {
+        Intent intent = new Intent(ACTION_REQUEST_PERMISSIONS);
+        PackageManager packageManager = mContext.getPackageManager();
+        intent.setPackage(packageManager.getPermissionControllerPackageName());
+        return intent.resolveActivity(packageManager);
+    }
+
     int createVirtualDisplay(@NonNull VirtualDisplayConfig virtualDisplayConfig,
             @NonNull IVirtualDisplayCallback callback, String packageName) {
         GenericWindowPolicyController gwpc;
diff --git a/services/core/java/com/android/server/connectivity/OWNERS b/services/core/java/com/android/server/connectivity/OWNERS
index 62c5737..c24680e9 100644
--- a/services/core/java/com/android/server/connectivity/OWNERS
+++ b/services/core/java/com/android/server/connectivity/OWNERS
@@ -1,2 +1,2 @@
 set noparent
-file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking
+file:platform/packages/modules/Connectivity:main:/OWNERS_core_networking
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index debf828..99a5398 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -33,7 +33,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.display.BrightnessSynchronizer;
-import com.android.internal.display.BrightnessUtils;
 import com.android.internal.util.Preconditions;
 import com.android.server.display.utils.Plog;
 import com.android.server.display.whitebalance.DisplayWhiteBalanceController;
diff --git a/core/java/com/android/internal/display/BrightnessUtils.java b/services/core/java/com/android/server/display/BrightnessUtils.java
similarity index 96%
rename from core/java/com/android/internal/display/BrightnessUtils.java
rename to services/core/java/com/android/server/display/BrightnessUtils.java
index 82b506b..84fa0cc 100644
--- a/core/java/com/android/internal/display/BrightnessUtils.java
+++ b/services/core/java/com/android/server/display/BrightnessUtils.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.internal.display;
+package com.android.server.display;
 
 import android.util.MathUtils;
 
diff --git a/services/core/java/com/android/server/display/RampAnimator.java b/services/core/java/com/android/server/display/RampAnimator.java
index e38c2c5..5ba042c 100644
--- a/services/core/java/com/android/server/display/RampAnimator.java
+++ b/services/core/java/com/android/server/display/RampAnimator.java
@@ -20,8 +20,6 @@
 import android.util.FloatProperty;
 import android.view.Choreographer;
 
-import com.android.internal.display.BrightnessUtils;
-
 /**
  * A custom animator that progressively updates a property value at
  * a given variable rate until it reaches a particular target value.
diff --git a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java
index 41053e9..68848a2 100644
--- a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java
+++ b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java
@@ -16,36 +16,66 @@
 
 package com.android.server.grammaticalinflection;
 
+import static android.app.Flags.systemTermsOfAddressEnabled;
 import static android.content.res.Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED;
 
 import android.annotation.Nullable;
+import android.app.GrammaticalInflectionManager;
 import android.app.IGrammaticalInflectionManager;
 import android.content.Context;
 import android.content.pm.PackageManagerInternal;
 import android.os.Binder;
-import android.os.IBinder;
+import android.os.Environment;
 import android.os.Process;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
 import android.os.SystemProperties;
+import android.util.AtomicFile;
 import android.util.Log;
+import android.util.SparseIntArray;
+import android.util.Xml;
 
 import com.android.internal.util.FrameworkStatsLog;
+import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.wm.ActivityTaskManagerInternal;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+
 /**
  * The implementation of IGrammaticalInflectionManager.aidl.
  *
  * <p>This service is API entry point for storing app-specific grammatical inflection.
  */
 public class GrammaticalInflectionService extends SystemService {
-    private final String TAG = "GrammaticalInflection";
-    private final GrammaticalInflectionBackupHelper mBackupHelper;
-    private final ActivityTaskManagerInternal mActivityTaskManagerInternal;
-    private PackageManagerInternal mPackageManagerInternal;
+    private static final String TAG = "GrammaticalInflection";
+    private static final String ATTR_NAME = "grammatical_gender";
+    private static final String USER_SETTINGS_FILE_NAME = "user_settings.xml";
+    private static final String TAG_GRAMMATICAL_INFLECTION = "grammatical_inflection";
     private static final String GRAMMATICAL_INFLECTION_ENABLED =
             "i18n.grammatical_Inflection.enabled";
 
+    private final GrammaticalInflectionBackupHelper mBackupHelper;
+    private final ActivityTaskManagerInternal mActivityTaskManagerInternal;
+    private final Object mLock = new Object();
+    private final SparseIntArray mGrammaticalGenderCache = new SparseIntArray();
+
+    private PackageManagerInternal mPackageManagerInternal;
+    private GrammaticalInflectionService.GrammaticalInflectionBinderService mBinderService;
+
     /**
      * Initializes the system service.
      * <p>
@@ -62,22 +92,46 @@
         mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
         mBackupHelper = new GrammaticalInflectionBackupHelper(
                 this, context.getPackageManager());
+        mBinderService = new GrammaticalInflectionBinderService();
     }
 
     @Override
     public void onStart() {
-        publishBinderService(Context.GRAMMATICAL_INFLECTION_SERVICE, mService);
+        publishBinderService(Context.GRAMMATICAL_INFLECTION_SERVICE, mBinderService);
         LocalServices.addService(GrammaticalInflectionManagerInternal.class,
                 new GrammaticalInflectionManagerInternalImpl());
     }
 
-    private final IBinder mService = new IGrammaticalInflectionManager.Stub() {
+    private final class GrammaticalInflectionBinderService extends
+            IGrammaticalInflectionManager.Stub {
         @Override
         public void setRequestedApplicationGrammaticalGender(
                 String appPackageName, int userId, int gender) {
             GrammaticalInflectionService.this.setRequestedApplicationGrammaticalGender(
                     appPackageName, userId, gender);
         }
+
+        @Override
+        public void setSystemWideGrammaticalGender(int userId, int grammaticalGender) {
+            checkCallerIsSystem();
+            checkSystemTermsOfAddressIsEnabled();
+            GrammaticalInflectionService.this.setSystemWideGrammaticalGender(grammaticalGender,
+                    userId);
+        }
+
+        @Override
+        public int getSystemGrammaticalGender(int userId) {
+            checkSystemTermsOfAddressIsEnabled();
+            return GrammaticalInflectionService.this.getSystemGrammaticalGender(userId);
+        }
+
+        @Override
+        public void onShellCommand(FileDescriptor in, FileDescriptor out,
+                FileDescriptor err, String[] args, ShellCallback callback,
+                ResultReceiver resultReceiver) {
+            (new GrammaticalInflectionShellCommand(mBinderService))
+                    .exec(this, in, out, err, args, callback, resultReceiver);
+        }
     };
 
     private final class GrammaticalInflectionManagerInternalImpl
@@ -94,12 +148,6 @@
         public void stageAndApplyRestoredPayload(byte[] payload, int userId) {
             mBackupHelper.stageAndApplyRestoredPayload(payload, userId);
         }
-
-        private void checkCallerIsSystem() {
-            if (Binder.getCallingUid() != Process.SYSTEM_UID) {
-                throw new SecurityException("Caller is not system.");
-            }
-        }
     }
 
     protected int getApplicationGrammaticalGender(String appPackageName, int userId) {
@@ -137,4 +185,105 @@
 
         updater.setGrammaticalGender(gender).commit();
     }
+
+    protected void setSystemWideGrammaticalGender(int grammaticalGender, int userId) {
+        if (!GrammaticalInflectionManager.VALID_GRAMMATICAL_GENDER_VALUES.contains(
+                grammaticalGender)) {
+            throw new IllegalArgumentException("Unknown grammatical gender");
+        }
+
+        synchronized (mLock) {
+            final File file = getGrammaticalGenderFile(userId);
+            final AtomicFile atomicFile = new AtomicFile(file);
+            FileOutputStream stream = null;
+            try {
+                stream = atomicFile.startWrite();
+                stream.write(toXmlByteArray(grammaticalGender, stream));
+                atomicFile.finishWrite(stream);
+                mGrammaticalGenderCache.put(userId, grammaticalGender);
+            } catch (IOException e) {
+                Log.e(TAG, "Failed to write file " + atomicFile, e);
+                if (stream != null) {
+                    atomicFile.failWrite(stream);
+                }
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    // TODO(b/298591009): Add a new AppOp value for the apps that want to access the grammatical
+    //  gender.
+    public int getSystemGrammaticalGender(int userId) {
+        synchronized (mLock) {
+            final File file = getGrammaticalGenderFile(userId);
+            if (!file.exists()) {
+                Log.d(TAG, "User " + userId + "doesn't have the grammatical gender file.");
+                return GRAMMATICAL_GENDER_NOT_SPECIFIED;
+            }
+
+            if (mGrammaticalGenderCache.indexOfKey(userId) < 0) {
+                try {
+                    InputStream in = new FileInputStream(file);
+                    final TypedXmlPullParser parser = Xml.resolvePullParser(in);
+                    mGrammaticalGenderCache.put(userId, getGrammaticalGenderFromXml(parser));
+                } catch (IOException | XmlPullParserException e) {
+                    Log.e(TAG, "Failed to parse XML configuration from " + file, e);
+                }
+            }
+            return mGrammaticalGenderCache.get(userId);
+        }
+    }
+
+    private File getGrammaticalGenderFile(int userId) {
+        final File dir = new File(Environment.getDataSystemCeDirectory(userId),
+                TAG_GRAMMATICAL_INFLECTION);
+        return new File(dir, USER_SETTINGS_FILE_NAME);
+    }
+
+    private byte[] toXmlByteArray(int grammaticalGender, FileOutputStream fileStream) {
+
+        try {
+            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+            TypedXmlSerializer out = Xml.resolveSerializer(fileStream);
+            out.setOutput(outputStream, StandardCharsets.UTF_8.name());
+            out.startDocument(/* encoding= */ null, /* standalone= */ true);
+            out.startTag(null, TAG_GRAMMATICAL_INFLECTION);
+            out.attributeInt(null, ATTR_NAME, grammaticalGender);
+            out.endTag(null, TAG_GRAMMATICAL_INFLECTION);
+            out.endDocument();
+
+            return outputStream.toByteArray();
+        } catch (IOException e) {
+            return null;
+        }
+    }
+
+    private int getGrammaticalGenderFromXml(TypedXmlPullParser parser)
+            throws IOException, XmlPullParserException {
+
+        XmlUtils.nextElement(parser);
+        while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
+            String tagName = parser.getName();
+            if (TAG_GRAMMATICAL_INFLECTION.equals(tagName)) {
+                return parser.getAttributeInt(null, ATTR_NAME);
+            } else {
+                XmlUtils.nextElement(parser);
+            }
+        }
+
+        return GRAMMATICAL_GENDER_NOT_SPECIFIED;
+    }
+
+    private void checkCallerIsSystem() {
+        int callingUid = Binder.getCallingUid();
+        if (callingUid != Process.SYSTEM_UID && callingUid != Process.SHELL_UID) {
+            throw new SecurityException("Caller is not system and shell.");
+        }
+    }
+
+    private void checkSystemTermsOfAddressIsEnabled() {
+        if (!systemTermsOfAddressEnabled()) {
+            throw new RuntimeException("The flag must be enabled to allow calling the API.");
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionShellCommand.java b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionShellCommand.java
new file mode 100644
index 0000000..d223728
--- /dev/null
+++ b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionShellCommand.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.grammaticalinflection;
+
+import static android.content.res.Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED;
+
+import android.app.ActivityManager;
+import android.app.GrammaticalInflectionManager;
+import android.app.IGrammaticalInflectionManager;
+import android.content.res.Configuration;
+import android.os.RemoteException;
+import android.os.ShellCommand;
+import android.os.UserHandle;
+import android.util.SparseArray;
+
+import java.io.PrintWriter;
+
+/**
+ * Shell commands for {@link GrammaticalInflectionService}
+ */
+class GrammaticalInflectionShellCommand extends ShellCommand {
+
+    private static final SparseArray<String> GRAMMATICAL_GENDER_MAP = new SparseArray<>();
+    static {
+        GRAMMATICAL_GENDER_MAP.put(Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED,
+                "Not specified (0)");
+        GRAMMATICAL_GENDER_MAP.put(Configuration.GRAMMATICAL_GENDER_NEUTRAL, "Neuter (1)");
+        GRAMMATICAL_GENDER_MAP.put(Configuration.GRAMMATICAL_GENDER_FEMININE, "Feminine (2)");
+        GRAMMATICAL_GENDER_MAP.put(Configuration.GRAMMATICAL_GENDER_MASCULINE, "Masculine (3)");
+    }
+
+    private final IGrammaticalInflectionManager mBinderService;
+
+    GrammaticalInflectionShellCommand(IGrammaticalInflectionManager grammaticalInflectionManager) {
+        mBinderService = grammaticalInflectionManager;
+    }
+
+    @Override
+    public int onCommand(String cmd) {
+        if (cmd == null) {
+            return handleDefaultCommands(cmd);
+        }
+        switch (cmd) {
+            case "set-system-grammatical-gender":
+                return runSetSystemWideGrammaticalGender();
+            case "get-system-grammatical-gender":
+                return runGetSystemGrammaticalGender();
+            default: {
+                return handleDefaultCommands(cmd);
+            }
+        }
+    }
+
+    @Override
+    public void onHelp() {
+        PrintWriter pw = getOutPrintWriter();
+        pw.println("Grammatical inflection manager (grammatical_inflection) shell commands:");
+        pw.println("  help");
+        pw.println("      Print this help text.");
+        pw.println(
+                "  set-system-grammatical-gender [--user <USER_ID>] [--grammaticalGender "
+                        + "<GRAMMATICAL_GENDER>]");
+        pw.println("      Set the system grammatical gender for system.");
+        pw.println("      --user <USER_ID>: apply for the given user, "
+                + "the current user is used when unspecified.");
+        pw.println(
+                "      --grammaticalGender <GRAMMATICAL_GENDER>: The terms of address the user "
+                        + "preferred in system, not specified (0) is used when unspecified.");
+        pw.println(
+                "                 eg. 0 = not_specified, 1 = neuter, 2 = feminine, 3 = masculine"
+                        + ".");
+        pw.println(
+                "  get-system-grammatical-gender [--user <USER_ID>]");
+        pw.println("      Get the system grammatical gender for system.");
+        pw.println("      --user <USER_ID>: apply for the given user, "
+                + "the current user is used when unspecified.");
+    }
+
+    private int runSetSystemWideGrammaticalGender() {
+        int userId = ActivityManager.getCurrentUser();
+        int grammaticalGender = GRAMMATICAL_GENDER_NOT_SPECIFIED;
+        do {
+            String option = getNextOption();
+            if (option == null) {
+                break;
+            }
+            switch (option) {
+                case "--user": {
+                    userId = UserHandle.parseUserArg(getNextArgRequired());
+                    break;
+                }
+                case "-g":
+                case "--grammaticalGender": {
+                    grammaticalGender = parseGrammaticalGender();
+                    break;
+                }
+                default: {
+                    throw new IllegalArgumentException("Unknown option: " + option);
+                }
+            }
+        } while (true);
+
+        try {
+            mBinderService.setSystemWideGrammaticalGender(userId, grammaticalGender);
+        } catch (RemoteException e) {
+            getOutPrintWriter().println("Remote Exception: " + e);
+        }
+        return 0;
+    }
+
+    private int runGetSystemGrammaticalGender() {
+        int userId = ActivityManager.getCurrentUser();
+        do {
+            String option = getNextOption();
+            if (option == null) {
+                break;
+            }
+            switch (option) {
+                case "--user": {
+                    userId = UserHandle.parseUserArg(getNextArgRequired());
+                    break;
+                }
+                default: {
+                    throw new IllegalArgumentException("Unknown option: " + option);
+                }
+            }
+        } while (true);
+
+        try {
+            int grammaticalGender = mBinderService.getSystemGrammaticalGender(userId);
+            getOutPrintWriter().println(GRAMMATICAL_GENDER_MAP.get(grammaticalGender));
+        } catch (RemoteException e) {
+            getOutPrintWriter().println("Remote Exception: " + e);
+        }
+        return 0;
+    }
+
+    private int parseGrammaticalGender() {
+        String arg = getNextArg();
+        if (arg == null) {
+            return GRAMMATICAL_GENDER_NOT_SPECIFIED;
+        } else {
+            int grammaticalGender = Integer.parseInt(arg);
+            if (GrammaticalInflectionManager.VALID_GRAMMATICAL_GENDER_VALUES.contains(
+                    grammaticalGender)) {
+                return grammaticalGender;
+            } else {
+                return GRAMMATICAL_GENDER_NOT_SPECIFIED;
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/grammaticalinflection/OWNERS b/services/core/java/com/android/server/grammaticalinflection/OWNERS
index 5f16ba9..41d079e 100644
--- a/services/core/java/com/android/server/grammaticalinflection/OWNERS
+++ b/services/core/java/com/android/server/grammaticalinflection/OWNERS
@@ -2,3 +2,4 @@
 allenwtsu@google.com
 goldmanj@google.com
 calvinpan@google.com
+zoeychen@google.com
diff --git a/services/core/java/com/android/server/net/OWNERS b/services/core/java/com/android/server/net/OWNERS
index 9c96d46f..d0e95dd 100644
--- a/services/core/java/com/android/server/net/OWNERS
+++ b/services/core/java/com/android/server/net/OWNERS
@@ -1,5 +1,5 @@
 set noparent
-file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking
+file:platform/packages/modules/Connectivity:main:/OWNERS_core_networking
 
 jsharkey@android.com
 sudheersai@google.com
diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java
index 3d61f3e..b055a3f 100644
--- a/services/core/java/com/android/server/pm/RemovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java
@@ -402,7 +402,7 @@
                 mBroadcastHelper.sendPreferredActivityChangedBroadcast(UserHandle.USER_ALL);
             }
         } else if (!deletedPs.isSystem() && outInfo != null && !outInfo.mIsUpdate
-                && outInfo.mRemovedUsers != null) {
+                && outInfo.mRemovedUsers != null && !outInfo.mIsExternal) {
             // For non-system uninstalls with DELETE_KEEP_DATA, set the installed state to false
             // for affected users. This does not apply to app updates where the old apk is replaced
             // but the old data remains.
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index 04d1da6..390c45b 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -145,6 +145,19 @@
           "include-filter": "android.content.pm.cts.PackageManagerShellCommandMultiUserTest"
         }
       ]
+    },
+    {
+      "file_patterns": [
+        "(/|^)InstallPackageHelper\\.java",
+        "services/core/java/com/android/server/pm/parsing/.*",
+        "services/core/java/com/android/server/pm/pkg/parsing/.*"
+      ],
+      "name": "SdkSandboxManagerServiceUnitTests",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
     }
   ],
   "imports": [
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index dfc9b8b..097656c 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -198,7 +198,6 @@
 import com.android.internal.accessibility.util.AccessibilityUtils;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.AssistUtils;
-import com.android.internal.display.BrightnessUtils;
 import com.android.internal.inputmethod.SoftInputShowHideReason;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
@@ -218,6 +217,7 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemServiceManager;
 import com.android.server.UiThread;
+import com.android.server.display.BrightnessUtils;
 import com.android.server.input.InputManagerInternal;
 import com.android.server.input.KeyboardMetricsCollector;
 import com.android.server.input.KeyboardMetricsCollector.KeyboardLogEvent;
diff --git a/services/core/java/com/android/server/security/rkp/OWNERS b/services/core/java/com/android/server/security/rkp/OWNERS
index 348f940..ea6dc72 100644
--- a/services/core/java/com/android/server/security/rkp/OWNERS
+++ b/services/core/java/com/android/server/security/rkp/OWNERS
@@ -1 +1 @@
-file:platform/frameworks/base:master:/core/java/android/security/rkp/OWNERS
+file:platform/frameworks/base:main:/core/java/android/security/rkp/OWNERS
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index a0c7870..ed10346 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -580,7 +580,7 @@
     IBinder mRequestedLaunchingTaskFragmentToken;
 
     // Tracking splash screen status from previous activity
-    boolean mAllowIconSplashScreen = true;
+    boolean mSplashScreenStyleSolidColor = false;
 
     boolean mPauseSchedulePendingForPip = false;
 
@@ -2408,7 +2408,8 @@
     @VisibleForTesting
     boolean addStartingWindow(String pkg, int resolvedTheme, ActivityRecord from, boolean newTask,
             boolean taskSwitch, boolean processRunning, boolean allowTaskSnapshot,
-            boolean activityCreated, boolean allowIcon, boolean activityAllDrawn) {
+            boolean activityCreated, boolean isSimple,
+            boolean activityAllDrawn) {
         // If the display is frozen, we won't do anything until the actual window is
         // displayed so there is no reason to put in the starting window.
         if (!okToDisplay()) {
@@ -2443,8 +2444,8 @@
 
         final int typeParameter = StartingSurfaceController
                 .makeStartingWindowTypeParameter(newTask, taskSwitch, processRunning,
-                        allowTaskSnapshot, activityCreated, allowIcon, useLegacy,
-                        activityAllDrawn, type, packageName, mUserId);
+                        allowTaskSnapshot, activityCreated, isSimple, useLegacy, activityAllDrawn,
+                        type, packageName, mUserId);
 
         if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
             if (isActivityTypeHome()) {
@@ -5365,7 +5366,7 @@
                 // Finish should only ever commit visibility=false, so we can check full containment
                 // rather than just direct membership.
                 inFinishingTransition = mTransitionController.inFinishingTransition(this);
-                if (!inFinishingTransition && !mDisplayContent.isSleeping()) {
+                if (!inFinishingTransition && (visible || !mDisplayContent.isSleeping())) {
                     Slog.e(TAG, "setVisibility=" + visible
                             + " while transition is not collecting or finishing "
                             + this + " caller=" + Debug.getCallers(8));
@@ -6746,7 +6747,7 @@
     void onFirstWindowDrawn(WindowState win) {
         firstWindowDrawn = true;
         // stop tracking
-        mAllowIconSplashScreen = false;
+        mSplashScreenStyleSolidColor = true;
 
         if (mStartingWindow != null) {
             ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Finish starting %s"
@@ -6795,7 +6796,7 @@
     void onStartingWindowDrawn() {
         boolean wasTaskVisible = false;
         if (task != null) {
-            mAllowIconSplashScreen = false;
+            mSplashScreenStyleSolidColor = true;
             wasTaskVisible = !setTaskHasBeenVisible();
         }
 
@@ -7320,32 +7321,19 @@
     }
 
     /**
-     * Checks whether an icon splash screen can be used in the starting window based on the
-     * preference in the {@code options} and this activity's theme, giving higher priority to the
-     * {@code options}'s preference.
-     *
-     * When no preference is specified, a default behaviour is defined:
-     *  - if the activity is started from the home or shell app, an icon can be used
-     *  - if the activity is started from SystemUI, an icon should not be used
-     *  - if there is a launching activity, use its preference
-     *  - if none of the above is met, only use an icon when the activity is started for the first
-     *    time from a System app
-     *
-     * The returned value is sent to WmShell, which will make the final decision on what splash
-     * screen type will be used.
-     *
-     * @return true if an icon can be used in the splash screen
-     *         false when an icon should not be used in the splash screen
+     * @return true if a solid color splash screen must be used
+     *         false when an icon splash screen can be used, but the final decision for whether to
+     *               use an icon or solid color splash screen will be made by WmShell.
      */
-    private boolean canUseIconSplashScreen(ActivityRecord sourceRecord,
+    private boolean shouldUseSolidColorSplashScreen(ActivityRecord sourceRecord,
             boolean startActivity, ActivityOptions options, int resolvedTheme) {
         if (sourceRecord == null && !startActivity) {
-            // Shouldn't use an icon if this activity is not top activity. This could happen when
-            // adding a splash screen window to the warm start activity which is re-create because
-            // top is finishing.
+            // Use simple style if this activity is not top activity. This could happen when adding
+            // a splash screen window to the warm start activity which is re-create because top is
+            // finishing.
             final ActivityRecord above = task.getActivityAbove(this);
             if (above != null) {
-                return false;
+                return true;
             }
         }
 
@@ -7353,33 +7341,32 @@
         final int optionsStyle = options != null ? options.getSplashScreenStyle() :
                 SplashScreen.SPLASH_SCREEN_STYLE_UNDEFINED;
         if (optionsStyle == SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR) {
-            return false;
+            return true;
         } else if (optionsStyle == SplashScreen.SPLASH_SCREEN_STYLE_ICON
                     || isIconStylePreferred(resolvedTheme)) {
-            return true;
+            return false;
         }
 
         // Choose the default behavior when neither the ActivityRecord nor the activity theme have
         // specified a splash screen style.
 
         if (mLaunchSourceType == LAUNCH_SOURCE_TYPE_HOME || launchedFromUid == Process.SHELL_UID) {
-            return true;
-        } else if (mLaunchSourceType == LAUNCH_SOURCE_TYPE_SYSTEMUI) {
             return false;
+        } else if (mLaunchSourceType == LAUNCH_SOURCE_TYPE_SYSTEMUI) {
+            return true;
         } else {
-            // Need to check sourceRecord in case this activity is launched from a service or a
-            // trampoline activity.
+            // Need to check sourceRecord in case this activity is launched from a service.
             if (sourceRecord == null) {
                 sourceRecord = searchCandidateLaunchingActivity();
             }
 
             if (sourceRecord != null) {
-                return sourceRecord.mAllowIconSplashScreen;
+                return sourceRecord.mSplashScreenStyleSolidColor;
             }
 
             // Use an icon if the activity was launched from System for the first start.
-            // Otherwise, can't use an icon splash screen.
-            return mLaunchSourceType == LAUNCH_SOURCE_TYPE_SYSTEM && startActivity;
+            // Otherwise, must use solid color splash screen.
+            return mLaunchSourceType != LAUNCH_SOURCE_TYPE_SYSTEM || !startActivity;
         }
     }
 
@@ -7443,7 +7430,7 @@
         final int resolvedTheme = evaluateStartingWindowTheme(prev, packageName, theme,
                 splashScreenTheme);
 
-        mAllowIconSplashScreen = canUseIconSplashScreen(sourceRecord, startActivity,
+        mSplashScreenStyleSolidColor = shouldUseSolidColorSplashScreen(sourceRecord, startActivity,
                 startOptions, resolvedTheme);
 
         final boolean activityCreated =
@@ -7455,7 +7442,7 @@
 
         final boolean scheduled = addStartingWindow(packageName, resolvedTheme,
                 prev, newTask || newSingleActivity, taskSwitch, processRunning,
-                allowTaskSnapshot(), activityCreated, mAllowIconSplashScreen, allDrawn);
+                allowTaskSnapshot(), activityCreated, mSplashScreenStyleSolidColor, allDrawn);
         if (DEBUG_STARTING_WINDOW_VERBOSE && scheduled) {
             Slog.d(TAG, "Scheduled starting window for " + this);
         }
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 184de58..442269a 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -64,6 +64,7 @@
 import android.os.Environment;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.text.TextUtils;
@@ -506,6 +507,16 @@
 
         Slog.i(TAG, "Loading recents for user " + userId + " into memory.");
         List<Task> tasks = mTaskPersister.restoreTasksForUserLocked(userId, preaddedTasks);
+
+        // Tasks are ordered from most recent to least recent. Update the last active time to be
+        // in sync with task recency when device reboots, so the most recent task has the
+        // highest last active time
+        long currentElapsedTime = SystemClock.elapsedRealtime();
+        for (int i = 0; i < tasks.size(); i++) {
+            Task task = tasks.get(i);
+            task.lastActiveTime = currentElapsedTime - i;
+        }
+
         mTasks.addAll(tasks);
         cleanupLocked(userId);
         mUsersWithRecentsLoaded.put(userId, true);
diff --git a/services/core/java/com/android/server/wm/StartingSurfaceController.java b/services/core/java/com/android/server/wm/StartingSurfaceController.java
index a0517be..a55c232 100644
--- a/services/core/java/com/android/server/wm/StartingSurfaceController.java
+++ b/services/core/java/com/android/server/wm/StartingSurfaceController.java
@@ -19,12 +19,12 @@
 import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_CREATED;
 import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_DRAWN;
 import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_HANDLE_SOLID_COLOR_SCREEN;
-import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_ICON;
 import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT;
 import static android.window.StartingWindowInfo.TYPE_PARAMETER_LEGACY_SPLASH_SCREEN;
 import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK;
 import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING;
 import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_USE_SOLID_COLOR_SPLASH_SCREEN;
 
 import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_TYPE_SNAPSHOT;
 import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_TYPE_SPLASH_SCREEN;
@@ -102,7 +102,7 @@
 
     static int makeStartingWindowTypeParameter(boolean newTask, boolean taskSwitch,
             boolean processRunning, boolean allowTaskSnapshot, boolean activityCreated,
-            boolean allowIcon, boolean useLegacy, boolean activityDrawn, int startingWindowType,
+            boolean isSolidColor, boolean useLegacy, boolean activityDrawn, int startingWindowType,
             String packageName, int userId) {
         int parameter = 0;
         if (newTask) {
@@ -120,8 +120,8 @@
         if (activityCreated || startingWindowType == STARTING_WINDOW_TYPE_SNAPSHOT) {
             parameter |= TYPE_PARAMETER_ACTIVITY_CREATED;
         }
-        if (allowIcon) {
-            parameter |= TYPE_PARAMETER_ALLOW_ICON;
+        if (isSolidColor) {
+            parameter |= TYPE_PARAMETER_USE_SOLID_COLOR_SPLASH_SCREEN;
         }
         if (useLegacy) {
             parameter |= TYPE_PARAMETER_LEGACY_SPLASH_SCREEN;
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 5d95bc7..50bc825 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -255,6 +255,11 @@
     boolean mClearedForReorderActivityToFront;
 
     /**
+     * Whether the TaskFragment surface is managed by a system {@link TaskFragmentOrganizer}.
+     */
+    boolean mIsSurfaceManagedBySystemOrganizer = false;
+
+    /**
      * When we are in the process of pausing an activity, before starting the
      * next one, this variable holds the activity that is currently being paused.
      *
@@ -449,13 +454,21 @@
 
     void setTaskFragmentOrganizer(@NonNull TaskFragmentOrganizerToken organizer, int uid,
             @NonNull String processName) {
+        setTaskFragmentOrganizer(organizer, uid, processName,
+                false /* isSurfaceManagedBySystemOrganizer */);
+    }
+
+    void setTaskFragmentOrganizer(@NonNull TaskFragmentOrganizerToken organizer, int uid,
+            @NonNull String processName, boolean isSurfaceManagedBySystemOrganizer) {
         mTaskFragmentOrganizer = ITaskFragmentOrganizer.Stub.asInterface(organizer.asBinder());
         mTaskFragmentOrganizerUid = uid;
         mTaskFragmentOrganizerProcessName = processName;
+        mIsSurfaceManagedBySystemOrganizer = isSurfaceManagedBySystemOrganizer;
     }
 
     void onTaskFragmentOrganizerRemoved() {
         mTaskFragmentOrganizer = null;
+        mIsSurfaceManagedBySystemOrganizer = false;
     }
 
     /** Whether this TaskFragment is organized by the given {@code organizer}. */
@@ -2396,6 +2409,9 @@
         if (mDelayOrganizedTaskFragmentSurfaceUpdate || mTaskFragmentOrganizer == null) {
             return;
         }
+        if (mIsSurfaceManagedBySystemOrganizer) {
+            return;
+        }
         if (mTransitionController.isShellTransitionsEnabled()
                 && !mTransitionController.isCollecting(this)) {
             // TaskFragmentOrganizer doesn't have access to the surface for security reasons, so
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index ea722b6..04164c2 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -26,6 +26,7 @@
 import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_VANISHED;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
+import static com.android.server.wm.ActivityTaskManagerService.enforceTaskPermission;
 import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED;
 import static com.android.server.wm.WindowOrganizerController.configurationsAreEqualForOrganizer;
 
@@ -50,12 +51,15 @@
 import android.window.ITaskFragmentOrganizerController;
 import android.window.TaskFragmentInfo;
 import android.window.TaskFragmentOperation;
+import android.window.TaskFragmentOrganizerToken;
 import android.window.TaskFragmentParentInfo;
 import android.window.TaskFragmentTransaction;
 import android.window.WindowContainerTransaction;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.ProtoLogGroup;
 import com.android.internal.protolog.common.ProtoLog;
+import com.android.window.flags.Flags;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -133,6 +137,13 @@
                 new WeakHashMap<>();
 
         /**
+         * Whether this {@link android.window.TaskFragmentOrganizer} is a system organizer. If true,
+         * the {@link android.view.SurfaceControl} of the {@link TaskFragment} is provided to the
+         * client in the {@link TYPE_TASK_FRAGMENT_APPEARED} event.
+         */
+        private final boolean mIsSystemOrganizer;
+
+        /**
          * {@link RemoteAnimationDefinition} for embedded activities transition animation that is
          * organized by this organizer.
          */
@@ -147,10 +158,12 @@
          */
         private final ArrayMap<IBinder, Integer> mDeferredTransitions = new ArrayMap<>();
 
-        TaskFragmentOrganizerState(ITaskFragmentOrganizer organizer, int pid, int uid) {
+        TaskFragmentOrganizerState(@NonNull ITaskFragmentOrganizer organizer, int pid, int uid,
+                boolean isSystemOrganizer) {
             mOrganizer = organizer;
             mOrganizerPid = pid;
             mOrganizerUid = uid;
+            mIsSystemOrganizer = isSystemOrganizer;
             try {
                 mOrganizer.asBinder().linkToDeath(this, 0 /*flags*/);
             } catch (RemoteException e) {
@@ -235,11 +248,15 @@
             tf.mTaskFragmentAppearedSent = true;
             mLastSentTaskFragmentInfos.put(tf, info);
             mTaskFragmentTaskIds.put(tf, taskId);
-            return new TaskFragmentTransaction.Change(
+            final TaskFragmentTransaction.Change change = new TaskFragmentTransaction.Change(
                     TYPE_TASK_FRAGMENT_APPEARED)
                     .setTaskFragmentToken(tf.getFragmentToken())
                     .setTaskFragmentInfo(info)
                     .setTaskId(taskId);
+            if (mIsSystemOrganizer) {
+                change.setTaskFragmentSurfaceControl(tf.getSurfaceControl());
+            }
+            return change;
         }
 
         @NonNull
@@ -435,8 +452,25 @@
                 : null;
     }
 
+    @VisibleForTesting
+    void registerOrganizer(@NonNull ITaskFragmentOrganizer organizer) {
+        registerOrganizerInternal(organizer, false /* isSystemOrganizer */);
+    }
+
     @Override
-    public void registerOrganizer(@NonNull ITaskFragmentOrganizer organizer) {
+    public void registerOrganizer(
+            @NonNull ITaskFragmentOrganizer organizer, boolean isSystemOrganizer) {
+        registerOrganizerInternal(
+                organizer,
+                Flags.taskFragmentSystemOrganizerFlag() && isSystemOrganizer);
+    }
+
+    @VisibleForTesting
+    void registerOrganizerInternal(
+            @NonNull ITaskFragmentOrganizer organizer, boolean isSystemOrganizer) {
+        if (isSystemOrganizer) {
+            enforceTaskPermission("registerSystemOrganizer()");
+        }
         final int pid = Binder.getCallingPid();
         final int uid = Binder.getCallingUid();
         synchronized (mGlobalLock) {
@@ -448,7 +482,7 @@
                         "Replacing existing organizer currently unsupported");
             }
             mTaskFragmentOrganizerState.put(organizer.asBinder(),
-                    new TaskFragmentOrganizerState(organizer, pid, uid));
+                    new TaskFragmentOrganizerState(organizer, pid, uid, isSystemOrganizer));
             mPendingTaskFragmentEvents.put(organizer.asBinder(), new ArrayList<>());
         }
     }
@@ -711,6 +745,12 @@
         }
     }
 
+    boolean isSystemOrganizer(@NonNull TaskFragmentOrganizerToken token) {
+        final TaskFragmentOrganizerState state =
+                mTaskFragmentOrganizerState.get(token.asBinder());
+        return state != null && state.mIsSystemOrganizer;
+    }
+
     @Nullable
     private PendingTaskFragmentEvent getLastPendingParentInfoChangedEvent(
             @NonNull ITaskFragmentOrganizer organizer, @NonNull Task task) {
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 6d7e297..376cad7 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -99,6 +99,7 @@
 import android.window.TaskFragmentAnimationParams;
 import android.window.TaskFragmentCreationParams;
 import android.window.TaskFragmentOperation;
+import android.window.TaskFragmentOrganizerToken;
 import android.window.WindowContainerToken;
 import android.window.WindowContainerTransaction;
 
@@ -1993,8 +1994,10 @@
                 creationParams.getFragmentToken(), true /* createdByOrganizer */);
         // Set task fragment organizer immediately, since it might have to be notified about further
         // actions.
-        taskFragment.setTaskFragmentOrganizer(creationParams.getOrganizer(),
-                ownerActivity.getUid(), ownerActivity.info.processName);
+        TaskFragmentOrganizerToken organizerToken = creationParams.getOrganizer();
+        taskFragment.setTaskFragmentOrganizer(organizerToken,
+                ownerActivity.getUid(), ownerActivity.info.processName,
+                mTaskFragmentOrganizerController.isSystemOrganizer(organizerToken));
         final int position;
         if (creationParams.getPairedPrimaryFragmentToken() != null) {
             // When there is a paired primary TaskFragment, we want to place the new TaskFragment
diff --git a/services/net/OWNERS b/services/net/OWNERS
index 62c5737..c24680e9 100644
--- a/services/net/OWNERS
+++ b/services/net/OWNERS
@@ -1,2 +1,2 @@
 set noparent
-file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking
+file:platform/packages/modules/Connectivity:main:/OWNERS_core_networking
diff --git a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionResetTest.kt b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionResetTest.kt
index 823ce45..0547719 100644
--- a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionResetTest.kt
+++ b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionResetTest.kt
@@ -112,4 +112,4 @@
         @JvmStatic
         fun data(): Array<Action> = Action.values()
     }
-}
\ No newline at end of file
+}
diff --git a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionStatesTest.kt b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionStatesTest.kt
index f085bd7..c44b2c5 100644
--- a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionStatesTest.kt
+++ b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionStatesTest.kt
@@ -43,8 +43,7 @@
     @Parameterized.Parameter(0) lateinit var action: Action
 
     @Before
-    override fun setUp() {
-        super.setUp()
+    fun setUp() {
         if (action == Action.ON_USER_ADDED) {
             createUserState(USER_ID_NEW)
         }
@@ -881,4 +880,4 @@
         @JvmStatic
         fun data(): Array<Action> = Action.values()
     }
-}
\ No newline at end of file
+}
diff --git a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyTest.kt b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyTest.kt
new file mode 100644
index 0000000..e4e3368
--- /dev/null
+++ b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyTest.kt
@@ -0,0 +1,430 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.permission.test
+
+import android.content.pm.PermissionGroupInfo
+import android.content.pm.PermissionInfo
+import com.android.server.permission.access.GetStateScope
+import com.android.server.permission.access.immutable.* // ktlint-disable no-wildcard-imports
+import com.android.server.permission.access.permission.AppIdPermissionPolicy
+import com.android.server.permission.access.permission.Permission
+import com.android.server.permission.access.permission.PermissionFlags
+import com.android.server.testutils.mock
+import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.Test
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+
+class AppIdPermissionPolicyTest : BaseAppIdPermissionPolicyTest() {
+    @Test
+    fun testOnAppIdRemoved_appIdIsRemoved_permissionFlagsCleared() {
+        val parsedPermission = mockParsedPermission(PERMISSION_NAME_0, PACKAGE_NAME_0)
+        val permissionOwnerPackageState = mockPackageState(
+            APP_ID_0,
+            mockAndroidPackage(PACKAGE_NAME_0, permissions = listOf(parsedPermission))
+        )
+        val requestingPackageState = mockPackageState(
+            APP_ID_1,
+            mockAndroidPackage(PACKAGE_NAME_1, requestedPermissions = setOf(PERMISSION_NAME_0))
+        )
+        addPackageState(permissionOwnerPackageState)
+        addPackageState(requestingPackageState)
+        addPermission(parsedPermission)
+        setPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0, PermissionFlags.INSTALL_GRANTED)
+
+        mutateState {
+            with(appIdPermissionPolicy) {
+                onAppIdRemoved(APP_ID_1)
+            }
+        }
+
+        val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
+        val expectedNewFlags = 0
+        assertWithMessage(
+            "After onAppIdRemoved() is called for appId $APP_ID_1 that requests a permission" +
+                " owns by appId $APP_ID_0 with existing permission flags. The actual permission" +
+                " flags $actualFlags should be null"
+        )
+            .that(actualFlags)
+            .isEqualTo(expectedNewFlags)
+    }
+
+    @Test
+    fun testOnStorageVolumeMounted_nonSystemAppAfterNonSystemUpdate_remainsRevoked() {
+        val permissionOwnerPackageState = mockPackageState(APP_ID_0, mockSimpleAndroidPackage())
+        val installedPackageState = mockPackageState(
+            APP_ID_1,
+            mockAndroidPackage(PACKAGE_NAME_1, requestedPermissions = setOf(PERMISSION_NAME_0))
+        )
+        addPackageState(permissionOwnerPackageState)
+        addPackageState(installedPackageState)
+        addPermission(defaultPermission)
+        val oldFlags = PermissionFlags.INSTALL_REVOKED
+        setPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0, oldFlags)
+
+        mutateState {
+            with(appIdPermissionPolicy) {
+                onStorageVolumeMounted(null, listOf(installedPackageState.packageName), false)
+            }
+        }
+
+        val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
+        val expectedNewFlags = oldFlags
+        assertWithMessage(
+            "After onStorageVolumeMounted() is called for a non-system app that requests a normal" +
+                " permission with existing INSTALL_REVOKED flag after a non-system-update" +
+                " (such as an OTA update), the actual permission flags should remain revoked." +
+                " The actual permission flags $actualFlags should match the expected flags" +
+                " $expectedNewFlags"
+        )
+            .that(actualFlags)
+            .isEqualTo(expectedNewFlags)
+    }
+
+    @Test
+    fun testOnPackageRemoved_packageIsRemoved_permissionDefinitionsAndStatesAreUpdated() {
+        val permissionOwnerPackageState = mockPackageState(
+            APP_ID_0,
+            mockAndroidPackage(
+                PACKAGE_NAME_0,
+                requestedPermissions = setOf(PERMISSION_NAME_0),
+                permissions = listOf(defaultPermission)
+            )
+        )
+        val requestingPackageState = mockPackageState(
+            APP_ID_1,
+            mockAndroidPackage(PACKAGE_NAME_1, requestedPermissions = setOf(PERMISSION_NAME_0))
+        )
+        addPackageState(permissionOwnerPackageState)
+        addPackageState(requestingPackageState)
+        addPermission(defaultPermission)
+        val oldFlags = PermissionFlags.INSTALL_GRANTED
+        setPermissionFlags(APP_ID_0, USER_ID_0, PERMISSION_NAME_0, oldFlags)
+        setPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0, oldFlags)
+
+        mutateState {
+            removePackageState(permissionOwnerPackageState)
+            with(appIdPermissionPolicy) {
+                onPackageRemoved(PACKAGE_NAME_0, APP_ID_0)
+            }
+        }
+
+        assertWithMessage(
+            "After onPackageRemoved() is called for a permission owner, the permission" +
+                " definitions owned by this package should be removed"
+        )
+            .that(getPermission(PERMISSION_NAME_0))
+            .isNull()
+
+        val app0ActualFlags = getPermissionFlags(APP_ID_0, USER_ID_0, PERMISSION_NAME_0)
+        val app0ExpectedNewFlags = 0
+        assertWithMessage(
+            "After onPackageRemoved() is called for a permission owner, the permission states of" +
+                " this app should be trimmed. The actual permission flags $app0ActualFlags should" +
+                " match the expected flags $app0ExpectedNewFlags"
+        )
+            .that(app0ActualFlags)
+            .isEqualTo(app0ExpectedNewFlags)
+
+        val app1ActualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
+        val app1ExpectedNewFlags = PermissionFlags.INSTALL_REVOKED
+        assertWithMessage(
+            "After onPackageRemoved() is called for a permission owner, the permission states of" +
+                " the permission requester should remain unchanged. The actual permission flags" +
+                " $app1ActualFlags should match the expected flags $app1ExpectedNewFlags"
+        )
+            .that(app1ActualFlags)
+            .isEqualTo(app1ExpectedNewFlags)
+    }
+
+    @Test
+    fun testOnPackageInstalled_nonSystemAppIsInstalled_upgradeExemptFlagIsCleared() {
+        val oldFlags = PermissionFlags.SOFT_RESTRICTED or PermissionFlags.UPGRADE_EXEMPT
+        testOnPackageInstalled(
+            oldFlags,
+            permissionInfoFlags = PermissionInfo.FLAG_SOFT_RESTRICTED
+        ) {}
+        val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
+        val expectedNewFlags = PermissionFlags.SOFT_RESTRICTED
+        assertWithMessage(
+            "After onPackageInstalled() is called for a non-system app that requests a runtime" +
+                " soft restricted permission, UPGRADE_EXEMPT flag should be removed. The actual" +
+                " permission flags $actualFlags should match the expected flags $expectedNewFlags"
+        )
+            .that(actualFlags)
+            .isEqualTo(expectedNewFlags)
+    }
+
+    @Test
+    fun testOnPackageInstalled_systemAppIsInstalled_upgradeExemptFlagIsRetained() {
+        val oldFlags = PermissionFlags.SOFT_RESTRICTED or PermissionFlags.UPGRADE_EXEMPT
+        testOnPackageInstalled(
+            oldFlags,
+            permissionInfoFlags = PermissionInfo.FLAG_SOFT_RESTRICTED,
+            isInstalledPackageSystem = true
+        ) {}
+        val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
+        val expectedNewFlags = oldFlags
+        assertWithMessage(
+            "After onPackageInstalled() is called for a system app that requests a runtime" +
+                " soft restricted permission, UPGRADE_EXEMPT flag should be retained. The actual" +
+                " permission flags $actualFlags should match the expected flags $expectedNewFlags"
+        )
+            .that(actualFlags)
+            .isEqualTo(expectedNewFlags)
+    }
+
+    @Test
+    fun testOnPackageInstalled_requestedPermissionAlsoRequestedBySystemApp_exemptFlagIsRetained() {
+        val oldFlags = PermissionFlags.SOFT_RESTRICTED or PermissionFlags.UPGRADE_EXEMPT
+        testOnPackageInstalled(
+            oldFlags,
+            permissionInfoFlags = PermissionInfo.FLAG_SOFT_RESTRICTED
+        ) {
+            val systemAppPackageState = mockPackageState(
+                APP_ID_1,
+                mockAndroidPackage(PACKAGE_NAME_2, requestedPermissions = setOf(PERMISSION_NAME_0)),
+                isSystem = true
+            )
+            addPackageState(systemAppPackageState)
+        }
+        val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
+        val expectedNewFlags = oldFlags
+        assertWithMessage(
+            "After onPackageInstalled() is called for a non-system app that requests a runtime" +
+                " soft restricted permission, and that permission is also requested by a system" +
+                " app in the same appId, UPGRADE_EXEMPT flag should be retained. The actual" +
+                " permission flags $actualFlags should match the expected flags $expectedNewFlags"
+        )
+            .that(actualFlags)
+            .isEqualTo(expectedNewFlags)
+    }
+
+    @Test
+    fun testOnPackageInstalled_restrictedPermissionsNotExempt_getsRestrictionFlags() {
+        val oldFlags = PermissionFlags.RESTRICTION_REVOKED
+        testOnPackageInstalled(
+            oldFlags,
+            permissionInfoFlags = PermissionInfo.FLAG_HARD_RESTRICTED
+        ) {}
+        val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
+        val expectedNewFlags = oldFlags
+        assertWithMessage(
+            "After onPackageInstalled() is called for a non-system app that requests a runtime" +
+                " hard restricted permission that is not exempted. The actual permission flags" +
+                " $actualFlags should match the expected flags $expectedNewFlags"
+        )
+            .that(actualFlags)
+            .isEqualTo(expectedNewFlags)
+    }
+
+    @Test
+    fun testOnPackageInstalled_restrictedPermissionsIsExempted_clearsRestrictionFlags() {
+        val oldFlags = PermissionFlags.SOFT_RESTRICTED or PermissionFlags.INSTALLER_EXEMPT
+        testOnPackageInstalled(
+            oldFlags,
+            permissionInfoFlags = PermissionInfo.FLAG_SOFT_RESTRICTED
+        ) {}
+        val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
+        val expectedNewFlags = PermissionFlags.INSTALLER_EXEMPT
+        assertWithMessage(
+            "After onPackageInstalled() is called for a non-system app that requests a runtime" +
+                " soft restricted permission that is exempted. The actual permission flags" +
+                " $actualFlags should match the expected flags $expectedNewFlags"
+        )
+            .that(actualFlags)
+            .isEqualTo(expectedNewFlags)
+    }
+
+    private fun testOnPackageInstalled(
+        oldFlags: Int,
+        permissionInfoFlags: Int = 0,
+        isInstalledPackageSystem: Boolean = false,
+        additionalSetup: () -> Unit
+    ) {
+        val parsedPermission = mockParsedPermission(
+            PERMISSION_NAME_0,
+            PACKAGE_NAME_0,
+            protectionLevel = PermissionInfo.PROTECTION_DANGEROUS,
+            flags = permissionInfoFlags
+        )
+        val permissionOwnerPackageState = mockPackageState(
+            APP_ID_0,
+            mockAndroidPackage(PACKAGE_NAME_0, permissions = listOf(parsedPermission))
+        )
+        addPackageState(permissionOwnerPackageState)
+        addPermission(parsedPermission)
+
+        additionalSetup()
+
+        mutateState {
+            val installedPackageState = mockPackageState(
+                APP_ID_1,
+                mockAndroidPackage(
+                    PACKAGE_NAME_1,
+                    requestedPermissions = setOf(PERMISSION_NAME_0),
+                ),
+                isSystem = isInstalledPackageSystem,
+            )
+            addPackageState(installedPackageState, newState)
+            setPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0, oldFlags, newState)
+            with(appIdPermissionPolicy) {
+                onPackageInstalled(installedPackageState, USER_ID_0)
+            }
+        }
+    }
+
+    @Test
+    fun testOnStateMutated_notEmpty_isCalledForEachListener() {
+        val mockListener = mock<AppIdPermissionPolicy.OnPermissionFlagsChangedListener> {}
+        appIdPermissionPolicy.addOnPermissionFlagsChangedListener(mockListener)
+
+        GetStateScope(oldState).apply {
+            with(appIdPermissionPolicy) {
+                onStateMutated()
+            }
+        }
+
+        verify(mockListener, times(1)).onStateMutated()
+    }
+
+    @Test
+    fun testGetPermissionTrees() {
+        val permissionTrees: IndexedMap<String, Permission>
+        GetStateScope(oldState).apply {
+            with(appIdPermissionPolicy) {
+                permissionTrees = getPermissionTrees()
+            }
+        }
+
+        assertThat(oldState.systemState.permissionTrees).isEqualTo(permissionTrees)
+    }
+
+    @Test
+    fun testFindPermissionTree() {
+        val permissionTree = createSimplePermission(isTree = true)
+        val actualPermissionTree: Permission?
+        oldState.mutateSystemState().mutatePermissionTrees()[PERMISSION_TREE_NAME] = permissionTree
+
+        GetStateScope(oldState).apply {
+            with(appIdPermissionPolicy) {
+                actualPermissionTree = findPermissionTree(PERMISSION_BELONGS_TO_A_TREE)
+            }
+        }
+
+        assertThat(actualPermissionTree).isEqualTo(permissionTree)
+    }
+
+    @Test
+    fun testAddPermissionTree() {
+        val permissionTree = createSimplePermission(isTree = true)
+
+        mutateState {
+            with(appIdPermissionPolicy) {
+                addPermissionTree(permissionTree)
+            }
+        }
+
+        assertThat(newState.systemState.permissionTrees[PERMISSION_TREE_NAME])
+            .isEqualTo(permissionTree)
+    }
+
+    @Test
+    fun testGetPermissionGroups() {
+        val permissionGroups: IndexedMap<String, PermissionGroupInfo>
+        GetStateScope(oldState).apply {
+            with(appIdPermissionPolicy) {
+                permissionGroups = getPermissionGroups()
+            }
+        }
+
+        assertThat(oldState.systemState.permissionGroups).isEqualTo(permissionGroups)
+    }
+
+    @Test
+    fun testGetPermissions() {
+        val permissions: IndexedMap<String, Permission>
+        GetStateScope(oldState).apply {
+            with(appIdPermissionPolicy) {
+                permissions = getPermissions()
+            }
+        }
+
+        assertThat(oldState.systemState.permissions).isEqualTo(permissions)
+    }
+
+    @Test
+    fun testAddPermission() {
+        val permission = createSimplePermission()
+
+        mutateState {
+            with(appIdPermissionPolicy) {
+                addPermission(permission)
+            }
+        }
+
+        assertThat(newState.systemState.permissions[PERMISSION_NAME_0]).isEqualTo(permission)
+    }
+
+    @Test
+    fun testRemovePermission() {
+        val permission = createSimplePermission()
+
+        mutateState {
+            with(appIdPermissionPolicy) {
+                addPermission(permission)
+                removePermission(permission)
+            }
+        }
+
+        assertThat(newState.systemState.permissions[PERMISSION_NAME_0]).isNull()
+    }
+
+    @Test
+    fun testGetUidPermissionFlags() {
+        val uidPermissionFlags: IndexedMap<String, Int>?
+        GetStateScope(oldState).apply {
+            with(appIdPermissionPolicy) {
+                uidPermissionFlags = getUidPermissionFlags(APP_ID_0, USER_ID_0)
+            }
+        }
+
+        assertThat(oldState.userStates[USER_ID_0]!!.appIdPermissionFlags[APP_ID_0])
+            .isEqualTo(uidPermissionFlags)
+    }
+
+    @Test
+    fun testUpdateAndGetPermissionFlags() {
+        val flags = PermissionFlags.INSTALL_GRANTED
+        var actualFlags = 0
+        mutateState {
+            with(appIdPermissionPolicy) {
+                updatePermissionFlags(
+                    APP_ID_0,
+                    USER_ID_0,
+                    PERMISSION_NAME_0,
+                    PermissionFlags.MASK_ALL,
+                    flags
+                )
+                actualFlags = getPermissionFlags(APP_ID_0, USER_ID_0, PERMISSION_NAME_0)
+            }
+        }
+
+        assertThat(actualFlags).isEqualTo(flags)
+    }
+}
diff --git a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/BaseAppIdPermissionPolicyTest.kt b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/BaseAppIdPermissionPolicyTest.kt
index 7966c5c..ec84bc3 100644
--- a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/BaseAppIdPermissionPolicyTest.kt
+++ b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/BaseAppIdPermissionPolicyTest.kt
@@ -34,7 +34,6 @@
 import com.android.server.permission.access.immutable.* // ktlint-disable no-wildcard-imports
 import com.android.server.permission.access.permission.AppIdPermissionPolicy
 import com.android.server.permission.access.permission.Permission
-import com.android.server.permission.access.permission.PermissionFlags
 import com.android.server.permission.access.util.hasBits
 import com.android.server.pm.parsing.PackageInfoUtils
 import com.android.server.pm.pkg.AndroidPackage
@@ -45,10 +44,8 @@
 import com.android.server.testutils.any
 import com.android.server.testutils.mock
 import com.android.server.testutils.whenever
-import com.google.common.truth.Truth.assertWithMessage
 import org.junit.Before
 import org.junit.Rule
-import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentMatchers.anyLong
 
@@ -56,7 +53,7 @@
  * Mocking unit test for AppIdPermissionPolicy.
  */
 @RunWith(AndroidJUnit4::class)
-open class BaseAppIdPermissionPolicyTest {
+abstract class BaseAppIdPermissionPolicyTest {
     protected lateinit var oldState: MutableAccessState
     protected lateinit var newState: MutableAccessState
 
@@ -80,7 +77,7 @@
         .build()
 
     @Before
-    open fun setUp() {
+    fun baseSetUp() {
         oldState = MutableAccessState()
         createUserState(USER_ID_0)
         oldState.mutateExternalState().setPackageStates(ArrayMap())
@@ -139,78 +136,6 @@
         }
     }
 
-    @Test
-    fun testOnAppIdRemoved_appIdIsRemoved_permissionFlagsCleared() {
-        val parsedPermission = mockParsedPermission(PERMISSION_NAME_0, PACKAGE_NAME_0)
-        val permissionOwnerPackageState = mockPackageState(
-            APP_ID_0,
-            mockAndroidPackage(PACKAGE_NAME_0, permissions = listOf(parsedPermission))
-        )
-        val requestingPackageState = mockPackageState(
-            APP_ID_1,
-            mockAndroidPackage(PACKAGE_NAME_1, requestedPermissions = setOf(PERMISSION_NAME_0))
-        )
-        addPackageState(permissionOwnerPackageState)
-        addPackageState(requestingPackageState)
-        addPermission(parsedPermission)
-        setPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0, PermissionFlags.INSTALL_GRANTED)
-
-        mutateState {
-            with(appIdPermissionPolicy) {
-                onAppIdRemoved(APP_ID_1)
-            }
-        }
-
-        val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
-        val expectedNewFlags = 0
-        assertWithMessage(
-            "After onAppIdRemoved() is called for appId $APP_ID_1 that requests a permission" +
-                " owns by appId $APP_ID_0 with existing permission flags. The actual permission" +
-                " flags $actualFlags should be null"
-        )
-            .that(actualFlags)
-            .isEqualTo(expectedNewFlags)
-    }
-
-    @Test
-    fun testOnPackageRemoved_packageIsRemoved_permissionsAreTrimmedAndStatesAreEvaluated() {
-        // TODO
-        // shouldn't reuse test cases because it's really different despite it's also for
-        // trim permission states. It's different because it's package removal
-    }
-
-    @Test
-    fun testOnPackageInstalled_nonSystemAppIsInstalled_upgradeExemptFlagIsCleared() {
-        // TODO
-        // should be fine for it to be its own test cases and not to re-use
-        // clearRestrictedPermissionImplicitExemption
-    }
-
-    @Test
-    fun testOnPackageInstalled_systemAppIsInstalled_upgradeExemptFlagIsRetained() {
-        // TODO
-    }
-
-    @Test
-    fun testOnPackageInstalled_requestedPermissionAlsoRequestedBySystemApp_exemptFlagIsRetained() {
-        // TODO
-    }
-
-    @Test
-    fun testOnPackageInstalled_restrictedPermissionsNotExempt_getsRestrictionFlags() {
-        // TODO
-    }
-
-    @Test
-    fun testOnPackageInstalled_restrictedPermissionsIsExempted_clearsRestrictionFlags() {
-        // TODO
-    }
-
-    @Test
-    fun testOnStateMutated_notEmpty_isCalledForEachListener() {
-        // TODO
-    }
-
     /**
      * Mock an AndroidPackage with PACKAGE_NAME_0, PERMISSION_NAME_0 and PERMISSION_GROUP_NAME_0
      */
@@ -221,6 +146,15 @@
             permissions = listOf(defaultPermissionTree, defaultPermission)
         )
 
+    protected fun createSimplePermission(isTree: Boolean = false): Permission {
+        val parsedPermission = if (isTree) { defaultPermissionTree } else { defaultPermission }
+        val permissionInfo = PackageInfoUtils.generatePermissionInfo(
+            parsedPermission,
+            PackageManager.GET_META_DATA.toLong()
+        )!!
+        return Permission(permissionInfo, true, Permission.TYPE_MANIFEST, APP_ID_0)
+    }
+
     protected inline fun mutateState(action: MutateStateScope.() -> Unit) {
         newState = oldState.toMutable()
         MutateStateScope(oldState, newState).action()
@@ -330,15 +264,26 @@
     ) {
         state.mutateExternalState().apply {
             setPackageStates(
-                packageStates.toMutableMap().apply {
-                    put(packageState.packageName, packageState)
-                }
+                packageStates.toMutableMap().apply { put(packageState.packageName, packageState) }
             )
             mutateAppIdPackageNames().mutateOrPut(packageState.appId) { MutableIndexedListSet() }
                 .add(packageState.packageName)
         }
     }
 
+    protected fun removePackageState(
+        packageState: PackageState,
+        state: MutableAccessState = oldState
+    ) {
+        state.mutateExternalState().apply {
+            setPackageStates(
+                packageStates.toMutableMap().apply { remove(packageState.packageName) }
+            )
+            mutateAppIdPackageNames().mutateOrPut(packageState.appId) { MutableIndexedListSet() }
+                .remove(packageState.packageName)
+        }
+    }
+
     protected fun addDisabledSystemPackageState(
         packageState: PackageState,
         state: MutableAccessState = oldState
@@ -429,6 +374,7 @@
         @JvmStatic protected val PERMISSION_NAME_0 = "permissionName0"
         @JvmStatic protected val PERMISSION_NAME_1 = "permissionName1"
         @JvmStatic protected val PERMISSION_NAME_2 = "permissionName2"
+        @JvmStatic protected val PERMISSION_BELONGS_TO_A_TREE = "permissionTree.permission"
         @JvmStatic protected val PERMISSION_READ_EXTERNAL_STORAGE =
             Manifest.permission.READ_EXTERNAL_STORAGE
         @JvmStatic protected val PERMISSION_POST_NOTIFICATIONS =
diff --git a/services/tests/RemoteProvisioningServiceTests/OWNERS b/services/tests/RemoteProvisioningServiceTests/OWNERS
index 348f940..ea6dc72 100644
--- a/services/tests/RemoteProvisioningServiceTests/OWNERS
+++ b/services/tests/RemoteProvisioningServiceTests/OWNERS
@@ -1 +1 @@
-file:platform/frameworks/base:master:/core/java/android/security/rkp/OWNERS
+file:platform/frameworks/base:main:/core/java/android/security/rkp/OWNERS
diff --git a/services/tests/displayservicetests/src/com/android/server/display/BrightnessSynchronizerTest.java b/services/tests/displayservicetests/src/com/android/server/display/BrightnessSynchronizerTest.java
index 7a4327c..2fd6e5f 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/BrightnessSynchronizerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/BrightnessSynchronizerTest.java
@@ -19,7 +19,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.isA;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -28,18 +27,15 @@
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.database.ContentObserver;
-import android.hardware.display.BrightnessInfo;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManager.DisplayListener;
 import android.net.Uri;
 import android.os.Handler;
-import android.os.PowerManager;
 import android.os.UserHandle;
 import android.os.test.TestLooper;
 import android.provider.Settings;
 import android.test.mock.MockContentResolver;
 import android.view.Display;
-import android.view.DisplayAdjustments;
 
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.filters.SmallTest;
@@ -63,7 +59,6 @@
     private static final float EPSILON = 0.00001f;
     private static final Uri BRIGHTNESS_URI =
             Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS);
-    private static final float BRIGHTNESS_MAX = 0.6f;
 
     private Context mContext;
     private MockContentResolver mContentResolverSpy;
@@ -71,7 +66,6 @@
     private DisplayListener mDisplayListener;
     private ContentObserver mContentObserver;
     private TestLooper mTestLooper;
-    private BrightnessSynchronizer mSynchronizer;
 
     @Mock private DisplayManager mDisplayManagerMock;
     @Captor private ArgumentCaptor<DisplayListener> mDisplayListenerCaptor;
@@ -80,17 +74,7 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-
-        Display display = mock(Display.class);
-        when(display.getDisplayAdjustments()).thenReturn(new DisplayAdjustments());
-        BrightnessInfo info = new BrightnessInfo(PowerManager.BRIGHTNESS_INVALID_FLOAT,
-                PowerManager.BRIGHTNESS_MIN, BRIGHTNESS_MAX,
-                BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF, BRIGHTNESS_MAX,
-                BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE);
-        when(display.getBrightnessInfo()).thenReturn(info);
-
-        mContext = spy(new ContextWrapper(
-                ApplicationProvider.getApplicationContext().createDisplayContext(display)));
+        mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
         mContentResolverSpy = spy(new MockContentResolver(mContext));
         mContentResolverSpy.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
         when(mContext.getContentResolver()).thenReturn(mContentResolverSpy);
@@ -144,12 +128,13 @@
     @Test
     public void testSetSameIntValue_nothingUpdated() {
         putFloatSetting(0.5f);
+        putIntSetting(128);
         start();
 
-        putIntSetting(fToI(0.5f));
+        putIntSetting(128);
         advanceTime(10);
         verify(mDisplayManagerMock, times(0)).setBrightness(
-                eq(Display.DEFAULT_DISPLAY), eq(0.5f));
+                eq(Display.DEFAULT_DISPLAY), eq(iToF(128)));
     }
 
     @Test
@@ -169,13 +154,14 @@
         // Verify that this update did not get sent to float, because synchronizer
         // is still waiting for confirmation of its first value.
         verify(mDisplayManagerMock, times(0)).setBrightness(
-                Display.DEFAULT_DISPLAY, iToF(20));
+                eq(Display.DEFAULT_DISPLAY), eq(iToF(20)));
 
         // Send the confirmation of the initial change. This should trigger the new value to
         // finally be processed and we can verify that the new value (20) is sent.
         putIntSetting(fToI(0.4f));
         advanceTime(10);
-        verify(mDisplayManagerMock).setBrightness(Display.DEFAULT_DISPLAY, iToF(20));
+        verify(mDisplayManagerMock).setBrightness(
+                eq(Display.DEFAULT_DISPLAY), eq(iToF(20)));
 
     }
 
@@ -197,7 +183,8 @@
         advanceTime(200);
 
         // Verify that the new value gets sent because the timeout expired.
-        verify(mDisplayManagerMock).setBrightness(Display.DEFAULT_DISPLAY, iToF(20));
+        verify(mDisplayManagerMock).setBrightness(
+                eq(Display.DEFAULT_DISPLAY), eq(iToF(20)));
 
         // Send a confirmation of the initial event, BrightnessSynchronizer should treat this as a
         // new event because the timeout had already expired
@@ -209,14 +196,14 @@
 
         // Verify we sent what would have been the confirmation as a new event to displaymanager.
         // We do both fToI and iToF because the conversions are not symmetric.
-        verify(mDisplayManagerMock).setBrightness(Display.DEFAULT_DISPLAY,
-                iToF(fToI(0.4f)));
+        verify(mDisplayManagerMock).setBrightness(
+                eq(Display.DEFAULT_DISPLAY), eq(iToF(fToI(0.4f))));
     }
 
-    private void start() {
-        mSynchronizer = new BrightnessSynchronizer(mContext, mTestLooper.getLooper(),
+    private BrightnessSynchronizer start() {
+        BrightnessSynchronizer bs = new BrightnessSynchronizer(mContext, mTestLooper.getLooper(),
                 mClock::now);
-        mSynchronizer.startSynchronizing();
+        bs.startSynchronizing();
         verify(mDisplayManagerMock).registerDisplayListener(mDisplayListenerCaptor.capture(),
                 isA(Handler.class), eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS));
         mDisplayListener = mDisplayListenerCaptor.getValue();
@@ -224,6 +211,7 @@
         verify(mContentResolverSpy).registerContentObserver(eq(BRIGHTNESS_URI), eq(false),
                 mContentObserverCaptor.capture(), eq(UserHandle.USER_ALL));
         mContentObserver = mContentObserverCaptor.getValue();
+        return bs;
     }
 
     private int getIntSetting() throws Exception {
@@ -253,11 +241,11 @@
     }
 
     private int fToI(float brightness) {
-        return mSynchronizer.brightnessFloatToIntSetting(brightness);
+        return BrightnessSynchronizer.brightnessFloatToInt(brightness);
     }
 
     private float iToF(int brightness) {
-        return mSynchronizer.brightnessIntSettingToFloat(brightness);
+        return BrightnessSynchronizer.brightnessIntToFloat(brightness);
     }
 
     private void advanceTime(long timeMs) {
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
index 306de52..2396905 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -71,7 +71,6 @@
 import android.hardware.Sensor;
 import android.hardware.SensorManager;
 import android.hardware.display.BrightnessConfiguration;
-import android.hardware.display.BrightnessInfo;
 import android.hardware.display.Curve;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManagerGlobal;
@@ -95,7 +94,6 @@
 import android.os.RemoteException;
 import android.view.ContentRecordingSession;
 import android.view.Display;
-import android.view.DisplayAdjustments;
 import android.view.DisplayCutout;
 import android.view.DisplayEventReceiver;
 import android.view.DisplayInfo;
@@ -103,6 +101,7 @@
 import android.view.SurfaceControl;
 import android.window.DisplayWindowPolicyController;
 
+import androidx.test.InstrumentationRegistry;
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
@@ -333,11 +332,7 @@
         LocalServices.removeServiceForTest(UserManagerInternal.class);
         LocalServices.addService(UserManagerInternal.class, mMockUserManagerInternal);
         // TODO: b/287945043
-        Display display = mock(Display.class);
-        when(display.getDisplayAdjustments()).thenReturn(new DisplayAdjustments());
-        when(display.getBrightnessInfo()).thenReturn(mock(BrightnessInfo.class));
-        mContext = spy(new ContextWrapper(
-                ApplicationProvider.getApplicationContext().createDisplayContext(display)));
+        mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
         mResources = Mockito.spy(mContext.getResources());
         manageDisplaysPermission(/* granted= */ false);
         when(mContext.getResources()).thenReturn(mResources);
@@ -1912,6 +1907,7 @@
 
     @Test
     public void testSettingTwoBrightnessConfigurationsOnMultiDisplay() {
+        Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
         DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
 
         // get the first two internal displays
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/GenericWindowPolicyControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/GenericWindowPolicyControllerTest.java
new file mode 100644
index 0000000..a7c8a6c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/GenericWindowPolicyControllerTest.java
@@ -0,0 +1,890 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.companion.virtual;
+
+import static android.content.pm.ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES;
+import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
+import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.WindowConfiguration;
+import android.companion.virtual.IVirtualDeviceIntentInterceptor;
+import android.companion.virtual.VirtualDeviceManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.net.Uri;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
+import android.util.ArraySet;
+import android.view.Display;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.internal.app.BlockedAppStreamingActivity;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class GenericWindowPolicyControllerTest {
+
+    private static final int DISPLAY_ID = Display.DEFAULT_DISPLAY + 1;
+    private static final int TEST_UID = 1234567;
+    private static final String DISPLAY_CATEGORY = "com.display.category";
+    private static final String NONBLOCKED_APP_PACKAGE_NAME = "com.someapp";
+    private static final String BLOCKED_PACKAGE_NAME = "com.blockedapp";
+    private static final int FLAG_CANNOT_DISPLAY_ON_REMOTE_DEVICES = 0x00000;
+    private static final String TEST_SITE = "http://test";
+    private static final ComponentName BLOCKED_APP_STREAMING_COMPONENT =
+            new ComponentName("android", BlockedAppStreamingActivity.class.getName());
+    private static final ComponentName BLOCKED_COMPONENT = new ComponentName(BLOCKED_PACKAGE_NAME,
+            BLOCKED_PACKAGE_NAME);
+    private static final ComponentName NONBLOCKED_COMPONENT = new ComponentName(
+            NONBLOCKED_APP_PACKAGE_NAME, NONBLOCKED_APP_PACKAGE_NAME);
+
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+    @Mock
+    private GenericWindowPolicyController.PipBlockedCallback mPipBlockedCallback;
+    @Mock
+    private VirtualDeviceManager.ActivityListener mActivityListener;
+    @Mock
+    private GenericWindowPolicyController.IntentListenerCallback mIntentListenerCallback;
+    @Mock
+    private GenericWindowPolicyController.ActivityBlockedCallback mActivityBlockedCallback;
+    @Mock
+    private GenericWindowPolicyController.RunningAppsChangedListener mRunningAppsChangedListener;
+    @Mock
+    private GenericWindowPolicyController.SecureWindowCallback mSecureWindowCallback;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void showTasksInHostDeviceRecents() {
+        GenericWindowPolicyController gwpc = createGwpc();
+
+        gwpc.setShowInHostDeviceRecents(true);
+        assertThat(gwpc.canShowTasksInHostDeviceRecents()).isTrue();
+
+        gwpc.setShowInHostDeviceRecents(false);
+        assertThat(gwpc.canShowTasksInHostDeviceRecents()).isFalse();
+    }
+
+    @Test
+    public void containsUid() {
+        GenericWindowPolicyController gwpc = createGwpc();
+
+        assertThat(gwpc.containsUid(TEST_UID)).isFalse();
+
+        gwpc.onRunningAppsChanged(new ArraySet<>(Arrays.asList(TEST_UID)));
+        assertThat(gwpc.containsUid(TEST_UID)).isTrue();
+
+        gwpc.onRunningAppsChanged(new ArraySet<>());
+        assertThat(gwpc.containsUid(TEST_UID)).isFalse();
+    }
+
+    @Test
+    public void isEnteringPipAllowed_falseByDefault() {
+        GenericWindowPolicyController gwpc = createGwpc();
+
+        assertThat(gwpc.isEnteringPipAllowed(TEST_UID)).isFalse();
+        verify(mPipBlockedCallback).onEnteringPipBlocked(TEST_UID);
+    }
+
+    @Test
+    public void isEnteringPipAllowed_dpcSupportsPinned_allowed() {
+        GenericWindowPolicyController gwpc = createGwpc();
+        gwpc.setSupportedWindowingModes(new HashSet<>(
+                Arrays.asList(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
+                        WindowConfiguration.WINDOWING_MODE_PINNED)));
+        assertThat(gwpc.isEnteringPipAllowed(TEST_UID)).isTrue();
+        verify(mPipBlockedCallback, never()).onEnteringPipBlocked(TEST_UID);
+    }
+
+    @Test
+    public void openNonBlockedAppOnVirtualDisplay_isNotBlocked() {
+        GenericWindowPolicyController gwpc = createGwpc();
+        gwpc.setDisplayId(DISPLAY_ID);
+
+        ActivityInfo activityInfo = getActivityInfo(
+                NONBLOCKED_APP_PACKAGE_NAME,
+                NONBLOCKED_APP_PACKAGE_NAME,
+                /* displayOnRemoteDevices */ true,
+                /* targetDisplayCategory */ null);
+        assertActivityCanBeLaunched(gwpc, activityInfo);
+    }
+
+    @Test
+    public void activityDoesNotSupportDisplayOnRemoteDevices_isBlocked() {
+        GenericWindowPolicyController gwpc = createGwpc();
+        gwpc.setDisplayId(DISPLAY_ID);
+
+        ActivityInfo activityInfo = getActivityInfo(
+                NONBLOCKED_APP_PACKAGE_NAME,
+                NONBLOCKED_APP_PACKAGE_NAME,
+                /* displayOnRemoteDevices */ false,
+                /* targetDisplayCategory */ null);
+        assertActivityIsBlocked(gwpc, activityInfo);
+    }
+
+    @Test
+    public void openBlockedComponentOnVirtualDisplay_isBlocked() {
+        GenericWindowPolicyController gwpc = createGwpcWithBlockedComponent(BLOCKED_COMPONENT);
+        gwpc.setDisplayId(DISPLAY_ID);
+
+        ActivityInfo activityInfo = getActivityInfo(
+                BLOCKED_PACKAGE_NAME,
+                BLOCKED_PACKAGE_NAME,
+                /* displayOnRemoteDevices */ true,
+                /* targetDisplayCategory */ null);
+        assertActivityIsBlocked(gwpc, activityInfo);
+    }
+
+    @Test
+    public void addActivityPolicyExemption_openBlockedOnVirtualDisplay_isBlocked() {
+        GenericWindowPolicyController gwpc = createGwpc();
+        gwpc.setDisplayId(DISPLAY_ID);
+        gwpc.setActivityLaunchDefaultAllowed(true);
+        gwpc.addActivityPolicyExemption(BLOCKED_COMPONENT);
+
+        ActivityInfo activityInfo = getActivityInfo(
+                BLOCKED_PACKAGE_NAME,
+                BLOCKED_PACKAGE_NAME,
+                /* displayOnRemoteDevices */ true,
+                /* targetDisplayCategory */ null);
+        assertActivityIsBlocked(gwpc, activityInfo);
+    }
+
+    @Test
+    public void openNotAllowedComponentOnBlocklistVirtualDisplay_isBlocked() {
+        GenericWindowPolicyController gwpc = createGwpcWithAllowedComponent(NONBLOCKED_COMPONENT);
+        gwpc.setDisplayId(DISPLAY_ID);
+
+        ActivityInfo activityInfo = getActivityInfo(
+                BLOCKED_PACKAGE_NAME,
+                BLOCKED_PACKAGE_NAME,
+                /* displayOnRemoteDevices */ true,
+                /* targetDisplayCategory */ null);
+        assertActivityIsBlocked(gwpc, activityInfo);
+    }
+
+    @Test
+    public void addActivityPolicyExemption_openNotAllowedOnVirtualDisplay_isBlocked() {
+        GenericWindowPolicyController gwpc = createGwpc();
+        gwpc.setDisplayId(DISPLAY_ID);
+        gwpc.setActivityLaunchDefaultAllowed(false);
+        gwpc.addActivityPolicyExemption(NONBLOCKED_COMPONENT);
+
+        ActivityInfo activityInfo = getActivityInfo(
+                BLOCKED_PACKAGE_NAME,
+                BLOCKED_PACKAGE_NAME,
+                /* displayOnRemoteDevices */ true,
+                /* targetDisplayCategory */ null);
+        assertActivityIsBlocked(gwpc, activityInfo);
+    }
+
+    @Test
+    public void openAllowedComponentOnBlocklistVirtualDisplay_startsActivity() {
+        GenericWindowPolicyController gwpc = createGwpcWithAllowedComponent(NONBLOCKED_COMPONENT);
+        gwpc.setDisplayId(DISPLAY_ID);
+
+        ActivityInfo activityInfo = getActivityInfo(
+                NONBLOCKED_APP_PACKAGE_NAME,
+                NONBLOCKED_APP_PACKAGE_NAME,
+                /* displayOnRemoteDevices */ true,
+                /* targetDisplayCategory */ null);
+        assertActivityCanBeLaunched(gwpc, activityInfo);
+    }
+
+    @Test
+    public void addActivityPolicyExemption_openAllowedOnVirtualDisplay_startsActivity() {
+        GenericWindowPolicyController gwpc = createGwpc();
+        gwpc.setDisplayId(DISPLAY_ID);
+        gwpc.setActivityLaunchDefaultAllowed(false);
+        gwpc.addActivityPolicyExemption(NONBLOCKED_COMPONENT);
+
+        ActivityInfo activityInfo = getActivityInfo(
+                NONBLOCKED_APP_PACKAGE_NAME,
+                NONBLOCKED_APP_PACKAGE_NAME,
+                /* displayOnRemoteDevices */ true,
+                /* targetDisplayCategory */ null);
+        assertActivityCanBeLaunched(gwpc, activityInfo);
+    }
+
+    @Test
+    public void canActivityBeLaunched_mismatchingUserHandle_isBlocked() {
+        GenericWindowPolicyController gwpc = createGwpc();
+        gwpc.setDisplayId(DISPLAY_ID);
+
+        ActivityInfo activityInfo = getActivityInfo(
+                NONBLOCKED_APP_PACKAGE_NAME,
+                NONBLOCKED_APP_PACKAGE_NAME,
+                /* displayOnRemoteDevices */ true,
+                /* targetDisplayCategory */ null,
+                /* uid */ UserHandle.PER_USER_RANGE + 1);
+        assertActivityIsBlocked(gwpc, activityInfo);
+    }
+
+    @Test
+    public void canActivityBeLaunched_blockedAppStreamingComponent_isNeverBlocked() {
+        GenericWindowPolicyController gwpc = createGwpc();
+        gwpc.setDisplayId(DISPLAY_ID);
+
+        ActivityInfo activityInfo = getActivityInfo(
+                BLOCKED_APP_STREAMING_COMPONENT.getPackageName(),
+                BLOCKED_APP_STREAMING_COMPONENT.getClassName(),
+                /* displayOnRemoteDevices */ true,
+                /* targetDisplayCategory */ null);
+        assertActivityCanBeLaunched(gwpc, activityInfo);
+    }
+
+    @Test
+    public void canActivityBeLaunched_blockedAppStreamingComponentExplicitlyBlocked_isNeverBlocked() {
+        GenericWindowPolicyController gwpc = createGwpcWithBlockedComponent(
+                BLOCKED_APP_STREAMING_COMPONENT);
+        gwpc.setDisplayId(DISPLAY_ID);
+
+        ActivityInfo activityInfo = getActivityInfo(
+                BLOCKED_APP_STREAMING_COMPONENT.getPackageName(),
+                BLOCKED_APP_STREAMING_COMPONENT.getClassName(),
+                /* displayOnRemoteDevices */ true,
+                /* targetDisplayCategory */ null);
+
+        assertActivityCanBeLaunched(gwpc, activityInfo);
+    }
+
+    @Test
+    public void canActivityBeLaunched_blockedAppStreamingComponentExemptFromStreaming_isNeverBlocked() {
+        GenericWindowPolicyController gwpc = createGwpc();
+        gwpc.setDisplayId(DISPLAY_ID);
+        gwpc.setActivityLaunchDefaultAllowed(true);
+        gwpc.addActivityPolicyExemption(BLOCKED_APP_STREAMING_COMPONENT);
+
+        ActivityInfo activityInfo = getActivityInfo(
+                BLOCKED_APP_STREAMING_COMPONENT.getPackageName(),
+                BLOCKED_APP_STREAMING_COMPONENT.getClassName(),
+                /* displayOnRemoteDevices */ true,
+                /* targetDisplayCategory */ null);
+
+        assertActivityCanBeLaunched(gwpc, activityInfo);
+    }
+
+    @Test
+    public void canActivityBeLaunched_blockedAppStreamingComponentNotAllowlisted_isNeverBlocked() {
+        GenericWindowPolicyController gwpc = createGwpcWithAllowedComponent(NONBLOCKED_COMPONENT);
+        gwpc.setDisplayId(DISPLAY_ID);
+
+        ActivityInfo activityInfo = getActivityInfo(
+                BLOCKED_APP_STREAMING_COMPONENT.getPackageName(),
+                BLOCKED_APP_STREAMING_COMPONENT.getClassName(),
+                /* displayOnRemoteDevices */ true,
+                /* targetDisplayCategory */ null);
+
+        assertActivityCanBeLaunched(gwpc, activityInfo);
+    }
+
+    @Test
+    public void canActivityBeLaunched_blockedAppStreamingComponentNotExemptFromBlocklist_isNeverBlocked() {
+        GenericWindowPolicyController gwpc = createGwpc();
+        gwpc.setDisplayId(DISPLAY_ID);
+        gwpc.setActivityLaunchDefaultAllowed(false);
+        gwpc.addActivityPolicyExemption(NONBLOCKED_COMPONENT);
+
+        ActivityInfo activityInfo = getActivityInfo(
+                BLOCKED_APP_STREAMING_COMPONENT.getPackageName(),
+                BLOCKED_APP_STREAMING_COMPONENT.getClassName(),
+                /* displayOnRemoteDevices */ true,
+                /* targetDisplayCategory */ null);
+
+        assertActivityCanBeLaunched(gwpc, activityInfo);
+    }
+
+    @Test
+    public void canActivityBeLaunched_customDisplayCategoryMatches_isNotBlocked() {
+        GenericWindowPolicyController gwpc = createGwpcWithDisplayCategory(DISPLAY_CATEGORY);
+        gwpc.setDisplayId(DISPLAY_ID);
+
+        ActivityInfo activityInfo = getActivityInfo(
+                NONBLOCKED_APP_PACKAGE_NAME,
+                NONBLOCKED_APP_PACKAGE_NAME,
+                /* displayOnRemoteDevices */ true,
+                /* targetDisplayCategory */ DISPLAY_CATEGORY);
+
+        assertActivityCanBeLaunched(gwpc, activityInfo);
+    }
+
+    @Test
+    public void canActivityBeLaunched_customDisplayCategoryDoesNotMatch_isBlocked() {
+        GenericWindowPolicyController gwpc = createGwpcWithDisplayCategory(DISPLAY_CATEGORY);
+        gwpc.setDisplayId(DISPLAY_ID);
+
+        ActivityInfo activityInfo = getActivityInfo(
+                NONBLOCKED_APP_PACKAGE_NAME,
+                NONBLOCKED_APP_PACKAGE_NAME,
+                /* displayOnRemoteDevices */ true,
+                /* targetDisplayCategory */ "some.random.category");
+        assertActivityIsBlocked(gwpc, activityInfo);
+    }
+
+    @Test
+    public void canActivityBeLaunched_crossTaskLaunch_fromDefaultDisplay_isNotBlocked() {
+        GenericWindowPolicyController gwpc = createGwpc();
+        gwpc.setDisplayId(DISPLAY_ID);
+
+        ActivityInfo activityInfo = getActivityInfo(
+                NONBLOCKED_APP_PACKAGE_NAME,
+                NONBLOCKED_APP_PACKAGE_NAME,
+                /* displayOnRemoteDevices */ true,
+                /* targetDisplayCategory */ null);
+        assertActivityCanBeLaunched(gwpc, Display.DEFAULT_DISPLAY, true,
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, activityInfo);
+    }
+
+    @Test
+    public void canActivityBeLaunched_crossTaskLaunchFromVirtualDisplay_notExplicitlyBlocked_isNotBlocked() {
+        GenericWindowPolicyController gwpc = createGwpcWithCrossTaskNavigationBlockedFor(
+                BLOCKED_COMPONENT);
+        gwpc.setDisplayId(DISPLAY_ID);
+
+        ActivityInfo activityInfo = getActivityInfo(
+                NONBLOCKED_APP_PACKAGE_NAME,
+                NONBLOCKED_APP_PACKAGE_NAME,
+                /* displayOnRemoteDevices */ true,
+                /* targetDisplayCategory */ null);
+
+        assertActivityCanBeLaunched(gwpc, DISPLAY_ID, true,
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, activityInfo);
+    }
+
+    @Test
+    public void canActivityBeLaunched_crossTaskLaunchFromVirtualDisplay_explicitlyBlocked_isBlocked() {
+        GenericWindowPolicyController gwpc = createGwpcWithCrossTaskNavigationBlockedFor(
+                BLOCKED_COMPONENT);
+        gwpc.setDisplayId(DISPLAY_ID);
+
+        ActivityInfo activityInfo = getActivityInfo(
+                BLOCKED_PACKAGE_NAME,
+                BLOCKED_PACKAGE_NAME,
+                /* displayOnRemoteDevices */ true,
+                /* targetDisplayCategory */ null);
+        assertActivityIsBlocked(gwpc, DISPLAY_ID, true,
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, activityInfo);
+    }
+
+    @Test
+    public void canActivityBeLaunched_crossTaskLaunchFromVirtualDisplay_notAllowed_isBlocked() {
+        GenericWindowPolicyController gwpc = createGwpcWithCrossTaskNavigationAllowed(
+                NONBLOCKED_COMPONENT);
+        gwpc.setDisplayId(DISPLAY_ID);
+
+        ActivityInfo activityInfo = getActivityInfo(
+                BLOCKED_PACKAGE_NAME,
+                BLOCKED_PACKAGE_NAME,
+                /* displayOnRemoteDevices */ true,
+                /* targetDisplayCategory */ null);
+        assertActivityIsBlocked(gwpc, DISPLAY_ID, true,
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, activityInfo);
+    }
+
+    @Test
+    public void canActivityBeLaunched_crossTaskLaunchFromVirtualDisplay_allowed_isNotBlocked() {
+        GenericWindowPolicyController gwpc = createGwpcWithCrossTaskNavigationAllowed(
+                NONBLOCKED_COMPONENT);
+        gwpc.setDisplayId(DISPLAY_ID);
+
+        ActivityInfo activityInfo = getActivityInfo(
+                NONBLOCKED_APP_PACKAGE_NAME,
+                NONBLOCKED_APP_PACKAGE_NAME,
+                /* displayOnRemoteDevices */ true,
+                /* targetDisplayCategory */ null);
+        assertActivityCanBeLaunched(gwpc, DISPLAY_ID, true,
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, activityInfo);
+    }
+
+    @Test
+    public void canActivityBeLaunched_unsupportedWindowingMode_isBlocked() {
+        GenericWindowPolicyController gwpc = createGwpc();
+        gwpc.setDisplayId(DISPLAY_ID);
+
+        ActivityInfo activityInfo = getActivityInfo(
+                NONBLOCKED_APP_PACKAGE_NAME,
+                NONBLOCKED_APP_PACKAGE_NAME,
+                /* displayOnRemoteDevices */ true,
+                /* targetDisplayCategory */ null);
+        assertActivityIsBlocked(gwpc, DISPLAY_ID, true, WindowConfiguration.WINDOWING_MODE_PINNED,
+                activityInfo);
+    }
+
+    @Test
+    public void canActivityBeLaunched_permissionComponent_isBlocked() {
+        GenericWindowPolicyController gwpc = createGwpcWithPermissionComponent(BLOCKED_COMPONENT);
+        gwpc.setDisplayId(DISPLAY_ID);
+
+        ActivityInfo activityInfo = getActivityInfo(
+                BLOCKED_PACKAGE_NAME,
+                BLOCKED_PACKAGE_NAME,
+                /* displayOnRemoteDevices */ true,
+                /* targetDisplayCategory */ null);
+        assertActivityIsBlocked(gwpc, activityInfo);
+    }
+
+    @Test
+    public void registerRunningAppsChangedListener_onRunningAppsChanged_listenersNotified() {
+        ArraySet<Integer> uids = new ArraySet<>(Arrays.asList(TEST_UID));
+        GenericWindowPolicyController gwpc = createGwpc();
+
+        gwpc.registerRunningAppsChangedListener(mRunningAppsChangedListener);
+        gwpc.onRunningAppsChanged(uids);
+
+        assertThat(gwpc.getRunningAppsChangedListenersSizeForTesting()).isEqualTo(1);
+        verify(mRunningAppsChangedListener).onRunningAppsChanged(uids);
+    }
+
+    @Test
+    public void onRunningAppsChanged_empty_onDisplayEmpty() {
+        ArraySet<Integer> uids = new ArraySet<>();
+        GenericWindowPolicyController gwpc = createGwpc();
+        gwpc.setDisplayId(DISPLAY_ID);
+
+        gwpc.onRunningAppsChanged(uids);
+
+        assertThat(gwpc.getRunningAppsChangedListenersSizeForTesting()).isEqualTo(0);
+        verify(mActivityListener).onDisplayEmpty(DISPLAY_ID);
+    }
+
+    @Test
+    public void noRunningAppsChangedListener_onRunningAppsChanged_doesNotThrowException() {
+        ArraySet<Integer> uids = new ArraySet<>(Arrays.asList(TEST_UID));
+        GenericWindowPolicyController gwpc = createGwpc();
+
+        gwpc.onRunningAppsChanged(uids);
+
+        assertThat(gwpc.getRunningAppsChangedListenersSizeForTesting()).isEqualTo(0);
+        verify(mRunningAppsChangedListener, never()).onRunningAppsChanged(uids);
+    }
+
+    @Test
+    public void registerUnregisterRunningAppsChangedListener_onRunningAppsChanged_doesNotThrowException() {
+        ArraySet<Integer> uids = new ArraySet<>(Arrays.asList(TEST_UID));
+        GenericWindowPolicyController gwpc = createGwpc();
+
+        gwpc.registerRunningAppsChangedListener(mRunningAppsChangedListener);
+        gwpc.unregisterRunningAppsChangedListener(mRunningAppsChangedListener);
+        gwpc.onRunningAppsChanged(uids);
+
+        assertThat(gwpc.getRunningAppsChangedListenersSizeForTesting()).isEqualTo(0);
+        verify(mRunningAppsChangedListener, never()).onRunningAppsChanged(uids);
+    }
+
+    @Test
+    public void canActivityBeLaunched_intentInterceptedWhenRegistered_activityNoLaunch()
+            throws RemoteException {
+        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(TEST_SITE));
+
+        IVirtualDeviceIntentInterceptor.Stub interceptor =
+                mock(IVirtualDeviceIntentInterceptor.Stub.class);
+        doNothing().when(interceptor).onIntentIntercepted(any());
+        doReturn(interceptor).when(interceptor).asBinder();
+        doReturn(interceptor).when(interceptor).queryLocalInterface(anyString());
+
+        GenericWindowPolicyController gwpc = createGwpc();
+        ActivityInfo activityInfo = getActivityInfo(
+                NONBLOCKED_APP_PACKAGE_NAME,
+                NONBLOCKED_APP_PACKAGE_NAME,
+                /* displayOnRemoteDevices */ true,
+                /* targetDisplayCategory */ null);
+
+        // register interceptor and intercept intent
+        when(mIntentListenerCallback.shouldInterceptIntent(any(Intent.class))).thenReturn(true);
+        assertThat(gwpc.canActivityBeLaunched(activityInfo, intent,
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID, /*isNewTask=*/false))
+                .isFalse();
+
+        // unregister interceptor and launch activity
+        when(mIntentListenerCallback.shouldInterceptIntent(any(Intent.class))).thenReturn(false);
+        assertThat(gwpc.canActivityBeLaunched(activityInfo, intent,
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID, /*isNewTask=*/false))
+                .isTrue();
+    }
+
+    @Test
+    public void canActivityBeLaunched_noMatchIntentFilter_activityLaunches() {
+        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("testing"));
+
+        GenericWindowPolicyController gwpc = createGwpc();
+        ActivityInfo activityInfo = getActivityInfo(
+                NONBLOCKED_APP_PACKAGE_NAME,
+                NONBLOCKED_APP_PACKAGE_NAME,
+                /* displayOnRemoteDevices */ true,
+                /* targetDisplayCategory */ null);
+
+        // register interceptor with different filter
+        when(mIntentListenerCallback.shouldInterceptIntent(any(Intent.class))).thenReturn(false);
+        assertThat(gwpc.canActivityBeLaunched(activityInfo, intent,
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID, /*isNewTask=*/false))
+                .isTrue();
+        verify(mIntentListenerCallback).shouldInterceptIntent(any(Intent.class));
+    }
+
+    @Test
+    public void onTopActivitychanged_null_noCallback() {
+        GenericWindowPolicyController gwpc = createGwpc();
+
+        gwpc.onTopActivityChanged(null, 0, 0);
+        verify(mActivityListener, never())
+                .onTopActivityChanged(anyInt(), any(ComponentName.class), anyInt());
+    }
+
+    @Test
+    public void onTopActivitychanged_activityListenerCallbackObserved() {
+        int userId = 1000;
+        GenericWindowPolicyController gwpc = createGwpc();
+        gwpc.setDisplayId(DISPLAY_ID);
+
+        gwpc.onTopActivityChanged(BLOCKED_COMPONENT, 0, userId);
+        verify(mActivityListener)
+                .onTopActivityChanged(eq(DISPLAY_ID), eq(BLOCKED_COMPONENT), eq(userId));
+    }
+
+    @Test
+    public void keepActivityOnWindowFlagsChanged_noChange() {
+        GenericWindowPolicyController gwpc = createGwpc();
+        gwpc.setDisplayId(DISPLAY_ID);
+
+        ActivityInfo activityInfo = getActivityInfo(
+                NONBLOCKED_APP_PACKAGE_NAME,
+                NONBLOCKED_APP_PACKAGE_NAME,
+                /* displayOnRemoteDevices */ true,
+                /* targetDisplayCategory */ null);
+
+        assertThat(gwpc.keepActivityOnWindowFlagsChanged(activityInfo, 0, 0)).isTrue();
+
+        verify(mSecureWindowCallback, never()).onSecureWindowShown(DISPLAY_ID,
+                activityInfo.applicationInfo.uid);
+        verify(mActivityBlockedCallback, never()).onActivityBlocked(DISPLAY_ID, activityInfo);
+    }
+
+    @Test
+    public void keepActivityOnWindowFlagsChanged_flagSecure_isAllowedAfterTM() {
+        GenericWindowPolicyController gwpc = createGwpc();
+        gwpc.setDisplayId(DISPLAY_ID);
+
+        ActivityInfo activityInfo = getActivityInfo(
+                NONBLOCKED_APP_PACKAGE_NAME,
+                NONBLOCKED_APP_PACKAGE_NAME,
+                /* displayOnRemoteDevices */ true,
+                /* targetDisplayCategory */ null);
+
+        assertThat(gwpc.keepActivityOnWindowFlagsChanged(activityInfo, FLAG_SECURE, 0)).isTrue();
+
+        verify(mSecureWindowCallback).onSecureWindowShown(DISPLAY_ID,
+                activityInfo.applicationInfo.uid);
+        verify(mActivityBlockedCallback, never()).onActivityBlocked(DISPLAY_ID, activityInfo);
+    }
+
+    @Test
+    public void keepActivityOnWindowFlagsChanged_systemFlagHideNonSystemOverlayWindows_isAllowedAfterTM() {
+        GenericWindowPolicyController gwpc = createGwpc();
+        gwpc.setDisplayId(DISPLAY_ID);
+
+        ActivityInfo activityInfo = getActivityInfo(
+                NONBLOCKED_APP_PACKAGE_NAME,
+                NONBLOCKED_APP_PACKAGE_NAME,
+                /* displayOnRemoteDevices */ true,
+                /* targetDisplayCategory */ null);
+
+        assertThat(gwpc.keepActivityOnWindowFlagsChanged(activityInfo, 0,
+                SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS)).isTrue();
+
+        verify(mSecureWindowCallback, never()).onSecureWindowShown(DISPLAY_ID,
+                activityInfo.applicationInfo.uid);
+        verify(mActivityBlockedCallback, never()).onActivityBlocked(DISPLAY_ID, activityInfo);
+    }
+
+    @Test
+    public void getCustomHomeComponent_noneSet() {
+        GenericWindowPolicyController gwpc = createGwpc();
+
+        assertThat(gwpc.getCustomHomeComponent()).isNull();
+    }
+
+    @Test
+    public void getCustomHomeComponent_returnsHomeComponent() {
+        GenericWindowPolicyController gwpc = createGwpcWithCustomHomeComponent(
+                NONBLOCKED_COMPONENT);
+
+        assertThat(gwpc.getCustomHomeComponent()).isEqualTo(NONBLOCKED_COMPONENT);
+    }
+
+    private GenericWindowPolicyController createGwpc() {
+        return new GenericWindowPolicyController(
+                0,
+                0,
+                /* allowedUsers= */ new ArraySet<>(getCurrentUserId()),
+                /* activityLaunchAllowedByDefault= */ true,
+                /* activityPolicyExemptions= */ new ArraySet<>(),
+                /* crossTaskNavigationAllowedByDefault= */ true,
+                /* crossTaskNavigationExemptions= */ new ArraySet<>(),
+                /* permissionDialogComponent= */ null,
+                /* activityListener= */ mActivityListener,
+                /* pipBlockedCallback= */ mPipBlockedCallback,
+                /* activityBlockedCallback= */ mActivityBlockedCallback,
+                /* secureWindowCallback= */ mSecureWindowCallback,
+                /* intentListenerCallback= */ mIntentListenerCallback,
+                /* displayCategories= */ new ArraySet<>(),
+                /* showTasksInHostDeviceRecents= */ true,
+                /* customHomeComponent= */ null);
+    }
+
+    private GenericWindowPolicyController createGwpcWithCustomHomeComponent(
+            ComponentName homeComponent) {
+        return new GenericWindowPolicyController(
+                0,
+                0,
+                /* allowedUsers= */ new ArraySet<>(getCurrentUserId()),
+                /* activityLaunchAllowedByDefault= */ true,
+                /* activityPolicyExemptions= */ new ArraySet<>(),
+                /* crossTaskNavigationAllowedByDefault= */ true,
+                /* crossTaskNavigationExemptions= */ new ArraySet<>(),
+                /* permissionDialogComponent= */ null,
+                /* activityListener= */ mActivityListener,
+                /* pipBlockedCallback= */ mPipBlockedCallback,
+                /* activityBlockedCallback= */ mActivityBlockedCallback,
+                /* secureWindowCallback= */ null,
+                /* intentListenerCallback= */ mIntentListenerCallback,
+                /* displayCategories= */ new ArraySet<>(),
+                /* showTasksInHostDeviceRecents= */ true,
+                /* customHomeComponent= */ homeComponent);
+    }
+
+    private GenericWindowPolicyController createGwpcWithBlockedComponent(
+            ComponentName blockedComponent) {
+        return new GenericWindowPolicyController(
+                0,
+                0,
+                /* allowedUsers= */ new ArraySet<>(getCurrentUserId()),
+                /* activityLaunchAllowedByDefault= */ true,
+                /* activityPolicyExemptions= */ Collections.singleton(blockedComponent),
+                /* crossTaskNavigationAllowedByDefault= */ true,
+                /* crossTaskNavigationExemptions= */ new ArraySet<>(),
+                /* permissionDialogComponent= */ null,
+                /* activityListener= */ mActivityListener,
+                /* pipBlockedCallback= */ mPipBlockedCallback,
+                /* activityBlockedCallback= */ mActivityBlockedCallback,
+                /* secureWindowCallback= */ null,
+                /* intentListenerCallback= */ mIntentListenerCallback,
+                /* displayCategories= */ new ArraySet<>(),
+                /* showTasksInHostDeviceRecents= */ true,
+                /* customHomeComponent= */ null);
+    }
+
+    private GenericWindowPolicyController createGwpcWithAllowedComponent(
+            ComponentName allowedComponent) {
+        return new GenericWindowPolicyController(
+                0,
+                0,
+                /* allowedUsers= */ new ArraySet<>(getCurrentUserId()),
+                /* activityLaunchAllowedByDefault= */ false,
+                /* activityPolicyExemptions= */ Collections.singleton(allowedComponent),
+                /* crossTaskNavigationAllowedByDefault= */ true,
+                /* crossTaskNavigationExemptions= */ new ArraySet<>(),
+                /* permissionDialogComponent= */ null,
+                /* activityListener= */ mActivityListener,
+                /* pipBlockedCallback= */ mPipBlockedCallback,
+                /* activityBlockedCallback= */ mActivityBlockedCallback,
+                /* secureWindowCallback= */ null,
+                /* intentListenerCallback= */ mIntentListenerCallback,
+                /* displayCategories= */ new ArraySet<>(),
+                /* showTasksInHostDeviceRecents= */ true,
+                /* customHomeComponent= */ null);
+    }
+
+    private GenericWindowPolicyController createGwpcWithDisplayCategory(
+            String displayCategory) {
+        return new GenericWindowPolicyController(
+                0,
+                0,
+                /* allowedUsers= */ new ArraySet<>(getCurrentUserId()),
+                /* activityLaunchAllowedByDefault= */ true,
+                /* activityPolicyExemptions= */ new ArraySet<>(),
+                /* crossTaskNavigationAllowedByDefault= */ true,
+                /* crossTaskNavigationExemptions= */ new ArraySet<>(),
+                /* permissionDialogComponent= */ null,
+                /* activityListener= */ mActivityListener,
+                /* pipBlockedCallback= */ mPipBlockedCallback,
+                /* activityBlockedCallback= */ mActivityBlockedCallback,
+                /* secureWindowCallback= */ null,
+                /* intentListenerCallback= */ mIntentListenerCallback,
+                /* displayCategories= */ Collections.singleton(displayCategory),
+                /* showTasksInHostDeviceRecents= */ true,
+                /* customHomeComponent= */ null);
+    }
+
+    private GenericWindowPolicyController createGwpcWithCrossTaskNavigationBlockedFor(
+            ComponentName blockedComponent) {
+        return new GenericWindowPolicyController(
+                0,
+                0,
+                /* allowedUsers= */ new ArraySet<>(getCurrentUserId()),
+                /* activityLaunchAllowedByDefault= */ true,
+                /* activityPolicyExemptions= */ new ArraySet<>(),
+                /* crossTaskNavigationAllowedByDefault= */ true,
+                /* crossTaskNavigationExemptions= */ Collections.singleton(blockedComponent),
+                /* permissionDialogComponent= */ null,
+                /* activityListener= */ mActivityListener,
+                /* pipBlockedCallback= */ mPipBlockedCallback,
+                /* activityBlockedCallback= */ mActivityBlockedCallback,
+                /* secureWindowCallback= */ null,
+                /* intentListenerCallback= */ mIntentListenerCallback,
+                /* displayCategories= */ new ArraySet<>(),
+                /* showTasksInHostDeviceRecents= */ true,
+                /* customHomeComponent= */ null);
+    }
+
+    private GenericWindowPolicyController createGwpcWithCrossTaskNavigationAllowed(
+            ComponentName allowedComponent) {
+        return new GenericWindowPolicyController(
+                0,
+                0,
+                /* allowedUsers= */ new ArraySet<>(getCurrentUserId()),
+                /* activityLaunchAllowedByDefault= */ true,
+                /* activityPolicyExemptions= */ new ArraySet<>(),
+                /* crossTaskNavigationAllowedByDefault= */ false,
+                /* crossTaskNavigationExemptions= */ Collections.singleton(allowedComponent),
+                /* permissionDialogComponent= */ null,
+                /* activityListener= */ mActivityListener,
+                /* pipBlockedCallback= */ mPipBlockedCallback,
+                /* activityBlockedCallback= */ mActivityBlockedCallback,
+                /* secureWindowCallback= */ null,
+                /* intentListenerCallback= */ mIntentListenerCallback,
+                /* displayCategories= */ new ArraySet<>(),
+                /* showTasksInHostDeviceRecents= */ true,
+                /* customHomeComponent= */ null);
+    }
+
+    private GenericWindowPolicyController createGwpcWithPermissionComponent(
+            ComponentName permissionComponent) {
+        //TODO instert the component
+        return new GenericWindowPolicyController(
+                0,
+                0,
+                /* allowedUsers= */ new ArraySet<>(getCurrentUserId()),
+                /* activityLaunchAllowedByDefault= */ true,
+                /* activityPolicyExemptions= */ new ArraySet<>(),
+                /* crossTaskNavigationAllowedByDefault= */ false,
+                /* crossTaskNavigationExemptions= */ new ArraySet<>(),
+                /* permissionDialogComponent= */ permissionComponent,
+                /* activityListener= */ mActivityListener,
+                /* pipBlockedCallback= */ mPipBlockedCallback,
+                /* activityBlockedCallback= */ mActivityBlockedCallback,
+                /* secureWindowCallback= */ null,
+                /* intentListenerCallback= */ mIntentListenerCallback,
+                /* displayCategories= */ new ArraySet<>(),
+                /* showTasksInHostDeviceRecents= */ true,
+                /* customHomeComponent= */ null);
+    }
+
+    private Set<UserHandle> getCurrentUserId() {
+        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        return new ArraySet<>(Arrays.asList(context.getUser()));
+    }
+
+    private ActivityInfo getActivityInfo(
+            String packageName, String name, boolean displayOnRemoteDevices,
+            String requiredDisplayCategory) {
+        return getActivityInfo(packageName, name, displayOnRemoteDevices, requiredDisplayCategory,
+                0);
+    }
+
+    private ActivityInfo getActivityInfo(
+            String packageName, String name, boolean displayOnRemoteDevices,
+            String requiredDisplayCategory, int uid) {
+        ApplicationInfo applicationInfo = new ApplicationInfo();
+        applicationInfo.uid = uid;
+
+        ActivityInfo activityInfo = new ActivityInfo();
+        activityInfo.packageName = packageName;
+        activityInfo.name = name;
+        activityInfo.flags = displayOnRemoteDevices
+                ? FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES : FLAG_CANNOT_DISPLAY_ON_REMOTE_DEVICES;
+        activityInfo.applicationInfo = applicationInfo;
+        activityInfo.requiredDisplayCategory = requiredDisplayCategory;
+        return activityInfo;
+    }
+
+    private void assertActivityCanBeLaunched(GenericWindowPolicyController gwpc,
+            ActivityInfo activityInfo) {
+        assertActivityCanBeLaunched(gwpc, DISPLAY_ID, false,
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, activityInfo);
+    }
+
+    private void assertActivityCanBeLaunched(GenericWindowPolicyController gwpc, int fromDisplay,
+            boolean isNewTask, int windowingMode, ActivityInfo activityInfo) {
+        assertThat(gwpc.canActivityBeLaunched(activityInfo, null, windowingMode, fromDisplay,
+                isNewTask)).isTrue();
+
+        verify(mActivityBlockedCallback, never()).onActivityBlocked(fromDisplay, activityInfo);
+        verify(mIntentListenerCallback, never()).shouldInterceptIntent(any(Intent.class));
+    }
+
+    private void assertActivityIsBlocked(GenericWindowPolicyController gwpc,
+            ActivityInfo activityInfo) {
+        assertActivityIsBlocked(gwpc, DISPLAY_ID, false,
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, activityInfo);
+    }
+
+    private void assertActivityIsBlocked(GenericWindowPolicyController gwpc, int fromDisplay,
+            boolean isNewTask, int windowingMode, ActivityInfo activityInfo) {
+        assertThat(gwpc.canActivityBeLaunched(activityInfo, null, windowingMode, fromDisplay,
+                isNewTask)).isFalse();
+
+        verify(mActivityBlockedCallback).onActivityBlocked(fromDisplay, activityInfo);
+        verify(mIntentListenerCallback, never()).shouldInterceptIntent(any(Intent.class));
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
index 41af9e3..263d470 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
@@ -24,6 +24,7 @@
 import static android.content.Context.DEVICE_ID_INVALID;
 import static android.content.Intent.ACTION_VIEW;
 import static android.content.pm.ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES;
+import static android.content.pm.PackageManager.ACTION_REQUEST_PERMISSIONS;
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
@@ -57,6 +58,7 @@
 import android.companion.virtual.VirtualDeviceParams;
 import android.companion.virtual.audio.IAudioConfigChangedCallback;
 import android.companion.virtual.audio.IAudioRoutingCallback;
+import android.companion.virtual.flags.Flags;
 import android.companion.virtual.sensor.IVirtualSensorCallback;
 import android.companion.virtual.sensor.VirtualSensor;
 import android.companion.virtual.sensor.VirtualSensorCallback;
@@ -69,6 +71,7 @@
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
 import android.hardware.Sensor;
 import android.hardware.display.DisplayManagerGlobal;
 import android.hardware.display.DisplayManagerInternal;
@@ -100,6 +103,7 @@
 import android.os.RemoteException;
 import android.os.WorkSource;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.util.ArraySet;
@@ -211,6 +215,9 @@
     private static final String TEST_SITE = "http://test";
 
     @Rule
+    public SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+    @Rule
     public AdoptShellPermissionsRule mAdoptShellPermissionsRule = new AdoptShellPermissionsRule(
             InstrumentationRegistry.getInstrumentation().getUiAutomation(),
             Manifest.permission.CREATE_VIRTUAL_DEVICE);
@@ -298,7 +305,7 @@
         ActivityInfo activityInfo = getActivityInfo(
                 NONBLOCKED_APP_PACKAGE_NAME,
                 NONBLOCKED_APP_PACKAGE_NAME,
-                /* displayOnRemoveDevices= */ true,
+                /* displayOnRemoteDevices= */ true,
                 targetDisplayCategory);
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
                 activityInfo, mAssociationInfo.getDisplayName());
@@ -309,12 +316,12 @@
 
 
     private ActivityInfo getActivityInfo(
-            String packageName, String name, boolean displayOnRemoveDevices,
+            String packageName, String name, boolean displayOnRemoteDevices,
             String requiredDisplayCategory) {
         ActivityInfo activityInfo = new ActivityInfo();
         activityInfo.packageName = packageName;
         activityInfo.name = name;
-        activityInfo.flags = displayOnRemoveDevices
+        activityInfo.flags = displayOnRemoteDevices
                 ? FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES : FLAG_CANNOT_DISPLAY_ON_REMOTE_DEVICES;
         activityInfo.applicationInfo = mApplicationInfoMock;
         activityInfo.requiredDisplayCategory = requiredDisplayCategory;
@@ -328,6 +335,11 @@
         LocalServices.removeServiceForTest(DisplayManagerInternal.class);
         LocalServices.addService(DisplayManagerInternal.class, mDisplayManagerInternalMock);
 
+        mSetFlagsRule.disableFlags(Flags.FLAG_VDM_PUBLIC_APIS);
+        mSetFlagsRule.disableFlags(Flags.FLAG_DYNAMIC_POLICY);
+        mSetFlagsRule.disableFlags(Flags.FLAG_STREAM_PERMISSIONS);
+        mSetFlagsRule.disableFlags(Flags.FLAG_VDM_CUSTOM_HOME);
+
         doReturn(true).when(mInputManagerInternalMock).setVirtualMousePointerDisplayId(anyInt());
         doNothing().when(mInputManagerInternalMock).setPointerAcceleration(anyFloat(), anyInt());
         doNothing().when(mInputManagerInternalMock).setPointerIconVisible(anyBoolean(), anyInt());
@@ -1417,7 +1429,7 @@
         ActivityInfo activityInfo = getActivityInfo(
                 NONBLOCKED_APP_PACKAGE_NAME,
                 NONBLOCKED_APP_PACKAGE_NAME,
-                /* displayOnRemoveDevices */ true,
+                /* displayOnRemoteDevices */ true,
                 /* targetDisplayCategory */ null);
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
                 activityInfo, mAssociationInfo.getDisplayName());
@@ -1438,7 +1450,51 @@
         ActivityInfo activityInfo = getActivityInfo(
                 PERMISSION_CONTROLLER_PACKAGE_NAME,
                 PERMISSION_CONTROLLER_PACKAGE_NAME,
-                /* displayOnRemoveDevices */  false,
+                /* displayOnRemoteDevices */  false,
+                /* targetDisplayCategory */ null);
+        Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
+                activityInfo, mAssociationInfo.getDisplayName());
+        gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
+
+        verify(mContext).startActivityAsUser(argThat(intent ->
+                intent.filterEquals(blockedAppIntent)), any(), any());
+    }
+
+    @Test
+    public void openPermissionControllerOnVirtualDisplay_displayOnRemoteDevices_startsWhenFlagIsEnabled() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_STREAM_PERMISSIONS);
+        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
+        GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
+                DISPLAY_ID_1);
+        doNothing().when(mContext).startActivityAsUser(any(), any(), any());
+
+        ActivityInfo activityInfo = getActivityInfo(
+                PERMISSION_CONTROLLER_PACKAGE_NAME,
+                PERMISSION_CONTROLLER_PACKAGE_NAME,
+                /* displayOnRemoveDevices */ true,
+                /* targetDisplayCategory */ null);
+        Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
+                activityInfo, mAssociationInfo.getDisplayName());
+        gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
+
+        verify(mContext, never()).startActivityAsUser(argThat(intent ->
+                intent.filterEquals(blockedAppIntent)), any(), any());
+    }
+
+    @Test
+    public void openPermissionControllerOnVirtualDisplay_dontDisplayOnRemoteDevices_startsWhenFlagIsEnabled() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_STREAM_PERMISSIONS);
+        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
+        GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
+                DISPLAY_ID_1);
+        doNothing().when(mContext).startActivityAsUser(any(), any(), any());
+
+        ActivityInfo activityInfo = getActivityInfo(
+                PERMISSION_CONTROLLER_PACKAGE_NAME,
+                PERMISSION_CONTROLLER_PACKAGE_NAME,
+                /* displayOnRemoveDevices */ false,
                 /* targetDisplayCategory */ null);
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
                 activityInfo, mAssociationInfo.getDisplayName());
@@ -1459,7 +1515,7 @@
         ActivityInfo activityInfo = getActivityInfo(
                 SETTINGS_PACKAGE_NAME,
                 SETTINGS_PACKAGE_NAME,
-                /* displayOnRemoveDevices */ true,
+                /* displayOnRemoteDevices */ true,
                 /* targetDisplayCategory */ null);
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
                 activityInfo, mAssociationInfo.getDisplayName());
@@ -1480,7 +1536,7 @@
         ActivityInfo activityInfo = getActivityInfo(
                 VENDING_PACKAGE_NAME,
                 VENDING_PACKAGE_NAME,
-                /* displayOnRemoveDevices */ true,
+                /* displayOnRemoteDevices */ true,
                 /* targetDisplayCategory */ null);
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
                 activityInfo, mAssociationInfo.getDisplayName());
@@ -1501,7 +1557,7 @@
         ActivityInfo activityInfo = getActivityInfo(
                 GOOGLE_DIALER_PACKAGE_NAME,
                 GOOGLE_DIALER_PACKAGE_NAME,
-                /* displayOnRemoveDevices */ true,
+                /* displayOnRemoteDevices */ true,
                 /* targetDisplayCategory */ null);
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
                 activityInfo, mAssociationInfo.getDisplayName());
@@ -1522,7 +1578,7 @@
         ActivityInfo activityInfo = getActivityInfo(
                 GOOGLE_MAPS_PACKAGE_NAME,
                 GOOGLE_MAPS_PACKAGE_NAME,
-                /* displayOnRemoveDevices */ true,
+                /* displayOnRemoteDevices */ true,
                 /* targetDisplayCategory */ null);
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
                 activityInfo, mAssociationInfo.getDisplayName());
@@ -1562,6 +1618,54 @@
     }
 
     @Test
+    public void canActivityBeLaunched_permissionDialog_flagDisabled_isBlocked() {
+        mSetFlagsRule.disableFlags(Flags.FLAG_STREAM_PERMISSIONS);
+        VirtualDeviceParams params = new VirtualDeviceParams.Builder().build();
+        mDeviceImpl.close();
+        mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1, params);
+        doNothing().when(mContext).startActivityAsUser(any(), any(), any());
+
+        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
+        GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
+                DISPLAY_ID_1);
+        ComponentName permissionComponent = getPermissionDialogComponent();
+        ActivityInfo activityInfo = getActivityInfo(
+                permissionComponent.getPackageName(),
+                permissionComponent.getClassName(),
+                /* displayOnRemoteDevices */ true,
+                /* targetDisplayCategory */ null);
+        assertThat(gwpc.canActivityBeLaunched(activityInfo, null,
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false))
+                .isFalse();
+
+        Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
+                activityInfo, mAssociationInfo.getDisplayName());
+        verify(mContext).startActivityAsUser(argThat(intent ->
+                intent.filterEquals(blockedAppIntent)), any(), any());
+    }
+
+    @Test
+    public void canActivityBeLaunched_permissionDialog_flagEnabled_isStreamed() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_STREAM_PERMISSIONS);
+        VirtualDeviceParams params = new VirtualDeviceParams.Builder().build();
+        mDeviceImpl.close();
+        mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1, params);
+
+        addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
+        GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
+                DISPLAY_ID_1);
+        ComponentName permissionComponent = getPermissionDialogComponent();
+        ActivityInfo activityInfo = getActivityInfo(
+                permissionComponent.getPackageName(),
+                permissionComponent.getClassName(),
+                /* displayOnRemoteDevices */ true,
+                /* targetDisplayCategory */ null);
+        assertThat(gwpc.canActivityBeLaunched(activityInfo, null,
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false))
+                .isTrue();
+    }
+
+    @Test
     public void canActivityBeLaunched_activityCanLaunch() {
         Intent intent = new Intent(ACTION_VIEW, Uri.parse(TEST_SITE));
         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
@@ -1570,7 +1674,7 @@
         ActivityInfo activityInfo = getActivityInfo(
                 NONBLOCKED_APP_PACKAGE_NAME,
                 NONBLOCKED_APP_PACKAGE_NAME,
-                /* displayOnRemoveDevices */ true,
+                /* displayOnRemoteDevices */ true,
                 /* targetDisplayCategory */ null);
         assertThat(gwpc.canActivityBeLaunched(activityInfo, intent,
                 WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false))
@@ -1594,7 +1698,7 @@
         ActivityInfo activityInfo = getActivityInfo(
                 NONBLOCKED_APP_PACKAGE_NAME,
                 NONBLOCKED_APP_PACKAGE_NAME,
-                /* displayOnRemoveDevices */ true,
+                /* displayOnRemoteDevices */ true,
                 /* targetDisplayCategory */ null);
 
         IntentFilter intentFilter = new IntentFilter(Intent.ACTION_VIEW);
@@ -1637,7 +1741,7 @@
         ActivityInfo activityInfo = getActivityInfo(
                 NONBLOCKED_APP_PACKAGE_NAME,
                 NONBLOCKED_APP_PACKAGE_NAME,
-                /* displayOnRemoveDevices */ true,
+                /* displayOnRemoteDevices */ true,
                 /* targetDisplayCategory */ null);
 
         IntentFilter intentFilter = new IntentFilter(Intent.ACTION_VIEW);
@@ -1758,6 +1862,13 @@
                 NONBLOCKED_APP_PACKAGE_NAME);
     }
 
+    private ComponentName getPermissionDialogComponent() {
+        Intent intent = new Intent(ACTION_REQUEST_PERMISSIONS);
+        PackageManager packageManager = mContext.getPackageManager();
+        intent.setPackage(packageManager.getPermissionControllerPackageName());
+        return intent.resolveActivity(packageManager);
+    }
+
     /** Helper class to drop permissions temporarily and restore them at the end of a test. */
     static final class DropShellPermissionsTemporarily implements AutoCloseable {
         DropShellPermissionsTemporarily() {
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java
index c65452a..07dd59d2 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java
@@ -32,11 +32,12 @@
 import android.companion.virtual.flags.Flags;
 import android.os.Parcel;
 import android.platform.test.annotations.Presubmit;
-import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.SetFlagsRule;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -49,6 +50,10 @@
     private static final int VIRTUAL_DEVICE_ID = 42;
     private static final String PERSISTENT_ID = "persistentId";
     private static final String DEVICE_NAME = "VirtualDeviceName";
+    private static final String DISPLAY_NAME = "DisplayName";
+
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
 
     @Mock
     private IVirtualDevice mVirtualDevice;
@@ -87,7 +92,8 @@
     @Test
     public void parcelable_shouldRecreateSuccessfully() {
         VirtualDevice originalDevice =
-                new VirtualDevice(mVirtualDevice, VIRTUAL_DEVICE_ID, PERSISTENT_ID, DEVICE_NAME);
+                new VirtualDevice(mVirtualDevice, VIRTUAL_DEVICE_ID, PERSISTENT_ID, DEVICE_NAME,
+                        DISPLAY_NAME);
         Parcel parcel = Parcel.obtain();
         originalDevice.writeToParcel(parcel, 0);
         parcel.setDataPosition(0);
@@ -96,11 +102,13 @@
         assertThat(device.getDeviceId()).isEqualTo(VIRTUAL_DEVICE_ID);
         assertThat(device.getPersistentDeviceId()).isEqualTo(PERSISTENT_ID);
         assertThat(device.getName()).isEqualTo(DEVICE_NAME);
+        assertThat(device.getDisplayName().toString()).isEqualTo(DISPLAY_NAME);
     }
 
-    @RequiresFlagsEnabled(Flags.FLAG_VDM_PUBLIC_APIS)
     @Test
     public void virtualDevice_getDisplayIds() throws Exception {
+        mSetFlagsRule.enableFlags(Flags.FLAG_VDM_PUBLIC_APIS);
+
         VirtualDevice virtualDevice =
                 new VirtualDevice(
                         mVirtualDevice, VIRTUAL_DEVICE_ID, /*persistentId=*/null, /*name=*/null);
@@ -113,9 +121,10 @@
         assertThat(virtualDevice.getDisplayIds()).isEqualTo(displayIds);
     }
 
-    @RequiresFlagsEnabled(Flags.FLAG_VDM_PUBLIC_APIS)
     @Test
     public void virtualDevice_hasCustomSensorSupport() throws Exception {
+        mSetFlagsRule.enableFlags(Flags.FLAG_VDM_PUBLIC_APIS);
+
         VirtualDevice virtualDevice =
                 new VirtualDevice(
                         mVirtualDevice, VIRTUAL_DEVICE_ID, /*persistentId=*/null, /*name=*/null);
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
index 1c48b8a..ef5270e 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
@@ -82,6 +82,7 @@
                         /* activityPolicyExemptions= */ new ArraySet<>(),
                         /* crossTaskNavigationAllowedByDefault= */ true,
                         /* crossTaskNavigationExemptions= */ new ArraySet<>(),
+                        /* permissionDialogComponent */ null,
                         /* activityListener= */ null,
                         /* pipBlockedCallback= */ null,
                         /* activityBlockedCallback= */ null,
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index f65cb93..40ac7b1c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -2855,14 +2855,14 @@
                 .setTask(sourceRecord.getTask()).build();
         secondRecord.showStartingWindow(null /* prev */, true /* newTask */, false,
                 true /* startActivity */, sourceRecord);
-        assertTrue(secondRecord.mAllowIconSplashScreen);
+        assertFalse(secondRecord.mSplashScreenStyleSolidColor);
         secondRecord.onStartingWindowDrawn();
 
         final ActivityRecord finalRecord = new ActivityBuilder(mAtm)
                 .setTask(sourceRecord.getTask()).build();
         finalRecord.showStartingWindow(null /* prev */, true /* newTask */, false,
                 true /* startActivity */, secondRecord);
-        assertFalse(finalRecord.mAllowIconSplashScreen);
+        assertTrue(finalRecord.mSplashScreenStyleSolidColor);
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 25619b9..4c25a4b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -91,6 +91,7 @@
 import java.util.Random;
 import java.util.Set;
 import java.util.function.Function;
+import java.util.stream.Collectors;
 
 /**
  * Build/Install/Run:
@@ -563,6 +564,38 @@
     }
 
     @Test
+    public void testTasksWithCorrectOrderOfLastActiveTime() {
+        mRecentTasks.setOnlyTestVisibleRange();
+        mRecentTasks.unloadUserDataFromMemoryLocked(TEST_USER_0_ID);
+
+        // Setup some tasks for the user
+        mTaskPersister.mUserTaskIdsOverride = new SparseBooleanArray();
+        mTaskPersister.mUserTaskIdsOverride.put(1, true);
+        mTaskPersister.mUserTaskIdsOverride.put(2, true);
+        mTaskPersister.mUserTaskIdsOverride.put(3, true);
+        mTaskPersister.mUserTasksOverride = new ArrayList<>();
+        mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask1").build());
+        mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask2").build());
+        mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask3").build());
+
+        // Assert no user tasks are initially loaded
+        assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).hasLength(0);
+
+        // Load tasks
+        mRecentTasks.loadUserRecentsLocked(TEST_USER_0_ID);
+        assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_0_ID);
+
+        // Sort the time descendingly so the order should be in-sync with task recency (most
+        // recent to least recent)
+        List<Task> tasksSortedByTime = mRecentTasks.getRawTasks().stream()
+                .sorted((o1, o2) -> Long.compare(o2.lastActiveTime, o1.lastActiveTime))
+                .collect(Collectors.toList());
+
+        assertTrue("Task order is not in sync with its recency",
+                mRecentTasks.getRawTasks().equals(tasksSortedByTime));
+    }
+
+    @Test
     public void testOrderedIteration() {
         mRecentTasks.setOnlyTestVisibleRange();
         Task task1 = createTaskBuilder(".Task1").build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index bfa279d..2bf1385 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -212,7 +212,30 @@
         mController.dispatchPendingEvents();
 
         assertTaskFragmentParentInfoChangedTransaction(mTask);
-        assertTaskFragmentAppearedTransaction();
+        assertTaskFragmentAppearedTransaction(false /* hasSurfaceControl */);
+    }
+
+    @Test
+    public void testOnTaskFragmentAppeared_systemOrganizer() {
+        mController.unregisterOrganizer(mIOrganizer);
+        mController.registerOrganizerInternal(mIOrganizer, true /* isSystemOrganizer */);
+
+        // No-op when the TaskFragment is not attached.
+        mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
+        mController.dispatchPendingEvents();
+
+        verify(mOrganizer, never()).onTransactionReady(any());
+
+        // Send callback when the TaskFragment is attached.
+        setupMockParent(mTaskFragment, mTask);
+
+        mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
+        mController.dispatchPendingEvents();
+
+        assertTaskFragmentParentInfoChangedTransaction(mTask);
+
+        // System organizer should receive the SurfaceControl
+        assertTaskFragmentAppearedTransaction(true /* hasSurfaceControl */);
     }
 
     @Test
@@ -1664,7 +1687,7 @@
     }
 
     /** Asserts that there will be a transaction for TaskFragment appeared. */
-    private void assertTaskFragmentAppearedTransaction() {
+    private void assertTaskFragmentAppearedTransaction(boolean hasSurfaceControl) {
         verify(mOrganizer).onTransactionReady(mTransactionCaptor.capture());
         final TaskFragmentTransaction transaction = mTransactionCaptor.getValue();
         final List<TaskFragmentTransaction.Change> changes = transaction.getChanges();
@@ -1675,6 +1698,11 @@
         assertEquals(TYPE_TASK_FRAGMENT_APPEARED, change.getType());
         assertEquals(mTaskFragmentInfo, change.getTaskFragmentInfo());
         assertEquals(mFragmentToken, change.getTaskFragmentToken());
+        if (hasSurfaceControl) {
+            assertNotNull(change.getTaskFragmentSurfaceControl());
+        } else {
+            assertNull(change.getTaskFragmentSurfaceControl());
+        }
     }
 
     /** Asserts that there will be a transaction for TaskFragment info changed. */
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
index 6a9bb6c..5205bb0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
@@ -27,8 +27,12 @@
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyFloat;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.clearInvocations;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
@@ -124,6 +128,17 @@
     }
 
     @Test
+    public void testUpdateOrganizedTaskFragmentSurface_noSurfaceUpdateWhenOrganizedBySystem() {
+        clearInvocations(mTransaction);
+        mTaskFragment.mIsSurfaceManagedBySystemOrganizer = true;
+
+        mTaskFragment.updateOrganizedTaskFragmentSurface();
+
+        verify(mTransaction, never()).setPosition(eq(mLeash), anyFloat(), anyFloat());
+        verify(mTransaction, never()).setWindowCrop(eq(mLeash), anyInt(), anyInt());
+    }
+
+    @Test
     public void testShouldStartChangeTransition_relativePositionChange() {
         final Task task = createTask(mDisplayContent, WINDOWING_MODE_MULTI_WINDOW,
                 ACTIVITY_TYPE_STANDARD);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 36a8fc1..a5e0638 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -18,6 +18,7 @@
 
 import android.Manifest;
 import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -52,6 +53,7 @@
 import android.telephony.ims.feature.RcsFeature;
 
 import com.android.internal.telephony.ICarrierConfigLoader;
+import com.android.internal.telephony.flags.Flags;
 import com.android.telephony.Rlog;
 
 import java.util.List;
@@ -9436,22 +9438,9 @@
      * </carrier_config>
      * }</pre>
      * <p>
-     * If this carrier config is not present, the device overlay config
-     * {@code config_satellite_services_supported_by_providers} will be used. If the carrier config
-     * is present, the supported services associated with the PLMNs listed in the carrier config
-     * will override that of the device overlay config. The supported satellite services will be
-     * identified as follows:
-     * <ul>
-     * <li>For each PLMN that exists only in the carrier provided satellite services, use the
-     * carrier provided services as the supported services.</li>
-     * <li>For each PLMN that is present only in the device provided satellite services, use the
-     * device provided services as the supported services.</li>
-     * <li>For each PLMN that is present in both the carrier provided and device provided satellite
-     * services, use the carrier provided services as the supported services.</li>
-     * </ul>
-     * <p>
      * This config is empty by default.
      */
+    @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
     public static final String KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE =
             "carrier_supported_satellite_services_per_provider_bundle";
 
@@ -9462,9 +9451,8 @@
      * satellite provider and the carrier before enabling this flag.
      *
      * The default value is false.
-     *
-     * @hide
      */
+    @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
     public static final String KEY_SATELLITE_ATTACH_SUPPORTED_BOOL =
             "satellite_attach_supported_bool";
 
@@ -10430,8 +10418,12 @@
         sDefaults.putAll(Iwlan.getDefaults());
         sDefaults.putStringArray(KEY_CARRIER_CERTIFICATE_STRING_ARRAY, new String[0]);
         sDefaults.putBoolean(KEY_FORMAT_INCOMING_NUMBER_TO_NATIONAL_FOR_JP_BOOL, false);
-        sDefaults.putIntArray(KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY,
-                new int[] {4 /* BUSY */});
+        if (Flags.doNotOverridePreciseLabel()) {
+            sDefaults.putIntArray(KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY, new int[]{});
+        } else {
+            sDefaults.putIntArray(KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY,
+                    new int[]{4 /* BUSY */});
+        }
         sDefaults.putBoolean(KEY_PREVENT_CLIR_ACTIVATION_AND_DEACTIVATION_CODE_BOOL, false);
         sDefaults.putLong(KEY_DATA_SWITCH_VALIDATION_TIMEOUT_LONG, 5000);
         sDefaults.putStringArray(KEY_MMI_TWO_DIGIT_NUMBER_PATTERN_STRING_ARRAY, new String[0]);
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index a4527f12..8dc2de8 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -85,29 +85,11 @@
     @Nullable private final Context mContext;
 
     /**
-     * Create a new SatelliteManager object pinned to the given subscription ID.
-     * This is needed only to handle carrier specific satellite features.
-     * For eg: requestSatelliteAttachEnabledForCarrier and
-     *         requestIsSatelliteAttachEnabledForCarrier
-     *
-     * @return a SatelliteManager that uses the given subId for all satellite activities.
-     * @throws IllegalArgumentException if the subscription is invalid.
-     * @hide
-     */
-    public SatelliteManager createForSubscriptionId(int subId) {
-        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
-            throw new IllegalArgumentException("Invalid subscription ID");
-        }
-        return new SatelliteManager(mContext, subId);
-    }
-
-    /**
      * Create an instance of the SatelliteManager.
      *
      * @param context The context the SatelliteManager belongs to.
      * @hide
      */
-
     public SatelliteManager(@Nullable Context context) {
         this(context, SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
     }
@@ -846,8 +828,8 @@
     /**
      * Satellite communication restricted by geolocation. This can be
      * triggered based upon geofence input provided by carrier to enable or disable satellite.
-     * @hide
      */
+    @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
     public static final int SATELLITE_COMMUNICATION_RESTRICTION_REASON_GEOLOCATION = 1;
 
     /** @hide */
@@ -1643,26 +1625,28 @@
      * {@code true}.</li>
      * </ul>
      *
+     * @param subId The subscription ID of the carrier.
      * @param enableSatellite {@code true} to enable the satellite and {@code false} to disable.
      * @param executor The executor on which the error code listener will be called.
      * @param resultListener Listener for the {@link SatelliteError} result of the operation.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
-     * @hide
+     * @throws IllegalArgumentException if the subscription is invalid.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
-    public void requestSatelliteAttachEnabledForCarrier(boolean enableSatellite,
+    @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
+    public void requestSatelliteAttachEnabledForCarrier(int subId, boolean enableSatellite,
             @NonNull @CallbackExecutor Executor executor,
             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
         Objects.requireNonNull(executor);
         Objects.requireNonNull(resultListener);
 
         if (enableSatellite) {
-            removeSatelliteAttachRestrictionForCarrier(
+            removeSatelliteAttachRestrictionForCarrier(subId,
                     SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER, executor, resultListener);
         } else {
-            addSatelliteAttachRestrictionForCarrier(
+            addSatelliteAttachRestrictionForCarrier(subId,
                     SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER, executor, resultListener);
         }
     }
@@ -1671,6 +1655,7 @@
      * Request to get whether the carrier supported satellite plmn scan and attach by modem is
      * enabled by user.
      *
+     * @param subId The subscription ID of the carrier.
      * @param executor The executor on which the callback will be called.
      * @param callback The callback object to which the result will be delivered.
      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
@@ -1681,16 +1666,17 @@
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
-     * @hide
+     * @throws IllegalArgumentException if the subscription is invalid.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
-    public void requestIsSatelliteAttachEnabledForCarrier(
+    @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
+    public void requestIsSatelliteAttachEnabledForCarrier(int subId,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
         Objects.requireNonNull(executor);
         Objects.requireNonNull(callback);
 
-        Set<Integer> restrictionReason = getSatelliteAttachRestrictionReasonsForCarrier();
+        Set<Integer> restrictionReason = getSatelliteAttachRestrictionReasonsForCarrier(subId);
         executor.execute(() -> callback.onResult(
                 !restrictionReason.contains(SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER)));
     }
@@ -1699,19 +1685,25 @@
      * Add a restriction reason for disallowing carrier supported satellite plmn scan and attach
      * by modem.
      *
+     * @param subId The subscription ID of the carrier.
      * @param reason Reason for disallowing satellite communication.
      * @param executor The executor on which the error code listener will be called.
      * @param resultListener Listener for the {@link SatelliteError} result of the operation.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
-     * @hide
+     * @throws IllegalArgumentException if the subscription is invalid.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
-    public void addSatelliteAttachRestrictionForCarrier(
+    @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
+    public void addSatelliteAttachRestrictionForCarrier(int subId,
             @SatelliteCommunicationRestrictionReason int reason,
             @NonNull @CallbackExecutor Executor executor,
             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
+        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+            throw new IllegalArgumentException("Invalid subscription ID");
+        }
+
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null) {
@@ -1722,7 +1714,7 @@
                                 () -> resultListener.accept(result)));
                     }
                 };
-                telephony.addSatelliteAttachRestrictionForCarrier(mSubId, reason, errorCallback);
+                telephony.addSatelliteAttachRestrictionForCarrier(subId, reason, errorCallback);
             } else {
                 throw new IllegalStateException("telephony service is null.");
             }
@@ -1736,19 +1728,25 @@
      * Remove a restriction reason for disallowing carrier supported satellite plmn scan and attach
      * by modem.
      *
+     * @param subId The subscription ID of the carrier.
      * @param reason Reason for disallowing satellite communication.
      * @param executor The executor on which the error code listener will be called.
      * @param resultListener Listener for the {@link SatelliteError} result of the operation.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
-     * @hide
+     * @throws IllegalArgumentException if the subscription is invalid.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
-    public void removeSatelliteAttachRestrictionForCarrier(
+    @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
+    public void removeSatelliteAttachRestrictionForCarrier(int subId,
             @SatelliteCommunicationRestrictionReason int reason,
             @NonNull @CallbackExecutor Executor executor,
             @SatelliteResult @NonNull Consumer<Integer> resultListener) {
+        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+            throw new IllegalArgumentException("Invalid subscription ID");
+        }
+
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null) {
@@ -1759,7 +1757,7 @@
                                 () -> resultListener.accept(result)));
                     }
                 };
-                telephony.removeSatelliteAttachRestrictionForCarrier(mSubId, reason, errorCallback);
+                telephony.removeSatelliteAttachRestrictionForCarrier(subId, reason, errorCallback);
             } else {
                 throw new IllegalStateException("telephony service is null.");
             }
@@ -1773,34 +1771,40 @@
      * Get reasons for disallowing satellite attach, as requested by
      * {@link #addSatelliteAttachRestrictionForCarrier(int, Executor, Consumer)}
      *
+     * @param subId The subscription ID of the carrier.
      * @return Set of reasons for disallowing satellite communication.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
-     * @hide
+     * @throws IllegalArgumentException if the subscription is invalid.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
     @SatelliteCommunicationRestrictionReason
-    public @NonNull Set<Integer> getSatelliteAttachRestrictionReasonsForCarrier() {
+    @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
+    @NonNull public Set<Integer> getSatelliteAttachRestrictionReasonsForCarrier(int subId) {
+        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+            throw new IllegalArgumentException("Invalid subscription ID");
+        }
+
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null) {
                 int[] receivedArray =
-                        telephony.getSatelliteAttachRestrictionReasonsForCarrier(mSubId);
+                        telephony.getSatelliteAttachRestrictionReasonsForCarrier(subId);
                 if (receivedArray.length == 0) {
-                    logd("received set is empty, create empty set");
+                    logd("receivedArray is empty, create empty set");
                     return new HashSet<>();
                 } else {
                     return Arrays.stream(receivedArray).boxed().collect(Collectors.toSet());
                 }
             } else {
-                throw new IllegalStateException("telephony service is null.");
+                throw new IllegalStateException("Telephony service is null.");
             }
         } catch (RemoteException ex) {
             loge("getSatelliteAttachRestrictionReasonsForCarrier() RemoteException: " + ex);
             ex.rethrowFromSystemServer();
         }
-        return null;
+        return new HashSet<>();
     }
 
     private static ITelephony getITelephony() {
diff --git a/telephony/java/android/telephony/satellite/stub/ISatellite.aidl b/telephony/java/android/telephony/satellite/stub/ISatellite.aidl
index 02661de..0fcd0d6 100644
--- a/telephony/java/android/telephony/satellite/stub/ISatellite.aidl
+++ b/telephony/java/android/telephony/satellite/stub/ISatellite.aidl
@@ -392,7 +392,11 @@
      *
      * @param simSlot Indicates the SIM slot to which this API will be applied. The modem will use
      *                this information to determine the relevant carrier.
-     * @param plmnList The list of roaming PLMN used for connecting to satellite networks.
+     * @param carrierPlmnList The list of roaming PLMN used for connecting to satellite networks
+     *                        supported by user subscription.
+     * @param allSatellitePlmnList Modem should use the allSatellitePlmnList to identify satellite
+     *                             PLMNs that are not supported by the carrier and make sure not to
+     *                             attach to them.
      * @param resultCallback The callback to receive the error code result of the operation.
      *
      * Valid error codes returned:
@@ -404,8 +408,8 @@
      *   SatelliteError:RADIO_NOT_AVAILABLE
      *   SatelliteError:REQUEST_NOT_SUPPORTED
      */
-    void setSatellitePlmn(int simSlot, in List<String> plmnList,
-            in IIntegerConsumer resultCallback);
+    void setSatellitePlmn(int simSlot, in List<String> carrierPlmnList,
+            in List<String> allSatellitePlmnList, in IIntegerConsumer resultCallback);
 
     /**
      * Enable or disable satellite in the cellular modem associated with a carrier.
diff --git a/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java b/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java
index 6451daf..a9c09c9 100644
--- a/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java
+++ b/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java
@@ -214,12 +214,12 @@
         }
 
         @Override
-        public void setSatellitePlmn(int simSlot, List<String> plmnList,
-                IIntegerConsumer errorCallback)
+        public void setSatellitePlmn(int simSlot, List<String> carrierPlmnList,
+                List<String> devicePlmnList, IIntegerConsumer errorCallback)
                 throws RemoteException {
             executeMethodAsync(
-                    () -> SatelliteImplBase.this
-                            .setSatellitePlmn(simSlot, plmnList, errorCallback),
+                    () -> SatelliteImplBase.this.setSatellitePlmn(
+                            simSlot, carrierPlmnList, devicePlmnList, errorCallback),
                     "setSatellitePlmn");
         }
 
@@ -655,13 +655,15 @@
      * SIM profile. Acquisition of satellite based system is lower priority to terrestrial
      * networks. UE shall make all attempts to acquire terrestrial service prior to camping on
      * satellite LTE service.
-     * This method must only take effect if {@link #setSatelliteEnabledForCarrier} is {@code true},
-     * and return an error otherwise.
      *
      * @param simLogicalSlotIndex Indicates the SIM logical slot index to which this API will be
      * applied. The modem will use this information to determine the relevant carrier.
      * @param errorCallback The callback to receive the error code result of the operation.
-     * @param plmnList The list of roaming PLMN used for connecting to satellite networks.
+     * @param carrierPlmnList The list of roaming PLMN used for connecting to satellite networks
+     *                        supported by user subscription.
+     * @param allSatellitePlmnList Modem should use the allSatellitePlmnList to identify satellite
+     *                             PLMNs that are not supported by the carrier and make sure not to
+     *                             attach to them.
      *
      * Valid error codes returned:
      *   SatelliteError:NONE
@@ -672,7 +674,8 @@
      *   SatelliteError:RADIO_NOT_AVAILABLE
      *   SatelliteError:REQUEST_NOT_SUPPORTED
      */
-    public void setSatellitePlmn(@NonNull int simLogicalSlotIndex, @NonNull List<String> plmnList,
+    public void setSatellitePlmn(@NonNull int simLogicalSlotIndex,
+            @NonNull List<String> carrierPlmnList, @NonNull List<String> allSatellitePlmnList,
             @NonNull IIntegerConsumer errorCallback) {
         // stub implementation
     }
diff --git a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java
index f7719a6..d176b5e 100644
--- a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java
+++ b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java
@@ -38,6 +38,10 @@
     private static final boolean SKIP_METHOD_LOG = "1".equals(System.getenv(
             "HOSTTEST_SKIP_METHOD_LOG"));
 
+    /** If true, we won't print class load log. */
+    private static final boolean SKIP_CLASS_LOG = "1".equals(System.getenv(
+            "HOSTTEST_SKIP_CLASS_LOG"));
+
     /** If true, we won't perform non-stub method direct call check. */
     private static final boolean SKIP_NON_STUB_METHOD_CHECK = "1".equals(System.getenv(
             "HOSTTEST_SKIP_NON_STUB_METHOD_CHECK"));
@@ -57,17 +61,35 @@
     }
 
     /**
-     * Called from methods with FilterPolicy.Log.
+     * Trampoline method for method-call-hook.
+     */
+    public static void callMethodCallHook(
+            Class<?> methodClass,
+            String methodName,
+            String methodDescriptor,
+            String callbackMethod
+    ) {
+        callStaticMethodByName(callbackMethod, "method call hook", methodClass,
+                methodName, methodDescriptor);
+    }
+
+    /**
+     * I can be used as
+     * {@code --default-method-call-hook
+     * com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall}.
+     *
+     * It logs every single methods called.
      */
     public static void logMethodCall(
-            String methodClass,
+            Class<?> methodClass,
             String methodName,
             String methodDescriptor
     ) {
         if (SKIP_METHOD_LOG) {
             return;
         }
-        logPrintStream.println("# " + methodClass + "." + methodName + methodDescriptor);
+        logPrintStream.println("# method called: " + methodClass.getCanonicalName() + "."
+                + methodName + methodDescriptor);
     }
 
     private static final StackWalker sStackWalker =
@@ -146,52 +168,81 @@
         logPrintStream.println("! Class loaded: " + loadedClass.getCanonicalName()
                 + " calling hook " + callbackMethod);
 
-        // Forward the call to callbackMethod.
-        final int lastPeriod = callbackMethod.lastIndexOf(".");
-        final String className = callbackMethod.substring(0, lastPeriod);
-        final String methodName = callbackMethod.substring(lastPeriod + 1);
+        callStaticMethodByName(callbackMethod, "class load hook", loadedClass);
+    }
 
-        if (lastPeriod < 0 || className.isEmpty() || methodName.isEmpty()) {
+    private static void callStaticMethodByName(String classAndMethodName,
+            String description, Object... args) {
+        // Forward the call to callbackMethod.
+        final int lastPeriod = classAndMethodName.lastIndexOf(".");
+
+        if ((lastPeriod) < 0 || (lastPeriod == classAndMethodName.length() - 1)) {
             throw new HostTestException(String.format(
-                    "Unable to find class load hook: malformed method name \"%s\"",
-                    callbackMethod));
+                    "Unable to find %s: malformed method name \"%s\"",
+                    description,
+                    classAndMethodName));
         }
 
+        final String className = classAndMethodName.substring(0, lastPeriod);
+        final String methodName = classAndMethodName.substring(lastPeriod + 1);
+
         Class<?> clazz = null;
         try {
             clazz = Class.forName(className);
         } catch (Exception e) {
             throw new HostTestException(String.format(
-                    "Unable to find class load hook: Class %s not found", className), e);
+                    "Unable to find %s: Class %s not found",
+                    description,
+                    className), e);
         }
         if (!Modifier.isPublic(clazz.getModifiers())) {
             throw new HostTestException(String.format(
-                    "Unable to find class load hook: Class %s must be public", className));
+                    "Unable to find %s: Class %s must be public",
+                    description,
+                    className));
+        }
+
+        Class<?>[] argTypes = new Class[args.length];
+        for (int i = 0; i < args.length; i++) {
+            argTypes[i] = args[i].getClass();
         }
 
         Method method = null;
         try {
-            method = clazz.getMethod(methodName, Class.class);
+            method = clazz.getMethod(methodName, argTypes);
         } catch (Exception e) {
             throw new HostTestException(String.format(
-                    "Unable to find class load hook: class %s doesn't have method %s"
-                    + " (method must take exactly one parameter of type Class, and public static)",
-                    className,
-                    methodName), e);
+                    "Unable to find %s: class %s doesn't have method %s"
+                            + " (method must take exactly one parameter of type Class,"
+                            + " and public static)",
+                    description, className, methodName), e);
         }
         if (!(Modifier.isPublic(method.getModifiers())
                 && Modifier.isStatic(method.getModifiers()))) {
             throw new HostTestException(String.format(
-                    "Unable to find class load hook: Method %s in class %s must be public static",
-                    methodName, className));
+                    "Unable to find %s: Method %s in class %s must be public static",
+                    description, methodName, className));
         }
         try {
-            method.invoke(null, loadedClass);
+            method.invoke(null, args);
         } catch (Exception e) {
             throw new HostTestException(String.format(
-                    "Unable to invoke class load hook %s.%s",
-                    className,
-                    methodName), e);
+                    "Unable to invoke %s %s.%s",
+                    description, className, methodName), e);
         }
     }
+
+    /**
+     * I can be used as
+     * {@code --default-class-load-hook
+     * com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded}.
+     *
+     * It logs every loaded class.
+     */
+    public static void logClassLoaded(Class<?> clazz) {
+        if (SKIP_CLASS_LOG) {
+            return;
+        }
+        logPrintStream.println("# class loaded: " + clazz.getCanonicalName());
+    }
 }
diff --git a/tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt b/tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt
index 828d2a3..3f87527 100644
--- a/tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt
+++ b/tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt
@@ -6,8 +6,10 @@
 --enable-non-stub-method-check
 # --no-non-stub-method-check
 
-# --enable-method-logging
-
+#--default-method-call-hook
+#    com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+#--default-class-load-hook
+#    com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
 
 # Standard annotations.
 # Note, each line is a single argument, so we need newlines after each `--xxx-annotation`.
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
index 8db4b69..7531759 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
@@ -17,6 +17,7 @@
 
 import com.android.hoststubgen.asm.ClassNodes
 import com.android.hoststubgen.filters.AnnotationBasedFilter
+import com.android.hoststubgen.filters.DefaultHookInjectingFilter
 import com.android.hoststubgen.filters.ClassWidePolicyPropagatingFilter
 import com.android.hoststubgen.filters.ConstantFilter
 import com.android.hoststubgen.filters.FilterPolicy
@@ -156,22 +157,29 @@
         // This is used when a member (methods, fields, nested classes) don't get any polices
         // from upper filters. e.g. when a method has no annotations, then this filter will apply
         // the class-wide policy, if any. (if not, we'll fall back to the above filter.)
-        val classWidePropagator = ClassWidePolicyPropagatingFilter(filter)
+        filter = ClassWidePolicyPropagatingFilter(filter)
+
+        // Inject default hooks from options.
+        filter = DefaultHookInjectingFilter(
+            options.defaultClassLoadHook,
+            options.defaultMethodCallHook,
+            filter
+        )
 
         // Next, Java annotation based filter.
         filter = AnnotationBasedFilter(
-                errors,
-                allClasses,
-                options.stubAnnotations,
-                options.keepAnnotations,
-                options.stubClassAnnotations,
-                options.keepClassAnnotations,
-                options.throwAnnotations,
-                options.removeAnnotations,
-                options.substituteAnnotations,
-                options.nativeSubstituteAnnotations,
-                options.classLoadHookAnnotations,
-                classWidePropagator
+            errors,
+            allClasses,
+            options.stubAnnotations,
+            options.keepAnnotations,
+            options.stubClassAnnotations,
+            options.keepClassAnnotations,
+            options.throwAnnotations,
+            options.removeAnnotations,
+            options.substituteAnnotations,
+            options.nativeSubstituteAnnotations,
+            options.classLoadHookAnnotations,
+            filter
         )
 
         // Next, "text based" filter, which allows to override polices without touching
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
index 9a54ecf..bbb7dab 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
@@ -48,6 +48,9 @@
         var nativeSubstituteAnnotations: MutableSet<String> = mutableSetOf(),
         var classLoadHookAnnotations: MutableSet<String> = mutableSetOf(),
 
+        var defaultClassLoadHook: String? = null,
+        var defaultMethodCallHook: String? = null,
+
         var intersectStubJars: MutableSet<String> = mutableSetOf(),
 
         var policyOverrideFile: String? = null,
@@ -63,8 +66,6 @@
         var enablePreTrace: Boolean = false,
         var enablePostTrace: Boolean = false,
 
-        var enableMethodLogging: Boolean = false,
-
         var enableNonStubMethodCallDetection: Boolean = true,
 ) {
     companion object {
@@ -151,6 +152,12 @@
                         ret.classLoadHookAnnotations +=
                             ensureUniqueAnnotation(ai.nextArgRequired(arg))
 
+                    "--default-class-load-hook" ->
+                        ret.defaultClassLoadHook = ai.nextArgRequired(arg)
+
+                    "--default-method-call-hook" ->
+                        ret.defaultMethodCallHook = ai.nextArgRequired(arg)
+
                     "--intersect-stub-jar" ->
                         ret.intersectStubJars += ai.nextArgRequired(arg).ensureFileExists()
 
@@ -167,9 +174,6 @@
                     "--enable-post-trace" -> ret.enablePostTrace = true
                     "--no-post-trace" -> ret.enablePostTrace = false
 
-                    "--enable-method-logging" -> ret.enableMethodLogging = true
-                    "--no-method-logging" -> ret.enableMethodLogging = false
-
                     "--enable-non-stub-method-check" -> ret.enableNonStubMethodCallDetection = true
                     "--no-non-stub-method-check" -> ret.enableNonStubMethodCallDetection = false
 
@@ -290,6 +294,8 @@
               substituteAnnotations=$substituteAnnotations,
               nativeSubstituteAnnotations=$nativeSubstituteAnnotations,
               classLoadHookAnnotations=$classLoadHookAnnotations,
+              defaultClassLoadHook=$defaultClassLoadHook,
+              defaultMethodCallHook=$defaultMethodCallHook,
               intersectStubJars=$intersectStubJars,
               policyOverrideFile=$policyOverrideFile,
               defaultPolicy=$defaultPolicy,
@@ -299,7 +305,6 @@
               enableClassChecker=$enableClassChecker,
               enablePreTrace=$enablePreTrace,
               enablePostTrace=$enablePostTrace,
-              enableMethodLogging=$enableMethodLogging,
               enableNonStubMethodCallDetection=$enableNonStubMethodCallDetection,
             }
             """.trimIndent()
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt
index 9fbd6d0..f75062b 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt
@@ -31,3 +31,31 @@
     // Remove surrounding whitespace.
     return uncommented.trim()
 }
+
+/**
+ * Concatenate list [a] and [b] and return it. As an optimization, it returns an input
+ * [List] as-is if the other [List] is empty, so do not modify input [List]'s.
+ */
+fun <T> addLists(a: List<T>, b: List<T>): List<T> {
+    if (a.isEmpty()) {
+        return b
+    }
+    if (b.isEmpty()) {
+        return a
+    }
+    return a + b
+}
+
+/**
+ * Add element [b] to list [a] if [b] is not null. Otherwise, just return [a].
+ * (because the method may return [a] as-is, do not modify it after passing it.)
+ */
+fun <T> addNonNullElement(a: List<T>, b: T?): List<T> {
+    if (b == null) {
+        return a
+    }
+    if (a.isEmpty()) {
+        return listOf(b)
+    }
+    return a + b
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt
index 454569d..3f492e8 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt
@@ -19,6 +19,7 @@
 import com.android.hoststubgen.HostStubGenErrors
 import com.android.hoststubgen.HostStubGenInternalException
 import com.android.hoststubgen.InvalidAnnotationException
+import com.android.hoststubgen.addNonNullElement
 import com.android.hoststubgen.asm.ClassNodes
 import com.android.hoststubgen.asm.findAnnotationValueAsString
 import com.android.hoststubgen.asm.findAnyAnnotation
@@ -253,14 +254,14 @@
         return null
     }
 
-    override fun getClassLoadHook(className: String): String? {
-        classes.getClass(className).let { cn ->
+    override fun getClassLoadHooks(className: String): List<String> {
+        val e = classes.getClass(className).let { cn ->
             findAnyAnnotation(classLoadHookAnnotations,
                 cn.visibleAnnotations, cn.invisibleAnnotations)?.let { an ->
-                return getAnnotationField(an, "value")?.toHumanReadableMethodName()
+                getAnnotationField(an, "value")?.toHumanReadableMethodName()
             }
         }
-        return null
+        return addNonNullElement(super.getClassLoadHooks(className), e)
     }
 
     private data class MethodKey(val name: String, val desc: String)
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt
new file mode 100644
index 0000000..d771003
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.hoststubgen.filters
+
+import com.android.hoststubgen.addLists
+
+class DefaultHookInjectingFilter(
+    defaultClassLoadHook: String?,
+    defaultMethodCallHook: String?,
+    fallback: OutputFilter
+) : DelegatingFilter(fallback) {
+    /**
+     * Create a List containing a single element [e], if e != null. Otherwise, returns
+     * an empty list.
+     */
+    private fun toSingleList(e: String?): List<String> {
+        if (e == null) {
+            return emptyList()
+        }
+        return listOf(e)
+    }
+
+    private val defaultClassLoadHookAsList: List<String> = toSingleList(defaultClassLoadHook)
+    private val defaultMethodCallHookAsList: List<String> = toSingleList(defaultMethodCallHook)
+
+    override fun getClassLoadHooks(className: String): List<String> {
+        return addLists(super.getClassLoadHooks(className), defaultClassLoadHookAsList)
+    }
+
+    override fun getMethodCallHooks(
+        className: String,
+        methodName: String,
+        descriptor: String
+    ): List<String> {
+        return addLists(
+            super.getMethodCallHooks(className, methodName, descriptor),
+            defaultMethodCallHookAsList,
+            )
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt
index f0763c4..45f61c5 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt
@@ -66,7 +66,15 @@
         return fallback.getNativeSubstitutionClass(className)
     }
 
-    override fun getClassLoadHook(className: String): String? {
-        return fallback.getClassLoadHook(className)
+    override fun getClassLoadHooks(className: String): List<String> {
+        return fallback.getClassLoadHooks(className)
+    }
+
+    override fun getMethodCallHooks(
+        className: String,
+        methodName: String,
+        descriptor: String
+    ): List<String> {
+        return fallback.getMethodCallHooks(className, methodName, descriptor)
     }
 }
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt
index f3551d4..5659a35 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt
@@ -16,6 +16,7 @@
 package com.android.hoststubgen.filters
 
 import com.android.hoststubgen.UnknownApiException
+import com.android.hoststubgen.addNonNullElement
 import com.android.hoststubgen.asm.ClassNodes
 import com.android.hoststubgen.asm.toHumanReadableClassName
 import com.android.hoststubgen.asm.toHumanReadableMethodName
@@ -127,9 +128,9 @@
         mNativeSubstitutionClasses[getClassKey(from)] = to.toHumanReadableClassName()
     }
 
-    override fun getClassLoadHook(className: String): String? {
-        return mClassLoadHooks[getClassKey(className)]
-            ?: super.getClassLoadHook(className)
+    override fun getClassLoadHooks(className: String): List<String> {
+        return addNonNullElement(super.getClassLoadHooks(className),
+            mClassLoadHooks[getClassKey(className)])
     }
 
     fun setClassLoadHook(className: String, methodName: String) {
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt
index 392ee4b..3df16ff 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt
@@ -71,11 +71,22 @@
     }
 
     /**
-     * Return a "class load hook" method name for a given class.
+     * Return a "class load hook" class name for a given class.
      *
      * (which corresponds to @HostSideTestClassLoadHook of the standard annotations.)
      */
-    open fun getClassLoadHook(className: String): String? {
-        return null
+    open fun getClassLoadHooks(className: String): List<String> {
+        return emptyList()
+    }
+
+    /**
+     * Return the "method call hook" class name.
+     *
+     * The class has to have a function with the following signature:
+     * `public static void onMethodCalled(Class<?> clazz, String name, String descriptor)`.
+     */
+    open fun getMethodCallHooks(className: String, methodName: String, descriptor: String):
+            List<String> {
+        return emptyList()
     }
 }
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt
index ac06886..57b6689 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt
@@ -45,7 +45,7 @@
         return policy.needsInImpl
     }
 
-    private var classLoadHookMethod: String? = null
+    private var classLoadHooks: List<String> = emptyList()
 
     override fun visit(
         version: Int,
@@ -57,22 +57,22 @@
     ) {
         super.visit(version, access, name, signature, superName, interfaces)
 
-        classLoadHookMethod = filter.getClassLoadHook(currentClassName)
+        classLoadHooks = filter.getClassLoadHooks(currentClassName)
 
         // classLoadHookMethod is non-null, then we need to inject code to call it
         // in the class initializer.
         // If the target class already has a class initializer, then we need to inject code to it.
         // Otherwise, we need to create one.
 
-        classLoadHookMethod?.let { callback ->
-            log.d("  ClassLoadHook: $callback")
+        if (classLoadHooks.isNotEmpty()) {
+            log.d("  ClassLoadHooks: $classLoadHooks")
             if (!classes.hasClassInitializer(currentClassName)) {
-                injectClassLoadHook(callback)
+                injectClassLoadHook()
             }
         }
     }
 
-    private fun injectClassLoadHook(callback: String) {
+    private fun injectClassLoadHook() {
         writeRawMembers {
             // Create a class initializer to call onClassLoaded().
             // Each class can only have at most one class initializer, but the base class
@@ -87,7 +87,7 @@
                 // Method prologue
                 mv.visitCode()
 
-                writeClassLoadHookCall(mv)
+                writeClassLoadHookCalls(mv)
                 mv.visitInsn(Opcodes.RETURN)
 
                 // Method epilogue
@@ -97,21 +97,23 @@
         }
     }
 
-    private fun writeClassLoadHookCall(mv: MethodVisitor) {
-        // First argument: the class type.
-        mv.visitLdcInsn(Type.getType("L" + currentClassName + ";"))
+    private fun writeClassLoadHookCalls(mv: MethodVisitor) {
+        classLoadHooks.forEach { classLoadHook ->
+            // First argument: the class type.
+            mv.visitLdcInsn(Type.getType("L" + currentClassName + ";"))
 
-        // Second argument: method name
-        mv.visitLdcInsn(classLoadHookMethod)
+            // Second argument: method name
+            mv.visitLdcInsn(classLoadHook)
 
-        // Call HostTestUtils.onClassLoaded().
-        mv.visitMethodInsn(
-            Opcodes.INVOKESTATIC,
-            HostTestUtils.CLASS_INTERNAL_NAME,
-            "onClassLoaded",
-            "(Ljava/lang/Class;Ljava/lang/String;)V",
-            false
-        )
+            // Call HostTestUtils.onClassLoaded().
+            mv.visitMethodInsn(
+                Opcodes.INVOKESTATIC,
+                HostTestUtils.CLASS_INTERNAL_NAME,
+                "onClassLoaded",
+                "(Ljava/lang/Class;Ljava/lang/String;)V",
+                false
+            )
+        }
     }
 
     override fun updateAccessFlags(
@@ -138,20 +140,22 @@
         var innerVisitor = superVisitor
 
         //  If method logging is enabled, inject call to the logging method.
-        if (options.enableMethodLogging) {
-            innerVisitor = LogInjectingMethodAdapter(
-                    access,
-                    name,
-                    descriptor,
-                    signature,
-                    exceptions,
-                    innerVisitor,
-                    )
+        val methodCallHooks = filter.getMethodCallHooks(currentClassName, name, descriptor)
+        if (methodCallHooks.isNotEmpty()) {
+            innerVisitor = MethodCallHookInjectingAdapter(
+                access,
+                name,
+                descriptor,
+                signature,
+                exceptions,
+                innerVisitor,
+                methodCallHooks,
+                )
         }
 
         // If this class already has a class initializer and a class load hook is needed, then
         // we inject code.
-        if (classLoadHookMethod != null &&
+        if (classLoadHooks.isNotEmpty() &&
             name == CLASS_INITIALIZER_NAME &&
             descriptor == CLASS_INITIALIZER_DESC) {
             innerVisitor = ClassLoadHookInjectingMethodAdapter(
@@ -283,29 +287,37 @@
     }
 
     /**
-     * A method adapter that injects a call to HostTestUtils.logMethodCall() to every method.
+     * Inject calls to the method call hooks.
      *
      * Note, when the target method is a constructor, it may contain calls to `super(...)` or
      * `this(...)`. The logging code will be injected *before* such calls.
      */
-    private inner class LogInjectingMethodAdapter(
+    private inner class MethodCallHookInjectingAdapter(
             access: Int,
             val name: String,
             val descriptor: String,
             signature: String?,
             exceptions: Array<String>?,
-            next: MethodVisitor?
+            next: MethodVisitor?,
+            val hooks: List<String>,
     ) : MethodVisitor(OPCODE_VERSION, next) {
         override fun visitCode() {
             super.visitCode()
-            visitLdcInsn(currentClassName)
-            visitLdcInsn(name)
-            visitLdcInsn(descriptor)
-            visitMethodInsn(Opcodes.INVOKESTATIC,
+
+            hooks.forEach { hook ->
+                mv.visitLdcInsn(Type.getType("L" + currentClassName + ";"))
+                visitLdcInsn(name)
+                visitLdcInsn(descriptor)
+                visitLdcInsn(hook)
+
+                visitMethodInsn(
+                    Opcodes.INVOKESTATIC,
                     HostTestUtils.CLASS_INTERNAL_NAME,
-                    "logMethodCall",
-                    "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
-                    false)
+                    "callMethodCallHook",
+                    "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
+                    false
+                )
+            }
         }
     }
 
@@ -323,7 +335,7 @@
         override fun visitCode() {
             super.visitCode()
 
-            writeClassLoadHookCall(this)
+            writeClassLoadHookCalls(this)
         }
     }
 
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp b/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp
index 8c76a61..05d6a43 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp
@@ -53,6 +53,46 @@
     ],
 }
 
+// Same as "hoststubgen-test-tiny-framework-host", but with more options, to test more hoststubgen
+// features.
+java_genrule_host {
+    name: "hoststubgen-test-tiny-framework-host-ext",
+    defaults: ["hoststubgen-command-defaults"],
+    cmd: hoststubgen_common_options +
+        "--in-jar $(location :hoststubgen-test-tiny-framework) " +
+        "--policy-override-file $(location policy-override-tiny-framework.txt) " +
+
+        // More options.
+        "--default-method-call-hook com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall " +
+        "--default-class-load-hook com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded ",
+    srcs: [
+        ":hoststubgen-test-tiny-framework",
+        "policy-override-tiny-framework.txt",
+    ],
+}
+
+java_genrule_host {
+    name: "hoststubgen-test-tiny-framework-host-ext-stub",
+    cmd: "cp $(in) $(out)",
+    srcs: [
+        ":hoststubgen-test-tiny-framework-host-ext{host_stub.jar}",
+    ],
+    out: [
+        "host_stub.jar",
+    ],
+}
+
+java_genrule_host {
+    name: "hoststubgen-test-tiny-framework-host-ext-impl",
+    cmd: "cp $(in) $(out)",
+    srcs: [
+        ":hoststubgen-test-tiny-framework-host-ext{host_impl.jar}",
+    ],
+    out: [
+        "host_impl.jar",
+    ],
+}
+
 // Compile the test jar, using 2 rules.
 // 1. Build the test against the stub.
 java_library_host {
@@ -123,6 +163,30 @@
     visibility: ["//visibility:private"],
 }
 
+java_genrule_host {
+    name: "hoststubgen-test-tiny-framework-host-ext-stub-dump",
+    defaults: ["hoststubgen-jar-dump-defaults"],
+    srcs: [
+        ":hoststubgen-test-tiny-framework-host-ext-stub",
+    ],
+    out: [
+        "12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt",
+    ],
+    visibility: ["//visibility:private"],
+}
+
+java_genrule_host {
+    name: "hoststubgen-test-tiny-framework-host-ext-impl-dump",
+    defaults: ["hoststubgen-jar-dump-defaults"],
+    srcs: [
+        ":hoststubgen-test-tiny-framework-host-ext-impl",
+    ],
+    out: [
+        "13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt",
+    ],
+    visibility: ["//visibility:private"],
+}
+
 // Run it with `atest`. Compare the dump of the jar files to the golden output.
 python_test_host {
     name: "tiny-framework-dump-test",
@@ -136,6 +200,8 @@
         "hoststubgen-test-tiny-framework-host-stub-dump",
         "hoststubgen-test-tiny-framework-host-impl-dump",
         "hoststubgen-test-tiny-framework-orig-dump",
+        "hoststubgen-test-tiny-framework-host-ext-stub-dump",
+        "hoststubgen-test-tiny-framework-host-ext-impl-dump",
     ],
     test_suites: ["general-tests"],
 }
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/diff-and-update-golden.sh b/tools/hoststubgen/hoststubgen/test-tiny-framework/diff-and-update-golden.sh
index 4d58869..639fb16 100755
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/diff-and-update-golden.sh
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/diff-and-update-golden.sh
@@ -112,7 +112,7 @@
 
 if (( $three_way )) ; then
   echo "# Running 3-way diff with meld..."
-  run meld ${files[*]} &
+  run meld ${files[0]} ${files[1]} ${files[2]} &
 fi
 
 if (( $two_way )) ; then
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
new file mode 100644
index 0000000..43ceec4
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt
@@ -0,0 +1,837 @@
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
+  Compiled from "TinyFrameworkCallerCheck.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
+  minor version: 0
+  major version: 61
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 2, attributes: 4
+  private com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl();
+    descriptor: ()V
+    flags: (0x0002) ACC_PRIVATE
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+
+  public static int getOneStub();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=0, args_size=0
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestStub
+}
+InnerClasses:
+  private static #x= #x of #x;           // Impl=class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl of class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
+SourceFile: "TinyFrameworkCallerCheck.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck.class
+  Compiled from "TinyFrameworkCallerCheck.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 3, attributes: 5
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+
+  public static int getOne_withCheck();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=0, args_size=0
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+
+  public static int getOne_noCheck();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=0, args_size=0
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+}
+InnerClasses:
+  private static #x= #x of #x;          // Impl=class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl of class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
+SourceFile: "TinyFrameworkCallerCheck.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations.class
+  Compiled from "TinyFrameworkClassAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 5, attributes: 3
+  public int stub;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestStub
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestStub
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestStub
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+
+  public static int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+
+  public java.lang.String visibleButUsesUnsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestStub
+}
+SourceFile: "TinyFrameworkClassAnnotations.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestStub
+  x: #x(#x=s#x)
+    android.hosttest.annotation.HostSideTestClassLoadHook(
+      value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+    )
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations.class
+  Compiled from "TinyFrameworkClassClassWideAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassWideAnnotations
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 3, methods: 8, attributes: 3
+  public int stub;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public int keep;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public int remove;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassWideAnnotations();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+
+  public int addOneInner(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+
+  public void toBeRemoved(java.lang.String);
+    descriptor: (Ljava/lang/String;)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+
+  public static int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+
+  public java.lang.String unsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+
+  public java.lang.String visibleButUsesUnsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+}
+SourceFile: "TinyFrameworkClassClassWideAnnotations.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.class
+  Compiled from "TinyFrameworkClassLoadHook.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 3, attributes: 3
+  public static final java.util.Set<java.lang.Class<?>> sLoadedClasses;
+    descriptor: Ljava/util/Set;
+    flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/Set<Ljava/lang/Class<*>;>;
+
+  private com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook();
+    descriptor: ()V
+    flags: (0x0002) ACC_PRIVATE
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+
+  public static void onClassLoaded(java.lang.Class<?>);
+    descriptor: (Ljava/lang/Class;)V
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+    Signature: #x                          // (Ljava/lang/Class<*>;)V
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=3, locals=0, args_size=0
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+}
+SourceFile: "TinyFrameworkClassLoadHook.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.class
+  Compiled from "TinyFrameworkClassWithInitializer.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializer
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 2, attributes: 3
+  public static boolean sInitialized;
+    descriptor: Z
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializer();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=3, locals=0, args_size=0
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+}
+SourceFile: "TinyFrameworkClassWithInitializer.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  x: #x(#x=s#x)
+    android.hosttest.annotation.HostSideTestClassLoadHook(
+      value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+    )
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.class
+  Compiled from "TinyFrameworkExceptionTester.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 2, attributes: 3
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+
+  public static int testException();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=0, args_size=0
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+}
+SourceFile: "TinyFrameworkExceptionTester.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.class
+  Compiled from "TinyFrameworkForTextPolicy.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPolicy
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 5, attributes: 2
+  public int stub;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPolicy();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+
+  public static int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+
+  public java.lang.String visibleButUsesUnsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+}
+SourceFile: "TinyFrameworkForTextPolicy.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.class
+  Compiled from "TinyFrameworkNative.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 5, attributes: 3
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+
+  public static native int nativeAddTwo(int);
+    descriptor: (I)I
+    flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+
+  public static int nativeAddTwo_should_be_like_this(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+
+  public static native long nativeLongPlus(long, long);
+    descriptor: (JJ)J
+    flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+
+  public static long nativeLongPlus_should_be_like_this(long, long);
+    descriptor: (JJ)J
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=4, args_size=2
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+}
+SourceFile: "TinyFrameworkNative.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+  x: #x(#x=s#x)
+    android.hosttest.annotation.HostSideTestNativeSubstitutionClass(
+      value="TinyFrameworkNative_host"
+    )
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 1, attributes: 4
+  public int value;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass(int);
+    descriptor: (I)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+}
+InnerClasses:
+  public static #x= #x of #x;            // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$InnerClass
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 1, attributes: 5
+  public int value;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$InnerClass(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses);
+    descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+}
+InnerClasses:
+  public #x= #x of #x;                   // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 2, attributes: 5
+  public int value;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+
+  public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=0, args_size=0
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+}
+InnerClasses:
+  public static #x= #x of #x;            // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass extends com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
+  super_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+  interfaces: 0, fields: 0, methods: 1, attributes: 4
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass(int);
+    descriptor: (I)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+}
+InnerClasses:
+  public static #x= #x of #x;            // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;            // SubClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 4, attributes: 5
+  public final java.util.function.Supplier<java.lang.Integer> mSupplier;
+    descriptor: Ljava/util/function/Supplier;
+    flags: (0x0011) ACC_PUBLIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+  public static final java.util.function.Supplier<java.lang.Integer> sSupplier;
+    descriptor: Ljava/util/function/Supplier;
+    flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+
+  public java.util.function.Supplier<java.lang.Integer> getSupplier();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+  public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=0, args_size=0
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=3, locals=0, args_size=0
+         x: new           #x                 // class java/lang/RuntimeException
+         x: dup
+         x: ldc           #x                 // String Stub!
+         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         x: athrow
+}
+InnerClasses:
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+  public static #x= #x of #x;           // SubClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;           // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;           // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public #x= #x of #x;                  // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
new file mode 100644
index 0000000..874789e
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt
@@ -0,0 +1,2348 @@
+## Class: android/hosttest/annotation/HostSideTestClassLoadHook.class
+  Compiled from "HostSideTestClassLoadHook.java"
+public interface android.hosttest.annotation.HostSideTestClassLoadHook extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 61
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestClassLoadHook
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 2, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class android/hosttest/annotation/HostSideTestClassLoadHook
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public abstract java.lang.String value();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+}
+SourceFile: "HostSideTestClassLoadHook.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+  x: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestKeep.class
+  Compiled from "HostSideTestKeep.java"
+public interface android.hosttest.annotation.HostSideTestKeep extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 61
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestKeep
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class android/hosttest/annotation/HostSideTestKeep
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "HostSideTestKeep.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+  x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestNativeSubstitutionClass.class
+  Compiled from "HostSideTestNativeSubstitutionClass.java"
+public interface android.hosttest.annotation.HostSideTestNativeSubstitutionClass extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 61
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestNativeSubstitutionClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 2, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class android/hosttest/annotation/HostSideTestNativeSubstitutionClass
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public abstract java.lang.String value();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+}
+SourceFile: "HostSideTestNativeSubstitutionClass.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+  x: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestRemove.class
+  Compiled from "HostSideTestRemove.java"
+public interface android.hosttest.annotation.HostSideTestRemove extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 61
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestRemove
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class android/hosttest/annotation/HostSideTestRemove
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "HostSideTestRemove.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+  x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestStub.class
+  Compiled from "HostSideTestStub.java"
+public interface android.hosttest.annotation.HostSideTestStub extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 61
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestStub
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class android/hosttest/annotation/HostSideTestStub
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "HostSideTestStub.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+  x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestSubstitute.class
+  Compiled from "HostSideTestSubstitute.java"
+public interface android.hosttest.annotation.HostSideTestSubstitute extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 61
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestSubstitute
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 2, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class android/hosttest/annotation/HostSideTestSubstitute
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public abstract java.lang.String suffix();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+}
+SourceFile: "HostSideTestSubstitute.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+  x: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.METHOD]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestThrow.class
+  Compiled from "HostSideTestThrow.java"
+public interface android.hosttest.annotation.HostSideTestThrow extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 61
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestThrow
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class android/hosttest/annotation/HostSideTestThrow
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "HostSideTestThrow.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+  x: #x(#x=[e#x.#x,e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestWholeClassKeep.class
+  Compiled from "HostSideTestWholeClassKeep.java"
+public interface android.hosttest.annotation.HostSideTestWholeClassKeep extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 61
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestWholeClassKeep
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class android/hosttest/annotation/HostSideTestWholeClassKeep
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "HostSideTestWholeClassKeep.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+  x: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestWholeClassStub.class
+  Compiled from "HostSideTestWholeClassStub.java"
+public interface android.hosttest.annotation.HostSideTestWholeClassStub extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 61
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestWholeClassStub
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 2
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class android/hosttest/annotation/HostSideTestWholeClassStub
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+}
+SourceFile: "HostSideTestWholeClassStub.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+  x: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE]
+    )
+  x: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
+  Compiled from "TinyFrameworkCallerCheck.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
+  minor version: 0
+  major version: 61
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 4, attributes: 4
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  private com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl();
+    descriptor: ()V
+    flags: (0x0002) ACC_PRIVATE
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl;
+
+  public static int getOneKeep();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl
+         x: ldc           #x                 // String getOneKeep
+         x: ldc           #x                 // String ()I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl
+        x: ldc           #x                 // String getOneKeep
+        x: ldc           #x                 // String ()I
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+        x: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        x: iconst_1
+        x: ireturn
+      LineNumberTable:
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static int getOneStub();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl
+         x: ldc           #x                 // String getOneStub
+         x: ldc           #x                 // String ()I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iconst_1
+        x: ireturn
+      LineNumberTable:
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestStub
+}
+InnerClasses:
+  private static #x= #x of #x;          // Impl=class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl of class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
+SourceFile: "TinyFrameworkCallerCheck.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck.class
+  Compiled from "TinyFrameworkCallerCheck.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 4, attributes: 5
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck;
+
+  public static int getOne_withCheck();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
+         x: ldc           #x                 // String getOne_withCheck
+         x: ldc           #x                 // String ()I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.getOneKeep:()I
+        x: ireturn
+      LineNumberTable:
+
+  public static int getOne_noCheck();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
+         x: ldc           #x                 // String getOne_noCheck
+         x: ldc           #x                 // String ()I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.getOneStub:()I
+        x: ireturn
+      LineNumberTable:
+}
+InnerClasses:
+  private static #x= #x of #x;          // Impl=class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl of class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
+SourceFile: "TinyFrameworkCallerCheck.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations.class
+  Compiled from "TinyFrameworkClassAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 8, attributes: 3
+  public int stub;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestStub
+
+  public int keep;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
+         x: ldc           #x                 // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+        x: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: aload_0
+        x: iconst_1
+        x: putfield      #x                 // Field stub:I
+        x: aload_0
+        x: iconst_2
+        x: putfield      #x                 // Field keep:I
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      15     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestStub
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
+         x: ldc           #x                 // String addOne
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: iload_1
+        x: invokevirtual #x                 // Method addOneInner:(I)I
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+           11       6     1 value   I
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestStub
+
+  public int addOneInner(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
+         x: ldc           #x                 // String addOneInner
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
+        x: ldc           #x                 // String addOneInner
+        x: ldc           #x                 // String (I)I
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+        x: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        x: iload_1
+        x: iconst_1
+        x: iadd
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           26       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+           26       4     1 value   I
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
+         x: ldc           #x                 // String addTwo
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iload_1
+        x: iconst_2
+        x: iadd
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+           11       4     1 value   I
+
+  public static int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
+         x: ldc           #x                 // String nativeAddThree
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iload_0
+        x: iconst_3
+        x: iadd
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       4     0 value   I
+
+  public java.lang.String unsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
+         x: ldc           #x                 // String unsupportedMethod
+         x: ldc           #x                 // String ()Ljava/lang/String;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
+        x: ldc           #x                 // String unsupportedMethod
+        x: ldc           #x                 // String ()Ljava/lang/String;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+        x: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
+        x: new           #x                 // class java/lang/RuntimeException
+        x: dup
+        x: ldc           #x                 // String Unreachable
+        x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+        x: athrow
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestThrow
+
+  public java.lang.String visibleButUsesUnsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
+         x: ldc           #x                 // String visibleButUsesUnsupportedMethod
+         x: ldc           #x                 // String ()Ljava/lang/String;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokevirtual #x                 // Method unsupportedMethod:()Ljava/lang/String;
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+    RuntimeInvisibleAnnotations:
+      x: #x()
+        android.hosttest.annotation.HostSideTestStub
+}
+SourceFile: "TinyFrameworkClassAnnotations.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestStub
+  x: #x(#x=s#x)
+    android.hosttest.annotation.HostSideTestClassLoadHook(
+      value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+    )
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations.class
+  Compiled from "TinyFrameworkClassClassWideAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassWideAnnotations
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 3, methods: 9, attributes: 3
+  public int stub;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public int keep;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public int remove;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassWideAnnotations();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: aload_0
+        x: iconst_1
+        x: putfield      #x                 // Field stub:I
+        x: aload_0
+        x: iconst_2
+        x: putfield      #x                 // Field keep:I
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      15     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations
+         x: ldc           #x                 // String addOne
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: iload_1
+        x: invokevirtual #x                 // Method addOneInner:(I)I
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+           11       6     1 value   I
+
+  public int addOneInner(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations
+         x: ldc           #x                 // String addOneInner
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iload_1
+        x: iconst_1
+        x: iadd
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+           11       4     1 value   I
+
+  public void toBeRemoved(java.lang.String);
+    descriptor: (Ljava/lang/String;)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations
+         x: ldc           #x                 // String toBeRemoved
+         x: ldc           #x                 // String (Ljava/lang/String;)V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: new           #x                 // class java/lang/RuntimeException
+        x: dup
+        x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":()V
+        x: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       8     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+           11       8     1   foo   Ljava/lang/String;
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations
+         x: ldc           #x                 // String addTwo
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iload_1
+        x: iconst_2
+        x: iadd
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+           11       4     1 value   I
+
+  public static int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations
+         x: ldc           #x                 // String nativeAddThree
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iload_0
+        x: iconst_3
+        x: iadd
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       4     0 value   I
+
+  public java.lang.String unsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations
+         x: ldc           #x                 // String unsupportedMethod
+         x: ldc           #x                 // String ()Ljava/lang/String;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                 // String This value shouldn\'t be seen on the host side.
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       3     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+
+  public java.lang.String visibleButUsesUnsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations
+         x: ldc           #x                 // String visibleButUsesUnsupportedMethod
+         x: ldc           #x                 // String ()Ljava/lang/String;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokevirtual #x                 // Method unsupportedMethod:()Ljava/lang/String;
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+}
+SourceFile: "TinyFrameworkClassClassWideAnnotations.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.class
+  Compiled from "TinyFrameworkClassLoadHook.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 3, attributes: 3
+  public static final java.util.Set<java.lang.Class<?>> sLoadedClasses;
+    descriptor: Ljava/util/Set;
+    flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/Set<Ljava/lang/Class<*>;>;
+
+  private com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook();
+    descriptor: ()V
+    flags: (0x0002) ACC_PRIVATE
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook;
+
+  public static void onClassLoaded(java.lang.Class<?>);
+    descriptor: (Ljava/lang/Class;)V
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook
+         x: ldc           #x                 // String onClassLoaded
+         x: ldc           #x                 // String (Ljava/lang/Class;)V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: getstatic     #x                 // Field sLoadedClasses:Ljava/util/Set;
+        x: aload_0
+        x: invokeinterface #x,  2           // InterfaceMethod java/util/Set.add:(Ljava/lang/Object;)Z
+        x: pop
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      11     0 clazz   Ljava/lang/Class;
+      LocalVariableTypeTable:
+        Start  Length  Slot  Name   Signature
+           11      11     0 clazz   Ljava/lang/Class<*>;
+    Signature: #x                          // (Ljava/lang/Class<*>;)V
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook
+         x: ldc           #x                 // String <clinit>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook
+        x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+        x: new           #x                 // class java/util/HashSet
+        x: dup
+        x: invokespecial #x                 // Method java/util/HashSet."<init>":()V
+        x: putstatic     #x                 // Field sLoadedClasses:Ljava/util/Set;
+        x: return
+      LineNumberTable:
+}
+SourceFile: "TinyFrameworkClassLoadHook.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.class
+  Compiled from "TinyFrameworkClassWithInitializer.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializer
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 2, attributes: 3
+  public static boolean sInitialized;
+    descriptor: Z
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializer();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer;
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer
+         x: ldc           #x                 // String <clinit>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer
+        x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+        x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer
+        x: ldc           #x                 // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+        x: iconst_1
+        x: putstatic     #x                 // Field sInitialized:Z
+        x: return
+      LineNumberTable:
+}
+SourceFile: "TinyFrameworkClassWithInitializer.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  x: #x(#x=s#x)
+    android.hosttest.annotation.HostSideTestClassLoadHook(
+      value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+    )
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.class
+  Compiled from "TinyFrameworkExceptionTester.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 3, attributes: 3
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester;
+
+  public static int testException();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=1, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester
+         x: ldc           #x                 // String testException
+         x: ldc           #x                 // String ()I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: new           #x                 // class java/lang/IllegalStateException
+        x: dup
+        x: ldc           #x                 // String Inner exception
+        x: invokespecial #x                 // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V
+        x: athrow
+        x: astore_0
+        x: new           #x                 // class java/lang/RuntimeException
+        x: dup
+        x: ldc           #x                 // String Outer exception
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;Ljava/lang/Throwable;)V
+        x: athrow
+      Exception table:
+         from    to  target type
+            11    21    21   Class java/lang/Exception
+      StackMapTable: number_of_entries = 1
+        frame_type = 85 /* same_locals_1_stack_item */
+          stack = [ class java/lang/Exception ]
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           22      11     0     e   Ljava/lang/Exception;
+}
+SourceFile: "TinyFrameworkExceptionTester.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.class
+  Compiled from "TinyFrameworkForTextPolicy.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPolicy
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 8, attributes: 2
+  public int stub;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public int keep;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         x: ldc           #x                 // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+        x: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPolicy();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: aload_0
+        x: iconst_1
+        x: putfield      #x                 // Field stub:I
+        x: aload_0
+        x: iconst_2
+        x: putfield      #x                 // Field keep:I
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      15     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         x: ldc           #x                 // String addOne
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: iload_1
+        x: invokevirtual #x                 // Method addOneInner:(I)I
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+           11       6     1 value   I
+
+  public int addOneInner(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         x: ldc           #x                 // String addOneInner
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+        x: ldc           #x                 // String addOneInner
+        x: ldc           #x                 // String (I)I
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+        x: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        x: iload_1
+        x: iconst_1
+        x: iadd
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           26       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+           26       4     1 value   I
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         x: ldc           #x                 // String addTwo
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iload_1
+        x: iconst_2
+        x: iadd
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+           11       4     1 value   I
+
+  public static int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         x: ldc           #x                 // String nativeAddThree
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iload_0
+        x: iconst_3
+        x: iadd
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       4     0 value   I
+
+  public java.lang.String unsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         x: ldc           #x                 // String unsupportedMethod
+         x: ldc           #x                 // String ()Ljava/lang/String;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+        x: ldc           #x                 // String unsupportedMethod
+        x: ldc           #x                 // String ()Ljava/lang/String;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+        x: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
+        x: new           #x                 // class java/lang/RuntimeException
+        x: dup
+        x: ldc           #x                 // String Unreachable
+        x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+        x: athrow
+
+  public java.lang.String visibleButUsesUnsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         x: ldc           #x                 // String visibleButUsesUnsupportedMethod
+         x: ldc           #x                 // String ()Ljava/lang/String;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokevirtual #x                 // Method unsupportedMethod:()Ljava/lang/String;
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+}
+SourceFile: "TinyFrameworkForTextPolicy.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.class
+  Compiled from "TinyFrameworkNative.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 6, attributes: 3
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+
+  public static int nativeAddTwo(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=1, args_size=1
+         x: iload_0
+         x: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeAddTwo:(I)I
+         x: ireturn
+
+  public static int nativeAddTwo_should_be_like_this(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+         x: ldc           #x                 // String nativeAddTwo_should_be_like_this
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: iload_0
+        x: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeAddTwo:(I)I
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0   arg   I
+
+  public static long nativeLongPlus(long, long);
+    descriptor: (JJ)J
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=4, args_size=2
+         x: lload_0
+         x: lload_2
+         x: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeLongPlus:(JJ)J
+         x: lreturn
+
+  public static long nativeLongPlus_should_be_like_this(long, long);
+    descriptor: (JJ)J
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=4, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+         x: ldc           #x                 // String nativeLongPlus_should_be_like_this
+         x: ldc           #x                 // String (JJ)J
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: lload_0
+        x: lload_2
+        x: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeLongPlus:(JJ)J
+        x: lreturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       6     0  arg1   J
+           11       6     2  arg2   J
+}
+SourceFile: "TinyFrameworkNative.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+  x: #x(#x=s#x)
+    android.hosttest.annotation.HostSideTestNativeSubstitutionClass(
+      value="TinyFrameworkNative_host"
+    )
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.class
+  Compiled from "TinyFrameworkNative_host.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 4, attributes: 3
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+         x: ldc           #x                  // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+        x: ldc           #x                 // String <init>
+        x: ldc           #x                 // String ()V
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+        x: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           26       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host;
+
+  public static int nativeAddTwo(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+         x: ldc           #x                 // String nativeAddTwo
+         x: ldc           #x                 // String (I)I
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+        x: ldc           #x                 // String nativeAddTwo
+        x: ldc           #x                 // String (I)I
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+        x: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        x: iload_0
+        x: iconst_2
+        x: iadd
+        x: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           26       4     0   arg   I
+
+  public static long nativeLongPlus(long, long);
+    descriptor: (JJ)J
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=4, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+         x: ldc           #x                 // String nativeLongPlus
+         x: ldc           #x                 // String (JJ)J
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+        x: ldc           #x                 // String nativeLongPlus
+        x: ldc           #x                 // String (JJ)J
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+        x: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        x: lload_0
+        x: lload_2
+        x: ladd
+        x: lreturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           26       4     0  arg1   J
+           26       4     2  arg2   J
+}
+SourceFile: "TinyFrameworkNative_host.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 61
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 1, methods: 4, attributes: 6
+  final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC
+
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses);
+    descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+    flags: (0x0000)
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: aload_1
+        x: putfield      #x                 // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+           11      10     1 this$0   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+         x: ldc           #x                 // String get
+         x: ldc           #x                 // String ()Ljava/lang/Integer;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+        x: ldc           #x                 // String get
+        x: ldc           #x                 // String ()Ljava/lang/Integer;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+        x: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        x: iconst_1
+        x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           26       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+         x: ldc           #x                 // String get
+         x: ldc           #x                 // String ()Ljava/lang/Object;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+        x: ldc           #x                 // String get
+        x: ldc           #x                 // String ()Ljava/lang/Object;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+        x: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        x: aload_0
+        x: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           26       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+}
+InnerClasses:
+  #x;                                     // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+EnclosingMethod: #x.#x                 // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+Signature: #x                           // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 61
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 4, attributes: 6
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2();
+    descriptor: ()V
+    flags: (0x0000)
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2;
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+         x: ldc           #x                 // String get
+         x: ldc           #x                 // String ()Ljava/lang/Integer;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+        x: ldc           #x                 // String get
+        x: ldc           #x                 // String ()Ljava/lang/Integer;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+        x: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        x: iconst_2
+        x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           26       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2;
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+         x: ldc           #x                 // String get
+         x: ldc           #x                 // String ()Ljava/lang/Object;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+        x: ldc           #x                 // String get
+        x: ldc           #x                 // String ()Ljava/lang/Object;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+        x: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        x: aload_0
+        x: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           26       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2;
+}
+InnerClasses:
+  #x;                                     // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+EnclosingMethod: #x.#x                 // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+Signature: #x                           // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 61
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 1, methods: 4, attributes: 6
+  final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC
+
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses);
+    descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+    flags: (0x0000)
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: aload_1
+        x: putfield      #x                 // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+           11      10     1 this$0   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+         x: ldc           #x                 // String get
+         x: ldc           #x                 // String ()Ljava/lang/Integer;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+        x: ldc           #x                 // String get
+        x: ldc           #x                 // String ()Ljava/lang/Integer;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+        x: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        x: iconst_3
+        x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           26       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+         x: ldc           #x                 // String get
+         x: ldc           #x                 // String ()Ljava/lang/Object;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+        x: ldc           #x                 // String get
+        x: ldc           #x                 // String ()Ljava/lang/Object;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+        x: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        x: aload_0
+        x: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           26       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+}
+InnerClasses:
+  #x;                                     // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+EnclosingMethod: #x.#x                // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.getSupplier
+Signature: #x                           // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 61
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 4, attributes: 6
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4();
+    descriptor: ()V
+    flags: (0x0000)
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4;
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+         x: ldc           #x                 // String get
+         x: ldc           #x                 // String ()Ljava/lang/Integer;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+        x: ldc           #x                 // String get
+        x: ldc           #x                 // String ()Ljava/lang/Integer;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+        x: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        x: iconst_4
+        x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           26       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4;
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+         x: ldc           #x                 // String get
+         x: ldc           #x                 // String ()Ljava/lang/Object;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+        x: ldc           #x                 // String get
+        x: ldc           #x                 // String ()Ljava/lang/Object;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+        x: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        x: aload_0
+        x: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           26       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4;
+}
+InnerClasses:
+  #x;                                     // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+EnclosingMethod: #x.#x                // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.getSupplier_static
+Signature: #x                           // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 2, attributes: 4
+  public int value;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass(int);
+    descriptor: (I)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String (I)V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: aload_0
+        x: iload_1
+        x: putfield      #x                 // Field value:I
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass;
+           11      10     1     x   I
+}
+InnerClasses:
+  public static #x= #x of #x;           // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$InnerClass
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 2, attributes: 5
+  public int value;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC
+
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$InnerClass(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses);
+    descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: aload_1
+        x: putfield      #x                 // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: aload_0
+        x: iconst_5
+        x: putfield      #x                 // Field value:I
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      15     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass;
+           11      15     1 this$0   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+}
+InnerClasses:
+  public #x= #x of #x;                  // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$1 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 61
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 4, attributes: 6
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$1();
+    descriptor: ()V
+    flags: (0x0000)
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1;
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+         x: ldc           #x                 // String get
+         x: ldc           #x                 // String ()Ljava/lang/Integer;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+        x: ldc           #x                 // String get
+        x: ldc           #x                 // String ()Ljava/lang/Integer;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+        x: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        x: bipush        7
+        x: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           26       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1;
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+         x: ldc           #x                 // String get
+         x: ldc           #x                 // String ()Ljava/lang/Object;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+        x: ldc           #x                 // String get
+        x: ldc           #x                 // String ()Ljava/lang/Object;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+        x: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        x: aload_0
+        x: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           26       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1;
+}
+InnerClasses:
+  public static #x= #x of #x;          // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  #x;                                     // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+EnclosingMethod: #x.#x                // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass.getSupplier_static
+Signature: #x                           // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 3, attributes: 5
+  public int value;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: aload_0
+        x: bipush        6
+        x: putfield      #x                 // Field value:I
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      11     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass;
+
+  public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+         x: ldc           #x                 // String getSupplier_static
+         x: ldc           #x                 // String ()Ljava/util/function/Supplier;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+        x: dup
+        x: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1."<init>":()V
+        x: areturn
+      LineNumberTable:
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+}
+InnerClasses:
+  public static #x= #x of #x;           // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass extends com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
+  super_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+  interfaces: 0, fields: 0, methods: 2, attributes: 4
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         x: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass(int);
+    descriptor: (I)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String (I)V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: iload_1
+        x: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass."<init>":(I)V
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass;
+           11       6     1     x   I
+}
+InnerClasses:
+  public static #x= #x of #x;           // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;           // SubClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 4, attributes: 5
+  public final java.util.function.Supplier<java.lang.Integer> mSupplier;
+    descriptor: Ljava/util/function/Supplier;
+    flags: (0x0011) ACC_PUBLIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+  public static final java.util.function.Supplier<java.lang.Integer> sSupplier;
+    descriptor: Ljava/util/function/Supplier;
+    flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+         x: ldc           #x                 // String <init>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: aload_0
+        x: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        x: aload_0
+        x: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+        x: dup
+        x: aload_0
+        x: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+        x: putfield      #x                 // Field mSupplier:Ljava/util/function/Supplier;
+        x: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      17     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+
+  public java.util.function.Supplier<java.lang.Integer> getSupplier();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+         x: ldc           #x                 // String getSupplier
+         x: ldc           #x                 // String ()Ljava/util/function/Supplier;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+        x: dup
+        x: aload_0
+        x: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+        x: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11       9     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+  public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+         x: ldc           #x                 // String getSupplier_static
+         x: ldc           #x                 // String ()Ljava/util/function/Supplier;
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+        x: dup
+        x: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4."<init>":()V
+        x: areturn
+      LineNumberTable:
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+         x: ldc           #x                 // String <clinit>
+         x: ldc           #x                 // String ()V
+         x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+         x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+        x: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+        x: ldc           #x                 // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+        x: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+        x: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+        x: dup
+        x: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2."<init>":()V
+        x: putstatic     #x                 // Field sSupplier:Ljava/util/function/Supplier;
+        x: return
+      LineNumberTable:
+}
+InnerClasses:
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+  public static #x= #x of #x;           // SubClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;           // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;           // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public #x= #x of #x;                  // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  x: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  x: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
diff --git a/tools/hoststubgen/scripts/run-all-tests.sh b/tools/hoststubgen/scripts/run-all-tests.sh
index 6bc0ddb..7600942 100755
--- a/tools/hoststubgen/scripts/run-all-tests.sh
+++ b/tools/hoststubgen/scripts/run-all-tests.sh
@@ -34,6 +34,7 @@
 
 run ./hoststubgen/test-framework/run-test-without-atest.sh
 run ./hoststubgen/test-tiny-framework/run-test-manually.sh
+run atest tiny-framework-dump-test
 run ./scripts/build-framework-hostside-jars-and-extract.sh
 
 # This script is already broken on goog/master
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionHelperDetector.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionHelperDetector.kt
index cbbf91b4..758de4d 100644
--- a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionHelperDetector.kt
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionHelperDetector.kt
@@ -131,7 +131,7 @@
                 priority = 6,
                 severity = Severity.ERROR,
                 implementation = Implementation(
-                        EnforcePermissionDetector::class.java,
+                        EnforcePermissionHelperDetector::class.java,
                         EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES)
                 )
         )