Merge "Fix several flaky DeviceStateManagerServiceTests" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 6b5554b..aabe87f 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -22,7 +22,6 @@
         ":android.os.flags-aconfig-java{.generated_srcjars}",
         ":android.os.vibrator.flags-aconfig-java{.generated_srcjars}",
         ":android.security.flags-aconfig-java{.generated_srcjars}",
-        ":android.media.flags-aconfig-java{.generated_srcjars}",
         ":camera_platform_flags_core_java_lib{.generated_srcjars}",
         ":com.android.window.flags.window-aconfig-java{.generated_srcjars}",
         ":com.android.text.flags-aconfig-java{.generated_srcjars}",
@@ -172,16 +171,3 @@
     aconfig_declarations: "android.os.vibrator.flags-aconfig",
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
-
-// Media
-aconfig_declarations {
-    name: "android.media.flags-aconfig",
-    package: "android.media",
-    srcs: ["media/java/android/media/*.aconfig"],
-}
-
-java_aconfig_library {
-    name: "android.media.flags-aconfig-java",
-    aconfig_declarations: "android.media.flags-aconfig",
-    defaults: ["framework-minus-apex-aconfig-java-defaults"],
-}
diff --git a/Android.bp b/Android.bp
index 431f0b9..57a5a3c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -71,7 +71,6 @@
         ":framework-jobscheduler-sources", // jobscheduler is not a module for R
         ":framework-keystore-sources",
         ":framework-identity-sources",
-        ":framework-location-sources",
         ":framework-mca-effect-sources",
         ":framework-mca-filterfw-sources",
         ":framework-mca-filterpacks-sources",
@@ -163,6 +162,12 @@
         //same purpose.
         "//external/robolectric:__subpackages__",
         "//frameworks/layoutlib:__subpackages__",
+
+        // This is for the same purpose as robolectric -- to build "framework.jar" for host-side
+        // testing.
+        // TODO: Once Ravenwood is stable, move the host side jar targets to this directory,
+        // and remove this line.
+        "//frameworks/base/tools/hoststubgen:__subpackages__",
     ],
 }
 
@@ -177,7 +182,6 @@
             "graphics/java",
             "identity/java",
             "keystore/java",
-            "location/java",
             "media/java",
             "media/mca/effect/java",
             "media/mca/filterfw/java",
@@ -287,7 +291,6 @@
             ":framework-jobscheduler-sources",
             ":framework-keystore-sources",
             ":framework-identity-sources",
-            ":framework-location-sources",
             ":framework-mca-effect-sources",
             ":framework-mca-filterfw-sources",
             ":framework-mca-filterpacks-sources",
@@ -405,6 +408,7 @@
         "audiopolicy-aidl-java",
         "sounddose-aidl-java",
         "modules-utils-expresslog",
+        "hoststubgen-annotations",
     ],
 }
 
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index a040b57..4e41f2c 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -271,9 +271,9 @@
         } else if (strcmp(arg, "--application") == 0) {
             application = true;
         } else if (strncmp(arg, "--nice-name=", 12) == 0) {
-            niceName.setTo(arg + 12);
+            niceName = (arg + 12);
         } else if (strncmp(arg, "--", 2) != 0) {
-            className.setTo(arg);
+            className = arg;
             break;
         } else {
             --i;
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 69c161a..f2d0efe 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -1041,7 +1041,7 @@
         return false;
     }
 
-    outString.setTo((char const*)entryMap->getDataPtr(), entryMap->getDataLength());
+    outString = String8((char const*)entryMap->getDataPtr(), entryMap->getDataLength());
     delete entryMap;
     return true;
 }
@@ -1341,7 +1341,7 @@
                                     part.audioData = (uint8_t *)map->getDataPtr();
                                     part.audioLength = map->getDataLength();
                                 } else if (leaf == "trim.txt") {
-                                    part.trimData.setTo((char const*)map->getDataPtr(),
+                                    part.trimData = String8((char const*)map->getDataPtr(),
                                                         map->getDataLength());
                                 } else {
                                     Animation::Frame frame;
@@ -1432,7 +1432,7 @@
     if (!exts) {
         glGetError();
     } else {
-        gl_extensions.setTo(exts);
+        gl_extensions = exts;
         if ((gl_extensions.find("GL_ARB_texture_non_power_of_two") != -1) ||
             (gl_extensions.find("GL_OES_texture_npot") != -1)) {
             mUseNpotTextures = true;
diff --git a/cmds/idmap2/libidmap2/CommandLineOptions.cpp b/cmds/idmap2/libidmap2/CommandLineOptions.cpp
index 888b3a5..2da05b3 100644
--- a/cmds/idmap2/libidmap2/CommandLineOptions.cpp
+++ b/cmds/idmap2/libidmap2/CommandLineOptions.cpp
@@ -19,6 +19,7 @@
 #include <algorithm>
 #include <cassert>
 #include <iomanip>
+#include <iterator>
 #include <memory>
 #include <ostream>
 #include <set>
diff --git a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
index 174d85c..9d04a7f 100644
--- a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
+++ b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
@@ -96,7 +96,7 @@
       auto value = target_entry_value.second;
 
       print(target_entry_value.first.to_string(), false, "config: %s",
-          target_entry_value.first.toString().string());
+          target_entry_value.first.toString().c_str());
 
       print(value.data_type, "type: %s",
             utils::DataTypeToString(value.data_type).data());
diff --git a/core/api/current.txt b/core/api/current.txt
index df41b1f..0e5a515 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -9681,14 +9681,24 @@
   public final class VirtualDevice implements android.os.Parcelable {
     method public int describeContents();
     method public int getDeviceId();
+    method @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) @NonNull public int[] getDisplayIds();
     method @Nullable public String getName();
     method @Nullable public String getPersistentDeviceId();
+    method @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) public boolean hasCustomSensorSupport();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.companion.virtual.VirtualDevice> CREATOR;
   }
 
   public final class VirtualDeviceManager {
+    method @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) @Nullable public android.companion.virtual.VirtualDevice getVirtualDevice(int);
     method @NonNull public java.util.List<android.companion.virtual.VirtualDevice> getVirtualDevices();
+    method @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) public void registerVirtualDeviceListener(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.VirtualDeviceListener);
+    method @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) public void unregisterVirtualDeviceListener(@NonNull android.companion.virtual.VirtualDeviceManager.VirtualDeviceListener);
+  }
+
+  @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) public static interface VirtualDeviceManager.VirtualDeviceListener {
+    method public default void onVirtualDeviceClosed(int);
+    method public default void onVirtualDeviceCreated(int);
   }
 
 }
@@ -20405,513 +20415,6 @@
 
 package android.location {
 
-  public class Address implements android.os.Parcelable {
-    ctor public Address(java.util.Locale);
-    method public void clearLatitude();
-    method public void clearLongitude();
-    method public int describeContents();
-    method public String getAddressLine(int);
-    method public String getAdminArea();
-    method public String getCountryCode();
-    method public String getCountryName();
-    method public android.os.Bundle getExtras();
-    method public String getFeatureName();
-    method public double getLatitude();
-    method public java.util.Locale getLocale();
-    method public String getLocality();
-    method public double getLongitude();
-    method public int getMaxAddressLineIndex();
-    method public String getPhone();
-    method public String getPostalCode();
-    method public String getPremises();
-    method public String getSubAdminArea();
-    method public String getSubLocality();
-    method public String getSubThoroughfare();
-    method public String getThoroughfare();
-    method public String getUrl();
-    method public boolean hasLatitude();
-    method public boolean hasLongitude();
-    method public void setAddressLine(int, String);
-    method public void setAdminArea(String);
-    method public void setCountryCode(String);
-    method public void setCountryName(String);
-    method public void setExtras(android.os.Bundle);
-    method public void setFeatureName(String);
-    method public void setLatitude(double);
-    method public void setLocality(String);
-    method public void setLongitude(double);
-    method public void setPhone(String);
-    method public void setPostalCode(String);
-    method public void setPremises(String);
-    method public void setSubAdminArea(String);
-    method public void setSubLocality(String);
-    method public void setSubThoroughfare(String);
-    method public void setThoroughfare(String);
-    method public void setUrl(String);
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.Address> CREATOR;
-  }
-
-  @Deprecated public class Criteria implements android.os.Parcelable {
-    ctor @Deprecated public Criteria();
-    ctor @Deprecated public Criteria(android.location.Criteria);
-    method @Deprecated public int describeContents();
-    method @Deprecated public int getAccuracy();
-    method @Deprecated public int getBearingAccuracy();
-    method @Deprecated public int getHorizontalAccuracy();
-    method @Deprecated public int getPowerRequirement();
-    method @Deprecated public int getSpeedAccuracy();
-    method @Deprecated public int getVerticalAccuracy();
-    method @Deprecated public boolean isAltitudeRequired();
-    method @Deprecated public boolean isBearingRequired();
-    method @Deprecated public boolean isCostAllowed();
-    method @Deprecated public boolean isSpeedRequired();
-    method @Deprecated public void setAccuracy(int);
-    method @Deprecated public void setAltitudeRequired(boolean);
-    method @Deprecated public void setBearingAccuracy(int);
-    method @Deprecated public void setBearingRequired(boolean);
-    method @Deprecated public void setCostAllowed(boolean);
-    method @Deprecated public void setHorizontalAccuracy(int);
-    method @Deprecated public void setPowerRequirement(int);
-    method @Deprecated public void setSpeedAccuracy(int);
-    method @Deprecated public void setSpeedRequired(boolean);
-    method @Deprecated public void setVerticalAccuracy(int);
-    method @Deprecated public void writeToParcel(android.os.Parcel, int);
-    field @Deprecated public static final int ACCURACY_COARSE = 2; // 0x2
-    field @Deprecated public static final int ACCURACY_FINE = 1; // 0x1
-    field @Deprecated public static final int ACCURACY_HIGH = 3; // 0x3
-    field @Deprecated public static final int ACCURACY_LOW = 1; // 0x1
-    field @Deprecated public static final int ACCURACY_MEDIUM = 2; // 0x2
-    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.Criteria> CREATOR;
-    field @Deprecated public static final int NO_REQUIREMENT = 0; // 0x0
-    field @Deprecated public static final int POWER_HIGH = 3; // 0x3
-    field @Deprecated public static final int POWER_LOW = 1; // 0x1
-    field @Deprecated public static final int POWER_MEDIUM = 2; // 0x2
-  }
-
-  public final class Geocoder {
-    ctor public Geocoder(@NonNull android.content.Context);
-    ctor public Geocoder(@NonNull android.content.Context, @NonNull java.util.Locale);
-    method @Deprecated @Nullable public java.util.List<android.location.Address> getFromLocation(@FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @IntRange int) throws java.io.IOException;
-    method public void getFromLocation(@FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @IntRange int, @NonNull android.location.Geocoder.GeocodeListener);
-    method @Deprecated @Nullable public java.util.List<android.location.Address> getFromLocationName(@NonNull String, @IntRange int) throws java.io.IOException;
-    method public void getFromLocationName(@NonNull String, @IntRange int, @NonNull android.location.Geocoder.GeocodeListener);
-    method @Deprecated @Nullable public java.util.List<android.location.Address> getFromLocationName(@NonNull String, @IntRange int, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double) throws java.io.IOException;
-    method public void getFromLocationName(@NonNull String, @IntRange int, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @NonNull android.location.Geocoder.GeocodeListener);
-    method public static boolean isPresent();
-  }
-
-  public static interface Geocoder.GeocodeListener {
-    method public default void onError(@Nullable String);
-    method public void onGeocode(@NonNull java.util.List<android.location.Address>);
-  }
-
-  public final class GnssAntennaInfo implements android.os.Parcelable {
-    method public int describeContents();
-    method @FloatRange(from=0.0f) public double getCarrierFrequencyMHz();
-    method @NonNull public android.location.GnssAntennaInfo.PhaseCenterOffset getPhaseCenterOffset();
-    method @Nullable public android.location.GnssAntennaInfo.SphericalCorrections getPhaseCenterVariationCorrections();
-    method @Nullable public android.location.GnssAntennaInfo.SphericalCorrections getSignalGainCorrections();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAntennaInfo> CREATOR;
-  }
-
-  public static class GnssAntennaInfo.Builder {
-    ctor @Deprecated public GnssAntennaInfo.Builder();
-    ctor public GnssAntennaInfo.Builder(double, @NonNull android.location.GnssAntennaInfo.PhaseCenterOffset);
-    ctor public GnssAntennaInfo.Builder(@NonNull android.location.GnssAntennaInfo);
-    method @NonNull public android.location.GnssAntennaInfo build();
-    method @NonNull public android.location.GnssAntennaInfo.Builder setCarrierFrequencyMHz(@FloatRange(from=0.0f) double);
-    method @NonNull public android.location.GnssAntennaInfo.Builder setPhaseCenterOffset(@NonNull android.location.GnssAntennaInfo.PhaseCenterOffset);
-    method @NonNull public android.location.GnssAntennaInfo.Builder setPhaseCenterVariationCorrections(@Nullable android.location.GnssAntennaInfo.SphericalCorrections);
-    method @NonNull public android.location.GnssAntennaInfo.Builder setSignalGainCorrections(@Nullable android.location.GnssAntennaInfo.SphericalCorrections);
-  }
-
-  public static interface GnssAntennaInfo.Listener {
-    method public void onGnssAntennaInfoReceived(@NonNull java.util.List<android.location.GnssAntennaInfo>);
-  }
-
-  public static final class GnssAntennaInfo.PhaseCenterOffset implements android.os.Parcelable {
-    ctor public GnssAntennaInfo.PhaseCenterOffset(double, double, double, double, double, double);
-    method public int describeContents();
-    method @FloatRange public double getXOffsetMm();
-    method @FloatRange public double getXOffsetUncertaintyMm();
-    method @FloatRange public double getYOffsetMm();
-    method @FloatRange public double getYOffsetUncertaintyMm();
-    method @FloatRange public double getZOffsetMm();
-    method @FloatRange public double getZOffsetUncertaintyMm();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAntennaInfo.PhaseCenterOffset> CREATOR;
-  }
-
-  public static final class GnssAntennaInfo.SphericalCorrections implements android.os.Parcelable {
-    ctor public GnssAntennaInfo.SphericalCorrections(@NonNull double[][], @NonNull double[][]);
-    method public int describeContents();
-    method @NonNull public double[][] getCorrectionUncertaintiesArray();
-    method @NonNull public double[][] getCorrectionsArray();
-    method @FloatRange(from=0.0f, to=180.0f) public double getDeltaPhi();
-    method @FloatRange(from=0.0f, to=360.0f) public double getDeltaTheta();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAntennaInfo.SphericalCorrections> CREATOR;
-  }
-
-  public final class GnssAutomaticGainControl implements android.os.Parcelable {
-    method public int describeContents();
-    method @IntRange(from=0) public long getCarrierFrequencyHz();
-    method public int getConstellationType();
-    method @FloatRange(from=0xffffd8f0, to=10000) public double getLevelDb();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAutomaticGainControl> CREATOR;
-  }
-
-  public static final class GnssAutomaticGainControl.Builder {
-    ctor public GnssAutomaticGainControl.Builder();
-    ctor public GnssAutomaticGainControl.Builder(@NonNull android.location.GnssAutomaticGainControl);
-    method @NonNull public android.location.GnssAutomaticGainControl build();
-    method @NonNull public android.location.GnssAutomaticGainControl.Builder setCarrierFrequencyHz(@IntRange(from=0) long);
-    method @NonNull public android.location.GnssAutomaticGainControl.Builder setConstellationType(int);
-    method @NonNull public android.location.GnssAutomaticGainControl.Builder setLevelDb(@FloatRange(from=0xffffd8f0, to=10000) double);
-  }
-
-  public final class GnssCapabilities implements android.os.Parcelable {
-    method public int describeContents();
-    method @NonNull public java.util.List<android.location.GnssSignalType> getGnssSignalTypes();
-    method public int hasAccumulatedDeltaRange();
-    method public boolean hasAntennaInfo();
-    method public boolean hasGeofencing();
-    method @Deprecated public boolean hasGnssAntennaInfo();
-    method public boolean hasLowPowerMode();
-    method public boolean hasMeasurementCorrections();
-    method public boolean hasMeasurementCorrectionsExcessPathLength();
-    method public boolean hasMeasurementCorrectionsForDriving();
-    method public boolean hasMeasurementCorrectionsLosSats();
-    method public boolean hasMeasurementCorrectionsReflectingPlane();
-    method public boolean hasMeasurementCorrelationVectors();
-    method public boolean hasMeasurements();
-    method public boolean hasMsa();
-    method public boolean hasMsb();
-    method public boolean hasNavigationMessages();
-    method public boolean hasOnDemandTime();
-    method public boolean hasPowerMultibandAcquisition();
-    method public boolean hasPowerMultibandTracking();
-    method public boolean hasPowerOtherModes();
-    method public boolean hasPowerSinglebandAcquisition();
-    method public boolean hasPowerSinglebandTracking();
-    method public boolean hasPowerTotal();
-    method public boolean hasSatelliteBlocklist();
-    method public boolean hasSatellitePvt();
-    method public boolean hasScheduling();
-    method public boolean hasSingleShotFix();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field public static final int CAPABILITY_SUPPORTED = 1; // 0x1
-    field public static final int CAPABILITY_UNKNOWN = 0; // 0x0
-    field public static final int CAPABILITY_UNSUPPORTED = 2; // 0x2
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssCapabilities> CREATOR;
-  }
-
-  public static final class GnssCapabilities.Builder {
-    ctor public GnssCapabilities.Builder();
-    ctor public GnssCapabilities.Builder(@NonNull android.location.GnssCapabilities);
-    method @NonNull public android.location.GnssCapabilities build();
-    method @NonNull public android.location.GnssCapabilities.Builder setGnssSignalTypes(@NonNull java.util.List<android.location.GnssSignalType>);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasAccumulatedDeltaRange(int);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasAntennaInfo(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasGeofencing(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasLowPowerMode(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrections(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrectionsExcessPathLength(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrectionsForDriving(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrectionsLosSats(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrectionsReflectingPlane(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrelationVectors(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurements(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasMsa(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasMsb(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasNavigationMessages(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasOnDemandTime(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasPowerMultibandAcquisition(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasPowerMultibandTracking(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasPowerOtherModes(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasPowerSinglebandAcquisition(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasPowerSinglebandTracking(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasPowerTotal(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasSatelliteBlocklist(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasSatellitePvt(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasScheduling(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasSingleShotFix(boolean);
-  }
-
-  public final class GnssClock implements android.os.Parcelable {
-    method public int describeContents();
-    method public double getBiasNanos();
-    method @FloatRange(from=0.0f) public double getBiasUncertaintyNanos();
-    method public double getDriftNanosPerSecond();
-    method @FloatRange(from=0.0f) public double getDriftUncertaintyNanosPerSecond();
-    method public long getElapsedRealtimeNanos();
-    method @FloatRange(from=0.0f) public double getElapsedRealtimeUncertaintyNanos();
-    method public long getFullBiasNanos();
-    method public int getHardwareClockDiscontinuityCount();
-    method public int getLeapSecond();
-    method @FloatRange(from=0.0) public double getReferenceCarrierFrequencyHzForIsb();
-    method @NonNull public String getReferenceCodeTypeForIsb();
-    method public int getReferenceConstellationTypeForIsb();
-    method public long getTimeNanos();
-    method @FloatRange(from=0.0f) public double getTimeUncertaintyNanos();
-    method public boolean hasBiasNanos();
-    method public boolean hasBiasUncertaintyNanos();
-    method public boolean hasDriftNanosPerSecond();
-    method public boolean hasDriftUncertaintyNanosPerSecond();
-    method public boolean hasElapsedRealtimeNanos();
-    method public boolean hasElapsedRealtimeUncertaintyNanos();
-    method public boolean hasFullBiasNanos();
-    method public boolean hasLeapSecond();
-    method public boolean hasReferenceCarrierFrequencyHzForIsb();
-    method public boolean hasReferenceCodeTypeForIsb();
-    method public boolean hasReferenceConstellationTypeForIsb();
-    method public boolean hasTimeUncertaintyNanos();
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssClock> CREATOR;
-  }
-
-  public final class GnssMeasurement implements android.os.Parcelable {
-    method public int describeContents();
-    method public double getAccumulatedDeltaRangeMeters();
-    method public int getAccumulatedDeltaRangeState();
-    method public double getAccumulatedDeltaRangeUncertaintyMeters();
-    method @Deprecated public double getAutomaticGainControlLevelDb();
-    method @FloatRange(from=0, to=63) public double getBasebandCn0DbHz();
-    method @Deprecated public long getCarrierCycles();
-    method public float getCarrierFrequencyHz();
-    method @Deprecated public double getCarrierPhase();
-    method @Deprecated public double getCarrierPhaseUncertainty();
-    method @FloatRange(from=0, to=63) public double getCn0DbHz();
-    method @NonNull public String getCodeType();
-    method public int getConstellationType();
-    method public double getFullInterSignalBiasNanos();
-    method @FloatRange(from=0.0) public double getFullInterSignalBiasUncertaintyNanos();
-    method public int getMultipathIndicator();
-    method public double getPseudorangeRateMetersPerSecond();
-    method public double getPseudorangeRateUncertaintyMetersPerSecond();
-    method public long getReceivedSvTimeNanos();
-    method public long getReceivedSvTimeUncertaintyNanos();
-    method public double getSatelliteInterSignalBiasNanos();
-    method @FloatRange(from=0.0) public double getSatelliteInterSignalBiasUncertaintyNanos();
-    method public double getSnrInDb();
-    method public int getState();
-    method public int getSvid();
-    method public double getTimeOffsetNanos();
-    method @Deprecated public boolean hasAutomaticGainControlLevelDb();
-    method public boolean hasBasebandCn0DbHz();
-    method @Deprecated public boolean hasCarrierCycles();
-    method public boolean hasCarrierFrequencyHz();
-    method @Deprecated public boolean hasCarrierPhase();
-    method @Deprecated public boolean hasCarrierPhaseUncertainty();
-    method public boolean hasCodeType();
-    method public boolean hasFullInterSignalBiasNanos();
-    method public boolean hasFullInterSignalBiasUncertaintyNanos();
-    method public boolean hasSatelliteInterSignalBiasNanos();
-    method public boolean hasSatelliteInterSignalBiasUncertaintyNanos();
-    method public boolean hasSnrInDb();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final int ADR_STATE_CYCLE_SLIP = 4; // 0x4
-    field public static final int ADR_STATE_HALF_CYCLE_REPORTED = 16; // 0x10
-    field public static final int ADR_STATE_HALF_CYCLE_RESOLVED = 8; // 0x8
-    field public static final int ADR_STATE_RESET = 2; // 0x2
-    field public static final int ADR_STATE_UNKNOWN = 0; // 0x0
-    field public static final int ADR_STATE_VALID = 1; // 0x1
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssMeasurement> CREATOR;
-    field public static final int MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
-    field public static final int MULTIPATH_INDICATOR_NOT_DETECTED = 2; // 0x2
-    field public static final int MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
-    field public static final int STATE_2ND_CODE_LOCK = 65536; // 0x10000
-    field public static final int STATE_BDS_D2_BIT_SYNC = 256; // 0x100
-    field public static final int STATE_BDS_D2_SUBFRAME_SYNC = 512; // 0x200
-    field public static final int STATE_BIT_SYNC = 2; // 0x2
-    field public static final int STATE_CODE_LOCK = 1; // 0x1
-    field public static final int STATE_GAL_E1BC_CODE_LOCK = 1024; // 0x400
-    field public static final int STATE_GAL_E1B_PAGE_SYNC = 4096; // 0x1000
-    field public static final int STATE_GAL_E1C_2ND_CODE_LOCK = 2048; // 0x800
-    field public static final int STATE_GLO_STRING_SYNC = 64; // 0x40
-    field public static final int STATE_GLO_TOD_DECODED = 128; // 0x80
-    field public static final int STATE_GLO_TOD_KNOWN = 32768; // 0x8000
-    field public static final int STATE_MSEC_AMBIGUOUS = 16; // 0x10
-    field public static final int STATE_SBAS_SYNC = 8192; // 0x2000
-    field public static final int STATE_SUBFRAME_SYNC = 4; // 0x4
-    field public static final int STATE_SYMBOL_SYNC = 32; // 0x20
-    field public static final int STATE_TOW_DECODED = 8; // 0x8
-    field public static final int STATE_TOW_KNOWN = 16384; // 0x4000
-    field public static final int STATE_UNKNOWN = 0; // 0x0
-  }
-
-  public final class GnssMeasurementRequest implements android.os.Parcelable {
-    method public int describeContents();
-    method @IntRange(from=0) public int getIntervalMillis();
-    method public boolean isFullTracking();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssMeasurementRequest> CREATOR;
-    field public static final int PASSIVE_INTERVAL = 2147483647; // 0x7fffffff
-  }
-
-  public static final class GnssMeasurementRequest.Builder {
-    ctor public GnssMeasurementRequest.Builder();
-    ctor public GnssMeasurementRequest.Builder(@NonNull android.location.GnssMeasurementRequest);
-    method @NonNull public android.location.GnssMeasurementRequest build();
-    method @NonNull public android.location.GnssMeasurementRequest.Builder setFullTracking(boolean);
-    method @NonNull public android.location.GnssMeasurementRequest.Builder setIntervalMillis(@IntRange(from=0) int);
-  }
-
-  public final class GnssMeasurementsEvent implements android.os.Parcelable {
-    method public int describeContents();
-    method @NonNull public android.location.GnssClock getClock();
-    method @NonNull public java.util.Collection<android.location.GnssAutomaticGainControl> getGnssAutomaticGainControls();
-    method @NonNull public java.util.Collection<android.location.GnssMeasurement> getMeasurements();
-    method public boolean hasIsFullTracking();
-    method public boolean isFullTracking();
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssMeasurementsEvent> CREATOR;
-  }
-
-  public static final class GnssMeasurementsEvent.Builder {
-    ctor public GnssMeasurementsEvent.Builder();
-    ctor public GnssMeasurementsEvent.Builder(@NonNull android.location.GnssMeasurementsEvent);
-    method @NonNull public android.location.GnssMeasurementsEvent build();
-    method @NonNull public android.location.GnssMeasurementsEvent.Builder clearIsFullTracking();
-    method @NonNull public android.location.GnssMeasurementsEvent.Builder setClock(@NonNull android.location.GnssClock);
-    method @NonNull public android.location.GnssMeasurementsEvent.Builder setGnssAutomaticGainControls(@NonNull java.util.Collection<android.location.GnssAutomaticGainControl>);
-    method @NonNull public android.location.GnssMeasurementsEvent.Builder setIsFullTracking(boolean);
-    method @NonNull public android.location.GnssMeasurementsEvent.Builder setMeasurements(@NonNull java.util.Collection<android.location.GnssMeasurement>);
-  }
-
-  public abstract static class GnssMeasurementsEvent.Callback {
-    ctor public GnssMeasurementsEvent.Callback();
-    method public void onGnssMeasurementsReceived(android.location.GnssMeasurementsEvent);
-    method @Deprecated public void onStatusChanged(int);
-    field @Deprecated public static final int STATUS_LOCATION_DISABLED = 2; // 0x2
-    field @Deprecated public static final int STATUS_NOT_ALLOWED = 3; // 0x3
-    field @Deprecated public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
-    field @Deprecated public static final int STATUS_READY = 1; // 0x1
-  }
-
-  public final class GnssNavigationMessage implements android.os.Parcelable {
-    method public int describeContents();
-    method @NonNull public byte[] getData();
-    method @IntRange(from=0xffffffff, to=120) public int getMessageId();
-    method public int getStatus();
-    method @IntRange(from=1) public int getSubmessageId();
-    method @IntRange(from=1, to=200) public int getSvid();
-    method public int getType();
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessage> CREATOR;
-    field public static final int STATUS_PARITY_PASSED = 1; // 0x1
-    field public static final int STATUS_PARITY_REBUILT = 2; // 0x2
-    field public static final int STATUS_UNKNOWN = 0; // 0x0
-    field public static final int TYPE_BDS_CNAV1 = 1283; // 0x503
-    field public static final int TYPE_BDS_CNAV2 = 1284; // 0x504
-    field public static final int TYPE_BDS_D1 = 1281; // 0x501
-    field public static final int TYPE_BDS_D2 = 1282; // 0x502
-    field public static final int TYPE_GAL_F = 1538; // 0x602
-    field public static final int TYPE_GAL_I = 1537; // 0x601
-    field public static final int TYPE_GLO_L1CA = 769; // 0x301
-    field public static final int TYPE_GPS_CNAV2 = 260; // 0x104
-    field public static final int TYPE_GPS_L1CA = 257; // 0x101
-    field public static final int TYPE_GPS_L2CNAV = 258; // 0x102
-    field public static final int TYPE_GPS_L5CNAV = 259; // 0x103
-    field public static final int TYPE_IRN_L5CA = 1793; // 0x701
-    field public static final int TYPE_QZS_L1CA = 1025; // 0x401
-    field public static final int TYPE_SBS = 513; // 0x201
-    field public static final int TYPE_UNKNOWN = 0; // 0x0
-  }
-
-  public abstract static class GnssNavigationMessage.Callback {
-    ctor public GnssNavigationMessage.Callback();
-    method public void onGnssNavigationMessageReceived(android.location.GnssNavigationMessage);
-    method @Deprecated public void onStatusChanged(int);
-    field @Deprecated public static final int STATUS_LOCATION_DISABLED = 2; // 0x2
-    field @Deprecated public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
-    field @Deprecated public static final int STATUS_READY = 1; // 0x1
-  }
-
-  public final class GnssSignalType implements android.os.Parcelable {
-    method @NonNull public static android.location.GnssSignalType create(int, @FloatRange(from=0.0f, fromInclusive=false) double, @NonNull String);
-    method public int describeContents();
-    method @FloatRange(from=0.0f, fromInclusive=false) public double getCarrierFrequencyHz();
-    method @NonNull public String getCodeType();
-    method public int getConstellationType();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssSignalType> CREATOR;
-  }
-
-  public final class GnssStatus implements android.os.Parcelable {
-    method public int describeContents();
-    method @FloatRange(from=0, to=360) public float getAzimuthDegrees(@IntRange(from=0) int);
-    method @FloatRange(from=0, to=63) public float getBasebandCn0DbHz(@IntRange(from=0) int);
-    method @FloatRange(from=0) public float getCarrierFrequencyHz(@IntRange(from=0) int);
-    method @FloatRange(from=0, to=63) public float getCn0DbHz(@IntRange(from=0) int);
-    method public int getConstellationType(@IntRange(from=0) int);
-    method @FloatRange(from=0xffffffa6, to=90) public float getElevationDegrees(@IntRange(from=0) int);
-    method @IntRange(from=0) public int getSatelliteCount();
-    method @IntRange(from=1, to=206) public int getSvid(@IntRange(from=0) int);
-    method public boolean hasAlmanacData(@IntRange(from=0) int);
-    method public boolean hasBasebandCn0DbHz(@IntRange(from=0) int);
-    method public boolean hasCarrierFrequencyHz(@IntRange(from=0) int);
-    method public boolean hasEphemerisData(@IntRange(from=0) int);
-    method public boolean usedInFix(@IntRange(from=0) int);
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
-    field public static final int CONSTELLATION_GALILEO = 6; // 0x6
-    field public static final int CONSTELLATION_GLONASS = 3; // 0x3
-    field public static final int CONSTELLATION_GPS = 1; // 0x1
-    field public static final int CONSTELLATION_IRNSS = 7; // 0x7
-    field public static final int CONSTELLATION_QZSS = 4; // 0x4
-    field public static final int CONSTELLATION_SBAS = 2; // 0x2
-    field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssStatus> CREATOR;
-  }
-
-  public static final class GnssStatus.Builder {
-    ctor public GnssStatus.Builder();
-    method @NonNull public android.location.GnssStatus.Builder addSatellite(int, @IntRange(from=1, to=200) int, @FloatRange(from=0, to=63) float, @FloatRange(from=0xffffffa6, to=90) float, @FloatRange(from=0, to=360) float, boolean, boolean, boolean, boolean, @FloatRange(from=0) float, boolean, @FloatRange(from=0, to=63) float);
-    method @NonNull public android.location.GnssStatus build();
-    method @NonNull public android.location.GnssStatus.Builder clearSatellites();
-  }
-
-  public abstract static class GnssStatus.Callback {
-    ctor public GnssStatus.Callback();
-    method public void onFirstFix(int);
-    method public void onSatelliteStatusChanged(@NonNull android.location.GnssStatus);
-    method public void onStarted();
-    method public void onStopped();
-  }
-
-  @Deprecated public final class GpsSatellite {
-    method @Deprecated public float getAzimuth();
-    method @Deprecated public float getElevation();
-    method @Deprecated public int getPrn();
-    method @Deprecated public float getSnr();
-    method @Deprecated public boolean hasAlmanac();
-    method @Deprecated public boolean hasEphemeris();
-    method @Deprecated public boolean usedInFix();
-  }
-
-  @Deprecated public final class GpsStatus {
-    method @Deprecated @NonNull public static android.location.GpsStatus create(@NonNull android.location.GnssStatus, int);
-    method @Deprecated public int getMaxSatellites();
-    method @Deprecated public Iterable<android.location.GpsSatellite> getSatellites();
-    method @Deprecated public int getTimeToFirstFix();
-    field @Deprecated public static final int GPS_EVENT_FIRST_FIX = 3; // 0x3
-    field @Deprecated public static final int GPS_EVENT_SATELLITE_STATUS = 4; // 0x4
-    field @Deprecated public static final int GPS_EVENT_STARTED = 1; // 0x1
-    field @Deprecated public static final int GPS_EVENT_STOPPED = 2; // 0x2
-  }
-
-  @Deprecated public static interface GpsStatus.Listener {
-    method @Deprecated public void onGpsStatusChanged(int);
-  }
-
-  @Deprecated public static interface GpsStatus.NmeaListener {
-    method @Deprecated public void onNmeaReceived(long, String);
-  }
-
   public class Location implements android.os.Parcelable {
     ctor public Location(@Nullable String);
     ctor public Location(@NonNull android.location.Location);
@@ -20990,219 +20493,6 @@
     field public static final int FORMAT_SECONDS = 2; // 0x2
   }
 
-  public interface LocationListener {
-    method public default void onFlushComplete(int);
-    method public void onLocationChanged(@NonNull android.location.Location);
-    method public default void onLocationChanged(@NonNull java.util.List<android.location.Location>);
-    method public default void onProviderDisabled(@NonNull String);
-    method public default void onProviderEnabled(@NonNull String);
-    method @Deprecated public default void onStatusChanged(String, int, android.os.Bundle);
-  }
-
-  public class LocationManager {
-    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addGpsStatusListener(android.location.GpsStatus.Listener);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull android.location.GpsStatus.NmeaListener);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull android.location.OnNmeaMessageListener);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull android.location.OnNmeaMessageListener, @Nullable android.os.Handler);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.OnNmeaMessageListener);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void addProximityAlert(double, double, float, long, @NonNull android.app.PendingIntent);
-    method public void addTestProvider(@NonNull String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int);
-    method public void addTestProvider(@NonNull String, @NonNull android.location.provider.ProviderProperties);
-    method public void addTestProvider(@NonNull String, @NonNull android.location.provider.ProviderProperties, @NonNull java.util.Set<java.lang.String>);
-    method @Deprecated public void clearTestProviderEnabled(@NonNull String);
-    method @Deprecated public void clearTestProviderLocation(@NonNull String);
-    method @Deprecated public void clearTestProviderStatus(@NonNull String);
-    method @NonNull public java.util.List<java.lang.String> getAllProviders();
-    method @Deprecated @Nullable public String getBestProvider(@NonNull android.location.Criteria, boolean);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull String, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull String, @NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
-    method @Nullable public java.util.List<android.location.GnssAntennaInfo> getGnssAntennaInfos();
-    method @NonNull public android.location.GnssCapabilities getGnssCapabilities();
-    method @Nullable public String getGnssHardwareModelName();
-    method public int getGnssYearOfHardware();
-    method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public android.location.GpsStatus getGpsStatus(@Nullable android.location.GpsStatus);
-    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public android.location.Location getLastKnownLocation(@NonNull String);
-    method @Deprecated @Nullable public android.location.LocationProvider getProvider(@NonNull String);
-    method @Nullable public android.location.provider.ProviderProperties getProviderProperties(@NonNull String);
-    method @NonNull public java.util.List<java.lang.String> getProviders(boolean);
-    method @Deprecated @NonNull public java.util.List<java.lang.String> getProviders(@NonNull android.location.Criteria, boolean);
-    method public boolean hasProvider(@NonNull String);
-    method public boolean isLocationEnabled();
-    method public boolean isProviderEnabled(@NonNull String);
-    method public boolean registerAntennaInfoListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssAntennaInfo.Listener);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback, @Nullable android.os.Handler);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
-    method @Deprecated public boolean registerGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback, @Nullable android.os.Handler);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssNavigationMessageCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssNavigationMessage.Callback);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssStatusCallback(@NonNull android.location.GnssStatus.Callback);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssStatusCallback(@NonNull android.location.GnssStatus.Callback, @Nullable android.os.Handler);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssStatusCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssStatus.Callback);
-    method @Deprecated public void removeGpsStatusListener(android.location.GpsStatus.Listener);
-    method @Deprecated public void removeNmeaListener(@NonNull android.location.GpsStatus.NmeaListener);
-    method public void removeNmeaListener(@NonNull android.location.OnNmeaMessageListener);
-    method @RequiresPermission(anyOf={"android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"}, apis="..22") public void removeProximityAlert(@NonNull android.app.PendingIntent);
-    method public void removeTestProvider(@NonNull String);
-    method @RequiresPermission(anyOf={"android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"}, apis="..22") public void removeUpdates(@NonNull android.location.LocationListener);
-    method public void removeUpdates(@NonNull android.app.PendingIntent);
-    method public void requestFlush(@NonNull String, @NonNull android.location.LocationListener, int);
-    method public void requestFlush(@NonNull String, @NonNull android.app.PendingIntent, int);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull android.location.LocationListener);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
-    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(long, float, @NonNull android.location.Criteria, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
-    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(long, float, @NonNull android.location.Criteria, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull android.app.PendingIntent);
-    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(long, float, @NonNull android.location.Criteria, @NonNull android.app.PendingIntent);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, @NonNull android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, @NonNull android.location.LocationRequest, @NonNull android.app.PendingIntent);
-    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull String, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
-    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull android.location.Criteria, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
-    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull String, @NonNull android.app.PendingIntent);
-    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull android.location.Criteria, @NonNull android.app.PendingIntent);
-    method public boolean sendExtraCommand(@NonNull String, @NonNull String, @Nullable android.os.Bundle);
-    method public void setTestProviderEnabled(@NonNull String, boolean);
-    method public void setTestProviderLocation(@NonNull String, @NonNull android.location.Location);
-    method @Deprecated public void setTestProviderStatus(@NonNull String, int, @Nullable android.os.Bundle, long);
-    method public void unregisterAntennaInfoListener(@NonNull android.location.GnssAntennaInfo.Listener);
-    method public void unregisterGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback);
-    method public void unregisterGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback);
-    method public void unregisterGnssStatusCallback(@NonNull android.location.GnssStatus.Callback);
-    field public static final String ACTION_GNSS_CAPABILITIES_CHANGED = "android.location.action.GNSS_CAPABILITIES_CHANGED";
-    field public static final String EXTRA_GNSS_CAPABILITIES = "android.location.extra.GNSS_CAPABILITIES";
-    field public static final String EXTRA_LOCATION_ENABLED = "android.location.extra.LOCATION_ENABLED";
-    field public static final String EXTRA_PROVIDER_ENABLED = "android.location.extra.PROVIDER_ENABLED";
-    field public static final String EXTRA_PROVIDER_NAME = "android.location.extra.PROVIDER_NAME";
-    field public static final String FUSED_PROVIDER = "fused";
-    field public static final String GPS_PROVIDER = "gps";
-    field public static final String KEY_FLUSH_COMPLETE = "flushComplete";
-    field public static final String KEY_LOCATIONS = "locations";
-    field public static final String KEY_LOCATION_CHANGED = "location";
-    field public static final String KEY_PROVIDER_ENABLED = "providerEnabled";
-    field public static final String KEY_PROXIMITY_ENTERING = "entering";
-    field @Deprecated public static final String KEY_STATUS_CHANGED = "status";
-    field public static final String MODE_CHANGED_ACTION = "android.location.MODE_CHANGED";
-    field public static final String NETWORK_PROVIDER = "network";
-    field public static final String PASSIVE_PROVIDER = "passive";
-    field public static final String PROVIDERS_CHANGED_ACTION = "android.location.PROVIDERS_CHANGED";
-  }
-
-  @Deprecated public class LocationProvider {
-    method @Deprecated public int getAccuracy();
-    method @Deprecated public String getName();
-    method @Deprecated public int getPowerRequirement();
-    method @Deprecated public boolean hasMonetaryCost();
-    method @Deprecated public boolean meetsCriteria(android.location.Criteria);
-    method @Deprecated public boolean requiresCell();
-    method @Deprecated public boolean requiresNetwork();
-    method @Deprecated public boolean requiresSatellite();
-    method @Deprecated public boolean supportsAltitude();
-    method @Deprecated public boolean supportsBearing();
-    method @Deprecated public boolean supportsSpeed();
-    field @Deprecated public static final int AVAILABLE = 2; // 0x2
-    field @Deprecated public static final int OUT_OF_SERVICE = 0; // 0x0
-    field @Deprecated public static final int TEMPORARILY_UNAVAILABLE = 1; // 0x1
-  }
-
-  public final class LocationRequest implements android.os.Parcelable {
-    method public int describeContents();
-    method @IntRange(from=1) public long getDurationMillis();
-    method @IntRange(from=0) public long getIntervalMillis();
-    method @IntRange(from=0) public long getMaxUpdateDelayMillis();
-    method @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) public int getMaxUpdates();
-    method @FloatRange(from=0, to=java.lang.Float.MAX_VALUE) public float getMinUpdateDistanceMeters();
-    method @IntRange(from=0) public long getMinUpdateIntervalMillis();
-    method public int getQuality();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.LocationRequest> CREATOR;
-    field public static final long PASSIVE_INTERVAL = 9223372036854775807L; // 0x7fffffffffffffffL
-    field public static final int QUALITY_BALANCED_POWER_ACCURACY = 102; // 0x66
-    field public static final int QUALITY_HIGH_ACCURACY = 100; // 0x64
-    field public static final int QUALITY_LOW_POWER = 104; // 0x68
-  }
-
-  public static final class LocationRequest.Builder {
-    ctor public LocationRequest.Builder(long);
-    ctor public LocationRequest.Builder(@NonNull android.location.LocationRequest);
-    method @NonNull public android.location.LocationRequest build();
-    method @NonNull public android.location.LocationRequest.Builder clearMinUpdateIntervalMillis();
-    method @NonNull public android.location.LocationRequest.Builder setDurationMillis(@IntRange(from=1) long);
-    method @NonNull public android.location.LocationRequest.Builder setIntervalMillis(@IntRange(from=0) long);
-    method @NonNull public android.location.LocationRequest.Builder setMaxUpdateDelayMillis(@IntRange(from=0) long);
-    method @NonNull public android.location.LocationRequest.Builder setMaxUpdates(@IntRange(from=1, to=java.lang.Integer.MAX_VALUE) int);
-    method @NonNull public android.location.LocationRequest.Builder setMinUpdateDistanceMeters(@FloatRange(from=0, to=java.lang.Float.MAX_VALUE) float);
-    method @NonNull public android.location.LocationRequest.Builder setMinUpdateIntervalMillis(@IntRange(from=0) long);
-    method @NonNull public android.location.LocationRequest.Builder setQuality(int);
-  }
-
-  public interface OnNmeaMessageListener {
-    method public void onNmeaMessage(String, long);
-  }
-
-  public abstract class SettingInjectorService extends android.app.Service {
-    ctor public SettingInjectorService(String);
-    method public final android.os.IBinder onBind(android.content.Intent);
-    method protected abstract boolean onGetEnabled();
-    method protected abstract String onGetSummary();
-    method public final void onStart(android.content.Intent, int);
-    method public final int onStartCommand(android.content.Intent, int, int);
-    method public static final void refreshSettings(@NonNull android.content.Context);
-    field public static final String ACTION_INJECTED_SETTING_CHANGED = "android.location.InjectedSettingChanged";
-    field public static final String ACTION_SERVICE_INTENT = "android.location.SettingInjectorService";
-    field public static final String ATTRIBUTES_NAME = "injected-location-setting";
-    field public static final String META_DATA_NAME = "android.location.SettingInjectorService";
-  }
-
-}
-
-package android.location.altitude {
-
-  public final class AltitudeConverter {
-    ctor public AltitudeConverter();
-    method @WorkerThread public void addMslAltitudeToLocation(@NonNull android.content.Context, @NonNull android.location.Location) throws java.io.IOException;
-  }
-
-}
-
-package android.location.provider {
-
-  public final class ProviderProperties implements android.os.Parcelable {
-    method public int describeContents();
-    method public int getAccuracy();
-    method public int getPowerUsage();
-    method public boolean hasAltitudeSupport();
-    method public boolean hasBearingSupport();
-    method public boolean hasCellRequirement();
-    method public boolean hasMonetaryCost();
-    method public boolean hasNetworkRequirement();
-    method public boolean hasSatelliteRequirement();
-    method public boolean hasSpeedSupport();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field public static final int ACCURACY_COARSE = 2; // 0x2
-    field public static final int ACCURACY_FINE = 1; // 0x1
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.provider.ProviderProperties> CREATOR;
-    field public static final int POWER_USAGE_HIGH = 3; // 0x3
-    field public static final int POWER_USAGE_LOW = 1; // 0x1
-    field public static final int POWER_USAGE_MEDIUM = 2; // 0x2
-  }
-
-  public static final class ProviderProperties.Builder {
-    ctor public ProviderProperties.Builder();
-    ctor public ProviderProperties.Builder(@NonNull android.location.provider.ProviderProperties);
-    method @NonNull public android.location.provider.ProviderProperties build();
-    method @NonNull public android.location.provider.ProviderProperties.Builder setAccuracy(int);
-    method @NonNull public android.location.provider.ProviderProperties.Builder setHasAltitudeSupport(boolean);
-    method @NonNull public android.location.provider.ProviderProperties.Builder setHasBearingSupport(boolean);
-    method @NonNull public android.location.provider.ProviderProperties.Builder setHasCellRequirement(boolean);
-    method @NonNull public android.location.provider.ProviderProperties.Builder setHasMonetaryCost(boolean);
-    method @NonNull public android.location.provider.ProviderProperties.Builder setHasNetworkRequirement(boolean);
-    method @NonNull public android.location.provider.ProviderProperties.Builder setHasSatelliteRequirement(boolean);
-    method @NonNull public android.location.provider.ProviderProperties.Builder setHasSpeedSupport(boolean);
-    method @NonNull public android.location.provider.ProviderProperties.Builder setPowerUsage(int);
-  }
-
 }
 
 package android.media {
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index e4846b8..3de7748 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -186,16 +186,6 @@
 
 }
 
-package android.location {
-
-  public class LocationManager {
-    method @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public boolean injectLocation(@NonNull android.location.Location);
-    method @RequiresPermission(android.Manifest.permission.CONTROL_AUTOMOTIVE_GNSS) public boolean isAutomotiveGnssSuspended();
-    method @RequiresPermission(android.Manifest.permission.CONTROL_AUTOMOTIVE_GNSS) public void setAutomotiveGnssSuspended(boolean);
-  }
-
-}
-
 package android.media {
 
   public class AudioManager {
diff --git a/core/api/module-lib-lint-baseline.txt b/core/api/module-lib-lint-baseline.txt
index 27436ce..471745a 100644
--- a/core/api/module-lib-lint-baseline.txt
+++ b/core/api/module-lib-lint-baseline.txt
@@ -17,18 +17,6 @@
     SAM-compatible parameters (such as parameter 1, "pw", in android.content.pm.PackageItemInfo.dumpBack) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
 SamShouldBeLast: android.content.pm.PackageItemInfo#dumpFront(android.util.Printer, String):
     SAM-compatible parameters (such as parameter 1, "pw", in android.content.pm.PackageItemInfo.dumpFront) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
-SamShouldBeLast: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler):
-    SAM-compatible parameters (such as parameter 1, "listener", in android.location.LocationManager.addNmeaListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
-SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(String, long, float, android.location.LocationListener, android.os.Looper):
-    SAM-compatible parameters (such as parameter 4, "listener", in android.location.LocationManager.requestLocationUpdates) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
-SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(android.location.LocationRequest, android.location.LocationListener, android.os.Looper):
-    SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestLocationUpdates) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
-SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(long, float, android.location.Criteria, android.location.LocationListener, android.os.Looper):
-    SAM-compatible parameters (such as parameter 4, "listener", in android.location.LocationManager.requestLocationUpdates) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
-SamShouldBeLast: android.location.LocationManager#requestSingleUpdate(String, android.location.LocationListener, android.os.Looper):
-    SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestSingleUpdate) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
-SamShouldBeLast: android.location.LocationManager#requestSingleUpdate(android.location.Criteria, android.location.LocationListener, android.os.Looper):
-    SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestSingleUpdate) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
 SamShouldBeLast: android.media.AudioManager#abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes):
     SAM-compatible parameters (such as parameter 1, "l", in android.media.AudioManager.abandonAudioFocus) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
 SamShouldBeLast: android.media.AudioManager#requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes, int, int):
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 0c61981..ff44a1b 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -6182,653 +6182,12 @@
 
 package android.location {
 
-  public abstract class BatchedLocationCallback {
-    ctor public BatchedLocationCallback();
-    method public void onLocationBatch(java.util.List<android.location.Location>);
-  }
-
-  public final class CorrelationVector implements android.os.Parcelable {
-    method public int describeContents();
-    method @FloatRange(from=0.0f) public double getFrequencyOffsetMetersPerSecond();
-    method @NonNull public int[] getMagnitude();
-    method @FloatRange(from=0.0f) public double getSamplingStartMeters();
-    method @FloatRange(from=0.0f, fromInclusive=false) public double getSamplingWidthMeters();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.CorrelationVector> CREATOR;
-  }
-
-  public static final class CorrelationVector.Builder {
-    ctor public CorrelationVector.Builder();
-    method @NonNull public android.location.CorrelationVector build();
-    method @NonNull public android.location.CorrelationVector.Builder setFrequencyOffsetMetersPerSecond(@FloatRange(from=0.0f) double);
-    method @NonNull public android.location.CorrelationVector.Builder setMagnitude(@NonNull int[]);
-    method @NonNull public android.location.CorrelationVector.Builder setSamplingStartMeters(@FloatRange(from=0.0f) double);
-    method @NonNull public android.location.CorrelationVector.Builder setSamplingWidthMeters(@FloatRange(from=0.0f, fromInclusive=false) double);
-  }
-
-  public final class Country implements android.os.Parcelable {
-    ctor public Country(@NonNull String, int);
-    method public int describeContents();
-    method @NonNull public String getCountryCode();
-    method public int getSource();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field public static final int COUNTRY_SOURCE_LOCALE = 3; // 0x3
-    field public static final int COUNTRY_SOURCE_LOCATION = 1; // 0x1
-    field public static final int COUNTRY_SOURCE_NETWORK = 0; // 0x0
-    field public static final int COUNTRY_SOURCE_SIM = 2; // 0x2
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.Country> CREATOR;
-  }
-
-  public class CountryDetector {
-    method public void registerCountryDetectorCallback(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Country>);
-    method public void unregisterCountryDetectorCallback(@NonNull java.util.function.Consumer<android.location.Country>);
-  }
-
-  public final class GnssCapabilities implements android.os.Parcelable {
-    method @Deprecated public boolean hasMeasurementCorrectionsReflectingPane();
-    method @Deprecated public boolean hasNavMessages();
-    method @Deprecated public boolean hasSatelliteBlacklist();
-  }
-
-  public final class GnssExcessPathInfo implements android.os.Parcelable {
-    method public int describeContents();
-    method @FloatRange(from=0.0f) public float getAttenuationDb();
-    method @FloatRange(from=0.0f) public float getExcessPathLengthMeters();
-    method @FloatRange(from=0.0f) public float getExcessPathLengthUncertaintyMeters();
-    method @NonNull public android.location.GnssReflectingPlane getReflectingPlane();
-    method public boolean hasAttenuation();
-    method public boolean hasExcessPathLength();
-    method public boolean hasExcessPathLengthUncertainty();
-    method public boolean hasReflectingPlane();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssExcessPathInfo> CREATOR;
-  }
-
-  public static final class GnssExcessPathInfo.Builder {
-    ctor public GnssExcessPathInfo.Builder();
-    method @NonNull public android.location.GnssExcessPathInfo build();
-    method @NonNull public android.location.GnssExcessPathInfo.Builder clearAttenuationDb();
-    method @NonNull public android.location.GnssExcessPathInfo.Builder clearExcessPathLengthMeters();
-    method @NonNull public android.location.GnssExcessPathInfo.Builder clearExcessPathLengthUncertaintyMeters();
-    method @NonNull public android.location.GnssExcessPathInfo.Builder setAttenuationDb(@FloatRange(from=0.0f) float);
-    method @NonNull public android.location.GnssExcessPathInfo.Builder setExcessPathLengthMeters(@FloatRange(from=0.0f) float);
-    method @NonNull public android.location.GnssExcessPathInfo.Builder setExcessPathLengthUncertaintyMeters(@FloatRange(from=0.0f) float);
-    method @NonNull public android.location.GnssExcessPathInfo.Builder setReflectingPlane(@Nullable android.location.GnssReflectingPlane);
-  }
-
-  public final class GnssMeasurement implements android.os.Parcelable {
-    method @Nullable public java.util.Collection<android.location.CorrelationVector> getCorrelationVectors();
-    method @Nullable public android.location.SatellitePvt getSatellitePvt();
-    method public boolean hasCorrelationVectors();
-    method public boolean hasSatellitePvt();
-  }
-
-  public final class GnssMeasurementCorrections implements android.os.Parcelable {
-    method public int describeContents();
-    method @FloatRange(from=-1000.0F, to=10000.0f) public double getAltitudeMeters();
-    method @FloatRange(from=0.0f, to=360.0f) public float getEnvironmentBearingDegrees();
-    method @FloatRange(from=0.0f, to=180.0f) public float getEnvironmentBearingUncertaintyDegrees();
-    method @FloatRange(from=0.0f) public double getHorizontalPositionUncertaintyMeters();
-    method @FloatRange(from=-90.0F, to=90.0f) public double getLatitudeDegrees();
-    method @FloatRange(from=-180.0F, to=180.0f) public double getLongitudeDegrees();
-    method @NonNull public java.util.List<android.location.GnssSingleSatCorrection> getSingleSatelliteCorrectionList();
-    method @IntRange(from=0) public long getToaGpsNanosecondsOfWeek();
-    method @FloatRange(from=0.0f) public double getVerticalPositionUncertaintyMeters();
-    method public boolean hasEnvironmentBearing();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.location.GnssMeasurementCorrections> CREATOR;
-  }
-
-  public static final class GnssMeasurementCorrections.Builder {
-    ctor public GnssMeasurementCorrections.Builder();
-    method @NonNull public android.location.GnssMeasurementCorrections build();
-    method @NonNull public android.location.GnssMeasurementCorrections.Builder setAltitudeMeters(@FloatRange(from=-1000.0F, to=10000.0f) double);
-    method @NonNull public android.location.GnssMeasurementCorrections.Builder setEnvironmentBearingDegrees(@FloatRange(from=0.0f, to=360.0f) float);
-    method @NonNull public android.location.GnssMeasurementCorrections.Builder setEnvironmentBearingUncertaintyDegrees(@FloatRange(from=0.0f, to=180.0f) float);
-    method @NonNull public android.location.GnssMeasurementCorrections.Builder setHorizontalPositionUncertaintyMeters(@FloatRange(from=0.0f) double);
-    method @NonNull public android.location.GnssMeasurementCorrections.Builder setLatitudeDegrees(@FloatRange(from=-90.0F, to=90.0f) double);
-    method @NonNull public android.location.GnssMeasurementCorrections.Builder setLongitudeDegrees(@FloatRange(from=-180.0F, to=180.0f) double);
-    method @NonNull public android.location.GnssMeasurementCorrections.Builder setSingleSatelliteCorrectionList(@NonNull java.util.List<android.location.GnssSingleSatCorrection>);
-    method @NonNull public android.location.GnssMeasurementCorrections.Builder setToaGpsNanosecondsOfWeek(@IntRange(from=0) long);
-    method @NonNull public android.location.GnssMeasurementCorrections.Builder setVerticalPositionUncertaintyMeters(@FloatRange(from=0.0f) double);
-  }
-
-  public final class GnssMeasurementRequest implements android.os.Parcelable {
-    method @NonNull public android.os.WorkSource getWorkSource();
-    method public boolean isCorrelationVectorOutputsEnabled();
-  }
-
-  public static final class GnssMeasurementRequest.Builder {
-    method @NonNull public android.location.GnssMeasurementRequest.Builder setCorrelationVectorOutputsEnabled(boolean);
-    method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.GnssMeasurementRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
-  }
-
-  public final class GnssReflectingPlane implements android.os.Parcelable {
-    method public int describeContents();
-    method @FloatRange(from=-1000.0F, to=10000.0f) public double getAltitudeMeters();
-    method @FloatRange(from=0.0f, to=360.0f) public double getAzimuthDegrees();
-    method @FloatRange(from=-90.0F, to=90.0f) public double getLatitudeDegrees();
-    method @FloatRange(from=-180.0F, to=180.0f) public double getLongitudeDegrees();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.location.GnssReflectingPlane> CREATOR;
-  }
-
-  public static final class GnssReflectingPlane.Builder {
-    ctor public GnssReflectingPlane.Builder();
-    method @NonNull public android.location.GnssReflectingPlane build();
-    method @NonNull public android.location.GnssReflectingPlane.Builder setAltitudeMeters(@FloatRange(from=-1000.0F, to=10000.0f) double);
-    method @NonNull public android.location.GnssReflectingPlane.Builder setAzimuthDegrees(@FloatRange(from=0.0f, to=360.0f) double);
-    method @NonNull public android.location.GnssReflectingPlane.Builder setLatitudeDegrees(@FloatRange(from=-90.0F, to=90.0f) double);
-    method @NonNull public android.location.GnssReflectingPlane.Builder setLongitudeDegrees(@FloatRange(from=-180.0F, to=180.0f) double);
-  }
-
-  public final class GnssRequest implements android.os.Parcelable {
-    method public int describeContents();
-    method public boolean isFullTracking();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssRequest> CREATOR;
-  }
-
-  public static final class GnssRequest.Builder {
-    ctor public GnssRequest.Builder();
-    ctor public GnssRequest.Builder(@NonNull android.location.GnssRequest);
-    method @NonNull public android.location.GnssRequest build();
-    method @NonNull public android.location.GnssRequest.Builder setFullTracking(boolean);
-  }
-
-  public final class GnssSingleSatCorrection implements android.os.Parcelable {
-    method public int describeContents();
-    method @FloatRange(from=0.0f, fromInclusive=false) public float getCarrierFrequencyHz();
-    method @FloatRange(from=0.0f) public float getCombinedAttenuationDb();
-    method public int getConstellationType();
-    method @FloatRange(from=0.0f) public float getExcessPathLengthMeters();
-    method @FloatRange(from=0.0f) public float getExcessPathLengthUncertaintyMeters();
-    method @NonNull public java.util.List<android.location.GnssExcessPathInfo> getGnssExcessPathInfoList();
-    method @FloatRange(from=0.0f, to=1.0f) public float getProbabilityLineOfSight();
-    method @Deprecated @Nullable public android.location.GnssReflectingPlane getReflectingPlane();
-    method @IntRange(from=0) public int getSatelliteId();
-    method public boolean hasCombinedAttenuation();
-    method public boolean hasExcessPathLength();
-    method public boolean hasExcessPathLengthUncertainty();
-    method @Deprecated public boolean hasReflectingPlane();
-    method public boolean hasValidSatelliteLineOfSight();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.location.GnssSingleSatCorrection> CREATOR;
-  }
-
-  public static final class GnssSingleSatCorrection.Builder {
-    ctor public GnssSingleSatCorrection.Builder();
-    method @NonNull public android.location.GnssSingleSatCorrection build();
-    method @NonNull public android.location.GnssSingleSatCorrection.Builder clearCombinedAttenuationDb();
-    method @NonNull public android.location.GnssSingleSatCorrection.Builder clearExcessPathLengthMeters();
-    method @NonNull public android.location.GnssSingleSatCorrection.Builder clearExcessPathLengthUncertaintyMeters();
-    method @NonNull public android.location.GnssSingleSatCorrection.Builder clearProbabilityLineOfSight();
-    method @NonNull public android.location.GnssSingleSatCorrection.Builder setCarrierFrequencyHz(@FloatRange(from=0.0f, fromInclusive=false) float);
-    method @NonNull public android.location.GnssSingleSatCorrection.Builder setCombinedAttenuationDb(@FloatRange(from=0.0f) float);
-    method @NonNull public android.location.GnssSingleSatCorrection.Builder setConstellationType(int);
-    method @NonNull public android.location.GnssSingleSatCorrection.Builder setExcessPathLengthMeters(@FloatRange(from=0.0f) float);
-    method @NonNull public android.location.GnssSingleSatCorrection.Builder setExcessPathLengthUncertaintyMeters(@FloatRange(from=0.0f) float);
-    method @NonNull public android.location.GnssSingleSatCorrection.Builder setGnssExcessPathInfoList(@NonNull java.util.List<android.location.GnssExcessPathInfo>);
-    method @NonNull public android.location.GnssSingleSatCorrection.Builder setProbabilityLineOfSight(@FloatRange(from=0.0f, to=1.0f) float);
-    method @Deprecated @NonNull public android.location.GnssSingleSatCorrection.Builder setReflectingPlane(@Nullable android.location.GnssReflectingPlane);
-    method @NonNull public android.location.GnssSingleSatCorrection.Builder setSatelliteId(@IntRange(from=0) int);
-  }
-
-  @Deprecated public class GpsClock implements android.os.Parcelable {
-    method @Deprecated public int describeContents();
-    method @Deprecated public double getBiasInNs();
-    method @Deprecated public double getBiasUncertaintyInNs();
-    method @Deprecated public double getDriftInNsPerSec();
-    method @Deprecated public double getDriftUncertaintyInNsPerSec();
-    method @Deprecated public long getFullBiasInNs();
-    method @Deprecated public short getLeapSecond();
-    method @Deprecated public long getTimeInNs();
-    method @Deprecated public double getTimeUncertaintyInNs();
-    method @Deprecated public byte getType();
-    method @Deprecated public boolean hasBiasInNs();
-    method @Deprecated public boolean hasBiasUncertaintyInNs();
-    method @Deprecated public boolean hasDriftInNsPerSec();
-    method @Deprecated public boolean hasDriftUncertaintyInNsPerSec();
-    method @Deprecated public boolean hasFullBiasInNs();
-    method @Deprecated public boolean hasLeapSecond();
-    method @Deprecated public boolean hasTimeUncertaintyInNs();
-    method @Deprecated public void reset();
-    method @Deprecated public void resetBiasInNs();
-    method @Deprecated public void resetBiasUncertaintyInNs();
-    method @Deprecated public void resetDriftInNsPerSec();
-    method @Deprecated public void resetDriftUncertaintyInNsPerSec();
-    method @Deprecated public void resetFullBiasInNs();
-    method @Deprecated public void resetLeapSecond();
-    method @Deprecated public void resetTimeUncertaintyInNs();
-    method @Deprecated public void set(android.location.GpsClock);
-    method @Deprecated public void setBiasInNs(double);
-    method @Deprecated public void setBiasUncertaintyInNs(double);
-    method @Deprecated public void setDriftInNsPerSec(double);
-    method @Deprecated public void setDriftUncertaintyInNsPerSec(double);
-    method @Deprecated public void setFullBiasInNs(long);
-    method @Deprecated public void setLeapSecond(short);
-    method @Deprecated public void setTimeInNs(long);
-    method @Deprecated public void setTimeUncertaintyInNs(double);
-    method @Deprecated public void setType(byte);
-    method @Deprecated public void writeToParcel(android.os.Parcel, int);
-    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.GpsClock> CREATOR;
-    field @Deprecated public static final byte TYPE_GPS_TIME = 2; // 0x2
-    field @Deprecated public static final byte TYPE_LOCAL_HW_TIME = 1; // 0x1
-    field @Deprecated public static final byte TYPE_UNKNOWN = 0; // 0x0
-  }
-
-  @Deprecated public class GpsMeasurement implements android.os.Parcelable {
-    method @Deprecated public int describeContents();
-    method @Deprecated public double getAccumulatedDeltaRangeInMeters();
-    method @Deprecated public short getAccumulatedDeltaRangeState();
-    method @Deprecated public double getAccumulatedDeltaRangeUncertaintyInMeters();
-    method @Deprecated public double getAzimuthInDeg();
-    method @Deprecated public double getAzimuthUncertaintyInDeg();
-    method @Deprecated public int getBitNumber();
-    method @Deprecated public long getCarrierCycles();
-    method @Deprecated public float getCarrierFrequencyInHz();
-    method @Deprecated public double getCarrierPhase();
-    method @Deprecated public double getCarrierPhaseUncertainty();
-    method @Deprecated public double getCn0InDbHz();
-    method @Deprecated public double getCodePhaseInChips();
-    method @Deprecated public double getCodePhaseUncertaintyInChips();
-    method @Deprecated public double getDopplerShiftInHz();
-    method @Deprecated public double getDopplerShiftUncertaintyInHz();
-    method @Deprecated public double getElevationInDeg();
-    method @Deprecated public double getElevationUncertaintyInDeg();
-    method @Deprecated public byte getLossOfLock();
-    method @Deprecated public byte getMultipathIndicator();
-    method @Deprecated public byte getPrn();
-    method @Deprecated public double getPseudorangeInMeters();
-    method @Deprecated public double getPseudorangeRateInMetersPerSec();
-    method @Deprecated public double getPseudorangeRateUncertaintyInMetersPerSec();
-    method @Deprecated public double getPseudorangeUncertaintyInMeters();
-    method @Deprecated public long getReceivedGpsTowInNs();
-    method @Deprecated public long getReceivedGpsTowUncertaintyInNs();
-    method @Deprecated public double getSnrInDb();
-    method @Deprecated public short getState();
-    method @Deprecated public short getTimeFromLastBitInMs();
-    method @Deprecated public double getTimeOffsetInNs();
-    method @Deprecated public boolean hasAzimuthInDeg();
-    method @Deprecated public boolean hasAzimuthUncertaintyInDeg();
-    method @Deprecated public boolean hasBitNumber();
-    method @Deprecated public boolean hasCarrierCycles();
-    method @Deprecated public boolean hasCarrierFrequencyInHz();
-    method @Deprecated public boolean hasCarrierPhase();
-    method @Deprecated public boolean hasCarrierPhaseUncertainty();
-    method @Deprecated public boolean hasCodePhaseInChips();
-    method @Deprecated public boolean hasCodePhaseUncertaintyInChips();
-    method @Deprecated public boolean hasDopplerShiftInHz();
-    method @Deprecated public boolean hasDopplerShiftUncertaintyInHz();
-    method @Deprecated public boolean hasElevationInDeg();
-    method @Deprecated public boolean hasElevationUncertaintyInDeg();
-    method @Deprecated public boolean hasPseudorangeInMeters();
-    method @Deprecated public boolean hasPseudorangeUncertaintyInMeters();
-    method @Deprecated public boolean hasSnrInDb();
-    method @Deprecated public boolean hasTimeFromLastBitInMs();
-    method @Deprecated public boolean isPseudorangeRateCorrected();
-    method @Deprecated public boolean isUsedInFix();
-    method @Deprecated public void reset();
-    method @Deprecated public void resetAzimuthInDeg();
-    method @Deprecated public void resetAzimuthUncertaintyInDeg();
-    method @Deprecated public void resetBitNumber();
-    method @Deprecated public void resetCarrierCycles();
-    method @Deprecated public void resetCarrierFrequencyInHz();
-    method @Deprecated public void resetCarrierPhase();
-    method @Deprecated public void resetCarrierPhaseUncertainty();
-    method @Deprecated public void resetCodePhaseInChips();
-    method @Deprecated public void resetCodePhaseUncertaintyInChips();
-    method @Deprecated public void resetDopplerShiftInHz();
-    method @Deprecated public void resetDopplerShiftUncertaintyInHz();
-    method @Deprecated public void resetElevationInDeg();
-    method @Deprecated public void resetElevationUncertaintyInDeg();
-    method @Deprecated public void resetPseudorangeInMeters();
-    method @Deprecated public void resetPseudorangeUncertaintyInMeters();
-    method @Deprecated public void resetSnrInDb();
-    method @Deprecated public void resetTimeFromLastBitInMs();
-    method @Deprecated public void set(android.location.GpsMeasurement);
-    method @Deprecated public void setAccumulatedDeltaRangeInMeters(double);
-    method @Deprecated public void setAccumulatedDeltaRangeState(short);
-    method @Deprecated public void setAccumulatedDeltaRangeUncertaintyInMeters(double);
-    method @Deprecated public void setAzimuthInDeg(double);
-    method @Deprecated public void setAzimuthUncertaintyInDeg(double);
-    method @Deprecated public void setBitNumber(int);
-    method @Deprecated public void setCarrierCycles(long);
-    method @Deprecated public void setCarrierFrequencyInHz(float);
-    method @Deprecated public void setCarrierPhase(double);
-    method @Deprecated public void setCarrierPhaseUncertainty(double);
-    method @Deprecated public void setCn0InDbHz(double);
-    method @Deprecated public void setCodePhaseInChips(double);
-    method @Deprecated public void setCodePhaseUncertaintyInChips(double);
-    method @Deprecated public void setDopplerShiftInHz(double);
-    method @Deprecated public void setDopplerShiftUncertaintyInHz(double);
-    method @Deprecated public void setElevationInDeg(double);
-    method @Deprecated public void setElevationUncertaintyInDeg(double);
-    method @Deprecated public void setLossOfLock(byte);
-    method @Deprecated public void setMultipathIndicator(byte);
-    method @Deprecated public void setPrn(byte);
-    method @Deprecated public void setPseudorangeInMeters(double);
-    method @Deprecated public void setPseudorangeRateInMetersPerSec(double);
-    method @Deprecated public void setPseudorangeRateUncertaintyInMetersPerSec(double);
-    method @Deprecated public void setPseudorangeUncertaintyInMeters(double);
-    method @Deprecated public void setReceivedGpsTowInNs(long);
-    method @Deprecated public void setReceivedGpsTowUncertaintyInNs(long);
-    method @Deprecated public void setSnrInDb(double);
-    method @Deprecated public void setState(short);
-    method @Deprecated public void setTimeFromLastBitInMs(short);
-    method @Deprecated public void setTimeOffsetInNs(double);
-    method @Deprecated public void setUsedInFix(boolean);
-    method @Deprecated public void writeToParcel(android.os.Parcel, int);
-    field @Deprecated public static final short ADR_STATE_CYCLE_SLIP = 4; // 0x4
-    field @Deprecated public static final short ADR_STATE_RESET = 2; // 0x2
-    field @Deprecated public static final short ADR_STATE_UNKNOWN = 0; // 0x0
-    field @Deprecated public static final short ADR_STATE_VALID = 1; // 0x1
-    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.GpsMeasurement> CREATOR;
-    field @Deprecated public static final byte LOSS_OF_LOCK_CYCLE_SLIP = 2; // 0x2
-    field @Deprecated public static final byte LOSS_OF_LOCK_OK = 1; // 0x1
-    field @Deprecated public static final byte LOSS_OF_LOCK_UNKNOWN = 0; // 0x0
-    field @Deprecated public static final byte MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
-    field @Deprecated public static final byte MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
-    field @Deprecated public static final byte MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
-    field @Deprecated public static final short STATE_BIT_SYNC = 2; // 0x2
-    field @Deprecated public static final short STATE_CODE_LOCK = 1; // 0x1
-    field @Deprecated public static final short STATE_MSEC_AMBIGUOUS = 16; // 0x10
-    field @Deprecated public static final short STATE_SUBFRAME_SYNC = 4; // 0x4
-    field @Deprecated public static final short STATE_TOW_DECODED = 8; // 0x8
-    field @Deprecated public static final short STATE_UNKNOWN = 0; // 0x0
-  }
-
-  @Deprecated public class GpsMeasurementsEvent implements android.os.Parcelable {
-    ctor @Deprecated public GpsMeasurementsEvent(android.location.GpsClock, android.location.GpsMeasurement[]);
-    method @Deprecated public int describeContents();
-    method @Deprecated @NonNull public android.location.GpsClock getClock();
-    method @Deprecated @NonNull public java.util.Collection<android.location.GpsMeasurement> getMeasurements();
-    method @Deprecated public void writeToParcel(android.os.Parcel, int);
-    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.GpsMeasurementsEvent> CREATOR;
-    field @Deprecated public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
-    field @Deprecated public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
-    field @Deprecated public static final int STATUS_READY = 1; // 0x1
-  }
-
-  @Deprecated public static interface GpsMeasurementsEvent.Listener {
-    method @Deprecated public void onGpsMeasurementsReceived(android.location.GpsMeasurementsEvent);
-    method @Deprecated public void onStatusChanged(int);
-  }
-
-  @Deprecated public class GpsNavigationMessage implements android.os.Parcelable {
-    method @Deprecated public int describeContents();
-    method @Deprecated @NonNull public byte[] getData();
-    method @Deprecated public short getMessageId();
-    method @Deprecated public byte getPrn();
-    method @Deprecated public short getStatus();
-    method @Deprecated public short getSubmessageId();
-    method @Deprecated public byte getType();
-    method @Deprecated public void reset();
-    method @Deprecated public void set(android.location.GpsNavigationMessage);
-    method @Deprecated public void setData(byte[]);
-    method @Deprecated public void setMessageId(short);
-    method @Deprecated public void setPrn(byte);
-    method @Deprecated public void setStatus(short);
-    method @Deprecated public void setSubmessageId(short);
-    method @Deprecated public void setType(byte);
-    method @Deprecated public void writeToParcel(android.os.Parcel, int);
-    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessage> CREATOR;
-    field @Deprecated public static final short STATUS_PARITY_PASSED = 1; // 0x1
-    field @Deprecated public static final short STATUS_PARITY_REBUILT = 2; // 0x2
-    field @Deprecated public static final short STATUS_UNKNOWN = 0; // 0x0
-    field @Deprecated public static final byte TYPE_CNAV2 = 4; // 0x4
-    field @Deprecated public static final byte TYPE_L1CA = 1; // 0x1
-    field @Deprecated public static final byte TYPE_L2CNAV = 2; // 0x2
-    field @Deprecated public static final byte TYPE_L5CNAV = 3; // 0x3
-    field @Deprecated public static final byte TYPE_UNKNOWN = 0; // 0x0
-  }
-
-  @Deprecated public class GpsNavigationMessageEvent implements android.os.Parcelable {
-    ctor @Deprecated public GpsNavigationMessageEvent(android.location.GpsNavigationMessage);
-    method @Deprecated public int describeContents();
-    method @Deprecated @NonNull public android.location.GpsNavigationMessage getNavigationMessage();
-    method @Deprecated public void writeToParcel(android.os.Parcel, int);
-    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessageEvent> CREATOR;
-    field @Deprecated public static int STATUS_GPS_LOCATION_DISABLED;
-    field @Deprecated public static int STATUS_NOT_SUPPORTED;
-    field @Deprecated public static int STATUS_READY;
-  }
-
-  @Deprecated public static interface GpsNavigationMessageEvent.Listener {
-    method @Deprecated public void onGpsNavigationMessageReceived(android.location.GpsNavigationMessageEvent);
-    method @Deprecated public void onStatusChanged(int);
-  }
-
-  public final class LastLocationRequest implements android.os.Parcelable {
-    method public int describeContents();
-    method public boolean isAdasGnssBypass();
-    method public boolean isHiddenFromAppOps();
-    method public boolean isLocationSettingsIgnored();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.LastLocationRequest> CREATOR;
-  }
-
-  public static final class LastLocationRequest.Builder {
-    ctor public LastLocationRequest.Builder();
-    ctor public LastLocationRequest.Builder(@NonNull android.location.LastLocationRequest);
-    method @NonNull public android.location.LastLocationRequest build();
-    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LastLocationRequest.Builder setAdasGnssBypass(boolean);
-    method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS) public android.location.LastLocationRequest.Builder setHiddenFromAppOps(boolean);
-    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LastLocationRequest.Builder setLocationSettingsIgnored(boolean);
-  }
-
   public class Location implements android.os.Parcelable {
     method public void makeComplete();
     method @Deprecated public void setIsFromMockProvider(boolean);
     field @Deprecated public static final String EXTRA_NO_GPS_LOCATION = "noGPSLocation";
   }
 
-  public class LocationManager {
-    method @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.INTERACT_ACROSS_USERS}) public void addProviderRequestChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.provider.ProviderRequest.ChangedListener);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void flushGnssBatch();
-    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
-    method @Nullable public String getExtraLocationControllerPackage();
-    method @Deprecated public int getGnssBatchSize();
-    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public android.location.Location getLastKnownLocation(@NonNull String, @NonNull android.location.LastLocationRequest);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void injectGnssMeasurementCorrections(@NonNull android.location.GnssMeasurementCorrections);
-    method public boolean isAdasGnssLocationEnabled();
-    method public boolean isExtraLocationControllerPackageEnabled();
-    method public boolean isLocationEnabledForUser(@NonNull android.os.UserHandle);
-    method public boolean isProviderEnabledForUser(@NonNull String, @NonNull android.os.UserHandle);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@NonNull String);
-    method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String, @Nullable String);
-    method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.UPDATE_APP_OPS_STATS}) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void removeProviderRequestChangedListener(@NonNull android.location.provider.ProviderRequest.ChangedListener);
-    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
-    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
-    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public void setAdasGnssLocationEnabled(boolean);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackage(@Nullable String);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackageEnabled(boolean);
-    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean setProviderEnabledForUser(@NonNull String, boolean, @NonNull android.os.UserHandle);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean unregisterGnssBatchedLocationCallback(@NonNull android.location.BatchedLocationCallback);
-    field public static final String ACTION_ADAS_GNSS_ENABLED_CHANGED = "android.location.action.ADAS_GNSS_ENABLED_CHANGED";
-    field public static final String EXTRA_ADAS_GNSS_ENABLED = "android.location.extra.ADAS_GNSS_ENABLED";
-    field @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public static final String GPS_HARDWARE_PROVIDER = "gps_hardware";
-  }
-
-  public final class LocationRequest implements android.os.Parcelable {
-    method @Deprecated @NonNull public static android.location.LocationRequest create();
-    method @Deprecated @NonNull public static android.location.LocationRequest createFromDeprecatedCriteria(@NonNull android.location.Criteria, long, float, boolean);
-    method @Deprecated @NonNull public static android.location.LocationRequest createFromDeprecatedProvider(@NonNull String, long, float, boolean);
-    method @Deprecated public long getExpireAt();
-    method @Deprecated public long getExpireIn();
-    method @Deprecated public long getFastestInterval();
-    method @Deprecated public boolean getHideFromAppOps();
-    method @Deprecated public long getInterval();
-    method @Deprecated public int getNumUpdates();
-    method @Deprecated @NonNull public String getProvider();
-    method @Deprecated public float getSmallestDisplacement();
-    method @NonNull public android.os.WorkSource getWorkSource();
-    method public boolean isAdasGnssBypass();
-    method public boolean isHiddenFromAppOps();
-    method public boolean isLocationSettingsIgnored();
-    method public boolean isLowPower();
-    method @Deprecated public boolean isLowPowerMode();
-    method @Deprecated @NonNull public android.location.LocationRequest setExpireAt(long);
-    method @Deprecated @NonNull public android.location.LocationRequest setExpireIn(long);
-    method @Deprecated @NonNull public android.location.LocationRequest setFastestInterval(long);
-    method @Deprecated public void setHideFromAppOps(boolean);
-    method @Deprecated @NonNull public android.location.LocationRequest setInterval(long);
-    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LocationRequest setLocationSettingsIgnored(boolean);
-    method @Deprecated @NonNull public android.location.LocationRequest setLowPowerMode(boolean);
-    method @Deprecated @NonNull public android.location.LocationRequest setNumUpdates(int);
-    method @Deprecated @NonNull public android.location.LocationRequest setProvider(@NonNull String);
-    method @Deprecated @NonNull public android.location.LocationRequest setQuality(int);
-    method @Deprecated @NonNull public android.location.LocationRequest setSmallestDisplacement(float);
-    method @Deprecated public void setWorkSource(@Nullable android.os.WorkSource);
-    field @Deprecated public static final int ACCURACY_BLOCK = 102; // 0x66
-    field @Deprecated public static final int ACCURACY_CITY = 104; // 0x68
-    field @Deprecated public static final int ACCURACY_FINE = 100; // 0x64
-    field @Deprecated public static final int POWER_HIGH = 203; // 0xcb
-    field @Deprecated public static final int POWER_LOW = 201; // 0xc9
-    field @Deprecated public static final int POWER_NONE = 200; // 0xc8
-  }
-
-  public static final class LocationRequest.Builder {
-    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LocationRequest.Builder setAdasGnssBypass(boolean);
-    method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS) public android.location.LocationRequest.Builder setHiddenFromAppOps(boolean);
-    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LocationRequest.Builder setLocationSettingsIgnored(boolean);
-    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.location.LocationRequest.Builder setLowPower(boolean);
-    method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.LocationRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
-  }
-
-  public final class SatellitePvt implements android.os.Parcelable {
-    method public int describeContents();
-    method @Nullable public android.location.SatellitePvt.ClockInfo getClockInfo();
-    method public int getEphemerisSource();
-    method @FloatRange public double getIonoDelayMeters();
-    method @IntRange(from=0, to=1023) public int getIssueOfDataClock();
-    method @IntRange(from=0, to=1023) public int getIssueOfDataEphemeris();
-    method @Nullable public android.location.SatellitePvt.PositionEcef getPositionEcef();
-    method @IntRange(from=0) public long getTimeOfClockSeconds();
-    method @IntRange(from=0) public long getTimeOfEphemerisSeconds();
-    method @FloatRange public double getTropoDelayMeters();
-    method @Nullable public android.location.SatellitePvt.VelocityEcef getVelocityEcef();
-    method public boolean hasIono();
-    method public boolean hasIssueOfDataClock();
-    method public boolean hasIssueOfDataEphemeris();
-    method public boolean hasPositionVelocityClockInfo();
-    method public boolean hasTimeOfClockSeconds();
-    method public boolean hasTimeOfEphemerisSeconds();
-    method public boolean hasTropo();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.SatellitePvt> CREATOR;
-    field public static final int EPHEMERIS_SOURCE_DEMODULATED = 0; // 0x0
-    field public static final int EPHEMERIS_SOURCE_OTHER = 3; // 0x3
-    field public static final int EPHEMERIS_SOURCE_SERVER_LONG_TERM = 2; // 0x2
-    field public static final int EPHEMERIS_SOURCE_SERVER_NORMAL = 1; // 0x1
-  }
-
-  public static final class SatellitePvt.Builder {
-    ctor public SatellitePvt.Builder();
-    method @NonNull public android.location.SatellitePvt build();
-    method @NonNull public android.location.SatellitePvt.Builder setClockInfo(@NonNull android.location.SatellitePvt.ClockInfo);
-    method @NonNull public android.location.SatellitePvt.Builder setEphemerisSource(int);
-    method @NonNull public android.location.SatellitePvt.Builder setIonoDelayMeters(@FloatRange(from=0.0f, to=100.0f) double);
-    method @NonNull public android.location.SatellitePvt.Builder setIssueOfDataClock(@IntRange(from=0, to=1023) int);
-    method @NonNull public android.location.SatellitePvt.Builder setIssueOfDataEphemeris(@IntRange(from=0, to=1023) int);
-    method @NonNull public android.location.SatellitePvt.Builder setPositionEcef(@NonNull android.location.SatellitePvt.PositionEcef);
-    method @NonNull public android.location.SatellitePvt.Builder setTimeOfClockSeconds(@IntRange(from=0) long);
-    method @NonNull public android.location.SatellitePvt.Builder setTimeOfEphemerisSeconds(@IntRange(from=0) long);
-    method @NonNull public android.location.SatellitePvt.Builder setTropoDelayMeters(@FloatRange(from=0.0f, to=100.0f) double);
-    method @NonNull public android.location.SatellitePvt.Builder setVelocityEcef(@NonNull android.location.SatellitePvt.VelocityEcef);
-  }
-
-  public static final class SatellitePvt.ClockInfo implements android.os.Parcelable {
-    ctor public SatellitePvt.ClockInfo(double, double, double);
-    method public int describeContents();
-    method @FloatRange public double getClockDriftMetersPerSecond();
-    method @FloatRange public double getHardwareCodeBiasMeters();
-    method @FloatRange public double getTimeCorrectionMeters();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.SatellitePvt.ClockInfo> CREATOR;
-  }
-
-  public static final class SatellitePvt.PositionEcef implements android.os.Parcelable {
-    ctor public SatellitePvt.PositionEcef(double, double, double, double);
-    method public int describeContents();
-    method @FloatRange(from=0.0f, fromInclusive=false) public double getUreMeters();
-    method @FloatRange public double getXMeters();
-    method @FloatRange public double getYMeters();
-    method @FloatRange public double getZMeters();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.SatellitePvt.PositionEcef> CREATOR;
-  }
-
-  public static final class SatellitePvt.VelocityEcef implements android.os.Parcelable {
-    ctor public SatellitePvt.VelocityEcef(double, double, double, double);
-    method public int describeContents();
-    method @FloatRange(from=0.0f, fromInclusive=false) public double getUreRateMetersPerSecond();
-    method @FloatRange public double getXMetersPerSecond();
-    method @FloatRange public double getYMetersPerSecond();
-    method @FloatRange public double getZMetersPerSecond();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.SatellitePvt.VelocityEcef> CREATOR;
-  }
-
-}
-
-package android.location.provider {
-
-  public abstract class LocationProviderBase {
-    ctor public LocationProviderBase(@NonNull android.content.Context, @NonNull String, @NonNull android.location.provider.ProviderProperties);
-    method @Nullable public final android.os.IBinder getBinder();
-    method @NonNull public android.location.provider.ProviderProperties getProperties();
-    method public boolean isAllowed();
-    method public abstract void onFlush(@NonNull android.location.provider.LocationProviderBase.OnFlushCompleteCallback);
-    method public abstract void onSendExtraCommand(@NonNull String, @Nullable android.os.Bundle);
-    method public abstract void onSetRequest(@NonNull android.location.provider.ProviderRequest);
-    method public void reportLocation(@NonNull android.location.Location);
-    method public void reportLocations(@NonNull java.util.List<android.location.Location>);
-    method public void setAllowed(boolean);
-    method public void setProperties(@NonNull android.location.provider.ProviderProperties);
-    field public static final String ACTION_FUSED_PROVIDER = "com.android.location.service.FusedLocationProvider";
-    field public static final String ACTION_GNSS_PROVIDER = "android.location.provider.action.GNSS_PROVIDER";
-    field public static final String ACTION_NETWORK_PROVIDER = "com.android.location.service.v3.NetworkLocationProvider";
-  }
-
-  public static interface LocationProviderBase.OnFlushCompleteCallback {
-    method public void onFlushComplete();
-  }
-
-  public final class ProviderRequest implements android.os.Parcelable {
-    method public int describeContents();
-    method @IntRange(from=0) public long getIntervalMillis();
-    method @IntRange(from=0) public long getMaxUpdateDelayMillis();
-    method public int getQuality();
-    method @NonNull public android.os.WorkSource getWorkSource();
-    method public boolean isActive();
-    method public boolean isLocationSettingsIgnored();
-    method public boolean isLowPower();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.provider.ProviderRequest> CREATOR;
-    field @NonNull public static final android.location.provider.ProviderRequest EMPTY_REQUEST;
-    field public static final long INTERVAL_DISABLED = 9223372036854775807L; // 0x7fffffffffffffffL
-  }
-
-  public static final class ProviderRequest.Builder {
-    ctor public ProviderRequest.Builder();
-    method @NonNull public android.location.provider.ProviderRequest build();
-    method @NonNull public android.location.provider.ProviderRequest.Builder setIntervalMillis(@IntRange(from=0) long);
-    method @NonNull public android.location.provider.ProviderRequest.Builder setLocationSettingsIgnored(boolean);
-    method @NonNull public android.location.provider.ProviderRequest.Builder setLowPower(boolean);
-    method @NonNull public android.location.provider.ProviderRequest.Builder setMaxUpdateDelayMillis(@IntRange(from=0) long);
-    method @NonNull public android.location.provider.ProviderRequest.Builder setQuality(int);
-    method @NonNull public android.location.provider.ProviderRequest.Builder setWorkSource(@NonNull android.os.WorkSource);
-  }
-
-  public static interface ProviderRequest.ChangedListener {
-    method public void onProviderRequestChanged(@NonNull String, @NonNull android.location.provider.ProviderRequest);
-  }
-
 }
 
 package android.media {
diff --git a/core/api/system-lint-baseline.txt b/core/api/system-lint-baseline.txt
index 6c23327..e7c0a91 100644
--- a/core/api/system-lint-baseline.txt
+++ b/core/api/system-lint-baseline.txt
@@ -135,16 +135,6 @@
     SAM-compatible parameters (such as parameter 1, "pw", in android.content.pm.ResolveInfo.dump) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
 SamShouldBeLast: android.location.Location#dump(android.util.Printer, String):
     SAM-compatible parameters (such as parameter 1, "pw", in android.location.Location.dump) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
-SamShouldBeLast: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler):
-    SAM-compatible parameters (such as parameter 1, "listener", in android.location.LocationManager.addNmeaListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
-SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(String, long, float, android.location.LocationListener, android.os.Looper):
-    SAM-compatible parameters (such as parameter 4, "listener", in android.location.LocationManager.requestLocationUpdates) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
-SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(long, float, android.location.Criteria, android.location.LocationListener, android.os.Looper):
-    SAM-compatible parameters (such as parameter 4, "listener", in android.location.LocationManager.requestLocationUpdates) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
-SamShouldBeLast: android.location.LocationManager#requestSingleUpdate(String, android.location.LocationListener, android.os.Looper):
-    SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestSingleUpdate) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
-SamShouldBeLast: android.location.LocationManager#requestSingleUpdate(android.location.Criteria, android.location.LocationListener, android.os.Looper):
-    SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestSingleUpdate) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
 SamShouldBeLast: android.media.AudioFocusRequest.Builder#setOnAudioFocusChangeListener(android.media.AudioManager.OnAudioFocusChangeListener, android.os.Handler):
     SAM-compatible parameters (such as parameter 1, "listener", in android.media.AudioFocusRequest.Builder.setOnAudioFocusChangeListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
 SamShouldBeLast: android.media.AudioManager#requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int):
diff --git a/core/api/system-removed.txt b/core/api/system-removed.txt
index 1c10356..aa17df3 100644
--- a/core/api/system-removed.txt
+++ b/core/api/system-removed.txt
@@ -114,20 +114,6 @@
 
 }
 
-package android.location {
-
-  public class LocationManager {
-    method @Deprecated public boolean addGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener);
-    method @Deprecated public boolean addGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String);
-    method @Deprecated public void removeGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener);
-    method @Deprecated public void removeGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setLocationControllerExtraPackage(String);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setLocationControllerExtraPackageEnabled(boolean);
-  }
-
-}
-
 package android.media.tv {
 
   public final class TvInputManager {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 29b5213..642813f 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -499,14 +499,14 @@
     method public int describeContents();
     method public int getActivityType();
     method @Nullable public android.graphics.Rect getAppBounds();
-    method public android.graphics.Rect getBounds();
+    method @NonNull public android.graphics.Rect getBounds();
     method @NonNull public android.graphics.Rect getMaxBounds();
     method public int getRotation();
     method public int getWindowingMode();
     method public static boolean isFloating(int);
     method public void setActivityType(int);
     method public void setAppBounds(@Nullable android.graphics.Rect);
-    method public void setBounds(android.graphics.Rect);
+    method public void setBounds(@Nullable android.graphics.Rect);
     method public void setMaxBounds(@Nullable android.graphics.Rect);
     method public void setRotation(int);
     method public void setTo(android.app.WindowConfiguration);
@@ -1748,109 +1748,6 @@
 
 }
 
-package android.location {
-
-  public final class GnssClock implements android.os.Parcelable {
-    ctor public GnssClock();
-    method public void reset();
-    method public void resetBiasNanos();
-    method public void resetBiasUncertaintyNanos();
-    method public void resetDriftNanosPerSecond();
-    method public void resetDriftUncertaintyNanosPerSecond();
-    method public void resetElapsedRealtimeNanos();
-    method public void resetElapsedRealtimeUncertaintyNanos();
-    method public void resetFullBiasNanos();
-    method public void resetLeapSecond();
-    method public void resetReferenceCarrierFrequencyHzForIsb();
-    method public void resetReferenceCodeTypeForIsb();
-    method public void resetReferenceConstellationTypeForIsb();
-    method public void resetTimeUncertaintyNanos();
-    method public void set(android.location.GnssClock);
-    method public void setBiasNanos(double);
-    method public void setBiasUncertaintyNanos(@FloatRange(from=0.0f) double);
-    method public void setDriftNanosPerSecond(double);
-    method public void setDriftUncertaintyNanosPerSecond(@FloatRange(from=0.0f) double);
-    method public void setElapsedRealtimeNanos(long);
-    method public void setElapsedRealtimeUncertaintyNanos(@FloatRange(from=0.0f) double);
-    method public void setFullBiasNanos(long);
-    method public void setHardwareClockDiscontinuityCount(int);
-    method public void setLeapSecond(int);
-    method public void setReferenceCarrierFrequencyHzForIsb(@FloatRange(from=0.0) double);
-    method public void setReferenceCodeTypeForIsb(@NonNull String);
-    method public void setReferenceConstellationTypeForIsb(int);
-    method public void setTimeNanos(long);
-    method public void setTimeUncertaintyNanos(@FloatRange(from=0.0f) double);
-  }
-
-  public final class GnssMeasurement implements android.os.Parcelable {
-    ctor public GnssMeasurement();
-    method public void reset();
-    method public void resetAutomaticGainControlLevel();
-    method public void resetBasebandCn0DbHz();
-    method @Deprecated public void resetCarrierCycles();
-    method public void resetCarrierFrequencyHz();
-    method @Deprecated public void resetCarrierPhase();
-    method @Deprecated public void resetCarrierPhaseUncertainty();
-    method public void resetCodeType();
-    method public void resetCorrelationVectors();
-    method public void resetFullInterSignalBiasNanos();
-    method public void resetFullInterSignalBiasUncertaintyNanos();
-    method public void resetSatelliteInterSignalBiasNanos();
-    method public void resetSatelliteInterSignalBiasUncertaintyNanos();
-    method public void resetSatellitePvt();
-    method public void resetSnrInDb();
-    method public void set(android.location.GnssMeasurement);
-    method public void setAccumulatedDeltaRangeMeters(double);
-    method public void setAccumulatedDeltaRangeState(int);
-    method public void setAccumulatedDeltaRangeUncertaintyMeters(double);
-    method @Deprecated public void setAutomaticGainControlLevelInDb(double);
-    method public void setBasebandCn0DbHz(double);
-    method @Deprecated public void setCarrierCycles(long);
-    method public void setCarrierFrequencyHz(float);
-    method @Deprecated public void setCarrierPhase(double);
-    method @Deprecated public void setCarrierPhaseUncertainty(double);
-    method public void setCn0DbHz(double);
-    method public void setCodeType(@NonNull String);
-    method public void setConstellationType(int);
-    method public void setCorrelationVectors(@Nullable java.util.Collection<android.location.CorrelationVector>);
-    method public void setFullInterSignalBiasNanos(double);
-    method public void setFullInterSignalBiasUncertaintyNanos(@FloatRange(from=0.0) double);
-    method public void setMultipathIndicator(int);
-    method public void setPseudorangeRateMetersPerSecond(double);
-    method public void setPseudorangeRateUncertaintyMetersPerSecond(double);
-    method public void setReceivedSvTimeNanos(long);
-    method public void setReceivedSvTimeUncertaintyNanos(long);
-    method public void setSatelliteInterSignalBiasNanos(double);
-    method public void setSatelliteInterSignalBiasUncertaintyNanos(@FloatRange(from=0.0) double);
-    method public void setSatellitePvt(@Nullable android.location.SatellitePvt);
-    method public void setSnrInDb(double);
-    method public void setState(int);
-    method public void setSvid(int);
-    method public void setTimeOffsetNanos(double);
-    field public static final int ADR_STATE_ALL = 31; // 0x1f
-  }
-
-  public final class GnssNavigationMessage implements android.os.Parcelable {
-    ctor public GnssNavigationMessage();
-    method public void reset();
-    method public void set(android.location.GnssNavigationMessage);
-    method public void setData(byte[]);
-    method public void setMessageId(@IntRange(from=0xffffffff, to=120) int);
-    method public void setStatus(int);
-    method public void setSubmessageId(@IntRange(from=1) int);
-    method public void setSvid(@IntRange(from=1, to=200) int);
-    method public void setType(int);
-  }
-
-  public class LocationManager {
-    method @NonNull public String[] getBackgroundThrottlingWhitelist();
-    method @NonNull public android.os.PackageTagsList getIgnoreSettingsAllowlist();
-    method @Deprecated @NonNull public String[] getIgnoreSettingsWhitelist();
-    method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public java.util.List<java.lang.String> getProviderPackages(@NonNull String);
-  }
-
-}
-
 package android.media {
 
   public final class AudioAttributes implements android.os.Parcelable {
diff --git a/core/api/test-lint-baseline.txt b/core/api/test-lint-baseline.txt
index 4a97280..1aaedab 100644
--- a/core/api/test-lint-baseline.txt
+++ b/core/api/test-lint-baseline.txt
@@ -87,50 +87,6 @@
     Methods must not throw generic exceptions (`java.lang.Exception`)
 
 
-GetterSetterNames: android.location.GnssClock#setBiasNanos(double):
-    Symmetric method for `hasBiasNanos` must be named `setHasBiasNanos`; was `setBiasNanos`
-GetterSetterNames: android.location.GnssClock#setBiasUncertaintyNanos(double):
-    Symmetric method for `hasBiasUncertaintyNanos` must be named `setHasBiasUncertaintyNanos`; was `setBiasUncertaintyNanos`
-GetterSetterNames: android.location.GnssClock#setDriftNanosPerSecond(double):
-    Symmetric method for `hasDriftNanosPerSecond` must be named `setHasDriftNanosPerSecond`; was `setDriftNanosPerSecond`
-GetterSetterNames: android.location.GnssClock#setDriftUncertaintyNanosPerSecond(double):
-    Symmetric method for `hasDriftUncertaintyNanosPerSecond` must be named `setHasDriftUncertaintyNanosPerSecond`; was `setDriftUncertaintyNanosPerSecond`
-GetterSetterNames: android.location.GnssClock#setElapsedRealtimeNanos(long):
-    Symmetric method for `hasElapsedRealtimeNanos` must be named `setHasElapsedRealtimeNanos`; was `setElapsedRealtimeNanos`
-GetterSetterNames: android.location.GnssClock#setElapsedRealtimeUncertaintyNanos(double):
-    Symmetric method for `hasElapsedRealtimeUncertaintyNanos` must be named `setHasElapsedRealtimeUncertaintyNanos`; was `setElapsedRealtimeUncertaintyNanos`
-GetterSetterNames: android.location.GnssClock#setFullBiasNanos(long):
-    Symmetric method for `hasFullBiasNanos` must be named `setHasFullBiasNanos`; was `setFullBiasNanos`
-GetterSetterNames: android.location.GnssClock#setLeapSecond(int):
-    Symmetric method for `hasLeapSecond` must be named `setHasLeapSecond`; was `setLeapSecond`
-GetterSetterNames: android.location.GnssClock#setReferenceCarrierFrequencyHzForIsb(double):
-    Symmetric method for `hasReferenceCarrierFrequencyHzForIsb` must be named `setHasReferenceCarrierFrequencyHzForIsb`; was `setReferenceCarrierFrequencyHzForIsb`
-GetterSetterNames: android.location.GnssClock#setReferenceCodeTypeForIsb(String):
-    Symmetric method for `hasReferenceCodeTypeForIsb` must be named `setHasReferenceCodeTypeForIsb`; was `setReferenceCodeTypeForIsb`
-GetterSetterNames: android.location.GnssClock#setReferenceConstellationTypeForIsb(int):
-    Symmetric method for `hasReferenceConstellationTypeForIsb` must be named `setHasReferenceConstellationTypeForIsb`; was `setReferenceConstellationTypeForIsb`
-GetterSetterNames: android.location.GnssClock#setTimeUncertaintyNanos(double):
-    Symmetric method for `hasTimeUncertaintyNanos` must be named `setHasTimeUncertaintyNanos`; was `setTimeUncertaintyNanos`
-GetterSetterNames: android.location.GnssMeasurement#setBasebandCn0DbHz(double):
-    Symmetric method for `hasBasebandCn0DbHz` must be named `setHasBasebandCn0DbHz`; was `setBasebandCn0DbHz`
-GetterSetterNames: android.location.GnssMeasurement#setCarrierFrequencyHz(float):
-    Symmetric method for `hasCarrierFrequencyHz` must be named `setHasCarrierFrequencyHz`; was `setCarrierFrequencyHz`
-GetterSetterNames: android.location.GnssMeasurement#setCodeType(String):
-    Symmetric method for `hasCodeType` must be named `setHasCodeType`; was `setCodeType`
-GetterSetterNames: android.location.GnssMeasurement#setCorrelationVectors(java.util.Collection<android.location.CorrelationVector>):
-    Symmetric method for `hasCorrelationVectors` must be named `setHasCorrelationVectors`; was `setCorrelationVectors`
-GetterSetterNames: android.location.GnssMeasurement#setFullInterSignalBiasNanos(double):
-    Symmetric method for `hasFullInterSignalBiasNanos` must be named `setHasFullInterSignalBiasNanos`; was `setFullInterSignalBiasNanos`
-GetterSetterNames: android.location.GnssMeasurement#setFullInterSignalBiasUncertaintyNanos(double):
-    Symmetric method for `hasFullInterSignalBiasUncertaintyNanos` must be named `setHasFullInterSignalBiasUncertaintyNanos`; was `setFullInterSignalBiasUncertaintyNanos`
-GetterSetterNames: android.location.GnssMeasurement#setSatelliteInterSignalBiasNanos(double):
-    Symmetric method for `hasSatelliteInterSignalBiasNanos` must be named `setHasSatelliteInterSignalBiasNanos`; was `setSatelliteInterSignalBiasNanos`
-GetterSetterNames: android.location.GnssMeasurement#setSatelliteInterSignalBiasUncertaintyNanos(double):
-    Symmetric method for `hasSatelliteInterSignalBiasUncertaintyNanos` must be named `setHasSatelliteInterSignalBiasUncertaintyNanos`; was `setSatelliteInterSignalBiasUncertaintyNanos`
-GetterSetterNames: android.location.GnssMeasurement#setSatellitePvt(android.location.SatellitePvt):
-    Symmetric method for `hasSatellitePvt` must be named `setHasSatellitePvt`; was `setSatellitePvt`
-GetterSetterNames: android.location.GnssMeasurement#setSnrInDb(double):
-    Symmetric method for `hasSnrInDb` must be named `setHasSnrInDb`; was `setSnrInDb`
 GetterSetterNames: android.net.NetworkPolicyManager#getRestrictBackground():
     Symmetric method for `setRestrictBackground` must be named `isRestrictBackground`; was `getRestrictBackground`
 
@@ -343,14 +299,6 @@
     Missing nullability on method `getCameraIdListNoLazy` return
 MissingNullability: android.hardware.display.AmbientDisplayConfiguration#AmbientDisplayConfiguration(android.content.Context) parameter #0:
     Missing nullability on parameter `context` in method `AmbientDisplayConfiguration`
-MissingNullability: android.location.GnssClock#set(android.location.GnssClock) parameter #0:
-    Missing nullability on parameter `clock` in method `set`
-MissingNullability: android.location.GnssMeasurement#set(android.location.GnssMeasurement) parameter #0:
-    Missing nullability on parameter `measurement` in method `set`
-MissingNullability: android.location.GnssNavigationMessage#set(android.location.GnssNavigationMessage) parameter #0:
-    Missing nullability on parameter `navigationMessage` in method `set`
-MissingNullability: android.location.GnssNavigationMessage#setData(byte[]) parameter #0:
-    Missing nullability on parameter `value` in method `setData`
 MissingNullability: android.media.AudioAttributes#getSdkUsages():
     Missing nullability on method `getSdkUsages` return
 MissingNullability: android.media.AudioManager#getPublicStreamTypes():
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index bf5b428..2c42df3 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -7670,14 +7670,17 @@
             }
             extras.putBoolean(EXTRA_SHOW_BIG_PICTURE_WHEN_COLLAPSED, mShowBigPictureWhenCollapsed);
 
-            // If the icon contains a bitmap, use the old extra so that listeners which look for
-            // that extra can still find the picture.  Don't include the new extra in that case,
-            // to avoid duplicating data.
-            if (mPictureIcon != null && mPictureIcon.getType() == Icon.TYPE_BITMAP) {
+            if (mPictureIcon == null) {
+                extras.remove(EXTRA_PICTURE_ICON);
+                extras.remove(EXTRA_PICTURE);
+            } else if (mPictureIcon.getType() == Icon.TYPE_BITMAP) {
+                // If the icon contains a bitmap, use the old extra so that listeners which look
+                // for that extra can still find the picture. Don't include the new extra in
+                // that case, to avoid duplicating data.
                 extras.putParcelable(EXTRA_PICTURE, mPictureIcon.getBitmap());
-                extras.putParcelable(EXTRA_PICTURE_ICON, null);
+                extras.remove(EXTRA_PICTURE_ICON);
             } else {
-                extras.putParcelable(EXTRA_PICTURE, null);
+                extras.remove(EXTRA_PICTURE);
                 extras.putParcelable(EXTRA_PICTURE_ICON, mPictureIcon);
             }
         }
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index bf238c3..019a1a8 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -267,12 +267,13 @@
         }
     };
 
-    // TODO(b/297672475): make this take @Nullable
     /**
      * Sets the bounds to the provided {@link Rect}.
+     * Passing {@code null} sets the bounds {@link Rect} to empty.
+     *
      * @param rect the new bounds value.
      */
-    public void setBounds(Rect rect) {
+    public void setBounds(@Nullable Rect rect) {
         if (rect == null) {
             mBounds.setEmpty();
             return;
@@ -282,8 +283,10 @@
     }
 
     /**
-     * Set {@link #mAppBounds} to the input Rect.
-     * @param rect The rect value to set {@link #mAppBounds} to.
+     * Sets the app bounds to the provided {@link Rect}.
+     * Passing {@code null} sets the bounds to {@code null}.
+     *
+     * @param rect the new app bounds value.
      * @see #getAppBounds()
      */
     public void setAppBounds(@Nullable Rect rect) {
@@ -297,7 +300,9 @@
 
     /**
      * Sets the maximum bounds to the provided {@link Rect}.
-     * @param rect the new bounds value.
+     * Passing {@code null} sets the bounds {@link Rect} to empty.
+     *
+     * @param rect the new max bounds value.
      * @see #getMaxBounds()
      */
     public void setMaxBounds(@Nullable Rect rect) {
@@ -364,8 +369,8 @@
         return mAppBounds;
     }
 
-    // TODO(b/297672475): make this return @NonNull
     /** @see #setBounds(Rect) */
+    @NonNull
     public Rect getBounds() {
         return mBounds;
     }
diff --git a/core/java/android/companion/virtual/IVirtualDevice.aidl b/core/java/android/companion/virtual/IVirtualDevice.aidl
index be699f4..c58561d 100644
--- a/core/java/android/companion/virtual/IVirtualDevice.aidl
+++ b/core/java/android/companion/virtual/IVirtualDevice.aidl
@@ -64,6 +64,16 @@
     String getPersistentDeviceId();
 
     /**
+     * Returns the IDs of all virtual displays of this device.
+     */
+    int[] getDisplayIds();
+
+    /**
+     * Returns the device policy for the given policy type.
+     */
+    int getDevicePolicy(int policyType);
+
+    /**
      * Closes the virtual device and frees all associated resources.
      */
     @EnforcePermission("CREATE_VIRTUAL_DEVICE")
diff --git a/core/java/android/companion/virtual/IVirtualDeviceListener.aidl b/core/java/android/companion/virtual/IVirtualDeviceListener.aidl
new file mode 100644
index 0000000..c6dd227
--- /dev/null
+++ b/core/java/android/companion/virtual/IVirtualDeviceListener.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.companion.virtual;
+
+/**
+ * Interface to listen for changes in the available virtual devices.
+ *
+ * @hide
+ */
+oneway interface IVirtualDeviceListener {
+
+    /**
+     * Called whenever a new virtual device has been added to the system.
+     */
+    void onVirtualDeviceCreated(int deviceId);
+
+    /**
+     * Called whenever a virtual device has been removed from the system.
+     */
+    void onVirtualDeviceClosed(int deviceId);
+}
diff --git a/core/java/android/companion/virtual/IVirtualDeviceManager.aidl b/core/java/android/companion/virtual/IVirtualDeviceManager.aidl
index ed8484f..b665036 100644
--- a/core/java/android/companion/virtual/IVirtualDeviceManager.aidl
+++ b/core/java/android/companion/virtual/IVirtualDeviceManager.aidl
@@ -18,6 +18,7 @@
 
 import android.companion.virtual.IVirtualDevice;
 import android.companion.virtual.IVirtualDeviceActivityListener;
+import android.companion.virtual.IVirtualDeviceListener;
 import android.companion.virtual.IVirtualDeviceSoundEffectListener;
 import android.companion.virtual.VirtualDevice;
 import android.companion.virtual.VirtualDeviceParams;
@@ -56,12 +57,27 @@
      */
     List<VirtualDevice> getVirtualDevices();
 
-   /**
+    /**
+     * Returns the details of the virtual device with the given ID, if any.
+     */
+    VirtualDevice getVirtualDevice(int deviceId);
+
+    /**
+     * Registers a virtual device listener to receive notifications for virtual device events.
+     */
+    void registerVirtualDeviceListener(in IVirtualDeviceListener listener);
+
+    /**
+     * Unregisters a previously registered virtual device listener.
+     */
+    void unregisterVirtualDeviceListener(in IVirtualDeviceListener listener);
+
+    /**
      * Returns the ID of the device which owns the display with the given ID.
      */
     int getDeviceIdForDisplayId(int displayId);
 
-   /**
+    /**
      * Checks whether the passed {@code deviceId} is a valid virtual device ID or not.
      * {@link VirtualDeviceManager#DEVICE_ID_DEFAULT} is not valid as it is the ID of the default
      * device which is not a virtual device. {@code deviceId} must correspond to a virtual device
diff --git a/core/java/android/companion/virtual/VirtualDevice.java b/core/java/android/companion/virtual/VirtualDevice.java
index ceaf7e4..4692f92 100644
--- a/core/java/android/companion/virtual/VirtualDevice.java
+++ b/core/java/android/companion/virtual/VirtualDevice.java
@@ -16,13 +16,17 @@
 
 package android.companion.virtual;
 
+import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM;
+import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_SENSORS;
+
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.companion.virtual.flags.Flags;
 import android.content.Context;
 import android.os.Parcel;
 import android.os.Parcelable;
-
-import java.util.Objects;
+import android.os.RemoteException;
 
 /**
  * Details of a particular virtual device.
@@ -31,9 +35,12 @@
  *
  * <p class="note">Not to be confused with {@link VirtualDeviceManager.VirtualDevice}, which is used
  * by the virtual device creator and allows them to manage the device.
+ *
+ * @see VirtualDeviceManager#registerVirtualDeviceListener
  */
 public final class VirtualDevice implements Parcelable {
 
+    private final @NonNull IVirtualDevice mVirtualDevice;
     private final int mId;
     private final @Nullable String mPersistentId;
     private final @Nullable String mName;
@@ -44,17 +51,20 @@
      *
      * @hide
      */
-    public VirtualDevice(int id, @Nullable String persistentId, @Nullable String name) {
+    public VirtualDevice(@NonNull IVirtualDevice virtualDevice, int id,
+            @Nullable String persistentId, @Nullable String name) {
         if (id <= Context.DEVICE_ID_DEFAULT) {
             throw new IllegalArgumentException("VirtualDevice ID must be greater than "
                     + Context.DEVICE_ID_DEFAULT);
         }
+        mVirtualDevice = virtualDevice;
         mId = id;
         mPersistentId = persistentId;
         mName = name;
     }
 
     private VirtualDevice(@NonNull Parcel parcel) {
+        mVirtualDevice = IVirtualDevice.Stub.asInterface(parcel.readStrongBinder());
         mId = parcel.readInt();
         mPersistentId = parcel.readString8();
         mName = parcel.readString8();
@@ -101,6 +111,40 @@
         return mName;
     }
 
+    /**
+     * 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
+     * IDs to {@link android.hardware.display.DisplayManager#getDisplay(int)}.</p>
+     */
+    @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
+    public @NonNull int[] getDisplayIds() {
+        try {
+            return mVirtualDevice.getDisplayIds();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns whether this device may have custom sensors.
+     *
+     * <p>Returning {@code true} does not necessarily mean that this device has sensors, it only
+     * means that a {@link android.hardware.SensorManager} instance created from a {@link Context}
+     * associated with this device will return this device's sensors, if any.</p>
+     *
+     * @see Context#getDeviceId()
+     * @see Context#createDeviceContext(int)
+     */
+    @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
+    public boolean hasCustomSensorSupport() {
+        try {
+            return mVirtualDevice.getDevicePolicy(POLICY_TYPE_SENSORS) == DEVICE_POLICY_CUSTOM;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -108,31 +152,13 @@
 
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeStrongBinder(mVirtualDevice.asBinder());
         dest.writeInt(mId);
         dest.writeString8(mPersistentId);
         dest.writeString8(mName);
     }
 
     @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (!(o instanceof VirtualDevice)) {
-            return false;
-        }
-        VirtualDevice that = (VirtualDevice) o;
-        return mId == that.mId
-                && Objects.equals(mPersistentId, that.mPersistentId)
-                && Objects.equals(mName, that.mName);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mId, mPersistentId, mName);
-    }
-
-    @Override
     @NonNull
     public String toString() {
         return "VirtualDevice("
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index 923e689..29b0ff3 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -55,11 +55,13 @@
 import android.hardware.input.VirtualTouchscreen;
 import android.hardware.input.VirtualTouchscreenConfig;
 import android.media.AudioManager;
+import android.os.Binder;
 import android.os.Looper;
 import android.os.RemoteException;
 import android.util.Log;
 import android.view.Surface;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.AnnotationValidations;
 
 import java.lang.annotation.ElementType;
@@ -67,6 +69,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.Executor;
@@ -147,6 +150,9 @@
     private final IVirtualDeviceManager mService;
     private final Context mContext;
 
+    @GuardedBy("mVirtualDeviceListeners")
+    private final List<VirtualDeviceListenerDelegate> mVirtualDeviceListeners = new ArrayList<>();
+
     /** @hide */
     public VirtualDeviceManager(
             @Nullable IVirtualDeviceManager service, @NonNull Context context) {
@@ -207,6 +213,88 @@
     }
 
     /**
+     * Returns the details of the virtual device with the given ID, if any.
+     *
+     * <p>The returned object is a read-only representation of the virtual device that expose its
+     * properties.</p>
+     */
+    @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
+    @Nullable
+    public android.companion.virtual.VirtualDevice getVirtualDevice(int deviceId) {
+        if (mService == null) {
+            Log.w(TAG, "Failed to retrieve virtual devices; no virtual device manager service.");
+            return null;
+        }
+        if (deviceId == Context.DEVICE_ID_INVALID || deviceId == Context.DEVICE_ID_DEFAULT) {
+            return null;  // Don't even bother making a Binder call.
+        }
+        try {
+            return mService.getVirtualDevice(deviceId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Registers a virtual device listener to receive notifications when virtual devices are created
+     * or closed.
+     *
+     * @param executor The executor where the listener is executed on.
+     * @param listener The listener to add.
+     * @see #unregisterVirtualDeviceListener
+     */
+    @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
+    public void registerVirtualDeviceListener(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull VirtualDeviceListener listener) {
+        if (mService == null) {
+            Log.w(TAG, "Failed to register listener; no virtual device manager service.");
+            return;
+        }
+        final VirtualDeviceListenerDelegate delegate =
+                new VirtualDeviceListenerDelegate(Objects.requireNonNull(executor),
+                        Objects.requireNonNull(listener));
+        synchronized (mVirtualDeviceListeners) {
+            try {
+                mService.registerVirtualDeviceListener(delegate);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+            mVirtualDeviceListeners.add(delegate);
+        }
+    }
+
+    /**
+     * Unregisters a virtual device listener previously registered with
+     * {@link #registerVirtualDeviceListener}.
+     *
+     * @param listener The listener to unregister.
+     * @see #registerVirtualDeviceListener
+     */
+    @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
+    public void unregisterVirtualDeviceListener(@NonNull VirtualDeviceListener listener) {
+        if (mService == null) {
+            Log.w(TAG, "Failed to unregister listener; no virtual device manager service.");
+            return;
+        }
+        Objects.requireNonNull(listener);
+        synchronized (mVirtualDeviceListeners) {
+            final Iterator<VirtualDeviceListenerDelegate> it = mVirtualDeviceListeners.iterator();
+            while (it.hasNext()) {
+                final VirtualDeviceListenerDelegate delegate = it.next();
+                if (delegate.mListener == listener) {
+                    try {
+                        mService.unregisterVirtualDeviceListener(delegate);
+                    } catch (RemoteException e) {
+                        throw e.rethrowFromSystemServer();
+                    }
+                    it.remove();
+                }
+            }
+        }
+    }
+
+    /**
      * Returns the device policy for the given virtual device and policy type.
      *
      * <p>In case the virtual device identifier is not valid, or there's no explicitly specified
@@ -748,7 +836,7 @@
          *
          * @param executor The executor where the listener is executed on.
          * @param soundEffectListener The listener to add.
-         * @see #removeActivityListener(ActivityListener)
+         * @see #removeSoundEffectListener(SoundEffectListener)
          */
         public void addSoundEffectListener(@CallbackExecutor @NonNull Executor executor,
                 @NonNull SoundEffectListener soundEffectListener) {
@@ -877,4 +965,59 @@
          */
         void onPlaySoundEffect(@AudioManager.SystemSoundEffect int effectType);
     }
+
+    /**
+     * Listener for changes in the available virtual devices.
+     */
+    @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
+    public interface VirtualDeviceListener {
+        /**
+         * Called whenever a new virtual device has been added to the system.
+         * Use {@link VirtualDeviceManager#getVirtualDevice(int)} to get more information about
+         * the device.
+         *
+         * @param deviceId The id of the virtual device that was added.
+         */
+        default void onVirtualDeviceCreated(int deviceId) {}
+
+        /**
+         * Called whenever a virtual device has been removed from the system.
+         *
+         * @param deviceId The id of the virtual device that was removed.
+         */
+        default void onVirtualDeviceClosed(int deviceId) {}
+    }
+
+    /**
+     * A wrapper for {@link VirtualDeviceListener} that executes callbacks on the given executor.
+     */
+    private static class VirtualDeviceListenerDelegate extends IVirtualDeviceListener.Stub {
+        private final VirtualDeviceListener mListener;
+        private final Executor mExecutor;
+
+        private VirtualDeviceListenerDelegate(Executor executor, VirtualDeviceListener listener) {
+            mExecutor = executor;
+            mListener = listener;
+        }
+
+        @Override
+        public void onVirtualDeviceCreated(int deviceId) {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> mListener.onVirtualDeviceCreated(deviceId));
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void onVirtualDeviceClosed(int deviceId) {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> mListener.onVirtualDeviceClosed(deviceId));
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+    }
 }
diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java
index 037e814a..51df257 100644
--- a/core/java/android/companion/virtual/VirtualDeviceParams.java
+++ b/core/java/android/companion/virtual/VirtualDeviceParams.java
@@ -202,14 +202,12 @@
 
     private final int mLockState;
     @NonNull private final ArraySet<UserHandle> mUsersWithMatchingAccounts;
-    @NonNull private final ArraySet<ComponentName> mAllowedCrossTaskNavigations;
-    @NonNull private final ArraySet<ComponentName> mBlockedCrossTaskNavigations;
     @NavigationPolicy
     private final int mDefaultNavigationPolicy;
-    @NonNull private final ArraySet<ComponentName> mAllowedActivities;
-    @NonNull private final ArraySet<ComponentName> mBlockedActivities;
+    @NonNull private final ArraySet<ComponentName> mCrossTaskNavigationExceptions;
     @ActivityPolicy
     private final int mDefaultActivityPolicy;
+    @NonNull private final ArraySet<ComponentName> mActivityPolicyExceptions;
     @Nullable private final String mName;
     // Mapping of @PolicyType to @DevicePolicy
     @NonNull private final SparseIntArray mDevicePolicies;
@@ -221,12 +219,10 @@
     private VirtualDeviceParams(
             @LockState int lockState,
             @NonNull Set<UserHandle> usersWithMatchingAccounts,
-            @NonNull Set<ComponentName> allowedCrossTaskNavigations,
-            @NonNull Set<ComponentName> blockedCrossTaskNavigations,
             @NavigationPolicy int defaultNavigationPolicy,
-            @NonNull Set<ComponentName> allowedActivities,
-            @NonNull Set<ComponentName> blockedActivities,
+            @NonNull Set<ComponentName> crossTaskNavigationExceptions,
             @ActivityPolicy int defaultActivityPolicy,
+            @NonNull Set<ComponentName> activityPolicyExceptions,
             @Nullable String name,
             @NonNull SparseIntArray devicePolicies,
             @NonNull List<VirtualSensorConfig> virtualSensorConfigs,
@@ -236,14 +232,12 @@
         mLockState = lockState;
         mUsersWithMatchingAccounts =
                 new ArraySet<>(Objects.requireNonNull(usersWithMatchingAccounts));
-        mAllowedCrossTaskNavigations =
-                new ArraySet<>(Objects.requireNonNull(allowedCrossTaskNavigations));
-        mBlockedCrossTaskNavigations =
-                new ArraySet<>(Objects.requireNonNull(blockedCrossTaskNavigations));
         mDefaultNavigationPolicy = defaultNavigationPolicy;
-        mAllowedActivities = new ArraySet<>(Objects.requireNonNull(allowedActivities));
-        mBlockedActivities = new ArraySet<>(Objects.requireNonNull(blockedActivities));
+        mCrossTaskNavigationExceptions =
+                new ArraySet<>(Objects.requireNonNull(crossTaskNavigationExceptions));
         mDefaultActivityPolicy = defaultActivityPolicy;
+        mActivityPolicyExceptions =
+                new ArraySet<>(Objects.requireNonNull(activityPolicyExceptions));
         mName = name;
         mDevicePolicies = Objects.requireNonNull(devicePolicies);
         mVirtualSensorConfigs = Objects.requireNonNull(virtualSensorConfigs);
@@ -256,12 +250,10 @@
     private VirtualDeviceParams(Parcel parcel) {
         mLockState = parcel.readInt();
         mUsersWithMatchingAccounts = (ArraySet<UserHandle>) parcel.readArraySet(null);
-        mAllowedCrossTaskNavigations = (ArraySet<ComponentName>) parcel.readArraySet(null);
-        mBlockedCrossTaskNavigations = (ArraySet<ComponentName>) parcel.readArraySet(null);
         mDefaultNavigationPolicy = parcel.readInt();
-        mAllowedActivities = (ArraySet<ComponentName>) parcel.readArraySet(null);
-        mBlockedActivities = (ArraySet<ComponentName>) parcel.readArraySet(null);
+        mCrossTaskNavigationExceptions = (ArraySet<ComponentName>) parcel.readArraySet(null);
         mDefaultActivityPolicy = parcel.readInt();
+        mActivityPolicyExceptions = (ArraySet<ComponentName>) parcel.readArraySet(null);
         mName = parcel.readString8();
         mDevicePolicies = parcel.readSparseIntArray();
         mVirtualSensorConfigs = new ArrayList<>();
@@ -301,7 +293,9 @@
      */
     @NonNull
     public Set<ComponentName> getAllowedCrossTaskNavigations() {
-        return Collections.unmodifiableSet(mAllowedCrossTaskNavigations);
+        return mDefaultNavigationPolicy == NAVIGATION_POLICY_DEFAULT_ALLOWED
+                ? Collections.emptySet()
+                : Collections.unmodifiableSet(mCrossTaskNavigationExceptions);
     }
 
     /**
@@ -314,7 +308,9 @@
      */
     @NonNull
     public Set<ComponentName> getBlockedCrossTaskNavigations() {
-        return Collections.unmodifiableSet(mBlockedCrossTaskNavigations);
+        return mDefaultNavigationPolicy == NAVIGATION_POLICY_DEFAULT_BLOCKED
+                ? Collections.emptySet()
+                : Collections.unmodifiableSet(mCrossTaskNavigationExceptions);
     }
 
     /**
@@ -338,7 +334,9 @@
      */
     @NonNull
     public Set<ComponentName> getAllowedActivities() {
-        return Collections.unmodifiableSet(mAllowedActivities);
+        return mDefaultActivityPolicy == ACTIVITY_POLICY_DEFAULT_ALLOWED
+                ? Collections.emptySet()
+                : Collections.unmodifiableSet(mActivityPolicyExceptions);
     }
 
     /**
@@ -349,7 +347,9 @@
      */
     @NonNull
     public Set<ComponentName> getBlockedActivities() {
-        return Collections.unmodifiableSet(mBlockedActivities);
+        return mDefaultActivityPolicy == ACTIVITY_POLICY_DEFAULT_BLOCKED
+                ? Collections.emptySet()
+                : Collections.unmodifiableSet(mActivityPolicyExceptions);
     }
 
     /**
@@ -439,12 +439,10 @@
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeInt(mLockState);
         dest.writeArraySet(mUsersWithMatchingAccounts);
-        dest.writeArraySet(mAllowedCrossTaskNavigations);
-        dest.writeArraySet(mBlockedCrossTaskNavigations);
         dest.writeInt(mDefaultNavigationPolicy);
-        dest.writeArraySet(mAllowedActivities);
-        dest.writeArraySet(mBlockedActivities);
+        dest.writeArraySet(mCrossTaskNavigationExceptions);
         dest.writeInt(mDefaultActivityPolicy);
+        dest.writeArraySet(mActivityPolicyExceptions);
         dest.writeString8(mName);
         dest.writeSparseIntArray(mDevicePolicies);
         dest.writeTypedList(mVirtualSensorConfigs);
@@ -477,11 +475,10 @@
         }
         return mLockState == that.mLockState
                 && mUsersWithMatchingAccounts.equals(that.mUsersWithMatchingAccounts)
-                && Objects.equals(mAllowedCrossTaskNavigations, that.mAllowedCrossTaskNavigations)
-                && Objects.equals(mBlockedCrossTaskNavigations, that.mBlockedCrossTaskNavigations)
+                && Objects.equals(
+                        mCrossTaskNavigationExceptions, that.mCrossTaskNavigationExceptions)
                 && mDefaultNavigationPolicy == that.mDefaultNavigationPolicy
-                && Objects.equals(mAllowedActivities, that.mAllowedActivities)
-                && Objects.equals(mBlockedActivities, that.mBlockedActivities)
+                && Objects.equals(mActivityPolicyExceptions, that.mActivityPolicyExceptions)
                 && mDefaultActivityPolicy == that.mDefaultActivityPolicy
                 && Objects.equals(mName, that.mName)
                 && mAudioPlaybackSessionId == that.mAudioPlaybackSessionId
@@ -491,10 +488,9 @@
     @Override
     public int hashCode() {
         int hashCode = Objects.hash(
-                mLockState, mUsersWithMatchingAccounts, mAllowedCrossTaskNavigations,
-                mBlockedCrossTaskNavigations, mDefaultNavigationPolicy, mAllowedActivities,
-                mBlockedActivities, mDefaultActivityPolicy, mName, mDevicePolicies,
-                mAudioPlaybackSessionId, mAudioRecordingSessionId);
+                mLockState, mUsersWithMatchingAccounts, mCrossTaskNavigationExceptions,
+                mDefaultNavigationPolicy, mActivityPolicyExceptions, mDefaultActivityPolicy, mName,
+                mDevicePolicies, mAudioPlaybackSessionId, mAudioRecordingSessionId);
         for (int i = 0; i < mDevicePolicies.size(); i++) {
             hashCode = 31 * hashCode + mDevicePolicies.keyAt(i);
             hashCode = 31 * hashCode + mDevicePolicies.valueAt(i);
@@ -508,12 +504,10 @@
         return "VirtualDeviceParams("
                 + " mLockState=" + mLockState
                 + " mUsersWithMatchingAccounts=" + mUsersWithMatchingAccounts
-                + " mAllowedCrossTaskNavigations=" + mAllowedCrossTaskNavigations
-                + " mBlockedCrossTaskNavigations=" + mBlockedCrossTaskNavigations
                 + " mDefaultNavigationPolicy=" + mDefaultNavigationPolicy
-                + " mAllowedActivities=" + mAllowedActivities
-                + " mBlockedActivities=" + mBlockedActivities
+                + " mCrossTaskNavigationExceptions=" + mCrossTaskNavigationExceptions
                 + " mDefaultActivityPolicy=" + mDefaultActivityPolicy
+                + " mActivityPolicyExceptions=" + mActivityPolicyExceptions
                 + " mName=" + mName
                 + " mDevicePolicies=" + mDevicePolicies
                 + " mAudioPlaybackSessionId=" + mAudioPlaybackSessionId
@@ -529,13 +523,11 @@
         pw.println(prefix + "mName=" + mName);
         pw.println(prefix + "mLockState=" + mLockState);
         pw.println(prefix + "mUsersWithMatchingAccounts=" + mUsersWithMatchingAccounts);
-        pw.println(prefix + "mAllowedCrossTaskNavigations=" + mAllowedCrossTaskNavigations);
-        pw.println(prefix + "mBlockedCrossTaskNavigations=" + mBlockedCrossTaskNavigations);
-        pw.println(prefix + "mAllowedActivities=" + mAllowedActivities);
-        pw.println(prefix + "mBlockedActivities=" + mBlockedActivities);
-        pw.println(prefix + "mDevicePolicies=" + mDevicePolicies);
         pw.println(prefix + "mDefaultNavigationPolicy=" + mDefaultNavigationPolicy);
+        pw.println(prefix + "mCrossTaskNavigationExceptions=" + mCrossTaskNavigationExceptions);
         pw.println(prefix + "mDefaultActivityPolicy=" + mDefaultActivityPolicy);
+        pw.println(prefix + "mActivityPolicyExceptions=" + mActivityPolicyExceptions);
+        pw.println(prefix + "mDevicePolicies=" + mDevicePolicies);
         pw.println(prefix + "mVirtualSensorConfigs=" + mVirtualSensorConfigs);
         pw.println(prefix + "mAudioPlaybackSessionId=" + mAudioPlaybackSessionId);
         pw.println(prefix + "mAudioRecordingSessionId=" + mAudioRecordingSessionId);
@@ -560,13 +552,11 @@
 
         private @LockState int mLockState = LOCK_STATE_DEFAULT;
         @NonNull private Set<UserHandle> mUsersWithMatchingAccounts = Collections.emptySet();
-        @NonNull private Set<ComponentName> mAllowedCrossTaskNavigations = Collections.emptySet();
-        @NonNull private Set<ComponentName> mBlockedCrossTaskNavigations = Collections.emptySet();
+        @NonNull private Set<ComponentName> mCrossTaskNavigationExceptions = Collections.emptySet();
         @NavigationPolicy
         private int mDefaultNavigationPolicy = NAVIGATION_POLICY_DEFAULT_ALLOWED;
         private boolean mDefaultNavigationPolicyConfigured = false;
-        @NonNull private Set<ComponentName> mBlockedActivities = Collections.emptySet();
-        @NonNull private Set<ComponentName> mAllowedActivities = Collections.emptySet();
+        @NonNull private Set<ComponentName> mActivityPolicyExceptions = Collections.emptySet();
         @ActivityPolicy
         private int mDefaultActivityPolicy = ACTIVITY_POLICY_DEFAULT_ALLOWED;
         private boolean mDefaultActivityPolicyConfigured = false;
@@ -705,12 +695,12 @@
             if (mDefaultNavigationPolicyConfigured
                     && mDefaultNavigationPolicy != NAVIGATION_POLICY_DEFAULT_BLOCKED) {
                 throw new IllegalArgumentException(
-                     "Allowed cross task navigation and blocked task navigation cannot "
+                     "Allowed cross task navigations and blocked cross task navigations cannot "
                      + " both be set.");
             }
             mDefaultNavigationPolicy = NAVIGATION_POLICY_DEFAULT_BLOCKED;
             mDefaultNavigationPolicyConfigured = true;
-            mAllowedCrossTaskNavigations = Objects.requireNonNull(allowedCrossTaskNavigations);
+            mCrossTaskNavigationExceptions = Objects.requireNonNull(allowedCrossTaskNavigations);
             return this;
         }
 
@@ -741,7 +731,7 @@
             }
             mDefaultNavigationPolicy = NAVIGATION_POLICY_DEFAULT_ALLOWED;
             mDefaultNavigationPolicyConfigured = true;
-            mBlockedCrossTaskNavigations = Objects.requireNonNull(blockedCrossTaskNavigations);
+            mCrossTaskNavigationExceptions = Objects.requireNonNull(blockedCrossTaskNavigations);
             return this;
         }
 
@@ -767,7 +757,7 @@
             }
             mDefaultActivityPolicy = ACTIVITY_POLICY_DEFAULT_BLOCKED;
             mDefaultActivityPolicyConfigured = true;
-            mAllowedActivities = Objects.requireNonNull(allowedActivities);
+            mActivityPolicyExceptions = Objects.requireNonNull(allowedActivities);
             return this;
         }
 
@@ -793,7 +783,7 @@
             }
             mDefaultActivityPolicy = ACTIVITY_POLICY_DEFAULT_ALLOWED;
             mDefaultActivityPolicyConfigured = true;
-            mBlockedActivities = Objects.requireNonNull(blockedActivities);
+            mActivityPolicyExceptions = Objects.requireNonNull(blockedActivities);
             return this;
         }
 
@@ -988,12 +978,10 @@
             return new VirtualDeviceParams(
                     mLockState,
                     mUsersWithMatchingAccounts,
-                    mAllowedCrossTaskNavigations,
-                    mBlockedCrossTaskNavigations,
                     mDefaultNavigationPolicy,
-                    mAllowedActivities,
-                    mBlockedActivities,
+                    mCrossTaskNavigationExceptions,
                     mDefaultActivityPolicy,
+                    mActivityPolicyExceptions,
                     mName,
                     mDevicePolicies,
                     mVirtualSensorConfigs,
diff --git a/core/java/android/companion/virtual/flags.aconfig b/core/java/android/companion/virtual/flags.aconfig
index 057b856..9ab3be6 100644
--- a/core/java/android/companion/virtual/flags.aconfig
+++ b/core/java/android/companion/virtual/flags.aconfig
@@ -13,3 +13,10 @@
   description: "Enable dynamic policy API"
   bug: "298401780"
 }
+
+flag {
+  name: "vdm_public_apis"
+  namespace: "virtual_devices"
+  description: "Enable public VDM API for device capabilities"
+  bug: "297253526"
+}
diff --git a/core/java/android/content/pm/ArchivedPackageParcel.aidl b/core/java/android/content/pm/ArchivedPackageParcel.aidl
index b34b708..6aeee89 100644
--- a/core/java/android/content/pm/ArchivedPackageParcel.aidl
+++ b/core/java/android/content/pm/ArchivedPackageParcel.aidl
@@ -29,7 +29,6 @@
     int versionCode;
     int versionCodeMajor;
     int targetSdkVersion;
-    boolean clearUserDataAllowed;
     boolean backupAllowed;
     boolean defaultToDeviceProtectedStorage;
     boolean requestLegacyExternalStorage;
diff --git a/core/java/android/content/pm/parsing/ApkLite.java b/core/java/android/content/pm/parsing/ApkLite.java
index 71cfd1b..8e7592a 100644
--- a/core/java/android/content/pm/parsing/ApkLite.java
+++ b/core/java/android/content/pm/parsing/ApkLite.java
@@ -140,11 +140,6 @@
     private final boolean mIsSdkLibrary;
 
     /**
-     * Indicates whether this application's data will be cleared on a failed restore.
-     */
-    private final boolean mClearUserDataAllowed;
-
-    /**
      *  Set to <code>false</code> if the application does not wish to permit any OS-driven
      *  backups of its data; <code>true</code> otherwise.
      */
@@ -219,7 +214,6 @@
         mRollbackDataPolicy = rollbackDataPolicy;
         mHasDeviceAdminReceiver = hasDeviceAdminReceiver;
         mIsSdkLibrary = isSdkLibrary;
-        mClearUserDataAllowed = clearUserDataAllowed;
         mBackupAllowed = backupAllowed;
         mDefaultToDeviceProtectedStorage = defaultToDeviceProtectedStorage;
         mRequestLegacyExternalStorage = requestLegacyExternalStorage;
@@ -261,7 +255,6 @@
         mRollbackDataPolicy = 0;
         mHasDeviceAdminReceiver = false;
         mIsSdkLibrary = false;
-        mClearUserDataAllowed = archivedPackage.clearUserDataAllowed;
         mBackupAllowed = archivedPackage.backupAllowed;
         mDefaultToDeviceProtectedStorage = archivedPackage.defaultToDeviceProtectedStorage;
         mRequestLegacyExternalStorage = archivedPackage.requestLegacyExternalStorage;
@@ -576,14 +569,6 @@
     }
 
     /**
-     * Indicates whether this application's data will be cleared on a failed restore.
-     */
-    @DataClass.Generated.Member
-    public boolean isClearUserDataAllowed() {
-        return mClearUserDataAllowed;
-    }
-
-    /**
      *  Set to <code>false</code> if the application does not wish to permit any OS-driven
      *  backups of its data; <code>true</code> otherwise.
      */
@@ -627,10 +612,10 @@
     }
 
     @DataClass.Generated(
-            time = 1693422809896L,
+            time = 1693513509013L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/content/pm/parsing/ApkLite.java",
-            inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mSplitTypes\nprivate final  int mVersionCodeMajor\nprivate final  int mVersionCode\nprivate final  int mRevisionCode\nprivate final  int mInstallLocation\nprivate final  int mMinSdkVersion\nprivate final  int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final  boolean mFeatureSplit\nprivate final  boolean mIsolatedSplits\nprivate final  boolean mSplitRequired\nprivate final  boolean mCoreApp\nprivate final  boolean mDebuggable\nprivate final  boolean mProfileableByShell\nprivate final  boolean mMultiArch\nprivate final  boolean mUse32bitAbi\nprivate final  boolean mExtractNativeLibs\nprivate final  boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final  boolean mOverlayIsStatic\nprivate final  int mOverlayPriority\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyName\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyValue\nprivate final  int mRollbackDataPolicy\nprivate final  boolean mHasDeviceAdminReceiver\nprivate final  boolean mIsSdkLibrary\nprivate final  boolean mClearUserDataAllowed\nprivate final  boolean mBackupAllowed\nprivate final  boolean mDefaultToDeviceProtectedStorage\nprivate final  boolean mRequestLegacyExternalStorage\nprivate final  boolean mUserDataFragile\nprivate final  boolean mClearUserDataOnFailedRestoreAllowed\npublic  long getLongVersionCode()\nprivate  boolean hasAnyRequiredSplitTypes()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
+            inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mSplitTypes\nprivate final  int mVersionCodeMajor\nprivate final  int mVersionCode\nprivate final  int mRevisionCode\nprivate final  int mInstallLocation\nprivate final  int mMinSdkVersion\nprivate final  int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final  boolean mFeatureSplit\nprivate final  boolean mIsolatedSplits\nprivate final  boolean mSplitRequired\nprivate final  boolean mCoreApp\nprivate final  boolean mDebuggable\nprivate final  boolean mProfileableByShell\nprivate final  boolean mMultiArch\nprivate final  boolean mUse32bitAbi\nprivate final  boolean mExtractNativeLibs\nprivate final  boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final  boolean mOverlayIsStatic\nprivate final  int mOverlayPriority\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyName\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyValue\nprivate final  int mRollbackDataPolicy\nprivate final  boolean mHasDeviceAdminReceiver\nprivate final  boolean mIsSdkLibrary\nprivate final  boolean mBackupAllowed\nprivate final  boolean mDefaultToDeviceProtectedStorage\nprivate final  boolean mRequestLegacyExternalStorage\nprivate final  boolean mUserDataFragile\nprivate final  boolean mClearUserDataOnFailedRestoreAllowed\npublic  long getLongVersionCode()\nprivate  boolean hasAnyRequiredSplitTypes()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/content/pm/parsing/PackageLite.java b/core/java/android/content/pm/parsing/PackageLite.java
index 4638af7..ccef9de 100644
--- a/core/java/android/content/pm/parsing/PackageLite.java
+++ b/core/java/android/content/pm/parsing/PackageLite.java
@@ -113,10 +113,6 @@
      */
     private final boolean mIsSdkLibrary;
     /**
-     * Indicates whether this application's data will be cleared on a failed restore.
-     */
-    private final boolean mClearUserDataAllowed;
-    /**
      *  Set to <code>false</code> if the application does not wish to permit any OS-driven
      *  backups of its data; <code>true</code> otherwise.
      */
@@ -175,7 +171,6 @@
         mSplitApkPaths = splitApkPaths;
         mSplitRevisionCodes = splitRevisionCodes;
         mTargetSdk = targetSdk;
-        mClearUserDataAllowed = baseApk.isClearUserDataAllowed();
         mBackupAllowed = baseApk.isBackupAllowed();
         mDefaultToDeviceProtectedStorage = baseApk.isDefaultToDeviceProtectedStorage();
         mRequestLegacyExternalStorage = baseApk.isRequestLegacyExternalStorage();
@@ -460,14 +455,6 @@
     }
 
     /**
-     * Indicates whether this application's data will be cleared on a failed restore.
-     */
-    @DataClass.Generated.Member
-    public boolean isClearUserDataAllowed() {
-        return mClearUserDataAllowed;
-    }
-
-    /**
      *  Set to <code>false</code> if the application does not wish to permit any OS-driven
      *  backups of its data; <code>true</code> otherwise.
      */
@@ -511,10 +498,10 @@
     }
 
     @DataClass.Generated(
-            time = 1693423910860L,
+            time = 1693513525097L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/content/pm/parsing/PackageLite.java",
-            inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.NonNull java.lang.String mBaseApkPath\nprivate final @android.annotation.Nullable java.lang.String[] mSplitApkPaths\nprivate final @android.annotation.Nullable java.lang.String[] mSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mUsesSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mBaseRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mSplitTypes\nprivate final  int mVersionCodeMajor\nprivate final  int mVersionCode\nprivate final  int mTargetSdk\nprivate final  int mBaseRevisionCode\nprivate final @android.annotation.Nullable int[] mSplitRevisionCodes\nprivate final  int mInstallLocation\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final @android.annotation.Nullable boolean[] mIsFeatureSplits\nprivate final  boolean mIsolatedSplits\nprivate final  boolean mSplitRequired\nprivate final  boolean mCoreApp\nprivate final  boolean mDebuggable\nprivate final  boolean mMultiArch\nprivate final  boolean mUse32bitAbi\nprivate final  boolean mExtractNativeLibs\nprivate final  boolean mProfileableByShell\nprivate final  boolean mUseEmbeddedDex\nprivate final  boolean mIsSdkLibrary\nprivate final  boolean mClearUserDataAllowed\nprivate final  boolean mBackupAllowed\nprivate final  boolean mDefaultToDeviceProtectedStorage\nprivate final  boolean mRequestLegacyExternalStorage\nprivate final  boolean mUserDataFragile\nprivate final  boolean mClearUserDataOnFailedRestoreAllowed\npublic  java.util.List<java.lang.String> getAllApkPaths()\npublic  long getLongVersionCode()\nprivate  boolean hasAnyRequiredSplitTypes()\nclass PackageLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
+            inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.NonNull java.lang.String mBaseApkPath\nprivate final @android.annotation.Nullable java.lang.String[] mSplitApkPaths\nprivate final @android.annotation.Nullable java.lang.String[] mSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mUsesSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mBaseRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mSplitTypes\nprivate final  int mVersionCodeMajor\nprivate final  int mVersionCode\nprivate final  int mTargetSdk\nprivate final  int mBaseRevisionCode\nprivate final @android.annotation.Nullable int[] mSplitRevisionCodes\nprivate final  int mInstallLocation\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final @android.annotation.Nullable boolean[] mIsFeatureSplits\nprivate final  boolean mIsolatedSplits\nprivate final  boolean mSplitRequired\nprivate final  boolean mCoreApp\nprivate final  boolean mDebuggable\nprivate final  boolean mMultiArch\nprivate final  boolean mUse32bitAbi\nprivate final  boolean mExtractNativeLibs\nprivate final  boolean mProfileableByShell\nprivate final  boolean mUseEmbeddedDex\nprivate final  boolean mIsSdkLibrary\nprivate final  boolean mBackupAllowed\nprivate final  boolean mDefaultToDeviceProtectedStorage\nprivate final  boolean mRequestLegacyExternalStorage\nprivate final  boolean mUserDataFragile\nprivate final  boolean mClearUserDataOnFailedRestoreAllowed\npublic  java.util.List<java.lang.String> getAllApkPaths()\npublic  long getLongVersionCode()\nprivate  boolean hasAnyRequiredSplitTypes()\nclass PackageLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 0f6f601..dfd3802 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -129,6 +129,7 @@
             mDynamicSensorCallbacks = new HashMap<>();
     private BroadcastReceiver mDynamicSensorBroadcastReceiver;
     private BroadcastReceiver mRuntimeSensorBroadcastReceiver;
+    private VirtualDeviceManager.VirtualDeviceListener mVirtualDeviceListener;
 
     // Looper associated with the context in which this instance was created.
     private final Looper mMainLooper;
@@ -518,7 +519,11 @@
     }
 
     private List<Sensor> createRuntimeSensorListLocked(int deviceId) {
-        setupRuntimeSensorBroadcastReceiver();
+        if (android.companion.virtual.flags.Flags.vdmPublicApis()) {
+            setupVirtualDeviceListener();
+        } else {
+            setupRuntimeSensorBroadcastReceiver();
+        }
         List<Sensor> list = new ArrayList<>();
         nativeGetRuntimeSensors(mNativeInstance, deviceId, list);
         mFullRuntimeSensorListByDevice.put(deviceId, list);
@@ -558,6 +563,34 @@
         }
     }
 
+    private void setupVirtualDeviceListener() {
+        if (mVirtualDeviceListener != null) {
+            return;
+        }
+        if (mVdm == null) {
+            mVdm = mContext.getSystemService(VirtualDeviceManager.class);
+            if (mVdm == null) {
+                return;
+            }
+        }
+        mVirtualDeviceListener = new VirtualDeviceManager.VirtualDeviceListener() {
+            @Override
+            public void onVirtualDeviceClosed(int deviceId) {
+                synchronized (mFullRuntimeSensorListByDevice) {
+                    List<Sensor> removedSensors =
+                            mFullRuntimeSensorListByDevice.removeReturnOld(deviceId);
+                    if (removedSensors != null) {
+                        for (Sensor s : removedSensors) {
+                            cleanupSensorConnection(s);
+                        }
+                    }
+                    mRuntimeSensorListByDeviceByType.remove(deviceId);
+                }
+            }
+        };
+        mVdm.registerVirtualDeviceListener(mContext.getMainExecutor(), mVirtualDeviceListener);
+    }
+
     private void setupDynamicSensorBroadcastReceiver() {
         if (mDynamicSensorBroadcastReceiver == null) {
             mDynamicSensorBroadcastReceiver = new BroadcastReceiver() {
@@ -581,12 +614,6 @@
         }
     }
 
-    private void teardownDynamicSensorBroadcastReceiver() {
-        mDynamicSensorCallbacks.clear();
-        mContext.unregisterReceiver(mDynamicSensorBroadcastReceiver);
-        mDynamicSensorBroadcastReceiver = null;
-    }
-
     /** @hide */
     protected void registerDynamicSensorCallbackImpl(
             DynamicSensorCallback callback, Handler handler) {
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index d352be1..943f0c4 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -16,6 +16,7 @@
 
 package android.hardware.camera2;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -31,6 +32,7 @@
 import android.util.Rational;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.camera.flags.Flags;
 
 import java.util.ArrayList;
 import java.util.Collections;
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 082a336..f4d783a 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -625,12 +625,13 @@
      * <style scoped>
      *  #rb { border-right-width: thick; }
      * </style>
+     *
+     * <h5>LEGACY-level guaranteed configurations</h5>
+     *
      * <p>Legacy devices ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
      * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY}) support at
      * least the following stream combinations:
      *
-     * <h5>LEGACY-level guaranteed configurations</h5>
-     *
      * <table>
      * <tr> <th colspan="2" id="rb">Target 1</th> <th colspan="2" id="rb">Target 2</th>  <th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
      * <tr> <th>Type</th><th id="rb">Max size</th> <th>Type</th><th id="rb">Max size</th> <th>Type</th><th id="rb">Max size</th></tr>
@@ -645,13 +646,13 @@
      * </table><br>
      * </p>
      *
+     * <h5>LIMITED-level additional guaranteed configurations</h5>
+     *
      * <p>Limited-level ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
      * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED}) devices
      * support at least the following stream combinations in addition to those for
      * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY} devices:
      *
-     * <h5>LIMITED-level additional guaranteed configurations</h5>
-     *
      * <table>
      * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
      * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
@@ -664,13 +665,13 @@
      * </table><br>
      * </p>
      *
+     * <h5>FULL-level additional guaranteed configurations</h5>
+     *
      * <p>FULL-level ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
      * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL}) devices
      * support at least the following stream combinations in addition to those for
      * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED} devices:
      *
-     * <h5>FULL-level additional guaranteed configurations</h5>
-     *
      * <table>
      * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
      * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr>
@@ -683,14 +684,14 @@
      * </table><br>
      * </p>
      *
+     * <h5>RAW-capability additional guaranteed configurations</h5>
+     *
      * <p>RAW-capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} includes
      * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_RAW RAW}) devices additionally support
      * at least the following stream combinations on both
      * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL} and
      * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED} devices:
      *
-     * <h5>RAW-capability additional guaranteed configurations</h5>
-     *
      * <table>
      * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
      * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr>
@@ -705,6 +706,8 @@
      * </table><br>
      * </p>
      *
+     * <h5>BURST-capability additional guaranteed configurations</h5>
+     *
      * <p>BURST-capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} includes
      * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE BURST_CAPTURE}) devices
      * support at least the below stream combinations in addition to those for
@@ -713,8 +716,6 @@
      * list for FULL-level devices, so this table is only relevant for LIMITED-level devices that
      * support the BURST_CAPTURE capability.
      *
-     * <h5>BURST-capability additional guaranteed configurations</h5>
-     *
      * <table>
      * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th rowspan="2">Sample use case(s)</th> </tr>
      * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr>
@@ -724,6 +725,8 @@
      * </table><br>
      * </p>
      *
+     * <h5>LEVEL-3 additional guaranteed configurations</h5>
+     *
      * <p>LEVEL-3 ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
      * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_3 LEVEL_3})
      * support at least the following stream combinations in addition to the combinations for
@@ -731,8 +734,6 @@
      * RAW capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} includes
      * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_RAW RAW}):
      *
-     * <h5>LEVEL-3 additional guaranteed configurations</h5>
-     *
      * <table>
      * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th><th colspan="2" id="rb">Target 4</th><th rowspan="2">Sample use case(s)</th> </tr>
      * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr>
@@ -741,14 +742,16 @@
      * </table><br>
      * </p>
      *
-     *<p>BACKWARD_COMPATIBLE devices capable of streaming concurrently with other devices as described by
-     * {@link android.hardware.camera2.CameraManager#getConcurrentCameraIds} have the
+     * <h5>Concurrent stream guaranteed configurations</h5>
+     *
+     * <p>BACKWARD_COMPATIBLE devices capable of streaming concurrently with other devices as
+     * described by {@link android.hardware.camera2.CameraManager#getConcurrentCameraIds} have the
      * following guaranteed streams (when streaming concurrently with other devices)</p>
+     *
      * <p> Note: The sizes mentioned for these concurrent streams are the maximum sizes guaranteed
      * to be supported. Sizes smaller than these, obtained by {@link StreamConfigurationMap#getOutputSizes} for a particular format, are supported as well. </p>
      *
-     * <h5>Concurrent stream guaranteed configurations</h5>
-     *
+     * <p>
      * <table>
      * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th rowspan="2">Sample use case(s)</th> </tr>
      * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr>
@@ -784,6 +787,8 @@
      * level and capabilities. Calling createCaptureSession with both JPEG and HEIC outputs is not
      * supported.</p>
      *
+     * <h5>LEGACY-level additional guaranteed combinations with multi-resolution outputs</h5>
+     *
      * <p>Devices capable of multi-resolution output for a particular format (
      * {@link android.hardware.camera2.params.MultiResolutionStreamConfigurationMap#getOutputInfo}
      * returns a non-empty list) support using {@link MultiResolutionImageReader} for MAXIMUM
@@ -794,8 +799,6 @@
      * stream combinations ({@code MULTI_RES} in the Max size column refers to a {@link
      * MultiResolutionImageReader} created based on the variable max resolutions supported):
      *
-     * <h5>LEGACY-level additional guaranteed combinations with MultiResolutionoutputs</h5>
-     *
      * <table>
      * <tr> <th colspan="2" id="rb">Target 1</th> <th colspan="2" id="rb">Target 2</th>  <th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
      * <tr> <th>Type</th><th id="rb">Max size</th> <th>Type</th><th id="rb">Max size</th> <th>Type</th><th id="rb">Max size</th></tr>
@@ -804,8 +807,12 @@
      * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td colspan="2" id="rb"></td> <td>Standard still imaging.</td> </tr>
      * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td>Still capture plus in-app processing.</td> </tr>
      * </table><br>
+     * </p>
+     *
+     * <h5>LIMITED-level additional guaranteed configurations with multi-resolution outputs</h5>
+     *
+     * <p>
      * <table>
-     * <tr><th colspan="7">LIMITED-level additional guaranteed configurations with MultiResolutionoutputs</th></tr>
      * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
      * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
      * <tr> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td>Two-input in-app processing with still capture.</td> </tr>
@@ -813,11 +820,11 @@
      * The same logic applies to other hardware levels and capabilities.
      * </p>
      *
-     * <p> Devices with the ULTRA_HIGH_RESOLUTION_SENSOR capability have some additional guarantees
-     * which clients can take advantage of : </p>
-     *
      * <h5>Additional guaranteed combinations for ULTRA_HIGH_RESOLUTION sensors</h5>
      *
+     * <p> Devices with the ULTRA_HIGH_RESOLUTION_SENSOR capability have some additional guarantees
+     * which clients can take advantage of:
+     *
      * <table>
      * <tr> <th colspan="3" id="rb">Target 1</th> <th colspan="3" id="rb">Target 2</th>  <th colspan="3" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
      * <tr> <th>Type</th><th id="rb"> SC Map</th><th id="rb">Max size</th> <th>Type</th><th id="rb"> SC Map</th><th id="rb">Max size</th> <th>Type</th><th id="rb"> SC Map</th><th id="rb">Max size</th></tr>
@@ -825,6 +832,7 @@
      * <tr> <td>{@code YUV / JPEG / RAW}</td><td id="rb">{@code MAX_RES}</td><td id="rb">{@code MAX}</td><td id="rb">{@code PRIV}</td><td id="rb">{@code DEFAULT}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PRIV / YUV}</td><td id="rb">{@code DEFAULT}</td><td id="rb">{@code RECORD}</td> <td>Ultra high res still capture with preview + app based RECORD size analysis</td> </tr>
      * <tr> <td>{@code YUV / JPEG / RAW}</td><td id="rb">{@code MAX_RES}</td><td id="rb">{@code MAX}</td><td id="rb">{@code PRIV}</td><td id="rb">{@code DEFAULT}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code JPEG / YUV / RAW}</td><td id="rb">{@code DEFAULT}</td><td id="rb">{@code MAX}</td> <td>Ultra high res still image capture with preview + default sensor pixel mode analysis stream</td> </tr>
      * </table><br>
+     * </p>
      *
      * <p> Here, SC Map, refers to the {@link StreamConfigurationMap}, the target stream sizes must
      * be chosen from. {@code DEFAULT} refers to the default sensor pixel mode {@link
@@ -834,17 +842,17 @@
      * Note: The same capture request must not mix targets from
      * {@link StreamConfigurationMap}s corresponding to different sensor pixel modes. </p>
      *
-     * <p> 10-bit output capable
-     * {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT}
-     * devices support at least the following stream combinations: </p>
-     *
      * <h5>10-bit output additional guaranteed configurations</h5>
      *
+     * <p>10-bit output capable
+     * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT}
+     * devices support at least the following stream combinations:
+     *
      * <table>
      * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
      * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
-     * <tr> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> }</td> <td colspan="4" id="rb"></td> <td>Simple preview, GPU video processing, or no-preview video recording.</td> </tr>
-     * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> }</td> <td colspan="4" id="rb"></td> <td>In-application video/image processing.</td> </tr>
+     * <tr> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> </td> <td colspan="4" id="rb"></td> <td>Simple preview, GPU video processing, or no-preview video recording.</td> </tr>
+     * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> </td> <td colspan="4" id="rb"></td> <td>In-application video/image processing.</td> </tr>
      * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM }</td> <td colspan="2" id="rb"></td> <td>Standard still imaging.</td> </tr>
      * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code MAXIMUM }</td> <td colspan="2" id="rb"></td> <td>Maximum-resolution in-app processing with preview.</td> </tr>
      * <tr> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM }</td> <td colspan="2" id="rb"></td> <td>Maximum-resolution two-input in-app processing.</td> </tr>
@@ -852,6 +860,8 @@
      * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code RECORD }</td> <td>{@code YUV}</td><td id="rb">{@code RECORD }</td> <td>High-resolution recording with in-app snapshot.</td> </tr>
      * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV }</td><td id="rb">{@code RECORD }</td> <td>{@code JPEG}</td><td id="rb">{@code RECORD }</td> <td>High-resolution recording with video snapshot.</td> </tr>
      * </table><br>
+     * </p>
+     *
      * <p>Here PRIV can be either 8 or 10-bit {@link android.graphics.ImageFormat#PRIVATE} pixel
      * format. YUV can be either {@link android.graphics.ImageFormat#YUV_420_888} or
      * {@link android.graphics.ImageFormat#YCBCR_P010}.
@@ -887,13 +897,13 @@
      * {@link CameraDevice#isSessionConfigurationSupported} to ensure that this particular
      * configuration is supported.</p>
      *
+     * <h5>STREAM_USE_CASE capability additional guaranteed configurations</h5>
+     *
      * <p>Devices with the STREAM_USE_CASE capability ({@link
      * CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} includes {@link
      * CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE}) support below additional
      * stream combinations:
      *
-     * <h5>STREAM_USE_CASE capability additional guaranteed configurations</h5>
-     *
      * <table>
      * <tr><th colspan="3" id="rb">Target 1</th><th colspan="3" id="rb">Target 2</th><th colspan="3" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
      * <tr><th>Type</th><th id="rb">Max size</th><th>Usecase</th><th>Type</th><th id="rb">Max size</th><th>Usecase</th><th>Type</th><th id="rb">Max size</th><th>Usecase</th> </tr>
@@ -913,12 +923,12 @@
      * </table><br>
      * </p>
      *
+     * <h5>STREAM_USE_CASE_CROPPED_RAW capability additional guaranteed configurations</h5>
+     *
      * <p>Devices that include the {@link CameraMetadata#SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW}
      * stream use-case in {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES},
      * support the additional stream combinations below:
      *
-     * <h5>STREAM_USE_CASE_CROPPED_RAW capability additional guaranteed configurations</h5>
-     *
      * <table>
      * <tr><th colspan="3" id="rb">Target 1</th><th colspan="3" id="rb">Target 2</th><th colspan="3" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
      * <tr><th>Type</th><th id="rb">Max size</th><th>Usecase</th><th>Type</th><th id="rb">Max size</th><th>Usecase</th><th>Type</th><th id="rb">Max size</th><th>Usecase</th> </tr>
@@ -926,16 +936,18 @@
      * <tr> <td>{@code PRIV / YUV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code CROPPED_RAW}</td> <td colspan="3" id="rb"></td> <td>Preview with cropped RAW still capture</td> </tr>
      * <tr> <td>{@code PRIV / YUV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV / JPEG}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code STILL_CAPTURE}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code CROPPED_RAW}</td> <td>Preview with YUV / JPEG and cropped RAW still capture</td> </tr>
      * <tr> <td>{@code PRIV / YUV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV / YUV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code VIDEO_RECORD / PREVIEW}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code CROPPED_RAW}</td> <td>Video recording with preview and cropped RAW still capture</td> </tr>
-     *
-     *
-     *<p> For devices where {@link CameraCharacteristics#CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES}
-     * includes {@link CameraMetadata#CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION},
-     * the following stream combinations are guaranteed,
-     * for CaptureRequests where {@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE} is set to
-     * {@link CameraMetadata#CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION} <p>
+     * </table><br>
+     * </p>
      *
      * <h5>Preview stabilization guaranteed stream configurations</h5>
      *
+     * <p>For devices where
+     * {@link CameraCharacteristics#CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES} includes
+     * {@link CameraMetadata#CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION},
+     * the following stream combinations are guaranteed,
+     * for CaptureRequests where {@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE} is set to
+     * {@link CameraMetadata#CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION}
+     *
      * <table>
      * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th rowspan="2">Sample use case(s)</th> </tr>
      * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
@@ -943,6 +955,8 @@
      * <tr> <td>{@code PRIV / YUV}</td><td id="rb">{@code s1440p}</td> <td>{@code JPEG / YUV}</td><td id="rb">{@code MAXIMUM }</td><td>Standard still imaging with stabilized preview.</td> </tr>
      * <tr> <td>{@code PRIV / YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV / YUV}</td><td id="rb">{@code s1440p }</td><td>High-resolution recording with stabilized preview and recording stream.</td> </tr>
      * </table><br>
+     * </p>
+     *
      * <p>
      * For the maximum size column, PREVIEW refers to the best size match to the device's screen
      * resolution, or to 1080p (1920x1080), whichever is smaller. RECORD refers to the camera
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 703f165..dd32384 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -16,6 +16,7 @@
 
 package android.hardware.camera2;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -34,6 +35,8 @@
 import android.util.SparseArray;
 import android.view.Surface;
 
+import com.android.internal.camera.flags.Flags;
+
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 746648b..9a80015 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -16,6 +16,7 @@
 
 package android.hardware.camera2;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -28,6 +29,8 @@
 import android.util.Log;
 import android.util.Rational;
 
+import com.android.internal.camera.flags.Flags;
+
 import java.util.List;
 
 /**
diff --git a/location/java/android/location/GeocoderParams.java b/core/java/android/location/GeocoderParams.java
similarity index 100%
rename from location/java/android/location/GeocoderParams.java
rename to core/java/android/location/GeocoderParams.java
diff --git a/location/java/android/location/Geofence.java b/core/java/android/location/Geofence.java
similarity index 100%
rename from location/java/android/location/Geofence.java
rename to core/java/android/location/Geofence.java
diff --git a/location/java/android/location/GnssSignalQuality.java b/core/java/android/location/GnssSignalQuality.java
similarity index 100%
rename from location/java/android/location/GnssSignalQuality.java
rename to core/java/android/location/GnssSignalQuality.java
diff --git a/location/java/android/location/IFusedGeofenceHardware.aidl b/core/java/android/location/IFusedGeofenceHardware.aidl
similarity index 100%
rename from location/java/android/location/IFusedGeofenceHardware.aidl
rename to core/java/android/location/IFusedGeofenceHardware.aidl
diff --git a/location/java/android/location/IGpsGeofenceHardware.aidl b/core/java/android/location/IGpsGeofenceHardware.aidl
similarity index 100%
rename from location/java/android/location/IGpsGeofenceHardware.aidl
rename to core/java/android/location/IGpsGeofenceHardware.aidl
diff --git a/location/java/android/location/Location.aidl b/core/java/android/location/Location.aidl
similarity index 100%
rename from location/java/android/location/Location.aidl
rename to core/java/android/location/Location.aidl
diff --git a/location/java/android/location/Location.java b/core/java/android/location/Location.java
similarity index 100%
rename from location/java/android/location/Location.java
rename to core/java/android/location/Location.java
diff --git a/location/java/android/location/LocationTime.java b/core/java/android/location/LocationTime.java
similarity index 100%
rename from location/java/android/location/LocationTime.java
rename to core/java/android/location/LocationTime.java
diff --git a/core/java/android/os/vibrator/flags.aconfig b/core/java/android/os/vibrator/flags.aconfig
index 361e244..c01ef3d 100644
--- a/core/java/android/os/vibrator/flags.aconfig
+++ b/core/java/android/os/vibrator/flags.aconfig
@@ -1,8 +1,15 @@
 package: "android.os.vibrator"
 
 flag {
-    namespace: "vibrator"
+    namespace: "haptics"
     name: "use_vibrator_haptic_feedback"
     description: "Enables performHapticFeedback to directly use the vibrator service instead of going through the window session"
     bug: "295459081"
+}
+
+flag {
+    namespace: "haptics"
+    name: "haptics_customization_enabled"
+    description: "Enables the haptics customization feature"
+    bug: "241918098"
 }
\ No newline at end of file
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 82756af..f823dbc 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4871,13 +4871,13 @@
         public static final String PEAK_REFRESH_RATE = "peak_refresh_rate";
 
         /**
-         * Control whether to stay awake on fold
+         * Control lock behavior on fold
          *
          * If this isn't set, the system falls back to a device specific default.
          * @hide
          */
         @Readable
-        public static final String STAY_AWAKE_ON_FOLD = "stay_awake_on_fold";
+        public static final String FOLD_LOCK_BEHAVIOR = "fold_lock_behavior_setting";
 
         /**
          * The amount of time in milliseconds before the device goes to sleep or begins
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 60d964e..d191ccd 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -8413,10 +8413,20 @@
             }
         }
 
-        if (mSurfaceControl.isValid() && !HardwareRenderer.isDrawingEnabled()) {
-            // When drawing is disabled the window layer won't have a valid buffer.
-            // Set a window crop so input can get delivered to the window.
-            mTransaction.setWindowCrop(mSurfaceControl, mSurfaceSize.x, mSurfaceSize.y).apply();
+        if (mSurfaceControl.isValid()) {
+            if (mPendingDragResizing && !mSurfaceSize.equals(
+                    mWinFrameInScreen.width(), mWinFrameInScreen.height())) {
+                // During drag-resize, a single fullscreen-sized surface is reused for optimization.
+                // Crop to the content size instead of the surface size to avoid exposing garbage
+                // content that is still on the surface from previous re-layouts (e.g. when
+                // resizing to a larger size).
+                mTransaction.setWindowCrop(mSurfaceControl,
+                        mWinFrameInScreen.width(), mWinFrameInScreen.height());
+            } else if (!HardwareRenderer.isDrawingEnabled()) {
+                // When drawing is disabled the window layer won't have a valid buffer.
+                // Set a window crop so input can get delivered to the window.
+                mTransaction.setWindowCrop(mSurfaceControl, mSurfaceSize.x, mSurfaceSize.y).apply();
+            }
         }
 
         mLastTransformHint = transformHint;
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index da09489..b4d7a94 100755
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -2109,7 +2109,7 @@
                 return;
             }
 
-            if (imm.isActive(this)) {
+            if (imm.hasActiveInputConnection(this)) {
                 // This means that SearchAutoComplete is already connected to the IME.
                 // InputMethodManager#showSoftInput() is guaranteed to pass client-side focus check.
                 mHasPendingShowSoftInputRequest = false;
diff --git a/core/java/com/android/internal/content/InstallLocationUtils.java b/core/java/com/android/internal/content/InstallLocationUtils.java
index a173ce1..f3dd0f8 100644
--- a/core/java/com/android/internal/content/InstallLocationUtils.java
+++ b/core/java/com/android/internal/content/InstallLocationUtils.java
@@ -454,8 +454,10 @@
         // Include raw dex metadata files
         sizeBytes += DexMetadataHelper.getPackageDexMetadataSize(pkg);
 
-        // Include all relevant native code
-        sizeBytes += NativeLibraryHelper.sumNativeBinariesWithOverride(handle, abiOverride);
+        if (pkg.isExtractNativeLibs()) {
+            // Include all relevant native code
+            sizeBytes += NativeLibraryHelper.sumNativeBinariesWithOverride(handle, abiOverride);
+        }
 
         return sizeBytes;
     }
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 86ca077..3e16df4d 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -2624,8 +2624,7 @@
 
     @Override
     public String toString() {
-        return "DecorView@" + Integer.toHexString(this.hashCode()) + "["
-                + getTitleSuffix(mWindow.getAttributes()) + "]";
+        return super.toString() + "[" + getTitleSuffix(mWindow.getAttributes()) + "]";
     }
 
     private static class ColorViewState {
diff --git a/core/java/com/android/internal/util/SettingsWrapper.java b/core/java/com/android/internal/util/SettingsWrapper.java
new file mode 100644
index 0000000..8cf6c18
--- /dev/null
+++ b/core/java/com/android/internal/util/SettingsWrapper.java
@@ -0,0 +1,36 @@
+/*
+ * 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.internal.util;
+
+import android.content.ContentResolver;
+import android.provider.Settings;
+
+/**
+ * A wrapper class for accessing and modifying system settings that would help with testing.
+ */
+public class SettingsWrapper {
+
+    /** Retrieves the string value of a system setting */
+    public String getStringForUser(ContentResolver contentResolver, String name, int userHandle) {
+        return Settings.System.getStringForUser(contentResolver, name, userHandle);
+    }
+
+    /** Updates the string value of a system setting */
+    public String putStringForUser(ContentResolver contentResolver, String name, int userHandle) {
+        return Settings.System.getStringForUser(contentResolver, name, userHandle);
+    }
+}
diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp
index 60da2c2..c0e9215 100644
--- a/core/jni/android_database_CursorWindow.cpp
+++ b/core/jni/android_database_CursorWindow.cpp
@@ -89,7 +89,7 @@
     CursorWindow* window;
 
     const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
-    name.setTo(nameStr);
+    name = nameStr;
     env->ReleaseStringUTFChars(nameObj, nameStr);
 
     if (cursorWindowSize < 0) {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index d898a23..32fe4e3 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -8242,6 +8242,10 @@
                  android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
 
+        <service android:name="com.android.server.notification.NotificationBitmapJobService"
+            android:permission="android.permission.BIND_JOB_SERVICE" >
+        </service>
+
         <service android:name="com.android.server.healthconnect.HealthConnectDailyService"
                  android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 302c7fa..367a4f5 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -935,6 +935,9 @@
          without impacting power, performance, and app compatibility (e.g. protected content). -->
     <bool name="config_reduceBrightColorsAvailable">@bool/config_setColorTransformAccelerated</bool>
 
+    <!-- Whether to show Fold lock behavior setting feature in Settings App -->
+    <bool name="config_fold_lock_behavior">false</bool>
+
     <string-array name="config_reduceBrightColorsCoefficientsNonlinear">
         <!-- a-coefficient --> <item>-0.4429953456</item>
         <!-- b-coefficient --> <item>-0.2434077725</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 02209a7..1965172 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -343,6 +343,7 @@
   <java-symbol type="string" name="config_defaultHealthConnectApp" />
   <java-symbol type="bool" name="config_sendAudioBecomingNoisy" />
   <java-symbol type="bool" name="config_enableScreenshotChord" />
+  <java-symbol type="bool" name="config_fold_lock_behavior" />
   <java-symbol type="bool" name="config_enableWifiDisplay" />
   <java-symbol type="bool" name="config_allowAnimationsInLowPowerMode" />
   <java-symbol type="bool" name="config_useDevInputEventForAudioJack" />
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index f9377fc..48dc167 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -1231,6 +1231,52 @@
     }
 
     @Test
+    public void testBigPictureStyle_setExtras_pictureIconNull_noPictureIconKey() {
+        Notification.BigPictureStyle bpStyle = new Notification.BigPictureStyle();
+        bpStyle.bigPicture((Bitmap) null);
+
+        Bundle extras = new Bundle();
+        bpStyle.addExtras(extras);
+
+        assertThat(extras.containsKey(EXTRA_PICTURE_ICON)).isFalse();
+    }
+
+    @Test
+    public void testBigPictureStyle_setExtras_pictureIconNull_noPictureKey() {
+        Notification.BigPictureStyle bpStyle = new Notification.BigPictureStyle();
+        bpStyle.bigPicture((Bitmap) null);
+
+        Bundle extras = new Bundle();
+        bpStyle.addExtras(extras);
+
+        assertThat(extras.containsKey(EXTRA_PICTURE)).isFalse();
+    }
+
+    @Test
+    public void testBigPictureStyle_setExtras_pictureIconTypeBitmap_noPictureIconKey() {
+        Bitmap bitmap = Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888);
+        Notification.BigPictureStyle bpStyle = new Notification.BigPictureStyle();
+        bpStyle.bigPicture(bitmap);
+
+        Bundle extras = new Bundle();
+        bpStyle.addExtras(extras);
+
+        assertThat(extras.containsKey(EXTRA_PICTURE_ICON)).isFalse();
+    }
+
+    @Test
+    public void testBigPictureStyle_setExtras_pictureIconTypeIcon_noPictureKey() {
+        Icon icon = Icon.createWithResource(mContext, R.drawable.btn_plus);
+        Notification.BigPictureStyle bpStyle = new Notification.BigPictureStyle();
+        bpStyle.bigPicture(icon);
+
+        Bundle extras = new Bundle();
+        bpStyle.addExtras(extras);
+
+        assertThat(extras.containsKey(EXTRA_PICTURE)).isFalse();
+    }
+
+    @Test
     public void testMessagingChange_text() {
         Notification.Builder nM1 = new Notification.Builder(mContext, "test")
                 .setStyle(new Notification.MessagingStyle("")
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/util/ExtensionHelper.java b/libs/WindowManager/Jetpack/src/androidx/window/util/ExtensionHelper.java
index 57f8308..6b193fc 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/util/ExtensionHelper.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/util/ExtensionHelper.java
@@ -25,10 +25,12 @@
 import android.hardware.display.DisplayManagerGlobal;
 import android.util.RotationUtils;
 import android.view.DisplayInfo;
+import android.view.Surface;
 import android.view.WindowManager;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.UiContext;
+import androidx.annotation.VisibleForTesting;
 
 /**
  * Util class for both Sidecar and Extensions.
@@ -42,18 +44,41 @@
     /**
      * Rotates the input rectangle specified in default display orientation to the current display
      * rotation.
+     *
+     * @param displayId the display id.
+     * @param rotation the target rotation relative to the default display orientation.
+     * @param inOutRect the input/output Rect as specified in the default display orientation.
      */
-    public static void rotateRectToDisplayRotation(int displayId, int rotation, Rect inOutRect) {
-        DisplayManagerGlobal dmGlobal = DisplayManagerGlobal.getInstance();
-        DisplayInfo displayInfo = dmGlobal.getDisplayInfo(displayId);
+    public static void rotateRectToDisplayRotation(
+            int displayId, @Surface.Rotation int rotation, @NonNull Rect inOutRect) {
+        final DisplayManagerGlobal dmGlobal = DisplayManagerGlobal.getInstance();
+        final DisplayInfo displayInfo = dmGlobal.getDisplayInfo(displayId);
 
-        boolean isSideRotation = rotation == ROTATION_90 || rotation == ROTATION_270;
-        int displayWidth = isSideRotation ? displayInfo.logicalHeight : displayInfo.logicalWidth;
-        int displayHeight = isSideRotation ? displayInfo.logicalWidth : displayInfo.logicalHeight;
+        rotateRectToDisplayRotation(displayInfo, rotation, inOutRect);
+    }
 
-        inOutRect.intersect(0, 0, displayWidth, displayHeight);
+    @VisibleForTesting
+    static void rotateRectToDisplayRotation(@NonNull DisplayInfo displayInfo,
+            @Surface.Rotation int rotation, @NonNull Rect inOutRect) {
+        // The inOutRect is specified in the default display orientation, so here we need to get
+        // the display width and height in the default orientation to perform the intersection and
+        // rotation.
+        final boolean isSideRotation =
+                displayInfo.rotation == ROTATION_90 || displayInfo.rotation == ROTATION_270;
+        final int baseDisplayWidth =
+                isSideRotation ? displayInfo.logicalHeight : displayInfo.logicalWidth;
+        final int baseDisplayHeight =
+                isSideRotation ? displayInfo.logicalWidth : displayInfo.logicalHeight;
 
-        RotationUtils.rotateBounds(inOutRect, displayWidth, displayHeight, rotation);
+        final boolean success = inOutRect.intersect(0, 0, baseDisplayWidth, baseDisplayHeight);
+        if (!success) {
+            throw new IllegalArgumentException("inOutRect must intersect with the display."
+                    + " inOutRect: " + inOutRect
+                    + ", baseDisplayWidth: " + baseDisplayWidth
+                    + ", baseDisplayHeight: " + baseDisplayHeight);
+        }
+
+        RotationUtils.rotateBounds(inOutRect, baseDisplayWidth, baseDisplayHeight, rotation);
     }
 
     /** Transforms rectangle from absolute coordinate space to the window coordinate space. */
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java
index 45564cb..0682692 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java
@@ -32,7 +32,7 @@
 import org.junit.runner.RunWith;
 
 /**
- * Test class for {@link WindowExtensionsTest}.
+ * Test class for {@link WindowExtensions}.
  *
  * Build/Install/Run:
  *  atest WMJetpackUnitTests:WindowExtensionsTest
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/util/ExtensionHelperTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/util/ExtensionHelperTest.java
new file mode 100644
index 0000000..ae783de
--- /dev/null
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/util/ExtensionHelperTest.java
@@ -0,0 +1,130 @@
+/*
+ * 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 androidx.window.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+import android.view.DisplayInfo;
+import android.view.Surface;
+
+import androidx.annotation.NonNull;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test class for {@link ExtensionHelper}.
+ *
+ * Build/Install/Run:
+ *  atest WMJetpackUnitTests:ExtensionHelperTest
+ */
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ExtensionHelperTest {
+
+    private static final int MOCK_DISPLAY_HEIGHT = 1000;
+    private static final int MOCK_DISPLAY_WIDTH = 2000;
+    private static final int MOCK_FEATURE_LEFT = 100;
+    private static final int MOCK_FEATURE_RIGHT = 200;
+
+    private static final int[] ROTATIONS = {
+            Surface.ROTATION_0,
+            Surface.ROTATION_90,
+            Surface.ROTATION_180,
+            Surface.ROTATION_270
+    };
+
+    private static final DisplayInfo[] MOCK_DISPLAY_INFOS = {
+            getMockDisplayInfo(Surface.ROTATION_0),
+            getMockDisplayInfo(Surface.ROTATION_90),
+            getMockDisplayInfo(Surface.ROTATION_180),
+            getMockDisplayInfo(Surface.ROTATION_270),
+    };
+
+    @Test
+    public void testRotateRectToDisplayRotation() {
+        for (int rotation : ROTATIONS) {
+            final Rect expectedResult = getExpectedFeatureRectAfterRotation(rotation);
+            // The method should return correctly rotated Rect even if the requested rotation value
+            // differs from the rotation in DisplayInfo. This is because the WindowConfiguration is
+            // not always synced with DisplayInfo.
+            for (DisplayInfo displayInfo : MOCK_DISPLAY_INFOS) {
+                final Rect rect = getMockFeatureRect();
+                ExtensionHelper.rotateRectToDisplayRotation(displayInfo, rotation, rect);
+                assertEquals(
+                        "Result Rect should equal to expected for rotation: " + rotation
+                                + "; displayInfo: " + displayInfo,
+                        expectedResult, rect);
+            }
+        }
+    }
+
+    @Test
+    public void testRotateRectToDisplayRotation_invalidInputRect() {
+        final Rect invalidRect = new Rect(
+                MOCK_DISPLAY_WIDTH + 10, 0, MOCK_DISPLAY_WIDTH + 10, MOCK_DISPLAY_HEIGHT);
+        assertThrows(IllegalArgumentException.class,
+                () -> ExtensionHelper.rotateRectToDisplayRotation(
+                        MOCK_DISPLAY_INFOS[0], ROTATIONS[0], invalidRect));
+    }
+
+
+    @NonNull
+    private static DisplayInfo getMockDisplayInfo(@Surface.Rotation int rotation) {
+        final DisplayInfo displayInfo = new DisplayInfo();
+        displayInfo.rotation = rotation;
+        if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) {
+            displayInfo.logicalWidth = MOCK_DISPLAY_WIDTH;
+            displayInfo.logicalHeight = MOCK_DISPLAY_HEIGHT;
+        } else {
+            displayInfo.logicalWidth = MOCK_DISPLAY_HEIGHT;
+            displayInfo.logicalHeight = MOCK_DISPLAY_WIDTH;
+        }
+        return displayInfo;
+    }
+
+    @NonNull
+    private static Rect getMockFeatureRect() {
+        return new Rect(MOCK_FEATURE_LEFT, 0, MOCK_FEATURE_RIGHT, MOCK_DISPLAY_HEIGHT);
+    }
+
+    @NonNull
+    private static Rect getExpectedFeatureRectAfterRotation(@Surface.Rotation int rotation) {
+        switch (rotation) {
+            case Surface.ROTATION_0:
+                return new Rect(
+                        MOCK_FEATURE_LEFT, 0, MOCK_FEATURE_RIGHT, MOCK_DISPLAY_HEIGHT);
+            case Surface.ROTATION_90:
+                return new Rect(0, MOCK_DISPLAY_WIDTH - MOCK_FEATURE_RIGHT,
+                        MOCK_DISPLAY_HEIGHT, MOCK_DISPLAY_WIDTH - MOCK_FEATURE_LEFT);
+            case Surface.ROTATION_180:
+                return new Rect(MOCK_DISPLAY_WIDTH - MOCK_FEATURE_RIGHT, 0,
+                        MOCK_DISPLAY_WIDTH - MOCK_FEATURE_LEFT, MOCK_DISPLAY_HEIGHT);
+            case Surface.ROTATION_270:
+                return new Rect(0, MOCK_FEATURE_LEFT, MOCK_DISPLAY_HEIGHT,
+                        MOCK_FEATURE_RIGHT);
+            default:
+                throw new IllegalArgumentException("Unknown rotation value: " + rotation);
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
index 9a2b812..85ea809 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
@@ -973,9 +973,9 @@
         pw.print("  suppressNotif: "); pw.println(shouldSuppressNotification());
         pw.print("  autoExpand:    "); pw.println(shouldAutoExpand());
         pw.print("  isDismissable: "); pw.println(mIsDismissable);
-        pw.println("  bubbleMetadataFlagListener null: " + (mBubbleMetadataFlagListener == null));
+        pw.println("  bubbleMetadataFlagListener null?: " + (mBubbleMetadataFlagListener == null));
         if (mExpandedView != null) {
-            mExpandedView.dump(pw);
+            mExpandedView.dump(pw, "  ");
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 645a961..dfdc79e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -1991,13 +1991,20 @@
      * Description of current bubble state.
      */
     private void dump(PrintWriter pw, String prefix) {
-        pw.println("BubbleController state:");
+        pw.print(prefix); pw.println("BubbleController state:");
+        pw.print(prefix); pw.println("  currentUserId= " + mCurrentUserId);
+        pw.print(prefix); pw.println("  isStatusBarShade= " + mIsStatusBarShade);
+        pw.print(prefix); pw.println("  isShowingAsBubbleBar= " + isShowingAsBubbleBar());
+        pw.println();
+
         mBubbleData.dump(pw);
         pw.println();
+
         if (mStackView != null) {
             mStackView.dump(pw);
         }
         pw.println();
+
         mImpl.mCachedState.dump(pw);
     }
 
@@ -2246,8 +2253,7 @@
                 pw.println("mIsStackExpanded: " + mIsStackExpanded);
                 pw.println("mSelectedBubbleKey: " + mSelectedBubbleKey);
 
-                pw.print("mSuppressedBubbleKeys: ");
-                pw.println(mSuppressedBubbleKeys.size());
+                pw.println("mSuppressedBubbleKeys: " + mSuppressedBubbleKeys.size());
                 for (String key : mSuppressedBubbleKeys) {
                     pw.println("   suppressing: " + key);
                 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index cc8f50e..c6f74af 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -1231,29 +1231,30 @@
      * Description of current bubble data state.
      */
     public void dump(PrintWriter pw) {
-        pw.print("selected: ");
+        pw.println("BubbleData state:");
+        pw.print("  selected: ");
         pw.println(mSelectedBubble != null
                 ? mSelectedBubble.getKey()
                 : "null");
-        pw.print("expanded: ");
+        pw.print("  expanded: ");
         pw.println(mExpanded);
 
-        pw.print("stack bubble count:    ");
+        pw.print("Stack bubble count: ");
         pw.println(mBubbles.size());
         for (Bubble bubble : mBubbles) {
             bubble.dump(pw);
         }
 
-        pw.print("overflow bubble count:    ");
+        pw.print("Overflow bubble count: ");
         pw.println(mOverflowBubbles.size());
         for (Bubble bubble : mOverflowBubbles) {
             bubble.dump(pw);
         }
 
-        pw.print("summaryKeys: ");
+        pw.print("SummaryKeys: ");
         pw.println(mSuppressedGroupKeys.size());
         for (String key : mSuppressedGroupKeys.keySet()) {
-            pw.println("   suppressing: " + key);
+            pw.println("     suppressing: " + key);
         }
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java
index 76662c4..1c0e052 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java
@@ -77,20 +77,25 @@
 
     static String formatBubblesString(List<Bubble> bubbles, BubbleViewProvider selected) {
         StringBuilder sb = new StringBuilder();
-        for (Bubble bubble : bubbles) {
+        for (int i = 0; i < bubbles.size(); i++) {
+            Bubble bubble = bubbles.get(i);
             if (bubble == null) {
-                sb.append("   <null> !!!!!\n");
+                sb.append("   <null> !!!!!");
             } else {
                 boolean isSelected = (selected != null
-                        && selected.getKey() != BubbleOverflow.KEY
+                        && !BubbleOverflow.KEY.equals(selected.getKey())
                         && bubble == selected);
                 String arrow = isSelected ? "=>" : "  ";
-                sb.append(String.format("%s Bubble{act=%12d, showInShade=%d, key=%s}\n",
+
+                sb.append(String.format("%s Bubble{act=%12d, showInShade=%d, key=%s}",
                         arrow,
                         bubble.getLastActivity(),
                         (bubble.showInShade() ? 1 : 0),
                         bubble.getKey()));
             }
+            if (i != bubbles.size() - 1) {
+                sb.append("\n");
+            }
         }
         return sb.toString();
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index e698601..37bcf1d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -1094,9 +1094,9 @@
     /**
      * Description of current expanded view state.
      */
-    public void dump(@NonNull PrintWriter pw) {
-        pw.print("BubbleExpandedView");
-        pw.print("  taskId:               "); pw.println(mTaskId);
-        pw.print("  stackView:            "); pw.println(mStackView);
+    public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
+        pw.print(prefix); pw.println("BubbleExpandedView:");
+        pw.print(prefix); pw.print("  taskId: "); pw.println(mTaskId);
+        pw.print(prefix); pw.print("  stackView: "); pw.println(mStackView);
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 52c9bf8..093ecb1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -305,8 +305,7 @@
 
         String bubblesOnScreen = BubbleDebugConfig.formatBubblesString(
                 getBubblesOnScreen(), getExpandedBubble());
-        pw.print("  stack visibility :       "); pw.println(getVisibility());
-        pw.print("  bubbles on screen:       "); pw.println(bubblesOnScreen);
+        pw.println("  bubbles on screen:       "); pw.println(bubblesOnScreen);
         pw.print("  gestureInProgress:       "); pw.println(mIsGestureInProgress);
         pw.print("  showingDismiss:          "); pw.println(mDismissView.isShowing());
         pw.print("  isExpansionAnimating:    "); pw.println(mIsExpansionAnimating);
@@ -314,7 +313,8 @@
         pw.print("  expandedContainerAlpha:  "); pw.println(mExpandedViewContainer.getAlpha());
         pw.print("  expandedContainerMatrix: ");
         pw.println(mExpandedViewContainer.getAnimationMatrix());
-
+        pw.print("  stack visibility :       "); pw.println(getVisibility());
+        pw.print("  temporarilyInvisible:    "); pw.println(mTemporarilyInvisible);
         mStackAnimationController.dump(pw);
         mExpandedAnimationController.dump(pw);
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
index de46b31..5c0e04a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
@@ -76,7 +76,7 @@
             minHeight = MIN_HEIGHT
             defaultMinSize = DEFAULT_MIN
             displayId = DISPLAY_ID
-            configuration.windowConfiguration.bounds = STARTING_BOUNDS
+            configuration.windowConfiguration.setBounds(STARTING_BOUNDS)
         }
         mockWindowDecoration.mDisplay = mockDisplay
         whenever(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
index 6f0599a..c0c4498 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
@@ -88,7 +88,7 @@
             minHeight = MIN_HEIGHT
             defaultMinSize = DEFAULT_MIN
             displayId = DISPLAY_ID
-            configuration.windowConfiguration.bounds = STARTING_BOUNDS
+            configuration.windowConfiguration.setBounds(STARTING_BOUNDS)
         }
         mockWindowDecoration.mDisplay = mockDisplay
         whenever(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
index 3465ddd..8913453 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
@@ -104,7 +104,7 @@
             minHeight = MIN_HEIGHT
             defaultMinSize = DEFAULT_MIN
             displayId = DISPLAY_ID
-            configuration.windowConfiguration.bounds = STARTING_BOUNDS
+            configuration.windowConfiguration.setBounds(STARTING_BOUNDS)
         }
         mockDesktopWindowDecoration.mDisplay = mockDisplay
         whenever(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index fa9447a..47a7f35 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -85,7 +85,10 @@
     export_include_dirs: ["include"],
     export_shared_lib_headers: ["libz"],
     static_libs: ["libincfs-utils"],
-    whole_static_libs: ["libincfs-utils"],
+    whole_static_libs: [
+        "libandroidfw_pathutils",
+        "libincfs-utils",
+    ],
     export_static_lib_headers: ["libincfs-utils"],
     target: {
         android: {
@@ -137,6 +140,28 @@
     },
 }
 
+cc_library_static {
+    name: "libandroidfw_pathutils",
+    defaults: ["libandroidfw_defaults"],
+    host_supported: true,
+    export_include_dirs: ["include_pathutils"],
+    srcs: [
+        "PathUtils.cpp",
+    ],
+    shared_libs: [
+        "libutils",
+    ],
+    target: {
+        windows: {
+            enabled: true,
+        },
+    },
+    visibility: [
+        ":__subpackages__",
+        "//frameworks/base/tools/aapt",
+    ],
+}
+
 common_test_libs = [
     "libandroidfw",
     "libbase",
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 795bb3c..fd6e18e 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -26,6 +26,7 @@
 #include <androidfw/AssetDir.h>
 #include <androidfw/AssetManager.h>
 #include <androidfw/misc.h>
+#include <androidfw/PathUtils.h>
 #include <androidfw/ResourceTypes.h>
 #include <androidfw/ZipFileRO.h>
 #include <cutils/atomic.h>
@@ -88,7 +89,7 @@
     const char* root = getenv("ANDROID_DATA");
     LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_DATA not set");
     String8 path(root);
-    path.appendPath(kResourceCache);
+    appendPath(path, kResourceCache);
 
     char buf[256]; // 256 chars should be enough for anyone...
     strncpy(buf, pkgPath.c_str(), 255);
@@ -104,7 +105,7 @@
         }
         ++p;
     }
-    path.appendPath(filename);
+    appendPath(path, filename);
     path.append("@idmap");
 
     return path;
@@ -181,7 +182,7 @@
 
     String8 realPath(path);
     if (kAppZipName) {
-        realPath.appendPath(kAppZipName);
+        appendPath(realPath, kAppZipName);
     }
     ap.type = ::getFileType(realPath.c_str());
     if (ap.type == kFileTypeRegular) {
@@ -367,7 +368,7 @@
     LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_ROOT not set");
 
     String8 path(root);
-    path.appendPath(kSystemAssets);
+    appendPath(path, kSystemAssets);
 
     return addAssetPath(path, NULL, false /* appAsLib */, true /* isSystemAsset */);
 }
@@ -439,7 +440,7 @@
     LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
 
     String8 assetName(kAssetsRoot);
-    assetName.appendPath(fileName);
+    appendPath(assetName, fileName);
 
     /*
      * For each top-level asset path, search for the asset.
@@ -587,8 +588,8 @@
                 const char* data = getenv("ANDROID_DATA");
                 LOG_ALWAYS_FATAL_IF(data == NULL, "ANDROID_DATA not set");
                 String8 overlaysListPath(data);
-                overlaysListPath.appendPath(kResourceCache);
-                overlaysListPath.appendPath("overlays.list");
+                appendPath(overlaysListPath, kResourceCache);
+                appendPath(overlaysListPath, "overlays.list");
                 addSystemOverlays(overlaysListPath.c_str(), ap.path, sharedRes, nextEntryIdx);
 #endif
                 sharedRes = const_cast<AssetManager*>(this)->
@@ -789,7 +790,7 @@
     /* look at the filesystem on disk */
     if (ap.type == kFileTypeDirectory) {
         String8 path(ap.path);
-        path.appendPath(fileName);
+        appendPath(path, fileName);
 
         pAsset = openAssetFromFileLocked(path, mode);
 
@@ -841,9 +842,9 @@
     sourceName.append(zipFileName);
     sourceName.append(":");
     if (dirName.length() > 0) {
-        sourceName.appendPath(dirName);
+        appendPath(sourceName, dirName);
     }
-    sourceName.appendPath(fileName);
+    appendPath(sourceName, fileName);
     return sourceName;
 }
 
@@ -853,7 +854,7 @@
 String8 AssetManager::createPathNameLocked(const asset_path& ap, const char* rootDir)
 {
     String8 path(ap.path);
-    if (rootDir != NULL) path.appendPath(rootDir);
+    if (rootDir != NULL) appendPath(path, rootDir);
     return path;
 }
 
@@ -897,7 +898,7 @@
 {
     Asset* pAsset = NULL;
 
-    if (strcasecmp(pathName.getPathExtension().c_str(), ".gz") == 0) {
+    if (strcasecmp(getPathExtension(pathName).c_str(), ".gz") == 0) {
         //printf("TRYING '%s'\n", (const char*) pathName);
         pAsset = Asset::createFromCompressedFile(pathName.c_str(), mode);
     } else {
@@ -1078,8 +1079,7 @@
     //printf("scanAndMergeDir: %s %s %s\n", ap.path.c_str(), rootDir, dirName);
 
     String8 path = createPathNameLocked(ap, rootDir);
-    if (dirName[0] != '\0')
-        path.appendPath(dirName);
+    if (dirName[0] != '\0') appendPath(path, dirName);
 
     SortedVector<AssetDir::FileInfo>* pContents = scanDirLocked(path);
     if (pContents == NULL)
@@ -1176,7 +1176,7 @@
             fileType = kFileTypeUnknown;
 #else
         // stat the file
-        fileType = ::getFileType(path.appendPathCopy(entry->d_name).c_str());
+        fileType = ::getFileType(appendPathCopy(path, entry->d_name).c_str());
 #endif
 
         if (fileType != kFileTypeRegular && fileType != kFileTypeDirectory)
@@ -1184,9 +1184,9 @@
 
         AssetDir::FileInfo info;
         info.set(String8(entry->d_name), fileType);
-        if (strcasecmp(info.getFileName().getPathExtension().c_str(), ".gz") == 0)
-            info.setFileName(info.getFileName().getBasePath());
-        info.setSourceName(path.appendPathCopy(info.getFileName()));
+        if (strcasecmp(getPathExtension(info.getFileName()).c_str(), ".gz") == 0)
+            info.setFileName(getBasePath(info.getFileName()));
+        info.setSourceName(appendPathCopy(path, info.getFileName()));
         pContents->add(info);
     }
 
@@ -1220,7 +1220,7 @@
 
     /* convert "sounds" to "rootDir/sounds" */
     if (rootDir != NULL) dirName = rootDir;
-    dirName.appendPath(baseDirName);
+    appendPath(dirName, baseDirName);
 
     /*
      * Scan through the list of files, looking for a match.  The files in
@@ -1269,7 +1269,7 @@
             if (nextSlash == NULL) {
                 /* this is a file in the requested directory */
 
-                info.set(String8(nameBuf).getPathLeaf(), kFileTypeRegular);
+                info.set(getPathLeaf(String8(nameBuf)), kFileTypeRegular);
 
                 info.setSourceName(
                     createZipSourceNameLocked(zipName, dirName, info.getFileName()));
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 6523469..edccb8a 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -91,6 +91,12 @@
   StringPoolRef entry_string_ref;
 };
 
+struct Theme::Entry {
+  ApkAssetsCookie cookie;
+  uint32_t type_spec_flags;
+  Res_value value;
+};
+
 AssetManager2::AssetManager2(ApkAssetsList apk_assets, const ResTable_config& configuration) {
   configurations_.push_back(configuration);
 
@@ -1605,12 +1611,6 @@
 
 Theme::~Theme() = default;
 
-struct Theme::Entry {
-  ApkAssetsCookie cookie;
-  uint32_t type_spec_flags;
-  Res_value value;
-};
-
 base::expected<std::monostate, NullOrIOError> Theme::ApplyStyle(uint32_t resid, bool force) {
   ATRACE_NAME("Theme::ApplyStyle");
 
diff --git a/libs/androidfw/BackupHelpers.cpp b/libs/androidfw/BackupHelpers.cpp
index 3582609..1a6a952 100644
--- a/libs/androidfw/BackupHelpers.cpp
+++ b/libs/androidfw/BackupHelpers.cpp
@@ -30,6 +30,7 @@
 #include <utime.h>
 #include <zlib.h>
 
+#include <androidfw/PathUtils.h>
 #include <log/log.h>
 #include <utils/ByteOrder.h>
 #include <utils/KeyedVector.h>
@@ -606,14 +607,14 @@
             prefix += packageName;
         }
         if (domain.length() > 0) {
-            prefix.appendPath(domain);
+            appendPath(prefix, domain);
         }
 
         // pax extended means we don't put in a prefix field, and put a different
         // string in the basic name field.  We can also construct the full path name
         // out of the substrings we've now built.
         fullname = prefix;
-        fullname.appendPath(relpath);
+        appendPath(fullname, relpath);
 
         // ustar:
         //    [   0 : 100 ]; file name/path
@@ -654,7 +655,7 @@
         // Now build the pax *header* templated on the ustar header
         memcpy(paxHeader, buf, 512);
 
-        String8 leaf = fullname.getPathLeaf();
+        String8 leaf = getPathLeaf(fullname);
         memset(paxHeader, 0, 100);                  // rewrite the name area
         snprintf(paxHeader, 100, "PaxHeader/%s", leaf.c_str());
         memset(paxHeader + 345, 0, 155);            // rewrite the prefix area
diff --git a/libs/androidfw/PathUtils.cpp b/libs/androidfw/PathUtils.cpp
new file mode 100644
index 0000000..df7a9f0
--- /dev/null
+++ b/libs/androidfw/PathUtils.cpp
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+
+#include <androidfw/PathUtils.h>
+
+#include <utils/Compat.h>
+
+namespace android {
+
+String8 getPathLeaf(const String8& str) {
+    const char* cp;
+    const char*const buf = str.c_str();
+
+    cp = strrchr(buf, OS_PATH_SEPARATOR);
+    if (cp == nullptr)
+        return str;
+    else
+        return String8(cp+1);
+}
+
+String8 getPathDir(const String8& str8) {
+    const char* cp;
+    const char*const str = str8.c_str();
+
+    cp = strrchr(str, OS_PATH_SEPARATOR);
+    if (cp == nullptr)
+        return String8();
+    else
+        return String8(str, cp - str);
+}
+
+static char* findExtension(const String8& str8) {
+    const char* lastSlash;
+    const char* lastDot;
+    const char* const str = str8.c_str();
+
+    // only look at the filename
+    lastSlash = strrchr(str, OS_PATH_SEPARATOR);
+    if (lastSlash == nullptr)
+        lastSlash = str;
+    else
+        lastSlash++;
+
+    // find the last dot
+    lastDot = strrchr(lastSlash, '.');
+    if (lastDot == nullptr)
+        return nullptr;
+
+    // looks good, ship it
+    return const_cast<char*>(lastDot);
+}
+
+String8 getPathExtension(const String8& str) {
+    char* ext;
+
+    ext = findExtension(str);
+    if (ext != nullptr)
+        return String8(ext);
+    else
+        return String8();
+}
+
+String8 getBasePath(const String8& str8) {
+    char* ext;
+    const char* const str = str8.c_str();
+
+    ext = findExtension(str8);
+    if (ext == nullptr)
+        return str8;
+    else
+        return String8(str, ext - str);
+}
+
+static void setPathName(String8& s, const char* name) {
+    size_t len = strlen(name);
+    char* buf = s.lockBuffer(len);
+
+    memcpy(buf, name, len);
+
+    // remove trailing path separator, if present
+    if (len > 0 && buf[len - 1] == OS_PATH_SEPARATOR) len--;
+    buf[len] = '\0';
+
+    s.unlockBuffer(len);
+}
+
+String8& appendPath(String8& str, const char* name) {
+    // TODO: The test below will fail for Win32 paths. Fix later or ignore.
+    if (name[0] != OS_PATH_SEPARATOR) {
+        if (*name == '\0') {
+            // nothing to do
+            return str;
+        }
+
+        size_t len = str.length();
+        if (len == 0) {
+            // no existing filename, just use the new one
+            setPathName(str, name);
+            return str;
+        }
+
+        // make room for oldPath + '/' + newPath
+        int newlen = strlen(name);
+
+        char* buf = str.lockBuffer(len+1+newlen);
+
+        // insert a '/' if needed
+        if (buf[len-1] != OS_PATH_SEPARATOR)
+            buf[len++] = OS_PATH_SEPARATOR;
+
+        memcpy(buf+len, name, newlen+1);
+        len += newlen;
+
+        str.unlockBuffer(len);
+        return str;
+    } else {
+        setPathName(str, name);
+        return str;
+    }
+}
+
+} // namespace android
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index ec14316..099287c 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -6291,13 +6291,13 @@
         if (append) {
             outString->append(tmp);
         } else {
-            outString->setTo(tmp);
+            *outString = tmp;
         }
     } else {
         if (append) {
             outString->append(String16(s, len));
         } else {
-            outString->setTo(s, len);
+            *outString = String16(s, len);
         }
     }
 
@@ -7500,10 +7500,10 @@
         *pOverlayCrc = dtohl(map[3]);
     }
     if (pTargetPath) {
-        pTargetPath->setTo(reinterpret_cast<const char*>(map + 4));
+        *pTargetPath = reinterpret_cast<const char*>(map + 4);
     }
     if (pOverlayPath) {
-        pOverlayPath->setTo(reinterpret_cast<const char*>(map + 4 + 256 / sizeof(uint32_t)));
+        *pOverlayPath = reinterpret_cast<const char*>(map + 4 + 256 / sizeof(uint32_t));
     }
     return true;
 }
diff --git a/libs/androidfw/include_pathutils/androidfw/PathUtils.h b/libs/androidfw/include_pathutils/androidfw/PathUtils.h
new file mode 100644
index 0000000..4debe8d
--- /dev/null
+++ b/libs/androidfw/include_pathutils/androidfw/PathUtils.h
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <utils/String8.h>
+
+/* This library contains path manipulation functions that are used only by androidfw and aapt.
+ * When it's possible, migrate all uses to std::filesystem::path.
+ */
+
+namespace android {
+
+/**
+ * Get just the filename component.
+ *
+ * DEPRECATED: use std::filesystem::path::filename
+ *
+ * "/tmp/foo/bar.c" --> "bar.c"
+ */
+String8 getPathLeaf(const String8& str);
+
+/**
+ * Remove the last (file name) component, leaving just the directory
+ * name.
+ *
+ * DEPRECATED: use std::filesystem::path::parent_path
+ *
+ * "/tmp/foo/bar.c" --> "/tmp/foo"
+ * "/tmp" --> "" // ????? shouldn't this be "/" ???? XXX
+ * "bar.c" --> ""
+ */
+String8 getPathDir(const String8& str);
+
+/**
+ * Return the filename extension.  This is the last '.' and any number
+ * of characters that follow it.  The '.' is included in case we
+ * decide to expand our definition of what constitutes an extension.
+ *
+ * DEPRECATED: use std::filesystem::path::extension
+ *
+ * "/tmp/foo/bar.c" --> ".c"
+ * "/tmp" --> ""
+ * "/tmp/foo.bar/baz" --> ""
+ * "foo.jpeg" --> ".jpeg"
+ * "foo." --> ""
+ */
+String8 getPathExtension(const String8& str);
+
+/**
+ * Return the path without the extension.  Rules for what constitutes
+ * an extension are described in the comment for getPathExtension().
+ *
+ * DEPRECATED: use std::filesystem::path::stem and std::filesystem::path::parent_path
+ *
+ * "/tmp/foo/bar.c" --> "/tmp/foo/bar"
+ */
+String8 getBasePath(const String8& str);
+
+/**
+ * Add a component to the pathname.  We guarantee that there is
+ * exactly one path separator between the old path and the new.
+ * If there is no existing name, we just copy the new name in.
+ *
+ * DEPRECATED: use std::filesystem::path::operator/=
+ *
+ * If leaf is a fully qualified path (i.e. starts with '/', it
+ * replaces whatever was there before.
+ */
+String8& appendPath(String8& str, const char* leaf);
+inline String8& appendPath(String8& str, const String8& leaf) {
+    return appendPath(str, leaf.c_str());
+}
+
+/**
+ * Like appendPath(), but does not affect this string.  Returns a new one instead.
+ *
+ * DEPRECATED: use std::filesystem::operator/
+ */
+inline String8 appendPathCopy(String8 str, const char* leaf) { return appendPath(str, leaf); }
+inline String8 appendPathCopy(String8 str, const String8& leaf) {
+    return appendPath(str, leaf.c_str());
+}
+
+} // namespace android
diff --git a/libs/androidfw/tests/ConfigDescription_test.cpp b/libs/androidfw/tests/ConfigDescription_test.cpp
index ec478b0..07bd175 100644
--- a/libs/androidfw/tests/ConfigDescription_test.cpp
+++ b/libs/androidfw/tests/ConfigDescription_test.cpp
@@ -159,17 +159,17 @@
   EXPECT_TRUE(TestParse("feminine", &config));
   EXPECT_EQ(android::ResTable_config::GRAMMATICAL_GENDER_FEMININE, config.grammaticalInflection);
   EXPECT_EQ(SDK_U, config.sdkVersion);
-  EXPECT_EQ(std::string("feminine-v34"), config.toString().string());
+  EXPECT_EQ(std::string("feminine-v34"), config.toString().c_str());
 
   EXPECT_TRUE(TestParse("masculine", &config));
   EXPECT_EQ(android::ResTable_config::GRAMMATICAL_GENDER_MASCULINE, config.grammaticalInflection);
   EXPECT_EQ(SDK_U, config.sdkVersion);
-  EXPECT_EQ(std::string("masculine-v34"), config.toString().string());
+  EXPECT_EQ(std::string("masculine-v34"), config.toString().c_str());
 
   EXPECT_TRUE(TestParse("neuter", &config));
   EXPECT_EQ(android::ResTable_config::GRAMMATICAL_GENDER_NEUTER, config.grammaticalInflection);
   EXPECT_EQ(SDK_U, config.sdkVersion);
-  EXPECT_EQ(std::string("neuter-v34"), config.toString().string());
+  EXPECT_EQ(std::string("neuter-v34"), config.toString().c_str());
 }
 
 }  // namespace android
diff --git a/libs/androidfw/tests/ResTable_test.cpp b/libs/androidfw/tests/ResTable_test.cpp
index 945981b..faac514 100644
--- a/libs/androidfw/tests/ResTable_test.cpp
+++ b/libs/androidfw/tests/ResTable_test.cpp
@@ -468,7 +468,7 @@
   String16 name(u"com.android.sparse:integer/foo_9");
   uint32_t flags;
   uint32_t resid =
-      table.identifierForName(name.string(), name.size(), nullptr, 0, nullptr, 0, &flags);
+      table.identifierForName(name.c_str(), name.size(), nullptr, 0, nullptr, 0, &flags);
   ASSERT_NE(0u, resid);
 
   Res_value val;
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 529a49e9..c959db3 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -120,9 +120,9 @@
         if (name) {
             const char* lastPeriod = strrchr(name, '.');
             if (lastPeriod) {
-                mName.setTo(lastPeriod + 1);
+                mName = (lastPeriod + 1);
             } else {
-                mName.setTo(name);
+                mName = name;
             }
         }
     }
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index c41cd04..abd9284 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -354,13 +354,12 @@
     return it != di.end() ? it->transform : kIdentityTransform;
 }
 
-void PointerController::dump(std::string& dump) {
+std::string PointerController::dump() {
     if (!mEnabled) {
-        dump += INDENT "PointerController: DISABLED due to ongoing PointerChoreographer refactor\n";
-        return;
+        return INDENT "PointerController: DISABLED due to ongoing PointerChoreographer refactor\n";
     }
 
-    dump += INDENT "PointerController:\n";
+    std::string dump = INDENT "PointerController:\n";
     std::scoped_lock lock(getLock());
     dump += StringPrintf(INDENT2 "Presentation: %s\n",
                          ftl::enum_string(mLocked.presentation).c_str());
@@ -373,6 +372,7 @@
     for (const auto& [_, spotController] : mLocked.spotControllers) {
         spotController.dump(dump, INDENT3);
     }
+    return dump;
 }
 
 } // namespace android
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index de39eda..aa7ca3c 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -75,7 +75,7 @@
     void onDisplayInfosChangedLocked(const std::vector<gui::DisplayInfo>& displayInfos)
             REQUIRES(getLock());
 
-    void dump(std::string& dump);
+    std::string dump();
 
 protected:
     using WindowListenerConsumer =
diff --git a/location/Android.bp b/location/Android.bp
index 46dca74..cfe0e49 100644
--- a/location/Android.bp
+++ b/location/Android.bp
@@ -7,18 +7,18 @@
     default_applicable_licenses: ["frameworks_base_license"],
 }
 
-//location sources that will populate the new module
 filegroup {
-    name: "framework-location-nonupdatable-sources",
+    name: "framework-location-sources",
     srcs: [
-        "placeholder_java/android/location/Placeholder.java",
+        "java/**/*.java",
+        "java/**/*.aidl",
     ],
 }
 
 java_sdk_library {
     name: "framework-location",
     srcs: [
-        ":framework-location-nonupdatable-sources",
+        ":framework-location-sources",
     ],
     defaults: ["framework-non-updatable-unbundled-defaults"],
     permitted_packages: [
diff --git a/location/api/current.txt b/location/api/current.txt
index d802177..33effdd 100644
--- a/location/api/current.txt
+++ b/location/api/current.txt
@@ -1 +1,725 @@
 // Signature format: 2.0
+package android.location {
+
+  public class Address implements android.os.Parcelable {
+    ctor public Address(java.util.Locale);
+    method public void clearLatitude();
+    method public void clearLongitude();
+    method public int describeContents();
+    method public String getAddressLine(int);
+    method public String getAdminArea();
+    method public String getCountryCode();
+    method public String getCountryName();
+    method public android.os.Bundle getExtras();
+    method public String getFeatureName();
+    method public double getLatitude();
+    method public java.util.Locale getLocale();
+    method public String getLocality();
+    method public double getLongitude();
+    method public int getMaxAddressLineIndex();
+    method public String getPhone();
+    method public String getPostalCode();
+    method public String getPremises();
+    method public String getSubAdminArea();
+    method public String getSubLocality();
+    method public String getSubThoroughfare();
+    method public String getThoroughfare();
+    method public String getUrl();
+    method public boolean hasLatitude();
+    method public boolean hasLongitude();
+    method public void setAddressLine(int, String);
+    method public void setAdminArea(String);
+    method public void setCountryCode(String);
+    method public void setCountryName(String);
+    method public void setExtras(android.os.Bundle);
+    method public void setFeatureName(String);
+    method public void setLatitude(double);
+    method public void setLocality(String);
+    method public void setLongitude(double);
+    method public void setPhone(String);
+    method public void setPostalCode(String);
+    method public void setPremises(String);
+    method public void setSubAdminArea(String);
+    method public void setSubLocality(String);
+    method public void setSubThoroughfare(String);
+    method public void setThoroughfare(String);
+    method public void setUrl(String);
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.Address> CREATOR;
+  }
+
+  @Deprecated public class Criteria implements android.os.Parcelable {
+    ctor @Deprecated public Criteria();
+    ctor @Deprecated public Criteria(android.location.Criteria);
+    method @Deprecated public int describeContents();
+    method @Deprecated public int getAccuracy();
+    method @Deprecated public int getBearingAccuracy();
+    method @Deprecated public int getHorizontalAccuracy();
+    method @Deprecated public int getPowerRequirement();
+    method @Deprecated public int getSpeedAccuracy();
+    method @Deprecated public int getVerticalAccuracy();
+    method @Deprecated public boolean isAltitudeRequired();
+    method @Deprecated public boolean isBearingRequired();
+    method @Deprecated public boolean isCostAllowed();
+    method @Deprecated public boolean isSpeedRequired();
+    method @Deprecated public void setAccuracy(int);
+    method @Deprecated public void setAltitudeRequired(boolean);
+    method @Deprecated public void setBearingAccuracy(int);
+    method @Deprecated public void setBearingRequired(boolean);
+    method @Deprecated public void setCostAllowed(boolean);
+    method @Deprecated public void setHorizontalAccuracy(int);
+    method @Deprecated public void setPowerRequirement(int);
+    method @Deprecated public void setSpeedAccuracy(int);
+    method @Deprecated public void setSpeedRequired(boolean);
+    method @Deprecated public void setVerticalAccuracy(int);
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated public static final int ACCURACY_COARSE = 2; // 0x2
+    field @Deprecated public static final int ACCURACY_FINE = 1; // 0x1
+    field @Deprecated public static final int ACCURACY_HIGH = 3; // 0x3
+    field @Deprecated public static final int ACCURACY_LOW = 1; // 0x1
+    field @Deprecated public static final int ACCURACY_MEDIUM = 2; // 0x2
+    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.Criteria> CREATOR;
+    field @Deprecated public static final int NO_REQUIREMENT = 0; // 0x0
+    field @Deprecated public static final int POWER_HIGH = 3; // 0x3
+    field @Deprecated public static final int POWER_LOW = 1; // 0x1
+    field @Deprecated public static final int POWER_MEDIUM = 2; // 0x2
+  }
+
+  public final class Geocoder {
+    ctor public Geocoder(@NonNull android.content.Context);
+    ctor public Geocoder(@NonNull android.content.Context, @NonNull java.util.Locale);
+    method @Deprecated @Nullable public java.util.List<android.location.Address> getFromLocation(@FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @IntRange int) throws java.io.IOException;
+    method public void getFromLocation(@FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @IntRange int, @NonNull android.location.Geocoder.GeocodeListener);
+    method @Deprecated @Nullable public java.util.List<android.location.Address> getFromLocationName(@NonNull String, @IntRange int) throws java.io.IOException;
+    method public void getFromLocationName(@NonNull String, @IntRange int, @NonNull android.location.Geocoder.GeocodeListener);
+    method @Deprecated @Nullable public java.util.List<android.location.Address> getFromLocationName(@NonNull String, @IntRange int, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double) throws java.io.IOException;
+    method public void getFromLocationName(@NonNull String, @IntRange int, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @NonNull android.location.Geocoder.GeocodeListener);
+    method public static boolean isPresent();
+  }
+
+  public static interface Geocoder.GeocodeListener {
+    method public default void onError(@Nullable String);
+    method public void onGeocode(@NonNull java.util.List<android.location.Address>);
+  }
+
+  public final class GnssAntennaInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method @FloatRange(from=0.0f) public double getCarrierFrequencyMHz();
+    method @NonNull public android.location.GnssAntennaInfo.PhaseCenterOffset getPhaseCenterOffset();
+    method @Nullable public android.location.GnssAntennaInfo.SphericalCorrections getPhaseCenterVariationCorrections();
+    method @Nullable public android.location.GnssAntennaInfo.SphericalCorrections getSignalGainCorrections();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAntennaInfo> CREATOR;
+  }
+
+  public static class GnssAntennaInfo.Builder {
+    ctor @Deprecated public GnssAntennaInfo.Builder();
+    ctor public GnssAntennaInfo.Builder(double, @NonNull android.location.GnssAntennaInfo.PhaseCenterOffset);
+    ctor public GnssAntennaInfo.Builder(@NonNull android.location.GnssAntennaInfo);
+    method @NonNull public android.location.GnssAntennaInfo build();
+    method @NonNull public android.location.GnssAntennaInfo.Builder setCarrierFrequencyMHz(@FloatRange(from=0.0f) double);
+    method @NonNull public android.location.GnssAntennaInfo.Builder setPhaseCenterOffset(@NonNull android.location.GnssAntennaInfo.PhaseCenterOffset);
+    method @NonNull public android.location.GnssAntennaInfo.Builder setPhaseCenterVariationCorrections(@Nullable android.location.GnssAntennaInfo.SphericalCorrections);
+    method @NonNull public android.location.GnssAntennaInfo.Builder setSignalGainCorrections(@Nullable android.location.GnssAntennaInfo.SphericalCorrections);
+  }
+
+  public static interface GnssAntennaInfo.Listener {
+    method public void onGnssAntennaInfoReceived(@NonNull java.util.List<android.location.GnssAntennaInfo>);
+  }
+
+  public static final class GnssAntennaInfo.PhaseCenterOffset implements android.os.Parcelable {
+    ctor public GnssAntennaInfo.PhaseCenterOffset(double, double, double, double, double, double);
+    method public int describeContents();
+    method @FloatRange public double getXOffsetMm();
+    method @FloatRange public double getXOffsetUncertaintyMm();
+    method @FloatRange public double getYOffsetMm();
+    method @FloatRange public double getYOffsetUncertaintyMm();
+    method @FloatRange public double getZOffsetMm();
+    method @FloatRange public double getZOffsetUncertaintyMm();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAntennaInfo.PhaseCenterOffset> CREATOR;
+  }
+
+  public static final class GnssAntennaInfo.SphericalCorrections implements android.os.Parcelable {
+    ctor public GnssAntennaInfo.SphericalCorrections(@NonNull double[][], @NonNull double[][]);
+    method public int describeContents();
+    method @NonNull public double[][] getCorrectionUncertaintiesArray();
+    method @NonNull public double[][] getCorrectionsArray();
+    method @FloatRange(from=0.0f, to=180.0f) public double getDeltaPhi();
+    method @FloatRange(from=0.0f, to=360.0f) public double getDeltaTheta();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAntennaInfo.SphericalCorrections> CREATOR;
+  }
+
+  public final class GnssAutomaticGainControl implements android.os.Parcelable {
+    method public int describeContents();
+    method @IntRange(from=0) public long getCarrierFrequencyHz();
+    method public int getConstellationType();
+    method @FloatRange(from=0xffffd8f0, to=10000) public double getLevelDb();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAutomaticGainControl> CREATOR;
+  }
+
+  public static final class GnssAutomaticGainControl.Builder {
+    ctor public GnssAutomaticGainControl.Builder();
+    ctor public GnssAutomaticGainControl.Builder(@NonNull android.location.GnssAutomaticGainControl);
+    method @NonNull public android.location.GnssAutomaticGainControl build();
+    method @NonNull public android.location.GnssAutomaticGainControl.Builder setCarrierFrequencyHz(@IntRange(from=0) long);
+    method @NonNull public android.location.GnssAutomaticGainControl.Builder setConstellationType(int);
+    method @NonNull public android.location.GnssAutomaticGainControl.Builder setLevelDb(@FloatRange(from=0xffffd8f0, to=10000) double);
+  }
+
+  public final class GnssCapabilities implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public java.util.List<android.location.GnssSignalType> getGnssSignalTypes();
+    method public int hasAccumulatedDeltaRange();
+    method public boolean hasAntennaInfo();
+    method public boolean hasGeofencing();
+    method @Deprecated public boolean hasGnssAntennaInfo();
+    method public boolean hasLowPowerMode();
+    method public boolean hasMeasurementCorrections();
+    method public boolean hasMeasurementCorrectionsExcessPathLength();
+    method public boolean hasMeasurementCorrectionsForDriving();
+    method public boolean hasMeasurementCorrectionsLosSats();
+    method public boolean hasMeasurementCorrectionsReflectingPlane();
+    method public boolean hasMeasurementCorrelationVectors();
+    method public boolean hasMeasurements();
+    method public boolean hasMsa();
+    method public boolean hasMsb();
+    method public boolean hasNavigationMessages();
+    method public boolean hasOnDemandTime();
+    method public boolean hasPowerMultibandAcquisition();
+    method public boolean hasPowerMultibandTracking();
+    method public boolean hasPowerOtherModes();
+    method public boolean hasPowerSinglebandAcquisition();
+    method public boolean hasPowerSinglebandTracking();
+    method public boolean hasPowerTotal();
+    method public boolean hasSatelliteBlocklist();
+    method public boolean hasSatellitePvt();
+    method public boolean hasScheduling();
+    method public boolean hasSingleShotFix();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int CAPABILITY_SUPPORTED = 1; // 0x1
+    field public static final int CAPABILITY_UNKNOWN = 0; // 0x0
+    field public static final int CAPABILITY_UNSUPPORTED = 2; // 0x2
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssCapabilities> CREATOR;
+  }
+
+  public static final class GnssCapabilities.Builder {
+    ctor public GnssCapabilities.Builder();
+    ctor public GnssCapabilities.Builder(@NonNull android.location.GnssCapabilities);
+    method @NonNull public android.location.GnssCapabilities build();
+    method @NonNull public android.location.GnssCapabilities.Builder setGnssSignalTypes(@NonNull java.util.List<android.location.GnssSignalType>);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasAccumulatedDeltaRange(int);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasAntennaInfo(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasGeofencing(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasLowPowerMode(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrections(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrectionsExcessPathLength(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrectionsForDriving(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrectionsLosSats(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrectionsReflectingPlane(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrelationVectors(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurements(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasMsa(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasMsb(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasNavigationMessages(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasOnDemandTime(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasPowerMultibandAcquisition(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasPowerMultibandTracking(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasPowerOtherModes(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasPowerSinglebandAcquisition(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasPowerSinglebandTracking(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasPowerTotal(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasSatelliteBlocklist(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasSatellitePvt(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasScheduling(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasSingleShotFix(boolean);
+  }
+
+  public final class GnssClock implements android.os.Parcelable {
+    method public int describeContents();
+    method public double getBiasNanos();
+    method @FloatRange(from=0.0f) public double getBiasUncertaintyNanos();
+    method public double getDriftNanosPerSecond();
+    method @FloatRange(from=0.0f) public double getDriftUncertaintyNanosPerSecond();
+    method public long getElapsedRealtimeNanos();
+    method @FloatRange(from=0.0f) public double getElapsedRealtimeUncertaintyNanos();
+    method public long getFullBiasNanos();
+    method public int getHardwareClockDiscontinuityCount();
+    method public int getLeapSecond();
+    method @FloatRange(from=0.0) public double getReferenceCarrierFrequencyHzForIsb();
+    method @NonNull public String getReferenceCodeTypeForIsb();
+    method public int getReferenceConstellationTypeForIsb();
+    method public long getTimeNanos();
+    method @FloatRange(from=0.0f) public double getTimeUncertaintyNanos();
+    method public boolean hasBiasNanos();
+    method public boolean hasBiasUncertaintyNanos();
+    method public boolean hasDriftNanosPerSecond();
+    method public boolean hasDriftUncertaintyNanosPerSecond();
+    method public boolean hasElapsedRealtimeNanos();
+    method public boolean hasElapsedRealtimeUncertaintyNanos();
+    method public boolean hasFullBiasNanos();
+    method public boolean hasLeapSecond();
+    method public boolean hasReferenceCarrierFrequencyHzForIsb();
+    method public boolean hasReferenceCodeTypeForIsb();
+    method public boolean hasReferenceConstellationTypeForIsb();
+    method public boolean hasTimeUncertaintyNanos();
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssClock> CREATOR;
+  }
+
+  public final class GnssMeasurement implements android.os.Parcelable {
+    method public int describeContents();
+    method public double getAccumulatedDeltaRangeMeters();
+    method public int getAccumulatedDeltaRangeState();
+    method public double getAccumulatedDeltaRangeUncertaintyMeters();
+    method @Deprecated public double getAutomaticGainControlLevelDb();
+    method @FloatRange(from=0, to=63) public double getBasebandCn0DbHz();
+    method @Deprecated public long getCarrierCycles();
+    method public float getCarrierFrequencyHz();
+    method @Deprecated public double getCarrierPhase();
+    method @Deprecated public double getCarrierPhaseUncertainty();
+    method @FloatRange(from=0, to=63) public double getCn0DbHz();
+    method @NonNull public String getCodeType();
+    method public int getConstellationType();
+    method public double getFullInterSignalBiasNanos();
+    method @FloatRange(from=0.0) public double getFullInterSignalBiasUncertaintyNanos();
+    method public int getMultipathIndicator();
+    method public double getPseudorangeRateMetersPerSecond();
+    method public double getPseudorangeRateUncertaintyMetersPerSecond();
+    method public long getReceivedSvTimeNanos();
+    method public long getReceivedSvTimeUncertaintyNanos();
+    method public double getSatelliteInterSignalBiasNanos();
+    method @FloatRange(from=0.0) public double getSatelliteInterSignalBiasUncertaintyNanos();
+    method public double getSnrInDb();
+    method public int getState();
+    method public int getSvid();
+    method public double getTimeOffsetNanos();
+    method @Deprecated public boolean hasAutomaticGainControlLevelDb();
+    method public boolean hasBasebandCn0DbHz();
+    method @Deprecated public boolean hasCarrierCycles();
+    method public boolean hasCarrierFrequencyHz();
+    method @Deprecated public boolean hasCarrierPhase();
+    method @Deprecated public boolean hasCarrierPhaseUncertainty();
+    method public boolean hasCodeType();
+    method public boolean hasFullInterSignalBiasNanos();
+    method public boolean hasFullInterSignalBiasUncertaintyNanos();
+    method public boolean hasSatelliteInterSignalBiasNanos();
+    method public boolean hasSatelliteInterSignalBiasUncertaintyNanos();
+    method public boolean hasSnrInDb();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int ADR_STATE_CYCLE_SLIP = 4; // 0x4
+    field public static final int ADR_STATE_HALF_CYCLE_REPORTED = 16; // 0x10
+    field public static final int ADR_STATE_HALF_CYCLE_RESOLVED = 8; // 0x8
+    field public static final int ADR_STATE_RESET = 2; // 0x2
+    field public static final int ADR_STATE_UNKNOWN = 0; // 0x0
+    field public static final int ADR_STATE_VALID = 1; // 0x1
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssMeasurement> CREATOR;
+    field public static final int MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
+    field public static final int MULTIPATH_INDICATOR_NOT_DETECTED = 2; // 0x2
+    field public static final int MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
+    field public static final int STATE_2ND_CODE_LOCK = 65536; // 0x10000
+    field public static final int STATE_BDS_D2_BIT_SYNC = 256; // 0x100
+    field public static final int STATE_BDS_D2_SUBFRAME_SYNC = 512; // 0x200
+    field public static final int STATE_BIT_SYNC = 2; // 0x2
+    field public static final int STATE_CODE_LOCK = 1; // 0x1
+    field public static final int STATE_GAL_E1BC_CODE_LOCK = 1024; // 0x400
+    field public static final int STATE_GAL_E1B_PAGE_SYNC = 4096; // 0x1000
+    field public static final int STATE_GAL_E1C_2ND_CODE_LOCK = 2048; // 0x800
+    field public static final int STATE_GLO_STRING_SYNC = 64; // 0x40
+    field public static final int STATE_GLO_TOD_DECODED = 128; // 0x80
+    field public static final int STATE_GLO_TOD_KNOWN = 32768; // 0x8000
+    field public static final int STATE_MSEC_AMBIGUOUS = 16; // 0x10
+    field public static final int STATE_SBAS_SYNC = 8192; // 0x2000
+    field public static final int STATE_SUBFRAME_SYNC = 4; // 0x4
+    field public static final int STATE_SYMBOL_SYNC = 32; // 0x20
+    field public static final int STATE_TOW_DECODED = 8; // 0x8
+    field public static final int STATE_TOW_KNOWN = 16384; // 0x4000
+    field public static final int STATE_UNKNOWN = 0; // 0x0
+  }
+
+  public final class GnssMeasurementRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method @IntRange(from=0) public int getIntervalMillis();
+    method public boolean isFullTracking();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssMeasurementRequest> CREATOR;
+    field public static final int PASSIVE_INTERVAL = 2147483647; // 0x7fffffff
+  }
+
+  public static final class GnssMeasurementRequest.Builder {
+    ctor public GnssMeasurementRequest.Builder();
+    ctor public GnssMeasurementRequest.Builder(@NonNull android.location.GnssMeasurementRequest);
+    method @NonNull public android.location.GnssMeasurementRequest build();
+    method @NonNull public android.location.GnssMeasurementRequest.Builder setFullTracking(boolean);
+    method @NonNull public android.location.GnssMeasurementRequest.Builder setIntervalMillis(@IntRange(from=0) int);
+  }
+
+  public final class GnssMeasurementsEvent implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public android.location.GnssClock getClock();
+    method @NonNull public java.util.Collection<android.location.GnssAutomaticGainControl> getGnssAutomaticGainControls();
+    method @NonNull public java.util.Collection<android.location.GnssMeasurement> getMeasurements();
+    method public boolean hasIsFullTracking();
+    method public boolean isFullTracking();
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssMeasurementsEvent> CREATOR;
+  }
+
+  public static final class GnssMeasurementsEvent.Builder {
+    ctor public GnssMeasurementsEvent.Builder();
+    ctor public GnssMeasurementsEvent.Builder(@NonNull android.location.GnssMeasurementsEvent);
+    method @NonNull public android.location.GnssMeasurementsEvent build();
+    method @NonNull public android.location.GnssMeasurementsEvent.Builder clearIsFullTracking();
+    method @NonNull public android.location.GnssMeasurementsEvent.Builder setClock(@NonNull android.location.GnssClock);
+    method @NonNull public android.location.GnssMeasurementsEvent.Builder setGnssAutomaticGainControls(@NonNull java.util.Collection<android.location.GnssAutomaticGainControl>);
+    method @NonNull public android.location.GnssMeasurementsEvent.Builder setIsFullTracking(boolean);
+    method @NonNull public android.location.GnssMeasurementsEvent.Builder setMeasurements(@NonNull java.util.Collection<android.location.GnssMeasurement>);
+  }
+
+  public abstract static class GnssMeasurementsEvent.Callback {
+    ctor public GnssMeasurementsEvent.Callback();
+    method public void onGnssMeasurementsReceived(android.location.GnssMeasurementsEvent);
+    method @Deprecated public void onStatusChanged(int);
+    field @Deprecated public static final int STATUS_LOCATION_DISABLED = 2; // 0x2
+    field @Deprecated public static final int STATUS_NOT_ALLOWED = 3; // 0x3
+    field @Deprecated public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
+    field @Deprecated public static final int STATUS_READY = 1; // 0x1
+  }
+
+  public final class GnssNavigationMessage implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public byte[] getData();
+    method @IntRange(from=0xffffffff, to=120) public int getMessageId();
+    method public int getStatus();
+    method @IntRange(from=1) public int getSubmessageId();
+    method @IntRange(from=1, to=200) public int getSvid();
+    method public int getType();
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessage> CREATOR;
+    field public static final int STATUS_PARITY_PASSED = 1; // 0x1
+    field public static final int STATUS_PARITY_REBUILT = 2; // 0x2
+    field public static final int STATUS_UNKNOWN = 0; // 0x0
+    field public static final int TYPE_BDS_CNAV1 = 1283; // 0x503
+    field public static final int TYPE_BDS_CNAV2 = 1284; // 0x504
+    field public static final int TYPE_BDS_D1 = 1281; // 0x501
+    field public static final int TYPE_BDS_D2 = 1282; // 0x502
+    field public static final int TYPE_GAL_F = 1538; // 0x602
+    field public static final int TYPE_GAL_I = 1537; // 0x601
+    field public static final int TYPE_GLO_L1CA = 769; // 0x301
+    field public static final int TYPE_GPS_CNAV2 = 260; // 0x104
+    field public static final int TYPE_GPS_L1CA = 257; // 0x101
+    field public static final int TYPE_GPS_L2CNAV = 258; // 0x102
+    field public static final int TYPE_GPS_L5CNAV = 259; // 0x103
+    field public static final int TYPE_IRN_L5CA = 1793; // 0x701
+    field public static final int TYPE_QZS_L1CA = 1025; // 0x401
+    field public static final int TYPE_SBS = 513; // 0x201
+    field public static final int TYPE_UNKNOWN = 0; // 0x0
+  }
+
+  public abstract static class GnssNavigationMessage.Callback {
+    ctor public GnssNavigationMessage.Callback();
+    method public void onGnssNavigationMessageReceived(android.location.GnssNavigationMessage);
+    method @Deprecated public void onStatusChanged(int);
+    field @Deprecated public static final int STATUS_LOCATION_DISABLED = 2; // 0x2
+    field @Deprecated public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
+    field @Deprecated public static final int STATUS_READY = 1; // 0x1
+  }
+
+  public final class GnssSignalType implements android.os.Parcelable {
+    method @NonNull public static android.location.GnssSignalType create(int, @FloatRange(from=0.0f, fromInclusive=false) double, @NonNull String);
+    method public int describeContents();
+    method @FloatRange(from=0.0f, fromInclusive=false) public double getCarrierFrequencyHz();
+    method @NonNull public String getCodeType();
+    method public int getConstellationType();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssSignalType> CREATOR;
+  }
+
+  public final class GnssStatus implements android.os.Parcelable {
+    method public int describeContents();
+    method @FloatRange(from=0, to=360) public float getAzimuthDegrees(@IntRange(from=0) int);
+    method @FloatRange(from=0, to=63) public float getBasebandCn0DbHz(@IntRange(from=0) int);
+    method @FloatRange(from=0) public float getCarrierFrequencyHz(@IntRange(from=0) int);
+    method @FloatRange(from=0, to=63) public float getCn0DbHz(@IntRange(from=0) int);
+    method public int getConstellationType(@IntRange(from=0) int);
+    method @FloatRange(from=0xffffffa6, to=90) public float getElevationDegrees(@IntRange(from=0) int);
+    method @IntRange(from=0) public int getSatelliteCount();
+    method @IntRange(from=1, to=206) public int getSvid(@IntRange(from=0) int);
+    method public boolean hasAlmanacData(@IntRange(from=0) int);
+    method public boolean hasBasebandCn0DbHz(@IntRange(from=0) int);
+    method public boolean hasCarrierFrequencyHz(@IntRange(from=0) int);
+    method public boolean hasEphemerisData(@IntRange(from=0) int);
+    method public boolean usedInFix(@IntRange(from=0) int);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
+    field public static final int CONSTELLATION_GALILEO = 6; // 0x6
+    field public static final int CONSTELLATION_GLONASS = 3; // 0x3
+    field public static final int CONSTELLATION_GPS = 1; // 0x1
+    field public static final int CONSTELLATION_IRNSS = 7; // 0x7
+    field public static final int CONSTELLATION_QZSS = 4; // 0x4
+    field public static final int CONSTELLATION_SBAS = 2; // 0x2
+    field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssStatus> CREATOR;
+  }
+
+  public static final class GnssStatus.Builder {
+    ctor public GnssStatus.Builder();
+    method @NonNull public android.location.GnssStatus.Builder addSatellite(int, @IntRange(from=1, to=200) int, @FloatRange(from=0, to=63) float, @FloatRange(from=0xffffffa6, to=90) float, @FloatRange(from=0, to=360) float, boolean, boolean, boolean, boolean, @FloatRange(from=0) float, boolean, @FloatRange(from=0, to=63) float);
+    method @NonNull public android.location.GnssStatus build();
+    method @NonNull public android.location.GnssStatus.Builder clearSatellites();
+  }
+
+  public abstract static class GnssStatus.Callback {
+    ctor public GnssStatus.Callback();
+    method public void onFirstFix(int);
+    method public void onSatelliteStatusChanged(@NonNull android.location.GnssStatus);
+    method public void onStarted();
+    method public void onStopped();
+  }
+
+  @Deprecated public final class GpsSatellite {
+    method @Deprecated public float getAzimuth();
+    method @Deprecated public float getElevation();
+    method @Deprecated public int getPrn();
+    method @Deprecated public float getSnr();
+    method @Deprecated public boolean hasAlmanac();
+    method @Deprecated public boolean hasEphemeris();
+    method @Deprecated public boolean usedInFix();
+  }
+
+  @Deprecated public final class GpsStatus {
+    method @Deprecated @NonNull public static android.location.GpsStatus create(@NonNull android.location.GnssStatus, int);
+    method @Deprecated public int getMaxSatellites();
+    method @Deprecated public Iterable<android.location.GpsSatellite> getSatellites();
+    method @Deprecated public int getTimeToFirstFix();
+    field @Deprecated public static final int GPS_EVENT_FIRST_FIX = 3; // 0x3
+    field @Deprecated public static final int GPS_EVENT_SATELLITE_STATUS = 4; // 0x4
+    field @Deprecated public static final int GPS_EVENT_STARTED = 1; // 0x1
+    field @Deprecated public static final int GPS_EVENT_STOPPED = 2; // 0x2
+  }
+
+  @Deprecated public static interface GpsStatus.Listener {
+    method @Deprecated public void onGpsStatusChanged(int);
+  }
+
+  @Deprecated public static interface GpsStatus.NmeaListener {
+    method @Deprecated public void onNmeaReceived(long, String);
+  }
+
+  public interface LocationListener {
+    method public default void onFlushComplete(int);
+    method public void onLocationChanged(@NonNull android.location.Location);
+    method public default void onLocationChanged(@NonNull java.util.List<android.location.Location>);
+    method public default void onProviderDisabled(@NonNull String);
+    method public default void onProviderEnabled(@NonNull String);
+    method @Deprecated public default void onStatusChanged(String, int, android.os.Bundle);
+  }
+
+  public class LocationManager {
+    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addGpsStatusListener(android.location.GpsStatus.Listener);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull android.location.GpsStatus.NmeaListener);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull android.location.OnNmeaMessageListener);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull android.location.OnNmeaMessageListener, @Nullable android.os.Handler);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.OnNmeaMessageListener);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void addProximityAlert(double, double, float, long, @NonNull android.app.PendingIntent);
+    method public void addTestProvider(@NonNull String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int);
+    method public void addTestProvider(@NonNull String, @NonNull android.location.provider.ProviderProperties);
+    method public void addTestProvider(@NonNull String, @NonNull android.location.provider.ProviderProperties, @NonNull java.util.Set<java.lang.String>);
+    method @Deprecated public void clearTestProviderEnabled(@NonNull String);
+    method @Deprecated public void clearTestProviderLocation(@NonNull String);
+    method @Deprecated public void clearTestProviderStatus(@NonNull String);
+    method @NonNull public java.util.List<java.lang.String> getAllProviders();
+    method @Deprecated @Nullable public String getBestProvider(@NonNull android.location.Criteria, boolean);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull String, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull String, @NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
+    method @Nullable public java.util.List<android.location.GnssAntennaInfo> getGnssAntennaInfos();
+    method @NonNull public android.location.GnssCapabilities getGnssCapabilities();
+    method @Nullable public String getGnssHardwareModelName();
+    method public int getGnssYearOfHardware();
+    method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public android.location.GpsStatus getGpsStatus(@Nullable android.location.GpsStatus);
+    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public android.location.Location getLastKnownLocation(@NonNull String);
+    method @Deprecated @Nullable public android.location.LocationProvider getProvider(@NonNull String);
+    method @Nullable public android.location.provider.ProviderProperties getProviderProperties(@NonNull String);
+    method @NonNull public java.util.List<java.lang.String> getProviders(boolean);
+    method @Deprecated @NonNull public java.util.List<java.lang.String> getProviders(@NonNull android.location.Criteria, boolean);
+    method public boolean hasProvider(@NonNull String);
+    method public boolean isLocationEnabled();
+    method public boolean isProviderEnabled(@NonNull String);
+    method public boolean registerAntennaInfoListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssAntennaInfo.Listener);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback, @Nullable android.os.Handler);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
+    method @Deprecated public boolean registerGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback, @Nullable android.os.Handler);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssNavigationMessageCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssNavigationMessage.Callback);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssStatusCallback(@NonNull android.location.GnssStatus.Callback);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssStatusCallback(@NonNull android.location.GnssStatus.Callback, @Nullable android.os.Handler);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssStatusCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssStatus.Callback);
+    method @Deprecated public void removeGpsStatusListener(android.location.GpsStatus.Listener);
+    method @Deprecated public void removeNmeaListener(@NonNull android.location.GpsStatus.NmeaListener);
+    method public void removeNmeaListener(@NonNull android.location.OnNmeaMessageListener);
+    method @RequiresPermission(anyOf={"android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"}, apis="..22") public void removeProximityAlert(@NonNull android.app.PendingIntent);
+    method public void removeTestProvider(@NonNull String);
+    method @RequiresPermission(anyOf={"android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"}, apis="..22") public void removeUpdates(@NonNull android.location.LocationListener);
+    method public void removeUpdates(@NonNull android.app.PendingIntent);
+    method public void requestFlush(@NonNull String, @NonNull android.location.LocationListener, int);
+    method public void requestFlush(@NonNull String, @NonNull android.app.PendingIntent, int);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull android.location.LocationListener);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(long, float, @NonNull android.location.Criteria, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(long, float, @NonNull android.location.Criteria, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull android.app.PendingIntent);
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(long, float, @NonNull android.location.Criteria, @NonNull android.app.PendingIntent);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, @NonNull android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, @NonNull android.location.LocationRequest, @NonNull android.app.PendingIntent);
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull String, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull android.location.Criteria, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull String, @NonNull android.app.PendingIntent);
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull android.location.Criteria, @NonNull android.app.PendingIntent);
+    method public boolean sendExtraCommand(@NonNull String, @NonNull String, @Nullable android.os.Bundle);
+    method public void setTestProviderEnabled(@NonNull String, boolean);
+    method public void setTestProviderLocation(@NonNull String, @NonNull android.location.Location);
+    method @Deprecated public void setTestProviderStatus(@NonNull String, int, @Nullable android.os.Bundle, long);
+    method public void unregisterAntennaInfoListener(@NonNull android.location.GnssAntennaInfo.Listener);
+    method public void unregisterGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback);
+    method public void unregisterGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback);
+    method public void unregisterGnssStatusCallback(@NonNull android.location.GnssStatus.Callback);
+    field public static final String ACTION_GNSS_CAPABILITIES_CHANGED = "android.location.action.GNSS_CAPABILITIES_CHANGED";
+    field public static final String EXTRA_GNSS_CAPABILITIES = "android.location.extra.GNSS_CAPABILITIES";
+    field public static final String EXTRA_LOCATION_ENABLED = "android.location.extra.LOCATION_ENABLED";
+    field public static final String EXTRA_PROVIDER_ENABLED = "android.location.extra.PROVIDER_ENABLED";
+    field public static final String EXTRA_PROVIDER_NAME = "android.location.extra.PROVIDER_NAME";
+    field public static final String FUSED_PROVIDER = "fused";
+    field public static final String GPS_PROVIDER = "gps";
+    field public static final String KEY_FLUSH_COMPLETE = "flushComplete";
+    field public static final String KEY_LOCATIONS = "locations";
+    field public static final String KEY_LOCATION_CHANGED = "location";
+    field public static final String KEY_PROVIDER_ENABLED = "providerEnabled";
+    field public static final String KEY_PROXIMITY_ENTERING = "entering";
+    field @Deprecated public static final String KEY_STATUS_CHANGED = "status";
+    field public static final String MODE_CHANGED_ACTION = "android.location.MODE_CHANGED";
+    field public static final String NETWORK_PROVIDER = "network";
+    field public static final String PASSIVE_PROVIDER = "passive";
+    field public static final String PROVIDERS_CHANGED_ACTION = "android.location.PROVIDERS_CHANGED";
+  }
+
+  @Deprecated public class LocationProvider {
+    method @Deprecated public int getAccuracy();
+    method @Deprecated public String getName();
+    method @Deprecated public int getPowerRequirement();
+    method @Deprecated public boolean hasMonetaryCost();
+    method @Deprecated public boolean meetsCriteria(android.location.Criteria);
+    method @Deprecated public boolean requiresCell();
+    method @Deprecated public boolean requiresNetwork();
+    method @Deprecated public boolean requiresSatellite();
+    method @Deprecated public boolean supportsAltitude();
+    method @Deprecated public boolean supportsBearing();
+    method @Deprecated public boolean supportsSpeed();
+    field @Deprecated public static final int AVAILABLE = 2; // 0x2
+    field @Deprecated public static final int OUT_OF_SERVICE = 0; // 0x0
+    field @Deprecated public static final int TEMPORARILY_UNAVAILABLE = 1; // 0x1
+  }
+
+  public final class LocationRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method @IntRange(from=1) public long getDurationMillis();
+    method @IntRange(from=0) public long getIntervalMillis();
+    method @IntRange(from=0) public long getMaxUpdateDelayMillis();
+    method @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) public int getMaxUpdates();
+    method @FloatRange(from=0, to=java.lang.Float.MAX_VALUE) public float getMinUpdateDistanceMeters();
+    method @IntRange(from=0) public long getMinUpdateIntervalMillis();
+    method public int getQuality();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.LocationRequest> CREATOR;
+    field public static final long PASSIVE_INTERVAL = 9223372036854775807L; // 0x7fffffffffffffffL
+    field public static final int QUALITY_BALANCED_POWER_ACCURACY = 102; // 0x66
+    field public static final int QUALITY_HIGH_ACCURACY = 100; // 0x64
+    field public static final int QUALITY_LOW_POWER = 104; // 0x68
+  }
+
+  public static final class LocationRequest.Builder {
+    ctor public LocationRequest.Builder(long);
+    ctor public LocationRequest.Builder(@NonNull android.location.LocationRequest);
+    method @NonNull public android.location.LocationRequest build();
+    method @NonNull public android.location.LocationRequest.Builder clearMinUpdateIntervalMillis();
+    method @NonNull public android.location.LocationRequest.Builder setDurationMillis(@IntRange(from=1) long);
+    method @NonNull public android.location.LocationRequest.Builder setIntervalMillis(@IntRange(from=0) long);
+    method @NonNull public android.location.LocationRequest.Builder setMaxUpdateDelayMillis(@IntRange(from=0) long);
+    method @NonNull public android.location.LocationRequest.Builder setMaxUpdates(@IntRange(from=1, to=java.lang.Integer.MAX_VALUE) int);
+    method @NonNull public android.location.LocationRequest.Builder setMinUpdateDistanceMeters(@FloatRange(from=0, to=java.lang.Float.MAX_VALUE) float);
+    method @NonNull public android.location.LocationRequest.Builder setMinUpdateIntervalMillis(@IntRange(from=0) long);
+    method @NonNull public android.location.LocationRequest.Builder setQuality(int);
+  }
+
+  public interface OnNmeaMessageListener {
+    method public void onNmeaMessage(String, long);
+  }
+
+  public abstract class SettingInjectorService extends android.app.Service {
+    ctor public SettingInjectorService(String);
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method protected abstract boolean onGetEnabled();
+    method protected abstract String onGetSummary();
+    method public final void onStart(android.content.Intent, int);
+    method public final int onStartCommand(android.content.Intent, int, int);
+    method public static final void refreshSettings(@NonNull android.content.Context);
+    field public static final String ACTION_INJECTED_SETTING_CHANGED = "android.location.InjectedSettingChanged";
+    field public static final String ACTION_SERVICE_INTENT = "android.location.SettingInjectorService";
+    field public static final String ATTRIBUTES_NAME = "injected-location-setting";
+    field public static final String META_DATA_NAME = "android.location.SettingInjectorService";
+  }
+
+}
+
+package android.location.altitude {
+
+  public final class AltitudeConverter {
+    ctor public AltitudeConverter();
+    method @WorkerThread public void addMslAltitudeToLocation(@NonNull android.content.Context, @NonNull android.location.Location) throws java.io.IOException;
+  }
+
+}
+
+package android.location.provider {
+
+  public final class ProviderProperties implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getAccuracy();
+    method public int getPowerUsage();
+    method public boolean hasAltitudeSupport();
+    method public boolean hasBearingSupport();
+    method public boolean hasCellRequirement();
+    method public boolean hasMonetaryCost();
+    method public boolean hasNetworkRequirement();
+    method public boolean hasSatelliteRequirement();
+    method public boolean hasSpeedSupport();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int ACCURACY_COARSE = 2; // 0x2
+    field public static final int ACCURACY_FINE = 1; // 0x1
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.provider.ProviderProperties> CREATOR;
+    field public static final int POWER_USAGE_HIGH = 3; // 0x3
+    field public static final int POWER_USAGE_LOW = 1; // 0x1
+    field public static final int POWER_USAGE_MEDIUM = 2; // 0x2
+  }
+
+  public static final class ProviderProperties.Builder {
+    ctor public ProviderProperties.Builder();
+    ctor public ProviderProperties.Builder(@NonNull android.location.provider.ProviderProperties);
+    method @NonNull public android.location.provider.ProviderProperties build();
+    method @NonNull public android.location.provider.ProviderProperties.Builder setAccuracy(int);
+    method @NonNull public android.location.provider.ProviderProperties.Builder setHasAltitudeSupport(boolean);
+    method @NonNull public android.location.provider.ProviderProperties.Builder setHasBearingSupport(boolean);
+    method @NonNull public android.location.provider.ProviderProperties.Builder setHasCellRequirement(boolean);
+    method @NonNull public android.location.provider.ProviderProperties.Builder setHasMonetaryCost(boolean);
+    method @NonNull public android.location.provider.ProviderProperties.Builder setHasNetworkRequirement(boolean);
+    method @NonNull public android.location.provider.ProviderProperties.Builder setHasSatelliteRequirement(boolean);
+    method @NonNull public android.location.provider.ProviderProperties.Builder setHasSpeedSupport(boolean);
+    method @NonNull public android.location.provider.ProviderProperties.Builder setPowerUsage(int);
+  }
+
+}
+
diff --git a/location/api/module-lib-current.txt b/location/api/module-lib-current.txt
index d802177..8c14b864 100644
--- a/location/api/module-lib-current.txt
+++ b/location/api/module-lib-current.txt
@@ -1 +1,11 @@
 // Signature format: 2.0
+package android.location {
+
+  public class LocationManager {
+    method @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public boolean injectLocation(@NonNull android.location.Location);
+    method @RequiresPermission(android.Manifest.permission.CONTROL_AUTOMOTIVE_GNSS) public boolean isAutomotiveGnssSuspended();
+    method @RequiresPermission(android.Manifest.permission.CONTROL_AUTOMOTIVE_GNSS) public void setAutomotiveGnssSuspended(boolean);
+  }
+
+}
+
diff --git a/location/api/module-lib-lint-baseline.txt b/location/api/module-lib-lint-baseline.txt
new file mode 100644
index 0000000..7cd6a86
--- /dev/null
+++ b/location/api/module-lib-lint-baseline.txt
@@ -0,0 +1,13 @@
+// Baseline format: 1.0
+SamShouldBeLast: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler):
+    SAM-compatible parameters (such as parameter 1, "listener", in android.location.LocationManager.addNmeaListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(String, long, float, android.location.LocationListener, android.os.Looper):
+    SAM-compatible parameters (such as parameter 4, "listener", in android.location.LocationManager.requestLocationUpdates) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(android.location.LocationRequest, android.location.LocationListener, android.os.Looper):
+    SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestLocationUpdates) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(long, float, android.location.Criteria, android.location.LocationListener, android.os.Looper):
+    SAM-compatible parameters (such as parameter 4, "listener", in android.location.LocationManager.requestLocationUpdates) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.location.LocationManager#requestSingleUpdate(String, android.location.LocationListener, android.os.Looper):
+    SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestSingleUpdate) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.location.LocationManager#requestSingleUpdate(android.location.Criteria, android.location.LocationListener, android.os.Looper):
+    SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestSingleUpdate) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
diff --git a/location/api/system-current.txt b/location/api/system-current.txt
index d802177..a1d6ab5 100644
--- a/location/api/system-current.txt
+++ b/location/api/system-current.txt
@@ -1 +1,646 @@
 // Signature format: 2.0
+package android.location {
+
+  public abstract class BatchedLocationCallback {
+    ctor public BatchedLocationCallback();
+    method public void onLocationBatch(java.util.List<android.location.Location>);
+  }
+
+  public final class CorrelationVector implements android.os.Parcelable {
+    method public int describeContents();
+    method @FloatRange(from=0.0f) public double getFrequencyOffsetMetersPerSecond();
+    method @NonNull public int[] getMagnitude();
+    method @FloatRange(from=0.0f) public double getSamplingStartMeters();
+    method @FloatRange(from=0.0f, fromInclusive=false) public double getSamplingWidthMeters();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.CorrelationVector> CREATOR;
+  }
+
+  public static final class CorrelationVector.Builder {
+    ctor public CorrelationVector.Builder();
+    method @NonNull public android.location.CorrelationVector build();
+    method @NonNull public android.location.CorrelationVector.Builder setFrequencyOffsetMetersPerSecond(@FloatRange(from=0.0f) double);
+    method @NonNull public android.location.CorrelationVector.Builder setMagnitude(@NonNull int[]);
+    method @NonNull public android.location.CorrelationVector.Builder setSamplingStartMeters(@FloatRange(from=0.0f) double);
+    method @NonNull public android.location.CorrelationVector.Builder setSamplingWidthMeters(@FloatRange(from=0.0f, fromInclusive=false) double);
+  }
+
+  public final class Country implements android.os.Parcelable {
+    ctor public Country(@NonNull String, int);
+    method public int describeContents();
+    method @NonNull public String getCountryCode();
+    method public int getSource();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int COUNTRY_SOURCE_LOCALE = 3; // 0x3
+    field public static final int COUNTRY_SOURCE_LOCATION = 1; // 0x1
+    field public static final int COUNTRY_SOURCE_NETWORK = 0; // 0x0
+    field public static final int COUNTRY_SOURCE_SIM = 2; // 0x2
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.Country> CREATOR;
+  }
+
+  public class CountryDetector {
+    method public void registerCountryDetectorCallback(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Country>);
+    method public void unregisterCountryDetectorCallback(@NonNull java.util.function.Consumer<android.location.Country>);
+  }
+
+  public final class GnssCapabilities implements android.os.Parcelable {
+    method @Deprecated public boolean hasMeasurementCorrectionsReflectingPane();
+    method @Deprecated public boolean hasNavMessages();
+    method @Deprecated public boolean hasSatelliteBlacklist();
+  }
+
+  public final class GnssExcessPathInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method @FloatRange(from=0.0f) public float getAttenuationDb();
+    method @FloatRange(from=0.0f) public float getExcessPathLengthMeters();
+    method @FloatRange(from=0.0f) public float getExcessPathLengthUncertaintyMeters();
+    method @NonNull public android.location.GnssReflectingPlane getReflectingPlane();
+    method public boolean hasAttenuation();
+    method public boolean hasExcessPathLength();
+    method public boolean hasExcessPathLengthUncertainty();
+    method public boolean hasReflectingPlane();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssExcessPathInfo> CREATOR;
+  }
+
+  public static final class GnssExcessPathInfo.Builder {
+    ctor public GnssExcessPathInfo.Builder();
+    method @NonNull public android.location.GnssExcessPathInfo build();
+    method @NonNull public android.location.GnssExcessPathInfo.Builder clearAttenuationDb();
+    method @NonNull public android.location.GnssExcessPathInfo.Builder clearExcessPathLengthMeters();
+    method @NonNull public android.location.GnssExcessPathInfo.Builder clearExcessPathLengthUncertaintyMeters();
+    method @NonNull public android.location.GnssExcessPathInfo.Builder setAttenuationDb(@FloatRange(from=0.0f) float);
+    method @NonNull public android.location.GnssExcessPathInfo.Builder setExcessPathLengthMeters(@FloatRange(from=0.0f) float);
+    method @NonNull public android.location.GnssExcessPathInfo.Builder setExcessPathLengthUncertaintyMeters(@FloatRange(from=0.0f) float);
+    method @NonNull public android.location.GnssExcessPathInfo.Builder setReflectingPlane(@Nullable android.location.GnssReflectingPlane);
+  }
+
+  public final class GnssMeasurement implements android.os.Parcelable {
+    method @Nullable public java.util.Collection<android.location.CorrelationVector> getCorrelationVectors();
+    method @Nullable public android.location.SatellitePvt getSatellitePvt();
+    method public boolean hasCorrelationVectors();
+    method public boolean hasSatellitePvt();
+  }
+
+  public final class GnssMeasurementCorrections implements android.os.Parcelable {
+    method public int describeContents();
+    method @FloatRange(from=-1000.0F, to=10000.0f) public double getAltitudeMeters();
+    method @FloatRange(from=0.0f, to=360.0f) public float getEnvironmentBearingDegrees();
+    method @FloatRange(from=0.0f, to=180.0f) public float getEnvironmentBearingUncertaintyDegrees();
+    method @FloatRange(from=0.0f) public double getHorizontalPositionUncertaintyMeters();
+    method @FloatRange(from=-90.0F, to=90.0f) public double getLatitudeDegrees();
+    method @FloatRange(from=-180.0F, to=180.0f) public double getLongitudeDegrees();
+    method @NonNull public java.util.List<android.location.GnssSingleSatCorrection> getSingleSatelliteCorrectionList();
+    method @IntRange(from=0) public long getToaGpsNanosecondsOfWeek();
+    method @FloatRange(from=0.0f) public double getVerticalPositionUncertaintyMeters();
+    method public boolean hasEnvironmentBearing();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.location.GnssMeasurementCorrections> CREATOR;
+  }
+
+  public static final class GnssMeasurementCorrections.Builder {
+    ctor public GnssMeasurementCorrections.Builder();
+    method @NonNull public android.location.GnssMeasurementCorrections build();
+    method @NonNull public android.location.GnssMeasurementCorrections.Builder setAltitudeMeters(@FloatRange(from=-1000.0F, to=10000.0f) double);
+    method @NonNull public android.location.GnssMeasurementCorrections.Builder setEnvironmentBearingDegrees(@FloatRange(from=0.0f, to=360.0f) float);
+    method @NonNull public android.location.GnssMeasurementCorrections.Builder setEnvironmentBearingUncertaintyDegrees(@FloatRange(from=0.0f, to=180.0f) float);
+    method @NonNull public android.location.GnssMeasurementCorrections.Builder setHorizontalPositionUncertaintyMeters(@FloatRange(from=0.0f) double);
+    method @NonNull public android.location.GnssMeasurementCorrections.Builder setLatitudeDegrees(@FloatRange(from=-90.0F, to=90.0f) double);
+    method @NonNull public android.location.GnssMeasurementCorrections.Builder setLongitudeDegrees(@FloatRange(from=-180.0F, to=180.0f) double);
+    method @NonNull public android.location.GnssMeasurementCorrections.Builder setSingleSatelliteCorrectionList(@NonNull java.util.List<android.location.GnssSingleSatCorrection>);
+    method @NonNull public android.location.GnssMeasurementCorrections.Builder setToaGpsNanosecondsOfWeek(@IntRange(from=0) long);
+    method @NonNull public android.location.GnssMeasurementCorrections.Builder setVerticalPositionUncertaintyMeters(@FloatRange(from=0.0f) double);
+  }
+
+  public final class GnssMeasurementRequest implements android.os.Parcelable {
+    method @NonNull public android.os.WorkSource getWorkSource();
+    method public boolean isCorrelationVectorOutputsEnabled();
+  }
+
+  public static final class GnssMeasurementRequest.Builder {
+    method @NonNull public android.location.GnssMeasurementRequest.Builder setCorrelationVectorOutputsEnabled(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.GnssMeasurementRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
+  }
+
+  public final class GnssReflectingPlane implements android.os.Parcelable {
+    method public int describeContents();
+    method @FloatRange(from=-1000.0F, to=10000.0f) public double getAltitudeMeters();
+    method @FloatRange(from=0.0f, to=360.0f) public double getAzimuthDegrees();
+    method @FloatRange(from=-90.0F, to=90.0f) public double getLatitudeDegrees();
+    method @FloatRange(from=-180.0F, to=180.0f) public double getLongitudeDegrees();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.location.GnssReflectingPlane> CREATOR;
+  }
+
+  public static final class GnssReflectingPlane.Builder {
+    ctor public GnssReflectingPlane.Builder();
+    method @NonNull public android.location.GnssReflectingPlane build();
+    method @NonNull public android.location.GnssReflectingPlane.Builder setAltitudeMeters(@FloatRange(from=-1000.0F, to=10000.0f) double);
+    method @NonNull public android.location.GnssReflectingPlane.Builder setAzimuthDegrees(@FloatRange(from=0.0f, to=360.0f) double);
+    method @NonNull public android.location.GnssReflectingPlane.Builder setLatitudeDegrees(@FloatRange(from=-90.0F, to=90.0f) double);
+    method @NonNull public android.location.GnssReflectingPlane.Builder setLongitudeDegrees(@FloatRange(from=-180.0F, to=180.0f) double);
+  }
+
+  public final class GnssRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method public boolean isFullTracking();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssRequest> CREATOR;
+  }
+
+  public static final class GnssRequest.Builder {
+    ctor public GnssRequest.Builder();
+    ctor public GnssRequest.Builder(@NonNull android.location.GnssRequest);
+    method @NonNull public android.location.GnssRequest build();
+    method @NonNull public android.location.GnssRequest.Builder setFullTracking(boolean);
+  }
+
+  public final class GnssSingleSatCorrection implements android.os.Parcelable {
+    method public int describeContents();
+    method @FloatRange(from=0.0f, fromInclusive=false) public float getCarrierFrequencyHz();
+    method @FloatRange(from=0.0f) public float getCombinedAttenuationDb();
+    method public int getConstellationType();
+    method @FloatRange(from=0.0f) public float getExcessPathLengthMeters();
+    method @FloatRange(from=0.0f) public float getExcessPathLengthUncertaintyMeters();
+    method @NonNull public java.util.List<android.location.GnssExcessPathInfo> getGnssExcessPathInfoList();
+    method @FloatRange(from=0.0f, to=1.0f) public float getProbabilityLineOfSight();
+    method @Deprecated @Nullable public android.location.GnssReflectingPlane getReflectingPlane();
+    method @IntRange(from=0) public int getSatelliteId();
+    method public boolean hasCombinedAttenuation();
+    method public boolean hasExcessPathLength();
+    method public boolean hasExcessPathLengthUncertainty();
+    method @Deprecated public boolean hasReflectingPlane();
+    method public boolean hasValidSatelliteLineOfSight();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.location.GnssSingleSatCorrection> CREATOR;
+  }
+
+  public static final class GnssSingleSatCorrection.Builder {
+    ctor public GnssSingleSatCorrection.Builder();
+    method @NonNull public android.location.GnssSingleSatCorrection build();
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder clearCombinedAttenuationDb();
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder clearExcessPathLengthMeters();
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder clearExcessPathLengthUncertaintyMeters();
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder clearProbabilityLineOfSight();
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder setCarrierFrequencyHz(@FloatRange(from=0.0f, fromInclusive=false) float);
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder setCombinedAttenuationDb(@FloatRange(from=0.0f) float);
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder setConstellationType(int);
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder setExcessPathLengthMeters(@FloatRange(from=0.0f) float);
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder setExcessPathLengthUncertaintyMeters(@FloatRange(from=0.0f) float);
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder setGnssExcessPathInfoList(@NonNull java.util.List<android.location.GnssExcessPathInfo>);
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder setProbabilityLineOfSight(@FloatRange(from=0.0f, to=1.0f) float);
+    method @Deprecated @NonNull public android.location.GnssSingleSatCorrection.Builder setReflectingPlane(@Nullable android.location.GnssReflectingPlane);
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder setSatelliteId(@IntRange(from=0) int);
+  }
+
+  @Deprecated public class GpsClock implements android.os.Parcelable {
+    method @Deprecated public int describeContents();
+    method @Deprecated public double getBiasInNs();
+    method @Deprecated public double getBiasUncertaintyInNs();
+    method @Deprecated public double getDriftInNsPerSec();
+    method @Deprecated public double getDriftUncertaintyInNsPerSec();
+    method @Deprecated public long getFullBiasInNs();
+    method @Deprecated public short getLeapSecond();
+    method @Deprecated public long getTimeInNs();
+    method @Deprecated public double getTimeUncertaintyInNs();
+    method @Deprecated public byte getType();
+    method @Deprecated public boolean hasBiasInNs();
+    method @Deprecated public boolean hasBiasUncertaintyInNs();
+    method @Deprecated public boolean hasDriftInNsPerSec();
+    method @Deprecated public boolean hasDriftUncertaintyInNsPerSec();
+    method @Deprecated public boolean hasFullBiasInNs();
+    method @Deprecated public boolean hasLeapSecond();
+    method @Deprecated public boolean hasTimeUncertaintyInNs();
+    method @Deprecated public void reset();
+    method @Deprecated public void resetBiasInNs();
+    method @Deprecated public void resetBiasUncertaintyInNs();
+    method @Deprecated public void resetDriftInNsPerSec();
+    method @Deprecated public void resetDriftUncertaintyInNsPerSec();
+    method @Deprecated public void resetFullBiasInNs();
+    method @Deprecated public void resetLeapSecond();
+    method @Deprecated public void resetTimeUncertaintyInNs();
+    method @Deprecated public void set(android.location.GpsClock);
+    method @Deprecated public void setBiasInNs(double);
+    method @Deprecated public void setBiasUncertaintyInNs(double);
+    method @Deprecated public void setDriftInNsPerSec(double);
+    method @Deprecated public void setDriftUncertaintyInNsPerSec(double);
+    method @Deprecated public void setFullBiasInNs(long);
+    method @Deprecated public void setLeapSecond(short);
+    method @Deprecated public void setTimeInNs(long);
+    method @Deprecated public void setTimeUncertaintyInNs(double);
+    method @Deprecated public void setType(byte);
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.GpsClock> CREATOR;
+    field @Deprecated public static final byte TYPE_GPS_TIME = 2; // 0x2
+    field @Deprecated public static final byte TYPE_LOCAL_HW_TIME = 1; // 0x1
+    field @Deprecated public static final byte TYPE_UNKNOWN = 0; // 0x0
+  }
+
+  @Deprecated public class GpsMeasurement implements android.os.Parcelable {
+    method @Deprecated public int describeContents();
+    method @Deprecated public double getAccumulatedDeltaRangeInMeters();
+    method @Deprecated public short getAccumulatedDeltaRangeState();
+    method @Deprecated public double getAccumulatedDeltaRangeUncertaintyInMeters();
+    method @Deprecated public double getAzimuthInDeg();
+    method @Deprecated public double getAzimuthUncertaintyInDeg();
+    method @Deprecated public int getBitNumber();
+    method @Deprecated public long getCarrierCycles();
+    method @Deprecated public float getCarrierFrequencyInHz();
+    method @Deprecated public double getCarrierPhase();
+    method @Deprecated public double getCarrierPhaseUncertainty();
+    method @Deprecated public double getCn0InDbHz();
+    method @Deprecated public double getCodePhaseInChips();
+    method @Deprecated public double getCodePhaseUncertaintyInChips();
+    method @Deprecated public double getDopplerShiftInHz();
+    method @Deprecated public double getDopplerShiftUncertaintyInHz();
+    method @Deprecated public double getElevationInDeg();
+    method @Deprecated public double getElevationUncertaintyInDeg();
+    method @Deprecated public byte getLossOfLock();
+    method @Deprecated public byte getMultipathIndicator();
+    method @Deprecated public byte getPrn();
+    method @Deprecated public double getPseudorangeInMeters();
+    method @Deprecated public double getPseudorangeRateInMetersPerSec();
+    method @Deprecated public double getPseudorangeRateUncertaintyInMetersPerSec();
+    method @Deprecated public double getPseudorangeUncertaintyInMeters();
+    method @Deprecated public long getReceivedGpsTowInNs();
+    method @Deprecated public long getReceivedGpsTowUncertaintyInNs();
+    method @Deprecated public double getSnrInDb();
+    method @Deprecated public short getState();
+    method @Deprecated public short getTimeFromLastBitInMs();
+    method @Deprecated public double getTimeOffsetInNs();
+    method @Deprecated public boolean hasAzimuthInDeg();
+    method @Deprecated public boolean hasAzimuthUncertaintyInDeg();
+    method @Deprecated public boolean hasBitNumber();
+    method @Deprecated public boolean hasCarrierCycles();
+    method @Deprecated public boolean hasCarrierFrequencyInHz();
+    method @Deprecated public boolean hasCarrierPhase();
+    method @Deprecated public boolean hasCarrierPhaseUncertainty();
+    method @Deprecated public boolean hasCodePhaseInChips();
+    method @Deprecated public boolean hasCodePhaseUncertaintyInChips();
+    method @Deprecated public boolean hasDopplerShiftInHz();
+    method @Deprecated public boolean hasDopplerShiftUncertaintyInHz();
+    method @Deprecated public boolean hasElevationInDeg();
+    method @Deprecated public boolean hasElevationUncertaintyInDeg();
+    method @Deprecated public boolean hasPseudorangeInMeters();
+    method @Deprecated public boolean hasPseudorangeUncertaintyInMeters();
+    method @Deprecated public boolean hasSnrInDb();
+    method @Deprecated public boolean hasTimeFromLastBitInMs();
+    method @Deprecated public boolean isPseudorangeRateCorrected();
+    method @Deprecated public boolean isUsedInFix();
+    method @Deprecated public void reset();
+    method @Deprecated public void resetAzimuthInDeg();
+    method @Deprecated public void resetAzimuthUncertaintyInDeg();
+    method @Deprecated public void resetBitNumber();
+    method @Deprecated public void resetCarrierCycles();
+    method @Deprecated public void resetCarrierFrequencyInHz();
+    method @Deprecated public void resetCarrierPhase();
+    method @Deprecated public void resetCarrierPhaseUncertainty();
+    method @Deprecated public void resetCodePhaseInChips();
+    method @Deprecated public void resetCodePhaseUncertaintyInChips();
+    method @Deprecated public void resetDopplerShiftInHz();
+    method @Deprecated public void resetDopplerShiftUncertaintyInHz();
+    method @Deprecated public void resetElevationInDeg();
+    method @Deprecated public void resetElevationUncertaintyInDeg();
+    method @Deprecated public void resetPseudorangeInMeters();
+    method @Deprecated public void resetPseudorangeUncertaintyInMeters();
+    method @Deprecated public void resetSnrInDb();
+    method @Deprecated public void resetTimeFromLastBitInMs();
+    method @Deprecated public void set(android.location.GpsMeasurement);
+    method @Deprecated public void setAccumulatedDeltaRangeInMeters(double);
+    method @Deprecated public void setAccumulatedDeltaRangeState(short);
+    method @Deprecated public void setAccumulatedDeltaRangeUncertaintyInMeters(double);
+    method @Deprecated public void setAzimuthInDeg(double);
+    method @Deprecated public void setAzimuthUncertaintyInDeg(double);
+    method @Deprecated public void setBitNumber(int);
+    method @Deprecated public void setCarrierCycles(long);
+    method @Deprecated public void setCarrierFrequencyInHz(float);
+    method @Deprecated public void setCarrierPhase(double);
+    method @Deprecated public void setCarrierPhaseUncertainty(double);
+    method @Deprecated public void setCn0InDbHz(double);
+    method @Deprecated public void setCodePhaseInChips(double);
+    method @Deprecated public void setCodePhaseUncertaintyInChips(double);
+    method @Deprecated public void setDopplerShiftInHz(double);
+    method @Deprecated public void setDopplerShiftUncertaintyInHz(double);
+    method @Deprecated public void setElevationInDeg(double);
+    method @Deprecated public void setElevationUncertaintyInDeg(double);
+    method @Deprecated public void setLossOfLock(byte);
+    method @Deprecated public void setMultipathIndicator(byte);
+    method @Deprecated public void setPrn(byte);
+    method @Deprecated public void setPseudorangeInMeters(double);
+    method @Deprecated public void setPseudorangeRateInMetersPerSec(double);
+    method @Deprecated public void setPseudorangeRateUncertaintyInMetersPerSec(double);
+    method @Deprecated public void setPseudorangeUncertaintyInMeters(double);
+    method @Deprecated public void setReceivedGpsTowInNs(long);
+    method @Deprecated public void setReceivedGpsTowUncertaintyInNs(long);
+    method @Deprecated public void setSnrInDb(double);
+    method @Deprecated public void setState(short);
+    method @Deprecated public void setTimeFromLastBitInMs(short);
+    method @Deprecated public void setTimeOffsetInNs(double);
+    method @Deprecated public void setUsedInFix(boolean);
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated public static final short ADR_STATE_CYCLE_SLIP = 4; // 0x4
+    field @Deprecated public static final short ADR_STATE_RESET = 2; // 0x2
+    field @Deprecated public static final short ADR_STATE_UNKNOWN = 0; // 0x0
+    field @Deprecated public static final short ADR_STATE_VALID = 1; // 0x1
+    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.GpsMeasurement> CREATOR;
+    field @Deprecated public static final byte LOSS_OF_LOCK_CYCLE_SLIP = 2; // 0x2
+    field @Deprecated public static final byte LOSS_OF_LOCK_OK = 1; // 0x1
+    field @Deprecated public static final byte LOSS_OF_LOCK_UNKNOWN = 0; // 0x0
+    field @Deprecated public static final byte MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
+    field @Deprecated public static final byte MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
+    field @Deprecated public static final byte MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
+    field @Deprecated public static final short STATE_BIT_SYNC = 2; // 0x2
+    field @Deprecated public static final short STATE_CODE_LOCK = 1; // 0x1
+    field @Deprecated public static final short STATE_MSEC_AMBIGUOUS = 16; // 0x10
+    field @Deprecated public static final short STATE_SUBFRAME_SYNC = 4; // 0x4
+    field @Deprecated public static final short STATE_TOW_DECODED = 8; // 0x8
+    field @Deprecated public static final short STATE_UNKNOWN = 0; // 0x0
+  }
+
+  @Deprecated public class GpsMeasurementsEvent implements android.os.Parcelable {
+    ctor @Deprecated public GpsMeasurementsEvent(android.location.GpsClock, android.location.GpsMeasurement[]);
+    method @Deprecated public int describeContents();
+    method @Deprecated @NonNull public android.location.GpsClock getClock();
+    method @Deprecated @NonNull public java.util.Collection<android.location.GpsMeasurement> getMeasurements();
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.GpsMeasurementsEvent> CREATOR;
+    field @Deprecated public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+    field @Deprecated public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
+    field @Deprecated public static final int STATUS_READY = 1; // 0x1
+  }
+
+  @Deprecated public static interface GpsMeasurementsEvent.Listener {
+    method @Deprecated public void onGpsMeasurementsReceived(android.location.GpsMeasurementsEvent);
+    method @Deprecated public void onStatusChanged(int);
+  }
+
+  @Deprecated public class GpsNavigationMessage implements android.os.Parcelable {
+    method @Deprecated public int describeContents();
+    method @Deprecated @NonNull public byte[] getData();
+    method @Deprecated public short getMessageId();
+    method @Deprecated public byte getPrn();
+    method @Deprecated public short getStatus();
+    method @Deprecated public short getSubmessageId();
+    method @Deprecated public byte getType();
+    method @Deprecated public void reset();
+    method @Deprecated public void set(android.location.GpsNavigationMessage);
+    method @Deprecated public void setData(byte[]);
+    method @Deprecated public void setMessageId(short);
+    method @Deprecated public void setPrn(byte);
+    method @Deprecated public void setStatus(short);
+    method @Deprecated public void setSubmessageId(short);
+    method @Deprecated public void setType(byte);
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessage> CREATOR;
+    field @Deprecated public static final short STATUS_PARITY_PASSED = 1; // 0x1
+    field @Deprecated public static final short STATUS_PARITY_REBUILT = 2; // 0x2
+    field @Deprecated public static final short STATUS_UNKNOWN = 0; // 0x0
+    field @Deprecated public static final byte TYPE_CNAV2 = 4; // 0x4
+    field @Deprecated public static final byte TYPE_L1CA = 1; // 0x1
+    field @Deprecated public static final byte TYPE_L2CNAV = 2; // 0x2
+    field @Deprecated public static final byte TYPE_L5CNAV = 3; // 0x3
+    field @Deprecated public static final byte TYPE_UNKNOWN = 0; // 0x0
+  }
+
+  @Deprecated public class GpsNavigationMessageEvent implements android.os.Parcelable {
+    ctor @Deprecated public GpsNavigationMessageEvent(android.location.GpsNavigationMessage);
+    method @Deprecated public int describeContents();
+    method @Deprecated @NonNull public android.location.GpsNavigationMessage getNavigationMessage();
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessageEvent> CREATOR;
+    field @Deprecated public static int STATUS_GPS_LOCATION_DISABLED;
+    field @Deprecated public static int STATUS_NOT_SUPPORTED;
+    field @Deprecated public static int STATUS_READY;
+  }
+
+  @Deprecated public static interface GpsNavigationMessageEvent.Listener {
+    method @Deprecated public void onGpsNavigationMessageReceived(android.location.GpsNavigationMessageEvent);
+    method @Deprecated public void onStatusChanged(int);
+  }
+
+  public final class LastLocationRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method public boolean isAdasGnssBypass();
+    method public boolean isHiddenFromAppOps();
+    method public boolean isLocationSettingsIgnored();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.LastLocationRequest> CREATOR;
+  }
+
+  public static final class LastLocationRequest.Builder {
+    ctor public LastLocationRequest.Builder();
+    ctor public LastLocationRequest.Builder(@NonNull android.location.LastLocationRequest);
+    method @NonNull public android.location.LastLocationRequest build();
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LastLocationRequest.Builder setAdasGnssBypass(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS) public android.location.LastLocationRequest.Builder setHiddenFromAppOps(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LastLocationRequest.Builder setLocationSettingsIgnored(boolean);
+  }
+
+  public class LocationManager {
+    method @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.INTERACT_ACROSS_USERS}) public void addProviderRequestChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.provider.ProviderRequest.ChangedListener);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void flushGnssBatch();
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
+    method @Nullable public String getExtraLocationControllerPackage();
+    method @Deprecated public int getGnssBatchSize();
+    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public android.location.Location getLastKnownLocation(@NonNull String, @NonNull android.location.LastLocationRequest);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void injectGnssMeasurementCorrections(@NonNull android.location.GnssMeasurementCorrections);
+    method public boolean isAdasGnssLocationEnabled();
+    method public boolean isExtraLocationControllerPackageEnabled();
+    method public boolean isLocationEnabledForUser(@NonNull android.os.UserHandle);
+    method public boolean isProviderEnabledForUser(@NonNull String, @NonNull android.os.UserHandle);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@NonNull String);
+    method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String, @Nullable String);
+    method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.UPDATE_APP_OPS_STATS}) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void removeProviderRequestChangedListener(@NonNull android.location.provider.ProviderRequest.ChangedListener);
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public void setAdasGnssLocationEnabled(boolean);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackage(@Nullable String);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackageEnabled(boolean);
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean setProviderEnabledForUser(@NonNull String, boolean, @NonNull android.os.UserHandle);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean unregisterGnssBatchedLocationCallback(@NonNull android.location.BatchedLocationCallback);
+    field public static final String ACTION_ADAS_GNSS_ENABLED_CHANGED = "android.location.action.ADAS_GNSS_ENABLED_CHANGED";
+    field public static final String EXTRA_ADAS_GNSS_ENABLED = "android.location.extra.ADAS_GNSS_ENABLED";
+    field @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public static final String GPS_HARDWARE_PROVIDER = "gps_hardware";
+  }
+
+  public final class LocationRequest implements android.os.Parcelable {
+    method @Deprecated @NonNull public static android.location.LocationRequest create();
+    method @Deprecated @NonNull public static android.location.LocationRequest createFromDeprecatedCriteria(@NonNull android.location.Criteria, long, float, boolean);
+    method @Deprecated @NonNull public static android.location.LocationRequest createFromDeprecatedProvider(@NonNull String, long, float, boolean);
+    method @Deprecated public long getExpireAt();
+    method @Deprecated public long getExpireIn();
+    method @Deprecated public long getFastestInterval();
+    method @Deprecated public boolean getHideFromAppOps();
+    method @Deprecated public long getInterval();
+    method @Deprecated public int getNumUpdates();
+    method @Deprecated @NonNull public String getProvider();
+    method @Deprecated public float getSmallestDisplacement();
+    method @NonNull public android.os.WorkSource getWorkSource();
+    method public boolean isAdasGnssBypass();
+    method public boolean isHiddenFromAppOps();
+    method public boolean isLocationSettingsIgnored();
+    method public boolean isLowPower();
+    method @Deprecated public boolean isLowPowerMode();
+    method @Deprecated @NonNull public android.location.LocationRequest setExpireAt(long);
+    method @Deprecated @NonNull public android.location.LocationRequest setExpireIn(long);
+    method @Deprecated @NonNull public android.location.LocationRequest setFastestInterval(long);
+    method @Deprecated public void setHideFromAppOps(boolean);
+    method @Deprecated @NonNull public android.location.LocationRequest setInterval(long);
+    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LocationRequest setLocationSettingsIgnored(boolean);
+    method @Deprecated @NonNull public android.location.LocationRequest setLowPowerMode(boolean);
+    method @Deprecated @NonNull public android.location.LocationRequest setNumUpdates(int);
+    method @Deprecated @NonNull public android.location.LocationRequest setProvider(@NonNull String);
+    method @Deprecated @NonNull public android.location.LocationRequest setQuality(int);
+    method @Deprecated @NonNull public android.location.LocationRequest setSmallestDisplacement(float);
+    method @Deprecated public void setWorkSource(@Nullable android.os.WorkSource);
+    field @Deprecated public static final int ACCURACY_BLOCK = 102; // 0x66
+    field @Deprecated public static final int ACCURACY_CITY = 104; // 0x68
+    field @Deprecated public static final int ACCURACY_FINE = 100; // 0x64
+    field @Deprecated public static final int POWER_HIGH = 203; // 0xcb
+    field @Deprecated public static final int POWER_LOW = 201; // 0xc9
+    field @Deprecated public static final int POWER_NONE = 200; // 0xc8
+  }
+
+  public static final class LocationRequest.Builder {
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LocationRequest.Builder setAdasGnssBypass(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS) public android.location.LocationRequest.Builder setHiddenFromAppOps(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LocationRequest.Builder setLocationSettingsIgnored(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.location.LocationRequest.Builder setLowPower(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.LocationRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
+  }
+
+  public final class SatellitePvt implements android.os.Parcelable {
+    method public int describeContents();
+    method @Nullable public android.location.SatellitePvt.ClockInfo getClockInfo();
+    method public int getEphemerisSource();
+    method @FloatRange public double getIonoDelayMeters();
+    method @IntRange(from=0, to=1023) public int getIssueOfDataClock();
+    method @IntRange(from=0, to=1023) public int getIssueOfDataEphemeris();
+    method @Nullable public android.location.SatellitePvt.PositionEcef getPositionEcef();
+    method @IntRange(from=0) public long getTimeOfClockSeconds();
+    method @IntRange(from=0) public long getTimeOfEphemerisSeconds();
+    method @FloatRange public double getTropoDelayMeters();
+    method @Nullable public android.location.SatellitePvt.VelocityEcef getVelocityEcef();
+    method public boolean hasIono();
+    method public boolean hasIssueOfDataClock();
+    method public boolean hasIssueOfDataEphemeris();
+    method public boolean hasPositionVelocityClockInfo();
+    method public boolean hasTimeOfClockSeconds();
+    method public boolean hasTimeOfEphemerisSeconds();
+    method public boolean hasTropo();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.SatellitePvt> CREATOR;
+    field public static final int EPHEMERIS_SOURCE_DEMODULATED = 0; // 0x0
+    field public static final int EPHEMERIS_SOURCE_OTHER = 3; // 0x3
+    field public static final int EPHEMERIS_SOURCE_SERVER_LONG_TERM = 2; // 0x2
+    field public static final int EPHEMERIS_SOURCE_SERVER_NORMAL = 1; // 0x1
+  }
+
+  public static final class SatellitePvt.Builder {
+    ctor public SatellitePvt.Builder();
+    method @NonNull public android.location.SatellitePvt build();
+    method @NonNull public android.location.SatellitePvt.Builder setClockInfo(@NonNull android.location.SatellitePvt.ClockInfo);
+    method @NonNull public android.location.SatellitePvt.Builder setEphemerisSource(int);
+    method @NonNull public android.location.SatellitePvt.Builder setIonoDelayMeters(@FloatRange(from=0.0f, to=100.0f) double);
+    method @NonNull public android.location.SatellitePvt.Builder setIssueOfDataClock(@IntRange(from=0, to=1023) int);
+    method @NonNull public android.location.SatellitePvt.Builder setIssueOfDataEphemeris(@IntRange(from=0, to=1023) int);
+    method @NonNull public android.location.SatellitePvt.Builder setPositionEcef(@NonNull android.location.SatellitePvt.PositionEcef);
+    method @NonNull public android.location.SatellitePvt.Builder setTimeOfClockSeconds(@IntRange(from=0) long);
+    method @NonNull public android.location.SatellitePvt.Builder setTimeOfEphemerisSeconds(@IntRange(from=0) long);
+    method @NonNull public android.location.SatellitePvt.Builder setTropoDelayMeters(@FloatRange(from=0.0f, to=100.0f) double);
+    method @NonNull public android.location.SatellitePvt.Builder setVelocityEcef(@NonNull android.location.SatellitePvt.VelocityEcef);
+  }
+
+  public static final class SatellitePvt.ClockInfo implements android.os.Parcelable {
+    ctor public SatellitePvt.ClockInfo(double, double, double);
+    method public int describeContents();
+    method @FloatRange public double getClockDriftMetersPerSecond();
+    method @FloatRange public double getHardwareCodeBiasMeters();
+    method @FloatRange public double getTimeCorrectionMeters();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.SatellitePvt.ClockInfo> CREATOR;
+  }
+
+  public static final class SatellitePvt.PositionEcef implements android.os.Parcelable {
+    ctor public SatellitePvt.PositionEcef(double, double, double, double);
+    method public int describeContents();
+    method @FloatRange(from=0.0f, fromInclusive=false) public double getUreMeters();
+    method @FloatRange public double getXMeters();
+    method @FloatRange public double getYMeters();
+    method @FloatRange public double getZMeters();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.SatellitePvt.PositionEcef> CREATOR;
+  }
+
+  public static final class SatellitePvt.VelocityEcef implements android.os.Parcelable {
+    ctor public SatellitePvt.VelocityEcef(double, double, double, double);
+    method public int describeContents();
+    method @FloatRange(from=0.0f, fromInclusive=false) public double getUreRateMetersPerSecond();
+    method @FloatRange public double getXMetersPerSecond();
+    method @FloatRange public double getYMetersPerSecond();
+    method @FloatRange public double getZMetersPerSecond();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.SatellitePvt.VelocityEcef> CREATOR;
+  }
+
+}
+
+package android.location.provider {
+
+  public abstract class LocationProviderBase {
+    ctor public LocationProviderBase(@NonNull android.content.Context, @NonNull String, @NonNull android.location.provider.ProviderProperties);
+    method @Nullable public final android.os.IBinder getBinder();
+    method @NonNull public android.location.provider.ProviderProperties getProperties();
+    method public boolean isAllowed();
+    method public abstract void onFlush(@NonNull android.location.provider.LocationProviderBase.OnFlushCompleteCallback);
+    method public abstract void onSendExtraCommand(@NonNull String, @Nullable android.os.Bundle);
+    method public abstract void onSetRequest(@NonNull android.location.provider.ProviderRequest);
+    method public void reportLocation(@NonNull android.location.Location);
+    method public void reportLocations(@NonNull java.util.List<android.location.Location>);
+    method public void setAllowed(boolean);
+    method public void setProperties(@NonNull android.location.provider.ProviderProperties);
+    field public static final String ACTION_FUSED_PROVIDER = "com.android.location.service.FusedLocationProvider";
+    field public static final String ACTION_GNSS_PROVIDER = "android.location.provider.action.GNSS_PROVIDER";
+    field public static final String ACTION_NETWORK_PROVIDER = "com.android.location.service.v3.NetworkLocationProvider";
+  }
+
+  public static interface LocationProviderBase.OnFlushCompleteCallback {
+    method public void onFlushComplete();
+  }
+
+  public final class ProviderRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method @IntRange(from=0) public long getIntervalMillis();
+    method @IntRange(from=0) public long getMaxUpdateDelayMillis();
+    method public int getQuality();
+    method @NonNull public android.os.WorkSource getWorkSource();
+    method public boolean isActive();
+    method public boolean isLocationSettingsIgnored();
+    method public boolean isLowPower();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.provider.ProviderRequest> CREATOR;
+    field @NonNull public static final android.location.provider.ProviderRequest EMPTY_REQUEST;
+    field public static final long INTERVAL_DISABLED = 9223372036854775807L; // 0x7fffffffffffffffL
+  }
+
+  public static final class ProviderRequest.Builder {
+    ctor public ProviderRequest.Builder();
+    method @NonNull public android.location.provider.ProviderRequest build();
+    method @NonNull public android.location.provider.ProviderRequest.Builder setIntervalMillis(@IntRange(from=0) long);
+    method @NonNull public android.location.provider.ProviderRequest.Builder setLocationSettingsIgnored(boolean);
+    method @NonNull public android.location.provider.ProviderRequest.Builder setLowPower(boolean);
+    method @NonNull public android.location.provider.ProviderRequest.Builder setMaxUpdateDelayMillis(@IntRange(from=0) long);
+    method @NonNull public android.location.provider.ProviderRequest.Builder setQuality(int);
+    method @NonNull public android.location.provider.ProviderRequest.Builder setWorkSource(@NonNull android.os.WorkSource);
+  }
+
+  public static interface ProviderRequest.ChangedListener {
+    method public void onProviderRequestChanged(@NonNull String, @NonNull android.location.provider.ProviderRequest);
+  }
+
+}
+
diff --git a/location/api/system-lint-baseline.txt b/location/api/system-lint-baseline.txt
new file mode 100644
index 0000000..a5e5752
--- /dev/null
+++ b/location/api/system-lint-baseline.txt
@@ -0,0 +1,11 @@
+// Baseline format: 1.0
+SamShouldBeLast: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler):
+    SAM-compatible parameters (such as parameter 1, "listener", in android.location.LocationManager.addNmeaListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(String, long, float, android.location.LocationListener, android.os.Looper):
+    SAM-compatible parameters (such as parameter 4, "listener", in android.location.LocationManager.requestLocationUpdates) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(long, float, android.location.Criteria, android.location.LocationListener, android.os.Looper):
+    SAM-compatible parameters (such as parameter 4, "listener", in android.location.LocationManager.requestLocationUpdates) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.location.LocationManager#requestSingleUpdate(String, android.location.LocationListener, android.os.Looper):
+    SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestSingleUpdate) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.location.LocationManager#requestSingleUpdate(android.location.Criteria, android.location.LocationListener, android.os.Looper):
+    SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestSingleUpdate) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
diff --git a/location/api/system-removed.txt b/location/api/system-removed.txt
index d802177..2755a9f 100644
--- a/location/api/system-removed.txt
+++ b/location/api/system-removed.txt
@@ -1 +1,15 @@
 // Signature format: 2.0
+package android.location {
+
+  public class LocationManager {
+    method @Deprecated public boolean addGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener);
+    method @Deprecated public boolean addGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String);
+    method @Deprecated public void removeGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener);
+    method @Deprecated public void removeGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setLocationControllerExtraPackage(String);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setLocationControllerExtraPackageEnabled(boolean);
+  }
+
+}
+
diff --git a/location/api/test-current.txt b/location/api/test-current.txt
index d802177..bdcb00a 100644
--- a/location/api/test-current.txt
+++ b/location/api/test-current.txt
@@ -1 +1,104 @@
 // Signature format: 2.0
+package android.location {
+
+  public final class GnssClock implements android.os.Parcelable {
+    ctor public GnssClock();
+    method public void reset();
+    method public void resetBiasNanos();
+    method public void resetBiasUncertaintyNanos();
+    method public void resetDriftNanosPerSecond();
+    method public void resetDriftUncertaintyNanosPerSecond();
+    method public void resetElapsedRealtimeNanos();
+    method public void resetElapsedRealtimeUncertaintyNanos();
+    method public void resetFullBiasNanos();
+    method public void resetLeapSecond();
+    method public void resetReferenceCarrierFrequencyHzForIsb();
+    method public void resetReferenceCodeTypeForIsb();
+    method public void resetReferenceConstellationTypeForIsb();
+    method public void resetTimeUncertaintyNanos();
+    method public void set(android.location.GnssClock);
+    method public void setBiasNanos(double);
+    method public void setBiasUncertaintyNanos(@FloatRange(from=0.0f) double);
+    method public void setDriftNanosPerSecond(double);
+    method public void setDriftUncertaintyNanosPerSecond(@FloatRange(from=0.0f) double);
+    method public void setElapsedRealtimeNanos(long);
+    method public void setElapsedRealtimeUncertaintyNanos(@FloatRange(from=0.0f) double);
+    method public void setFullBiasNanos(long);
+    method public void setHardwareClockDiscontinuityCount(int);
+    method public void setLeapSecond(int);
+    method public void setReferenceCarrierFrequencyHzForIsb(@FloatRange(from=0.0) double);
+    method public void setReferenceCodeTypeForIsb(@NonNull String);
+    method public void setReferenceConstellationTypeForIsb(int);
+    method public void setTimeNanos(long);
+    method public void setTimeUncertaintyNanos(@FloatRange(from=0.0f) double);
+  }
+
+  public final class GnssMeasurement implements android.os.Parcelable {
+    ctor public GnssMeasurement();
+    method public void reset();
+    method public void resetAutomaticGainControlLevel();
+    method public void resetBasebandCn0DbHz();
+    method @Deprecated public void resetCarrierCycles();
+    method public void resetCarrierFrequencyHz();
+    method @Deprecated public void resetCarrierPhase();
+    method @Deprecated public void resetCarrierPhaseUncertainty();
+    method public void resetCodeType();
+    method public void resetCorrelationVectors();
+    method public void resetFullInterSignalBiasNanos();
+    method public void resetFullInterSignalBiasUncertaintyNanos();
+    method public void resetSatelliteInterSignalBiasNanos();
+    method public void resetSatelliteInterSignalBiasUncertaintyNanos();
+    method public void resetSatellitePvt();
+    method public void resetSnrInDb();
+    method public void set(android.location.GnssMeasurement);
+    method public void setAccumulatedDeltaRangeMeters(double);
+    method public void setAccumulatedDeltaRangeState(int);
+    method public void setAccumulatedDeltaRangeUncertaintyMeters(double);
+    method @Deprecated public void setAutomaticGainControlLevelInDb(double);
+    method public void setBasebandCn0DbHz(double);
+    method @Deprecated public void setCarrierCycles(long);
+    method public void setCarrierFrequencyHz(float);
+    method @Deprecated public void setCarrierPhase(double);
+    method @Deprecated public void setCarrierPhaseUncertainty(double);
+    method public void setCn0DbHz(double);
+    method public void setCodeType(@NonNull String);
+    method public void setConstellationType(int);
+    method public void setCorrelationVectors(@Nullable java.util.Collection<android.location.CorrelationVector>);
+    method public void setFullInterSignalBiasNanos(double);
+    method public void setFullInterSignalBiasUncertaintyNanos(@FloatRange(from=0.0) double);
+    method public void setMultipathIndicator(int);
+    method public void setPseudorangeRateMetersPerSecond(double);
+    method public void setPseudorangeRateUncertaintyMetersPerSecond(double);
+    method public void setReceivedSvTimeNanos(long);
+    method public void setReceivedSvTimeUncertaintyNanos(long);
+    method public void setSatelliteInterSignalBiasNanos(double);
+    method public void setSatelliteInterSignalBiasUncertaintyNanos(@FloatRange(from=0.0) double);
+    method public void setSatellitePvt(@Nullable android.location.SatellitePvt);
+    method public void setSnrInDb(double);
+    method public void setState(int);
+    method public void setSvid(int);
+    method public void setTimeOffsetNanos(double);
+    field public static final int ADR_STATE_ALL = 31; // 0x1f
+  }
+
+  public final class GnssNavigationMessage implements android.os.Parcelable {
+    ctor public GnssNavigationMessage();
+    method public void reset();
+    method public void set(android.location.GnssNavigationMessage);
+    method public void setData(byte[]);
+    method public void setMessageId(@IntRange(from=0xffffffff, to=120) int);
+    method public void setStatus(int);
+    method public void setSubmessageId(@IntRange(from=1) int);
+    method public void setSvid(@IntRange(from=1, to=200) int);
+    method public void setType(int);
+  }
+
+  public class LocationManager {
+    method @NonNull public String[] getBackgroundThrottlingWhitelist();
+    method @NonNull public android.os.PackageTagsList getIgnoreSettingsAllowlist();
+    method @Deprecated @NonNull public String[] getIgnoreSettingsWhitelist();
+    method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public java.util.List<java.lang.String> getProviderPackages(@NonNull String);
+  }
+
+}
+
diff --git a/location/api/test-lint-baseline.txt b/location/api/test-lint-baseline.txt
new file mode 100644
index 0000000..189588e
--- /dev/null
+++ b/location/api/test-lint-baseline.txt
@@ -0,0 +1,54 @@
+// Baseline format: 1.0
+GetterSetterNames: android.location.GnssClock#setBiasNanos(double):
+    Symmetric method for `hasBiasNanos` must be named `setHasBiasNanos`; was `setBiasNanos`
+GetterSetterNames: android.location.GnssClock#setBiasUncertaintyNanos(double):
+    Symmetric method for `hasBiasUncertaintyNanos` must be named `setHasBiasUncertaintyNanos`; was `setBiasUncertaintyNanos`
+GetterSetterNames: android.location.GnssClock#setDriftNanosPerSecond(double):
+    Symmetric method for `hasDriftNanosPerSecond` must be named `setHasDriftNanosPerSecond`; was `setDriftNanosPerSecond`
+GetterSetterNames: android.location.GnssClock#setDriftUncertaintyNanosPerSecond(double):
+    Symmetric method for `hasDriftUncertaintyNanosPerSecond` must be named `setHasDriftUncertaintyNanosPerSecond`; was `setDriftUncertaintyNanosPerSecond`
+GetterSetterNames: android.location.GnssClock#setElapsedRealtimeNanos(long):
+    Symmetric method for `hasElapsedRealtimeNanos` must be named `setHasElapsedRealtimeNanos`; was `setElapsedRealtimeNanos`
+GetterSetterNames: android.location.GnssClock#setElapsedRealtimeUncertaintyNanos(double):
+    Symmetric method for `hasElapsedRealtimeUncertaintyNanos` must be named `setHasElapsedRealtimeUncertaintyNanos`; was `setElapsedRealtimeUncertaintyNanos`
+GetterSetterNames: android.location.GnssClock#setFullBiasNanos(long):
+    Symmetric method for `hasFullBiasNanos` must be named `setHasFullBiasNanos`; was `setFullBiasNanos`
+GetterSetterNames: android.location.GnssClock#setLeapSecond(int):
+    Symmetric method for `hasLeapSecond` must be named `setHasLeapSecond`; was `setLeapSecond`
+GetterSetterNames: android.location.GnssClock#setReferenceCarrierFrequencyHzForIsb(double):
+    Symmetric method for `hasReferenceCarrierFrequencyHzForIsb` must be named `setHasReferenceCarrierFrequencyHzForIsb`; was `setReferenceCarrierFrequencyHzForIsb`
+GetterSetterNames: android.location.GnssClock#setReferenceCodeTypeForIsb(String):
+    Symmetric method for `hasReferenceCodeTypeForIsb` must be named `setHasReferenceCodeTypeForIsb`; was `setReferenceCodeTypeForIsb`
+GetterSetterNames: android.location.GnssClock#setReferenceConstellationTypeForIsb(int):
+    Symmetric method for `hasReferenceConstellationTypeForIsb` must be named `setHasReferenceConstellationTypeForIsb`; was `setReferenceConstellationTypeForIsb`
+GetterSetterNames: android.location.GnssClock#setTimeUncertaintyNanos(double):
+    Symmetric method for `hasTimeUncertaintyNanos` must be named `setHasTimeUncertaintyNanos`; was `setTimeUncertaintyNanos`
+GetterSetterNames: android.location.GnssMeasurement#setBasebandCn0DbHz(double):
+    Symmetric method for `hasBasebandCn0DbHz` must be named `setHasBasebandCn0DbHz`; was `setBasebandCn0DbHz`
+GetterSetterNames: android.location.GnssMeasurement#setCarrierFrequencyHz(float):
+    Symmetric method for `hasCarrierFrequencyHz` must be named `setHasCarrierFrequencyHz`; was `setCarrierFrequencyHz`
+GetterSetterNames: android.location.GnssMeasurement#setCodeType(String):
+    Symmetric method for `hasCodeType` must be named `setHasCodeType`; was `setCodeType`
+GetterSetterNames: android.location.GnssMeasurement#setCorrelationVectors(java.util.Collection<android.location.CorrelationVector>):
+    Symmetric method for `hasCorrelationVectors` must be named `setHasCorrelationVectors`; was `setCorrelationVectors`
+GetterSetterNames: android.location.GnssMeasurement#setFullInterSignalBiasNanos(double):
+    Symmetric method for `hasFullInterSignalBiasNanos` must be named `setHasFullInterSignalBiasNanos`; was `setFullInterSignalBiasNanos`
+GetterSetterNames: android.location.GnssMeasurement#setFullInterSignalBiasUncertaintyNanos(double):
+    Symmetric method for `hasFullInterSignalBiasUncertaintyNanos` must be named `setHasFullInterSignalBiasUncertaintyNanos`; was `setFullInterSignalBiasUncertaintyNanos`
+GetterSetterNames: android.location.GnssMeasurement#setSatelliteInterSignalBiasNanos(double):
+    Symmetric method for `hasSatelliteInterSignalBiasNanos` must be named `setHasSatelliteInterSignalBiasNanos`; was `setSatelliteInterSignalBiasNanos`
+GetterSetterNames: android.location.GnssMeasurement#setSatelliteInterSignalBiasUncertaintyNanos(double):
+    Symmetric method for `hasSatelliteInterSignalBiasUncertaintyNanos` must be named `setHasSatelliteInterSignalBiasUncertaintyNanos`; was `setSatelliteInterSignalBiasUncertaintyNanos`
+GetterSetterNames: android.location.GnssMeasurement#setSatellitePvt(android.location.SatellitePvt):
+    Symmetric method for `hasSatellitePvt` must be named `setHasSatellitePvt`; was `setSatellitePvt`
+GetterSetterNames: android.location.GnssMeasurement#setSnrInDb(double):
+    Symmetric method for `hasSnrInDb` must be named `setHasSnrInDb`; was `setSnrInDb`
+
+MissingNullability: android.location.GnssClock#set(android.location.GnssClock) parameter #0:
+    Missing nullability on parameter `clock` in method `set`
+MissingNullability: android.location.GnssMeasurement#set(android.location.GnssMeasurement) parameter #0:
+    Missing nullability on parameter `measurement` in method `set`
+MissingNullability: android.location.GnssNavigationMessage#set(android.location.GnssNavigationMessage) parameter #0:
+    Missing nullability on parameter `navigationMessage` in method `set`
+MissingNullability: android.location.GnssNavigationMessage#setData(byte[]) parameter #0:
+    Missing nullability on parameter `value` in method `setData`
diff --git a/location/java/Android.bp b/location/java/Android.bp
deleted file mode 100644
index 543f2b1..0000000
--- a/location/java/Android.bp
+++ /dev/null
@@ -1,17 +0,0 @@
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "frameworks_base_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["frameworks_base_license"],
-}
-
-filegroup {
-    name: "framework-location-sources",
-    srcs: [
-        "**/*.java",
-        "**/*.aidl",
-    ],
-    visibility: ["//frameworks/base"],
-}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index e2f4072..842542f 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -4945,7 +4945,9 @@
             synchronized (this) {
                 while (!mQuit) {
                     final long timeToWait = timeOutTime - java.lang.System.currentTimeMillis();
-                    if (timeToWait < 0) { break; }
+                    if (timeToWait <= 0) {
+                        break;
+                    }
                     this.wait(timeToWait);
                 }
             }
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index c4f2159..12db8c0 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -30,6 +30,7 @@
 import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.UserInfo;
 import android.content.res.AssetFileDescriptor;
@@ -120,6 +121,53 @@
     public static final String ACTION_RINGTONE_PICKER = "android.intent.action.RINGTONE_PICKER";
 
     /**
+     * Given to the ringtone picker as a string that represents the category of ringtone picker that
+     * should be used. This value should also be returned once a ringtone is selected.
+     * <p>
+     * The categories are:
+     * <li>{@link #CATEGORY_RINGTONE_PICKER_SOUND}
+     * <li>{@link #CATEGORY_RINGTONE_PICKER_VIBRATION}
+     * <li>{@link #CATEGORY_RINGTONE_PICKER_RINGTONE}
+     * <li>{@link Intent#CATEGORY_DEFAULT}
+     *
+     * <p> If the category is {@link Intent#CATEGORY_DEFAULT} or absent, then the picker will
+     * default to a sound-only ringtone picker.
+     *
+     * <p> If the selected category was not supported, then the returned category will be null.
+     *
+     * @hide
+     */
+    public static final String EXTRA_RINGTONE_PICKER_CATEGORY =
+            "android.intent.extra.ringtone.RINGTONE_PICKER_CATEGORY";
+
+    /**
+     * A sound-only ringtone picker.
+     *
+     * @hide
+     * @see #EXTRA_RINGTONE_PICKER_CATEGORY
+     */
+    public static final String CATEGORY_RINGTONE_PICKER_SOUND =
+            "android.net.category.RINGTONE_PICKER_SOUND";
+
+    /**
+     * A vibration-only ringtone picker.
+     *
+     * @hide
+     * @see #EXTRA_RINGTONE_PICKER_CATEGORY
+     */
+    public static final String CATEGORY_RINGTONE_PICKER_VIBRATION =
+            "android.net.category.RINGTONE_PICKER_VIBRATION";
+
+    /**
+     * A combined sound and vibration ringtone picker.
+     *
+     * @hide
+     * @see #EXTRA_RINGTONE_PICKER_CATEGORY
+     */
+    public static final String CATEGORY_RINGTONE_PICKER_RINGTONE =
+            "android.net.category.RINGTONE_PICKER_RINGTONE";
+
+    /**
      * Given to the ringtone picker as a boolean. Whether to show an item for
      * "Default".
      * 
@@ -160,6 +208,18 @@
      */
     public static final String EXTRA_RINGTONE_EXISTING_URI =
             "android.intent.extra.ringtone.EXISTING_URI";
+
+    /**
+     * Similar to #EXTRA_RINGTONE_EXISTING_URI but the {@link Uri} can include both sound and
+     * vibration.
+     * <p>This can include silent sound/vibration explicitly by setting that part of the URI to
+     * null.
+     *
+     * @hide
+     * @see #ACTION_RINGTONE_PICKER
+     */
+    public static final String EXTRA_RINGTONE_EXISTING_RINGTONE_URI =
+            "android.intent.extra.ringtone.RINGTONE_EXISTING_RINGTONE_URI";
     
     /**
      * Given to the ringtone picker as a {@link Uri}. The {@link Uri} of the
diff --git a/media/java/android/media/flags.aconfig b/media/java/android/media/flags.aconfig
deleted file mode 100644
index 8567a3b..0000000
--- a/media/java/android/media/flags.aconfig
+++ /dev/null
@@ -1,8 +0,0 @@
-package: "android.media"
-
-flag {
-    name: "haptics_customization_enabled"
-    namespace: "media"
-    description: "Enables the haptics customization feature"
-    bug: "241918098"
-}
diff --git a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCamera.java b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCamera.java
index 364f466..e651090 100644
--- a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCamera.java
+++ b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCamera.java
@@ -36,6 +36,7 @@
 import com.google.zxing.BarcodeFormat;
 import com.google.zxing.BinaryBitmap;
 import com.google.zxing.DecodeHintType;
+import com.google.zxing.LuminanceSource;
 import com.google.zxing.MultiFormatReader;
 import com.google.zxing.ReaderException;
 import com.google.zxing.Result;
@@ -249,16 +250,10 @@
                     // Semaphore.acquire() blocking until permit is available, or the thread is
                     // interrupted.
                     imageGot.acquire();
-                    Result qrCode = null;
-                    try {
-                        qrCode =
-                                mReader.decodeWithState(
-                                        new BinaryBitmap(new HybridBinarizer(mImage)));
-                    } catch (ReaderException e) {
-                        // No logging since every time the reader cannot decode the
-                        // image, this ReaderException will be thrown.
-                    } finally {
-                        mReader.reset();
+                    Result qrCode = decodeQrCode(mImage);
+                    if (qrCode == null) {
+                        // Check color inversion QR code
+                        qrCode = decodeQrCode(mImage.invert());
                     }
                     if (qrCode != null) {
                         if (mScannerCallback.isValid(qrCode.getText())) {
@@ -272,6 +267,18 @@
             }
         }
 
+        private Result decodeQrCode(LuminanceSource source) {
+            try {
+                return mReader.decodeWithState(new BinaryBitmap(new HybridBinarizer(source)));
+            } catch (ReaderException e) {
+                // No logging since every time the reader cannot decode the
+                // image, this ReaderException will be thrown.
+            } finally {
+                mReader.reset();
+            }
+            return null;
+        }
+
         @Override
         protected void onPostExecute(String qrCode) {
             if (qrCode != null) {
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
index 6b0a906..248c60c 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
@@ -61,7 +61,7 @@
         Settings.System.TTY_MODE,
         Settings.System.MASTER_MONO,
         Settings.System.MASTER_BALANCE,
-        Settings.System.STAY_AWAKE_ON_FOLD,
+        Settings.System.FOLD_LOCK_BEHAVIOR,
         Settings.System.SOUND_EFFECTS_ENABLED,
         Settings.System.HAPTIC_FEEDBACK_ENABLED,
         Settings.System.POWER_SOUNDS_ENABLED,       // moved to global
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index 20740dc..17ce7c7 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -134,6 +134,7 @@
         VALIDATORS.put(System.HAPTIC_FEEDBACK_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.RINGTONE, URI_VALIDATOR);
         VALIDATORS.put(System.NOTIFICATION_SOUND, URI_VALIDATOR);
+        VALIDATORS.put(System.FOLD_LOCK_BEHAVIOR, ANY_STRING_VALIDATOR);
         VALIDATORS.put(System.ALARM_ALERT, URI_VALIDATOR);
         VALIDATORS.put(System.TEXT_AUTO_REPLACE, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.TEXT_AUTO_CAPS, BOOLEAN_VALIDATOR);
@@ -219,7 +220,6 @@
         VALIDATORS.put(System.WIFI_STATIC_DNS1, LENIENT_IP_ADDRESS_VALIDATOR);
         VALIDATORS.put(System.WIFI_STATIC_DNS2, LENIENT_IP_ADDRESS_VALIDATOR);
         VALIDATORS.put(System.SHOW_BATTERY_PERCENT, BOOLEAN_VALIDATOR);
-        VALIDATORS.put(System.STAY_AWAKE_ON_FOLD, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.NOTIFICATION_LIGHT_PULSE, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.WEAR_ACCESSIBILITY_GESTURE_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.WEAR_ACCESSIBILITY_GESTURE_ENABLED_DURING_OOBE, BOOLEAN_VALIDATOR);
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 089ddbe..bba79bb 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -552,10 +552,12 @@
                 optimize: true,
                 shrink: true,
                 shrink_resources: true,
+                ignore_warnings: false,
                 proguard_compatibility: false,
             },
             conditions_default: {
                 optimize: {
+                    ignore_warnings: false,
                     proguard_compatibility: false,
                 },
             },
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
index 13acde2..4822200 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt
@@ -137,6 +137,7 @@
             )
         }
 
+    val horizontalPadding = dimensionResource(R.dimen.qs_content_horizontal_padding)
     Row(
         modifier
             .fillMaxWidth()
@@ -150,6 +151,8 @@
             .padding(
                 top = dimensionResource(R.dimen.qs_footer_actions_top_padding),
                 bottom = dimensionResource(R.dimen.qs_footer_actions_bottom_padding),
+                start = horizontalPadding,
+                end = horizontalPadding,
             )
             .layout { measurable, constraints ->
                 // All buttons have a 4dp padding to increase their touch size. To be consistent
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
index e5cd439..7ac3901 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
@@ -16,15 +16,19 @@
 
 package com.android.systemui.qs.ui.composable
 
+import android.view.ViewGroup
 import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
 import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.unit.dp
 import com.android.compose.animation.scene.SceneScope
+import com.android.systemui.battery.BatteryMeterViewController
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.qs.footer.ui.compose.QuickSettings
 import com.android.systemui.qs.ui.viewmodel.QuickSettingsSceneViewModel
@@ -33,6 +37,10 @@
 import com.android.systemui.scene.shared.model.SceneModel
 import com.android.systemui.scene.shared.model.UserAction
 import com.android.systemui.scene.ui.composable.ComposableScene
+import com.android.systemui.shade.ui.composable.ExpandedShadeHeader
+import com.android.systemui.statusbar.phone.StatusBarIconController
+import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager
+import com.android.systemui.statusbar.phone.StatusBarLocation
 import javax.inject.Inject
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
@@ -44,6 +52,9 @@
 @Inject
 constructor(
     private val viewModel: QuickSettingsSceneViewModel,
+    private val tintedIconManagerFactory: TintedIconManager.Factory,
+    private val batteryMeterViewControllerFactory: BatteryMeterViewController.Factory,
+    private val statusBarIconController: StatusBarIconController,
 ) : ComposableScene {
     override val key = SceneKey.QuickSettings
 
@@ -61,6 +72,9 @@
     ) {
         QuickSettingsScene(
             viewModel = viewModel,
+            createTintedIconManager = tintedIconManagerFactory::create,
+            createBatteryMeterViewController = batteryMeterViewControllerFactory::create,
+            statusBarIconController = statusBarIconController,
             modifier = modifier,
         )
     }
@@ -69,16 +83,27 @@
 @Composable
 private fun SceneScope.QuickSettingsScene(
     viewModel: QuickSettingsSceneViewModel,
+    createTintedIconManager: (ViewGroup, StatusBarLocation) -> TintedIconManager,
+    createBatteryMeterViewController: (ViewGroup, StatusBarLocation) -> BatteryMeterViewController,
+    statusBarIconController: StatusBarIconController,
     modifier: Modifier = Modifier,
 ) {
     // TODO(b/280887232): implement the real UI.
-
-    Box(
-        modifier
-            .fillMaxSize()
-            .clickable(onClick = { viewModel.onContentClicked() })
-            .padding(horizontal = 16.dp, vertical = 48.dp)
+    Column(
+        horizontalAlignment = Alignment.CenterHorizontally,
+        modifier =
+            modifier
+                .fillMaxSize()
+                .clickable(onClick = { viewModel.onContentClicked() })
+                .padding(start = 16.dp, end = 16.dp, bottom = 48.dp)
     ) {
-        QuickSettings(modifier = Modifier.fillMaxHeight())
+        ExpandedShadeHeader(
+            viewModel = viewModel.shadeHeaderViewModel,
+            createTintedIconManager = createTintedIconManager,
+            createBatteryMeterViewController = createBatteryMeterViewController,
+            statusBarIconController = statusBarIconController,
+        )
+        Spacer(modifier = Modifier.height(16.dp))
+        QuickSettings()
     }
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt
index 21a10b1..be85bee 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt
@@ -5,10 +5,18 @@
 import com.android.compose.animation.scene.TransitionBuilder
 import com.android.systemui.notifications.ui.composable.Notifications
 import com.android.systemui.qs.footer.ui.compose.QuickSettings
+import com.android.systemui.shade.ui.composable.ShadeHeader
 
 fun TransitionBuilder.shadeToQuickSettingsTransition() {
     spec = tween(durationMillis = 500)
 
     translate(Notifications.Elements.Notifications, Edge.Bottom)
     timestampRange(endMillis = 83) { fade(QuickSettings.Elements.FooterActions) }
+
+    translate(ShadeHeader.Elements.CollapsedContent, y = ShadeHeader.Dimensions.CollapsedHeight)
+    translate(ShadeHeader.Elements.ExpandedContent, y = (-ShadeHeader.Dimensions.ExpandedHeight))
+
+    fractionRange(end = .14f) { fade(ShadeHeader.Elements.CollapsedContent) }
+
+    fractionRange(start = .58f) { fade(ShadeHeader.Elements.ExpandedContent) }
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
new file mode 100644
index 0000000..272e507
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
@@ -0,0 +1,314 @@
+/*
+ * 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.shade.ui.composable
+
+import android.view.ContextThemeWrapper
+import android.view.ViewGroup
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.RowScope
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.defaultMinSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.layout.widthIn
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.TransformOrigin
+import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.viewinterop.AndroidView
+import com.android.compose.animation.scene.ElementKey
+import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.ValueKey
+import com.android.compose.animation.scene.animateSharedFloatAsState
+import com.android.settingslib.Utils
+import com.android.systemui.R
+import com.android.systemui.battery.BatteryMeterView
+import com.android.systemui.battery.BatteryMeterViewController
+import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
+import com.android.systemui.statusbar.phone.StatusBarIconController
+import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager
+import com.android.systemui.statusbar.phone.StatusBarLocation
+import com.android.systemui.statusbar.phone.StatusIconContainer
+import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernShadeCarrierGroupMobileView
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.ShadeCarrierGroupMobileIconViewModel
+import com.android.systemui.statusbar.policy.Clock
+
+object ShadeHeader {
+    object Elements {
+        val FormatPlaceholder = ElementKey("ShadeHeaderFormatPlaceholder")
+        val ExpandedContent = ElementKey("ShadeHeaderExpandedContent")
+        val CollapsedContent = ElementKey("ShadeHeaderCollapsedContent")
+    }
+
+    object Keys {
+        val transitionProgress = ValueKey("ShadeHeaderTransitionProgress")
+    }
+
+    object Dimensions {
+        val CollapsedHeight = 48.dp
+        val ExpandedHeight = 120.dp
+    }
+}
+
+@Composable
+fun SceneScope.CollapsedShadeHeader(
+    viewModel: ShadeHeaderViewModel,
+    createTintedIconManager: (ViewGroup, StatusBarLocation) -> TintedIconManager,
+    createBatteryMeterViewController: (ViewGroup, StatusBarLocation) -> BatteryMeterViewController,
+    statusBarIconController: StatusBarIconController,
+    modifier: Modifier = Modifier,
+) {
+    // TODO(b/298153892): Remove this once animateSharedFloatAsState.element can be null.
+    Spacer(Modifier.element(ShadeHeader.Elements.FormatPlaceholder))
+    val formatProgress =
+        animateSharedFloatAsState(
+            0.0f,
+            ShadeHeader.Keys.transitionProgress,
+            ShadeHeader.Elements.FormatPlaceholder
+        )
+    val useExpandedFormat by
+        remember(formatProgress) { derivedStateOf { formatProgress.value > 0.5f } }
+
+    Row(
+        modifier =
+            modifier
+                .element(ShadeHeader.Elements.CollapsedContent)
+                .fillMaxWidth()
+                .defaultMinSize(minHeight = ShadeHeader.Dimensions.CollapsedHeight),
+    ) {
+        AndroidView(
+            factory = { context ->
+                Clock(ContextThemeWrapper(context, R.style.TextAppearance_QS_Status), null)
+            },
+            modifier = Modifier.align(Alignment.CenterVertically),
+        )
+        Spacer(modifier = Modifier.width(5.dp))
+        VariableDayDate(
+            viewModel = viewModel,
+            modifier = Modifier.widthIn(max = 90.dp).align(Alignment.CenterVertically),
+        )
+        Spacer(modifier = Modifier.weight(1f))
+        SystemIconContainer {
+            StatusIcons(
+                viewModel = viewModel,
+                createTintedIconManager = createTintedIconManager,
+                statusBarIconController = statusBarIconController,
+                useExpandedFormat = useExpandedFormat,
+                modifier = Modifier.align(Alignment.CenterVertically).padding(end = 6.dp),
+            )
+            BatteryIcon(
+                createBatteryMeterViewController = createBatteryMeterViewController,
+                useExpandedFormat = useExpandedFormat,
+                modifier = Modifier.align(Alignment.CenterVertically),
+            )
+        }
+    }
+}
+
+@Composable
+fun SceneScope.ExpandedShadeHeader(
+    viewModel: ShadeHeaderViewModel,
+    createTintedIconManager: (ViewGroup, StatusBarLocation) -> TintedIconManager,
+    createBatteryMeterViewController: (ViewGroup, StatusBarLocation) -> BatteryMeterViewController,
+    statusBarIconController: StatusBarIconController,
+    modifier: Modifier = Modifier,
+) {
+    // TODO(b/298153892): Remove this once animateSharedFloatAsState.element can be null.
+    Spacer(Modifier.element(ShadeHeader.Elements.FormatPlaceholder))
+    val formatProgress =
+        animateSharedFloatAsState(
+            1.0f,
+            ShadeHeader.Keys.transitionProgress,
+            ShadeHeader.Elements.FormatPlaceholder
+        )
+    val useExpandedFormat by
+        remember(formatProgress) { derivedStateOf { formatProgress.value > 0.5f } }
+
+    Column(
+        verticalArrangement = Arrangement.Bottom,
+        modifier =
+            modifier
+                .element(ShadeHeader.Elements.ExpandedContent)
+                .fillMaxWidth()
+                .defaultMinSize(minHeight = ShadeHeader.Dimensions.ExpandedHeight)
+    ) {
+        Row {
+            AndroidView(
+                factory = { context ->
+                    Clock(ContextThemeWrapper(context, R.style.TextAppearance_QS_Status), null)
+                },
+                modifier =
+                    Modifier.align(Alignment.CenterVertically)
+                        // use graphicsLayer instead of Modifier.scale to anchor transform to
+                        // top left corner
+                        .graphicsLayer(
+                            scaleX = 2.57f,
+                            scaleY = 2.57f,
+                            transformOrigin = TransformOrigin(0f, 0.5f)
+                        ),
+            )
+            Spacer(modifier = Modifier.weight(1f))
+            ShadeCarrierGroup(
+                viewModel = viewModel,
+                modifier = Modifier.align(Alignment.CenterVertically),
+            )
+        }
+        Spacer(modifier = Modifier.width(5.dp))
+        Row {
+            VariableDayDate(
+                viewModel = viewModel,
+                modifier = Modifier.widthIn(max = 90.dp).align(Alignment.CenterVertically),
+            )
+            Spacer(modifier = Modifier.weight(1f))
+            SystemIconContainer {
+                StatusIcons(
+                    viewModel = viewModel,
+                    createTintedIconManager = createTintedIconManager,
+                    statusBarIconController = statusBarIconController,
+                    useExpandedFormat = useExpandedFormat,
+                    modifier = Modifier.align(Alignment.CenterVertically).padding(end = 6.dp),
+                )
+                BatteryIcon(
+                    useExpandedFormat = useExpandedFormat,
+                    createBatteryMeterViewController = createBatteryMeterViewController,
+                    modifier = Modifier.align(Alignment.CenterVertically),
+                )
+            }
+        }
+    }
+}
+
+@Composable
+private fun BatteryIcon(
+    createBatteryMeterViewController: (ViewGroup, StatusBarLocation) -> BatteryMeterViewController,
+    useExpandedFormat: Boolean,
+    modifier: Modifier = Modifier,
+) {
+    AndroidView(
+        factory = { context ->
+            val batteryIcon = BatteryMeterView(context, null)
+            batteryIcon.setPercentShowMode(BatteryMeterView.MODE_ON)
+
+            val batteryMaterViewController =
+                createBatteryMeterViewController(batteryIcon, StatusBarLocation.QS)
+            batteryMaterViewController.init()
+            batteryMaterViewController.ignoreTunerUpdates()
+
+            batteryIcon
+        },
+        update = { batteryIcon ->
+            // TODO(b/298525212): use MODE_ESTIMATE in collapsed view when the screen
+            //  has no center cutout. See [QsBatteryModeController.getBatteryMode]
+            batteryIcon.setPercentShowMode(
+                if (useExpandedFormat) {
+                    BatteryMeterView.MODE_ESTIMATE
+                } else {
+                    BatteryMeterView.MODE_ON
+                }
+            )
+        },
+        modifier = modifier,
+    )
+}
+
+@Composable
+private fun ShadeCarrierGroup(
+    viewModel: ShadeHeaderViewModel,
+    modifier: Modifier = Modifier,
+) {
+    Row(modifier = modifier) {
+        val subIds by viewModel.mobileSubIds.collectAsState()
+
+        for (subId in subIds) {
+            Spacer(modifier = Modifier.width(5.dp))
+            AndroidView(
+                factory = { context ->
+                    ModernShadeCarrierGroupMobileView.constructAndBind(
+                        context = context,
+                        logger = viewModel.mobileIconsViewModel.logger,
+                        slot = "mobile_carrier_shade_group",
+                        viewModel =
+                            (viewModel.mobileIconsViewModel.viewModelForSub(
+                                subId,
+                                StatusBarLocation.SHADE_CARRIER_GROUP
+                            ) as ShadeCarrierGroupMobileIconViewModel),
+                    )
+                },
+            )
+        }
+    }
+}
+
+@Composable
+private fun StatusIcons(
+    viewModel: ShadeHeaderViewModel,
+    createTintedIconManager: (ViewGroup, StatusBarLocation) -> TintedIconManager,
+    statusBarIconController: StatusBarIconController,
+    useExpandedFormat: Boolean,
+    modifier: Modifier = Modifier,
+) {
+    val carrierIconSlots =
+        listOf(stringResource(id = com.android.internal.R.string.status_bar_mobile))
+    val isSingleCarrier by viewModel.isSingleCarrier.collectAsState()
+    val isTransitioning by viewModel.isTransitioning.collectAsState()
+
+    AndroidView(
+        factory = { context ->
+            val iconContainer = StatusIconContainer(context, null)
+            val iconManager = createTintedIconManager(iconContainer, StatusBarLocation.QS)
+            iconManager.setTint(
+                Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary)
+            )
+            statusBarIconController.addIconGroup(iconManager)
+
+            iconContainer
+        },
+        update = { iconContainer ->
+            iconContainer.setQsExpansionTransitioning(isTransitioning)
+            if (isSingleCarrier || !useExpandedFormat) {
+                iconContainer.removeIgnoredSlots(carrierIconSlots)
+            } else {
+                iconContainer.addIgnoredSlots(carrierIconSlots)
+            }
+        },
+        modifier = modifier,
+    )
+}
+
+@Composable
+private fun SystemIconContainer(
+    modifier: Modifier = Modifier,
+    content: @Composable RowScope.() -> Unit
+) {
+    // TODO(b/298524053): add hover state for this container
+    Row(
+        modifier = modifier.height(ShadeHeader.Dimensions.CollapsedHeight),
+        content = content,
+    )
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index f985aa2..b105637 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -16,9 +16,9 @@
 
 package com.android.systemui.shade.ui.composable
 
+import android.view.ViewGroup
 import androidx.compose.foundation.background
 import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Spacer
@@ -33,6 +33,7 @@
 import androidx.compose.ui.unit.dp
 import com.android.compose.animation.scene.ElementKey
 import com.android.compose.animation.scene.SceneScope
+import com.android.systemui.battery.BatteryMeterViewController
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.notifications.ui.composable.Notifications
@@ -43,6 +44,9 @@
 import com.android.systemui.scene.shared.model.UserAction
 import com.android.systemui.scene.ui.composable.ComposableScene
 import com.android.systemui.shade.ui.viewmodel.ShadeSceneViewModel
+import com.android.systemui.statusbar.phone.StatusBarIconController
+import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager
+import com.android.systemui.statusbar.phone.StatusBarLocation
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.SharingStarted
@@ -77,6 +81,9 @@
 constructor(
     @Application private val applicationScope: CoroutineScope,
     private val viewModel: ShadeSceneViewModel,
+    private val tintedIconManagerFactory: TintedIconManager.Factory,
+    private val batteryMeterViewControllerFactory: BatteryMeterViewController.Factory,
+    private val statusBarIconController: StatusBarIconController,
 ) : ComposableScene {
     override val key = SceneKey.Shade
 
@@ -92,7 +99,14 @@
     @Composable
     override fun SceneScope.Content(
         modifier: Modifier,
-    ) = ShadeScene(viewModel, modifier)
+    ) =
+        ShadeScene(
+            viewModel = viewModel,
+            createTintedIconManager = tintedIconManagerFactory::create,
+            createBatteryMeterViewController = batteryMeterViewControllerFactory::create,
+            statusBarIconController = statusBarIconController,
+            modifier = modifier,
+        )
 
     private fun destinationScenes(
         up: SceneKey,
@@ -107,6 +121,9 @@
 @Composable
 private fun SceneScope.ShadeScene(
     viewModel: ShadeSceneViewModel,
+    createTintedIconManager: (ViewGroup, StatusBarLocation) -> TintedIconManager,
+    createBatteryMeterViewController: (ViewGroup, StatusBarLocation) -> BatteryMeterViewController,
+    statusBarIconController: StatusBarIconController,
     modifier: Modifier = Modifier,
 ) {
     Box(modifier.element(Shade.Elements.Scrim)) {
@@ -116,16 +133,22 @@
                     .fillMaxSize()
                     .background(MaterialTheme.colorScheme.scrim, shape = Shade.Shapes.Scrim)
         )
-
         Column(
             horizontalAlignment = Alignment.CenterHorizontally,
-            verticalArrangement = Arrangement.spacedBy(16.dp),
             modifier =
                 Modifier.fillMaxSize()
                     .clickable(onClick = { viewModel.onContentClicked() })
-                    .padding(horizontal = 16.dp, vertical = 48.dp)
+                    .padding(start = 16.dp, end = 16.dp, bottom = 48.dp)
         ) {
+            CollapsedShadeHeader(
+                viewModel = viewModel.shadeHeaderViewModel,
+                createTintedIconManager = createTintedIconManager,
+                createBatteryMeterViewController = createBatteryMeterViewController,
+                statusBarIconController = statusBarIconController,
+            )
+            Spacer(modifier = Modifier.height(16.dp))
             QuickSettings(modifier = Modifier.height(160.dp))
+            Spacer(modifier = Modifier.height(16.dp))
             Notifications(modifier = Modifier.weight(1f))
         }
     }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/VariableDayDate.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/VariableDayDate.kt
new file mode 100644
index 0000000..799dbd6
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/VariableDayDate.kt
@@ -0,0 +1,64 @@
+package com.android.systemui.shade.ui.composable
+
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.Layout
+import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
+
+@Composable
+fun VariableDayDate(
+    viewModel: ShadeHeaderViewModel,
+    modifier: Modifier = Modifier,
+) {
+    val longerText = viewModel.longerDateText.collectAsState()
+    val shorterText = viewModel.shorterDateText.collectAsState()
+
+    Layout(
+        contents =
+            listOf(
+                {
+                    Text(
+                        text = longerText.value,
+                        style = MaterialTheme.typography.titleSmall,
+                        color = MaterialTheme.colorScheme.onBackground,
+                        maxLines = 1,
+                    )
+                },
+                {
+                    Text(
+                        text = shorterText.value,
+                        style = MaterialTheme.typography.titleSmall,
+                        color = MaterialTheme.colorScheme.onBackground,
+                        maxLines = 1,
+                    )
+                },
+            ),
+        modifier = modifier,
+    ) { measureables, constraints ->
+        check(measureables.size == 2)
+        check(measureables[0].size == 1)
+        check(measureables[1].size == 1)
+
+        val longerMeasurable = measureables[0][0]
+        val shorterMeasurable = measureables[1][0]
+
+        val longerPlaceable = longerMeasurable.measure(constraints)
+        val shorterPlaceable = shorterMeasurable.measure(constraints)
+
+        // If width < maxWidth (and not <=), we can assume that the text fits.
+        val placeable =
+            when {
+                longerPlaceable.width < constraints.maxWidth &&
+                    longerPlaceable.height <= constraints.maxHeight -> longerPlaceable
+                shorterPlaceable.width < constraints.maxWidth &&
+                    shorterPlaceable.height <= constraints.maxHeight -> shorterPlaceable
+                else -> null
+            }
+
+        layout(placeable?.width ?: 0, placeable?.height ?: 0) { placeable?.placeRelative(0, 0) }
+    }
+}
diff --git a/packages/SystemUI/res-keyguard/layout-land/keyguard_pin_view.xml b/packages/SystemUI/res-keyguard/layout-land/keyguard_pin_view.xml
deleted file mode 100644
index cd7ab98..0000000
--- a/packages/SystemUI/res-keyguard/layout-land/keyguard_pin_view.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
-**
-** 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.
-*/
--->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <include layout="@layout/keyguard_pin_view_landscape" />
-
-</FrameLayout>
diff --git a/packages/SystemUI/res-keyguard/layout-sw600dp-land/keyguard_pin_view.xml b/packages/SystemUI/res-keyguard/layout-sw600dp-land/keyguard_pin_view.xml
deleted file mode 100644
index 80cc8c0..0000000
--- a/packages/SystemUI/res-keyguard/layout-sw600dp-land/keyguard_pin_view.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
-**
-** 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.
-*/
--->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <include layout="@layout/keyguard_pin_view_portrait" />
-
-</FrameLayout>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
index 29e14c5..f3cd9e4 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
 **
-** Copyright 2012, The Android Open Source Project
+** 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.
@@ -16,10 +16,203 @@
 ** limitations under the License.
 */
 -->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+
+<com.android.keyguard.KeyguardPINView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/keyguard_pin_view"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    android:layout_gravity="center_horizontal|bottom"
+    android:clipChildren="false"
+    android:clipToPadding="false"
+    android:orientation="vertical"
+    androidprv:layout_maxWidth="@dimen/keyguard_security_width">
 
-    <include layout="@layout/keyguard_pin_view_portrait" />
+    <include layout="@layout/keyguard_bouncer_message_area"/>
 
-</FrameLayout>
+    <com.android.systemui.bouncer.ui.BouncerMessageView
+        android:id="@+id/bouncer_message_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical" />
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:id="@+id/pin_container"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_marginBottom="8dp"
+        android:clipChildren="false"
+        android:clipToPadding="false"
+        android:layout_weight="1"
+        android:layoutDirection="ltr"
+        android:orientation="vertical">
+
+        <!-- Set this to be just above key1. It would be better to introduce a barrier above
+             key1/key2/key3, then place this View above that. Sadly, that doesn't work (the Barrier
+             drops to the bottom of the page, and key1/2/3 all shoot up to the top-left). In any
+             case, the Flow should ensure that key1/2/3 all have the same top, so this should be
+             fine. -->
+        <com.android.keyguard.AlphaOptimizedRelativeLayout
+            android:id="@+id/row0"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingBottom="@dimen/num_pad_entry_row_margin_bottom"
+            androidprv:layout_constraintTop_toTopOf="parent"
+            androidprv:layout_constraintEnd_toEndOf="parent"
+            androidprv:layout_constraintStart_toStartOf="parent"
+            androidprv:layout_constraintBottom_toTopOf="@id/key1"
+            androidprv:layout_constraintVertical_bias="0.5">
+
+            <com.android.keyguard.PasswordTextView
+                android:id="@+id/pinEntry"
+                style="@style/Widget.TextView.Password"
+                android:layout_width="@dimen/keyguard_security_width"
+                android:layout_height="@dimen/keyguard_password_height"
+                android:layout_centerHorizontal="true"
+                android:layout_marginRight="72dp"
+                android:contentDescription="@string/keyguard_accessibility_pin_area"
+                androidprv:scaledTextSize="@integer/scaled_password_text_size" />
+        </com.android.keyguard.AlphaOptimizedRelativeLayout>
+
+        <!-- Guideline used to place the top row of keys relative to the screen height. This will be
+             updated in KeyguardPINView to reduce the height of the PIN pad. -->
+        <androidx.constraintlayout.widget.Guideline
+            android:id="@+id/pin_pad_top_guideline"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            androidprv:layout_constraintGuide_percent="0"
+            android:orientation="horizontal" />
+
+        <com.android.keyguard.KeyguardPinFlowView
+            android:id="@+id/flow1"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:orientation="horizontal"
+            android:clipChildren="false"
+            android:clipToPadding="false"
+
+            androidprv:constraint_referenced_ids="key1,key2,key3,key4,key5,key6,key7,key8,key9,delete_button,key0,key_enter"
+
+            androidprv:flow_horizontalGap="@dimen/num_pad_key_margin_end"
+
+            androidprv:flow_horizontalStyle="packed"
+            androidprv:flow_maxElementsWrap="3"
+
+            androidprv:flow_verticalBias="1.0"
+            androidprv:flow_verticalGap="@dimen/num_pad_entry_row_margin_bottom"
+            androidprv:flow_verticalStyle="packed"
+
+            androidprv:flow_wrapMode="aligned"
+            androidprv:layout_constraintBottom_toBottomOf="parent"
+            androidprv:layout_constraintEnd_toEndOf="parent"
+            androidprv:layout_constraintStart_toStartOf="parent"
+            androidprv:layout_constraintTop_toBottomOf="@id/pin_pad_top_guideline" />
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key1"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key2"
+            androidprv:digit="1"
+            androidprv:textView="@+id/pinEntry" />
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key2"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key3"
+            androidprv:digit="2"
+            androidprv:textView="@+id/pinEntry" />
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key3"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key4"
+            androidprv:digit="3"
+            androidprv:textView="@+id/pinEntry" />
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key4"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key5"
+            androidprv:digit="4"
+            androidprv:textView="@+id/pinEntry" />
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key5"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key6"
+            androidprv:digit="5"
+            androidprv:textView="@+id/pinEntry" />
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key6"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key7"
+            androidprv:digit="6"
+            androidprv:textView="@+id/pinEntry" />
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key7"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key8"
+            androidprv:digit="7"
+            androidprv:textView="@+id/pinEntry" />
+
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key8"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key9"
+            androidprv:digit="8"
+            androidprv:textView="@+id/pinEntry" />
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key9"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/delete_button"
+            androidprv:digit="9"
+            androidprv:textView="@+id/pinEntry" />
+
+        <com.android.keyguard.NumPadButton
+            android:id="@+id/delete_button"
+            style="@style/NumPadKey.Delete"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key0"
+            android:contentDescription="@string/keyboardview_keycode_delete" />
+
+        <com.android.keyguard.NumPadKey
+            android:id="@+id/key0"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key_enter"
+            androidprv:digit="0"
+            androidprv:textView="@+id/pinEntry" />
+
+        <com.android.keyguard.NumPadButton
+            android:id="@+id/key_enter"
+            style="@style/NumPadKey.Enter"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:contentDescription="@string/keyboardview_keycode_enter" />
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+    <include layout="@layout/keyguard_eca"
+        android:id="@+id/keyguard_selector_fade_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:layout_gravity="bottom|center_horizontal"
+        android:layout_marginTop="@dimen/keyguard_eca_top_margin"
+        android:layout_marginBottom="@dimen/keyguard_eca_bottom_margin"
+        android:gravity="center_horizontal"/>
+
+</com.android.keyguard.KeyguardPINView>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view_landscape.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view_landscape.xml
deleted file mode 100644
index e00742d..0000000
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view_landscape.xml
+++ /dev/null
@@ -1,231 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
-**
-** 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.
-*/
--->
-
-<com.android.keyguard.KeyguardPINView xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/keyguard_pin_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_gravity="center_horizontal|bottom"
-    android:clipChildren="false"
-    android:clipToPadding="false"
-    android:orientation="horizontal">
-
-    <androidx.constraintlayout.widget.ConstraintLayout
-        android:layout_width="0dp"
-        android:layout_height="match_parent"
-        android:layout_weight="2"
-        android:clipChildren="false"
-        android:clipToPadding="false"
-        android:layoutDirection="ltr"
-        android:orientation="vertical">
-
-        <include layout="@layout/keyguard_bouncer_message_area" />
-
-        <com.android.systemui.bouncer.ui.BouncerMessageView
-            android:id="@+id/bouncer_message_view"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="vertical"
-            androidprv:layout_constraintBottom_toTopOf="@+id/row0"
-            androidprv:layout_constraintTop_toTopOf="parent"
-            androidprv:layout_constraintVertical_chainStyle="packed" />
-
-        <!-- Set this to be just above key1. It would be better to introduce a barrier above
-         key1/key2/key3, then place this View above that. Sadly, that doesn't work (the Barrier
-         drops to the bottom of the page, and key1/2/3 all shoot up to the top-left). In any
-         case, the Flow should ensure that key1/2/3 all have the same top, so this should be
-         fine. -->
-        <com.android.keyguard.AlphaOptimizedRelativeLayout
-            android:id="@+id/row0"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:paddingBottom="@dimen/num_pad_entry_row_margin_bottom"
-            androidprv:layout_constraintBottom_toTopOf="@+id/keyguard_selector_fade_container"
-            androidprv:layout_constraintTop_toBottomOf="@+id/bouncer_message_view"
-            tools:layout_editor_absoluteX="-16dp">
-
-            <com.android.keyguard.PasswordTextView
-                android:id="@+id/pinEntry"
-                style="@style/Widget.TextView.Password"
-                android:layout_width="@dimen/keyguard_security_width"
-                android:layout_height="@dimen/keyguard_password_height"
-                android:layout_centerHorizontal="true"
-                android:layout_marginRight="72dp"
-                android:contentDescription="@string/keyguard_accessibility_pin_area"
-                androidprv:scaledTextSize="@integer/scaled_password_text_size" />
-        </com.android.keyguard.AlphaOptimizedRelativeLayout>
-
-        <include
-            android:id="@+id/keyguard_selector_fade_container"
-            layout="@layout/keyguard_eca"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_gravity="bottom|center_horizontal"
-            android:layout_marginBottom="@dimen/keyguard_eca_bottom_margin"
-            android:layout_marginTop="@dimen/keyguard_eca_top_margin"
-            android:gravity="center_horizontal"
-            android:orientation="vertical"
-            androidprv:layout_constraintBottom_toBottomOf="parent" />
-
-    </androidx.constraintlayout.widget.ConstraintLayout>
-
-    <androidx.constraintlayout.widget.ConstraintLayout
-        android:id="@+id/pin_container"
-        android:layout_width="0dp"
-        android:layout_height="match_parent"
-        android:layout_weight="3"
-        android:clipChildren="false"
-        android:clipToPadding="false"
-        android:layoutDirection="ltr"
-        android:orientation="vertical">
-
-        <!-- Guideline used to place the top row of keys relative to the screen height. This will be
-        updated in KeyguardPINView to reduce the height of the PIN pad. -->
-        <androidx.constraintlayout.widget.Guideline
-            android:id="@+id/pin_pad_top_guideline"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal"
-            androidprv:layout_constraintGuide_percent="0" />
-
-        <com.android.keyguard.KeyguardPinFlowView
-            android:id="@+id/flow1"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:clipChildren="false"
-            android:clipToPadding="false"
-            android:orientation="horizontal"
-
-            androidprv:constraint_referenced_ids="key1,key2,key3,key4,key5,key6,key7,key8,key9,delete_button,key0,key_enter"
-
-            androidprv:flow_horizontalGap="@dimen/num_pad_key_margin_end"
-
-            androidprv:flow_horizontalStyle="packed"
-            androidprv:flow_maxElementsWrap="3"
-
-            androidprv:flow_verticalBias="0.5"
-            androidprv:flow_verticalGap="@dimen/num_pad_entry_row_margin_bottom"
-            androidprv:flow_verticalStyle="packed"
-
-            androidprv:flow_wrapMode="aligned"
-            androidprv:layout_constraintBottom_toBottomOf="parent"
-            androidprv:layout_constraintEnd_toEndOf="parent"
-            androidprv:layout_constraintStart_toStartOf="parent"
-            androidprv:layout_constraintTop_toBottomOf="@id/pin_pad_top_guideline" />
-
-        <com.android.keyguard.NumPadButton
-            android:id="@+id/delete_button"
-            style="@style/NumPadKey.Delete"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key0"
-            android:contentDescription="@string/keyboardview_keycode_delete" />
-
-        <com.android.keyguard.NumPadButton
-            android:id="@+id/key_enter"
-            style="@style/NumPadKey.Enter"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:contentDescription="@string/keyboardview_keycode_enter" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key1"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key2"
-            androidprv:digit="1"
-            androidprv:textView="@+id/pinEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key2"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key3"
-            androidprv:digit="2"
-            androidprv:textView="@+id/pinEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key3"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key4"
-            androidprv:digit="3"
-            androidprv:textView="@+id/pinEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key4"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key5"
-            androidprv:digit="4"
-            androidprv:textView="@+id/pinEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key5"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key6"
-            androidprv:digit="5"
-            androidprv:textView="@+id/pinEntry" />
-
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key6"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key7"
-            androidprv:digit="6"
-            androidprv:textView="@+id/pinEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key7"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key8"
-            androidprv:digit="7"
-            androidprv:textView="@+id/pinEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key8"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key9"
-            androidprv:digit="8"
-            androidprv:textView="@+id/pinEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key9"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/delete_button"
-            androidprv:digit="9"
-            androidprv:textView="@+id/pinEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key0"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key_enter"
-            androidprv:digit="0"
-            androidprv:textView="@+id/pinEntry" />
-
-    </androidx.constraintlayout.widget.ConstraintLayout>
-
-</com.android.keyguard.KeyguardPINView>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view_portrait.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view_portrait.xml
deleted file mode 100644
index f3cd9e4..0000000
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view_portrait.xml
+++ /dev/null
@@ -1,218 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** 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.
-*/
--->
-
-<com.android.keyguard.KeyguardPINView xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/keyguard_pin_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_gravity="center_horizontal|bottom"
-    android:clipChildren="false"
-    android:clipToPadding="false"
-    android:orientation="vertical"
-    androidprv:layout_maxWidth="@dimen/keyguard_security_width">
-
-    <include layout="@layout/keyguard_bouncer_message_area"/>
-
-    <com.android.systemui.bouncer.ui.BouncerMessageView
-        android:id="@+id/bouncer_message_view"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical" />
-
-    <androidx.constraintlayout.widget.ConstraintLayout
-        android:id="@+id/pin_container"
-        android:layout_width="match_parent"
-        android:layout_height="0dp"
-        android:layout_marginBottom="8dp"
-        android:clipChildren="false"
-        android:clipToPadding="false"
-        android:layout_weight="1"
-        android:layoutDirection="ltr"
-        android:orientation="vertical">
-
-        <!-- Set this to be just above key1. It would be better to introduce a barrier above
-             key1/key2/key3, then place this View above that. Sadly, that doesn't work (the Barrier
-             drops to the bottom of the page, and key1/2/3 all shoot up to the top-left). In any
-             case, the Flow should ensure that key1/2/3 all have the same top, so this should be
-             fine. -->
-        <com.android.keyguard.AlphaOptimizedRelativeLayout
-            android:id="@+id/row0"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:paddingBottom="@dimen/num_pad_entry_row_margin_bottom"
-            androidprv:layout_constraintTop_toTopOf="parent"
-            androidprv:layout_constraintEnd_toEndOf="parent"
-            androidprv:layout_constraintStart_toStartOf="parent"
-            androidprv:layout_constraintBottom_toTopOf="@id/key1"
-            androidprv:layout_constraintVertical_bias="0.5">
-
-            <com.android.keyguard.PasswordTextView
-                android:id="@+id/pinEntry"
-                style="@style/Widget.TextView.Password"
-                android:layout_width="@dimen/keyguard_security_width"
-                android:layout_height="@dimen/keyguard_password_height"
-                android:layout_centerHorizontal="true"
-                android:layout_marginRight="72dp"
-                android:contentDescription="@string/keyguard_accessibility_pin_area"
-                androidprv:scaledTextSize="@integer/scaled_password_text_size" />
-        </com.android.keyguard.AlphaOptimizedRelativeLayout>
-
-        <!-- Guideline used to place the top row of keys relative to the screen height. This will be
-             updated in KeyguardPINView to reduce the height of the PIN pad. -->
-        <androidx.constraintlayout.widget.Guideline
-            android:id="@+id/pin_pad_top_guideline"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            androidprv:layout_constraintGuide_percent="0"
-            android:orientation="horizontal" />
-
-        <com.android.keyguard.KeyguardPinFlowView
-            android:id="@+id/flow1"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:orientation="horizontal"
-            android:clipChildren="false"
-            android:clipToPadding="false"
-
-            androidprv:constraint_referenced_ids="key1,key2,key3,key4,key5,key6,key7,key8,key9,delete_button,key0,key_enter"
-
-            androidprv:flow_horizontalGap="@dimen/num_pad_key_margin_end"
-
-            androidprv:flow_horizontalStyle="packed"
-            androidprv:flow_maxElementsWrap="3"
-
-            androidprv:flow_verticalBias="1.0"
-            androidprv:flow_verticalGap="@dimen/num_pad_entry_row_margin_bottom"
-            androidprv:flow_verticalStyle="packed"
-
-            androidprv:flow_wrapMode="aligned"
-            androidprv:layout_constraintBottom_toBottomOf="parent"
-            androidprv:layout_constraintEnd_toEndOf="parent"
-            androidprv:layout_constraintStart_toStartOf="parent"
-            androidprv:layout_constraintTop_toBottomOf="@id/pin_pad_top_guideline" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key1"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key2"
-            androidprv:digit="1"
-            androidprv:textView="@+id/pinEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key2"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key3"
-            androidprv:digit="2"
-            androidprv:textView="@+id/pinEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key3"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key4"
-            androidprv:digit="3"
-            androidprv:textView="@+id/pinEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key4"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key5"
-            androidprv:digit="4"
-            androidprv:textView="@+id/pinEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key5"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key6"
-            androidprv:digit="5"
-            androidprv:textView="@+id/pinEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key6"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key7"
-            androidprv:digit="6"
-            androidprv:textView="@+id/pinEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key7"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key8"
-            androidprv:digit="7"
-            androidprv:textView="@+id/pinEntry" />
-
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key8"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key9"
-            androidprv:digit="8"
-            androidprv:textView="@+id/pinEntry" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key9"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/delete_button"
-            androidprv:digit="9"
-            androidprv:textView="@+id/pinEntry" />
-
-        <com.android.keyguard.NumPadButton
-            android:id="@+id/delete_button"
-            style="@style/NumPadKey.Delete"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key0"
-            android:contentDescription="@string/keyboardview_keycode_delete" />
-
-        <com.android.keyguard.NumPadKey
-            android:id="@+id/key0"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key_enter"
-            androidprv:digit="0"
-            androidprv:textView="@+id/pinEntry" />
-
-        <com.android.keyguard.NumPadButton
-            android:id="@+id/key_enter"
-            style="@style/NumPadKey.Enter"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:contentDescription="@string/keyboardview_keycode_enter" />
-    </androidx.constraintlayout.widget.ConstraintLayout>
-
-    <include layout="@layout/keyguard_eca"
-        android:id="@+id/keyguard_selector_fade_container"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:layout_gravity="bottom|center_horizontal"
-        android:layout_marginTop="@dimen/keyguard_eca_top_margin"
-        android:layout_marginBottom="@dimen/keyguard_eca_bottom_margin"
-        android:gravity="center_horizontal"/>
-
-</com.android.keyguard.KeyguardPINView>
diff --git a/packages/SystemUI/res/values-sw600dp/bools.xml b/packages/SystemUI/res/values-sw600dp/bools.xml
index 05e38bd..d7ddf00 100644
--- a/packages/SystemUI/res/values-sw600dp/bools.xml
+++ b/packages/SystemUI/res/values-sw600dp/bools.xml
@@ -18,4 +18,12 @@
 <resources>
     <!-- Whether to show the user switcher in quick settings when only a single user is present. -->
     <bool name="qs_show_user_switcher_for_single_user">true</bool>
+
+    <!--  Do update bouncer constraints (port or land) on rotation.
+      Needed for bouncer refactor to use motion layout, because constraints should only be
+      changed on small screens. Only used when flag "lockscreen.enable_landscape" (b/293252410)
+      is enabled
+
+      False here so bouncers constraints are not updated when rotating on large screens -->
+    <bool name="update_bouncer_constraints">false</bool>
 </resources>
diff --git a/packages/SystemUI/res/values/bools.xml b/packages/SystemUI/res/values/bools.xml
index 405a59f..91d3a88 100644
--- a/packages/SystemUI/res/values/bools.xml
+++ b/packages/SystemUI/res/values/bools.xml
@@ -51,4 +51,12 @@
          This configuration will only apply when config_remoteInsetsControllerControlsSystemBars.
          is set to true. -->
     <bool name="config_remoteInsetsControllerSystemBarsCanBeShownByUserAction">false</bool>
+
+    <!--  Do update bouncer constraints (port or land) on rotation.
+      Needed for bouncer refactor to use motion layout, because constraints should only be
+      changed on small screens. Only used when flag "lockscreen.enable_landscape" (b/293252410)
+      is enabled
+
+      True here so bouncers constraints are updated when rotating on small screens -->
+    <bool name="update_bouncer_constraints">true</bool>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 016936a..c134806 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -934,4 +934,12 @@
 
     <!-- Flag controlling whether visual query attention detection has been enabled. -->
     <bool name="config_enableVisualQueryAttentionDetection">false</bool>
+
+    <!--
+    Whether the scene container framework is enabled.
+
+    The scene container framework is a newer (2023) way to organize the various "scenes" between the
+    bouncer, lockscreen, shade, and quick settings.
+    -->
+    <bool name="config_sceneContainerFrameworkEnabled">true</bool>
 </resources>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 579358f..d8c8080 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -233,4 +233,7 @@
     removed later.
     -->
     <item type="id" name="tag_smartspace_view" />
+
+    <!-- Tag set on the Compose implementation of the QS footer actions. -->
+    <item type="id" name="tag_compose_qs_footer_actions" />
 </resources>
diff --git a/packages/SystemUI/res/xml/media_session_expanded.xml b/packages/SystemUI/res/xml/media_session_expanded.xml
index 0cdc0f9..8bf7560d 100644
--- a/packages/SystemUI/res/xml/media_session_expanded.xml
+++ b/packages/SystemUI/res/xml/media_session_expanded.xml
@@ -54,10 +54,12 @@
         android:layout_marginStart="@dimen/qs_media_padding"
         android:layout_marginEnd="@dimen/qs_media_padding"
         app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
+        app:layout_constraintTop_toBottomOf="@id/media_seamless"
         app:layout_constrainedWidth="true"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintBottom_toTopOf="@id/header_artist"
-        app:layout_constraintHorizontal_bias="0" />
+        app:layout_constraintHorizontal_bias="0"
+        app:layout_constraintVertical_bias="1" />
 
     <Constraint
         android:id="@+id/media_explicit_indicator"
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java
index c9d9069..a72d813 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java
@@ -64,6 +64,11 @@
         return false;
     }
 
+    /** Change motion layout constraint set based on orientation */
+    protected void updateConstraints(int orientation) {
+        //Unless overridden, never update constrains (keeping default portrait constraints)
+    }
+
     protected AnimatorListenerAdapter getAnimationListener(int cuj) {
         return new AnimatorListenerAdapter() {
             private boolean mIsCancel;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index d90785d..a2d8c50 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -83,6 +83,7 @@
 import com.android.systemui.log.SessionTracker;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.scene.shared.flag.SceneContainerFlags;
 import com.android.systemui.shared.system.SysUiStatsLog;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -123,6 +124,7 @@
     private final UserSwitcherController mUserSwitcherController;
     private final GlobalSettings mGlobalSettings;
     private final FeatureFlags mFeatureFlags;
+    private final SceneContainerFlags mSceneContainerFlags;
     private final SessionTracker mSessionTracker;
     private final Optional<SideFpsController> mSideFpsController;
     private final FalsingA11yDelegate mFalsingA11yDelegate;
@@ -369,11 +371,9 @@
 
                 @Override
                 public void onOrientationChanged(int orientation) {
-                    if (mFeatureFlags.isEnabled(LOCKSCREEN_ENABLE_LANDSCAPE)) {
-                        // TODO(b/295603468)
-                        // Fix reinflation of views when flag is enabled.
-                        KeyguardSecurityContainerController.this
-                            .onDensityOrFontScaleOrOrientationChanged();
+                    if (mFeatureFlags.isEnabled(LOCKSCREEN_ENABLE_LANDSCAPE)
+                            && getResources().getBoolean(R.bool.update_bouncer_constraints)) {
+                        mSecurityViewFlipperController.updateConstraints(orientation);
                     }
                 }
             };
@@ -433,6 +433,7 @@
             FalsingManager falsingManager,
             UserSwitcherController userSwitcherController,
             FeatureFlags featureFlags,
+            SceneContainerFlags sceneContainerFlags,
             GlobalSettings globalSettings,
             SessionTracker sessionTracker,
             Optional<SideFpsController> sideFpsController,
@@ -466,6 +467,7 @@
         mFalsingManager = falsingManager;
         mUserSwitcherController = userSwitcherController;
         mFeatureFlags = featureFlags;
+        mSceneContainerFlags = sceneContainerFlags;
         mGlobalSettings = globalSettings;
         mSessionTracker = sessionTracker;
         mSideFpsController = sideFpsController;
@@ -503,7 +505,7 @@
 
         showPrimarySecurityScreen(false);
 
-        if (mFeatureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
+        if (mSceneContainerFlags.isEnabled()) {
             // When the scene framework says that the lockscreen has been dismissed, dismiss the
             // keyguard here, revealing the underlying app or launcher:
             mSceneTransitionCollectionJob = mJavaAdapter.get().alwaysCollectFlow(
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
index 4d2391a..891eb14 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
@@ -83,6 +83,14 @@
         return "";
     }
 
+    /** Updates the keyguard view's constraints based on orientation */
+    public void updateConstraints(int orientation) {
+        KeyguardInputView securityView = getSecurityView();
+        if (securityView != null) {
+            securityView.updateConstraints(orientation);
+        }
+    }
+
     @Override
     protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
         return p instanceof LayoutParams;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
index bc5b1ba..74f0beb 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
@@ -16,6 +16,8 @@
 
 package com.android.keyguard;
 
+import static com.android.systemui.flags.Flags.LOCKSCREEN_ENABLE_LANDSCAPE;
+
 import android.util.Log;
 import android.view.LayoutInflater;
 
@@ -116,30 +118,38 @@
     public void asynchronouslyInflateView(SecurityMode securityMode,
             KeyguardSecurityCallback keyguardSecurityCallback,
             @Nullable OnViewInflatedCallback onViewInflatedListener) {
-        int layoutId = getLayoutIdFor(securityMode);
-        int viewID = getKeyguardInputViewId(securityMode);
-        if (layoutId != 0 && viewID != 0) {
+        int layoutId = mFeatureFlags.isEnabled(LOCKSCREEN_ENABLE_LANDSCAPE)
+                ? getLayoutIdFor(securityMode) : getLegacyLayoutIdFor(securityMode);
+        if (layoutId != 0) {
             if (DEBUG) {
-                Log.v(TAG, "inflating on bg thread id = "
-                        + layoutId + " . viewID = " + viewID);
+                Log.v(TAG, "inflating on bg thread id = " + layoutId + " .");
             }
             mAsyncLayoutInflater.inflate(layoutId, mView,
                     (view, resId, parent) -> {
                         mView.addView(view);
                         KeyguardInputViewController<KeyguardInputView> childController =
                                 mKeyguardSecurityViewControllerFactory.create(
-                                        (KeyguardInputView) view.findViewById(viewID),
+                                        (KeyguardInputView) view,
                                         securityMode, keyguardSecurityCallback);
                         childController.init();
                         mChildren.add(childController);
                         if (onViewInflatedListener != null) {
                             onViewInflatedListener.onViewInflated(childController);
+
+                            // Portrait constrains are default
+                            if (mFeatureFlags.isEnabled(LOCKSCREEN_ENABLE_LANDSCAPE)
+                                    &&
+                                    getResources().getBoolean(R.bool.update_bouncer_constraints)) {
+                                // updateConstraints based on orientation (only on small screens)
+                                updateConstraints(getResources().getConfiguration().orientation);
+                            }
                         }
                     });
         }
     }
 
     private int getLayoutIdFor(SecurityMode securityMode) {
+        // TODO (b/297863911, b/297864907) - implement motion layout for other bouncers
         switch (securityMode) {
             case Pattern: return R.layout.keyguard_pattern_view;
             case PIN: return R.layout.keyguard_pin_view;
@@ -151,19 +161,23 @@
         }
     }
 
-    private int getKeyguardInputViewId(SecurityMode securityMode) {
-        //Keyguard Input View is not the root view of the layout, use these IDs for lookup.
+    private int getLegacyLayoutIdFor(SecurityMode securityMode) {
         switch (securityMode) {
-            case Pattern: return R.id.keyguard_pattern_view;
-            case PIN: return R.id.keyguard_pin_view;
-            case Password: return R.id.keyguard_password_view;
-            case SimPin: return R.id.keyguard_sim_pin_view;
-            case SimPuk: return R.id.keyguard_sim_puk_view;
+            case Pattern: return R.layout.keyguard_pattern_view;
+            case PIN: return R.layout.keyguard_pin_view;
+            case Password: return R.layout.keyguard_password_view;
+            case SimPin: return R.layout.keyguard_sim_pin_view;
+            case SimPuk: return R.layout.keyguard_sim_puk_view;
             default:
                 return 0;
         }
     }
 
+    /** Updates the keyguard view's constraints based on orientation */
+    public void updateConstraints(int orientation) {
+        mView.updateConstraints(orientation);
+    }
+
     /** Makes the supplied child visible if it is contained win this view, */
     public void show(KeyguardInputViewController<KeyguardInputView> childController) {
         int index = childController.getIndexIn(mView);
diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
index 0ca3883..b6f47e9 100644
--- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
@@ -31,6 +31,7 @@
 import androidx.annotation.NonNull;
 
 import com.android.systemui.R;
+import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
@@ -240,4 +241,50 @@
             }
         }
     }
+
+    /** */
+    @SysUISingleton
+    public static class Factory {
+        private final UserTracker mUserTracker;
+        private final ConfigurationController mConfigurationController;
+        private final TunerService mTunerService;
+        private final @Main Handler mMainHandler;
+        private final ContentResolver mContentResolver;
+        private final FeatureFlags mFeatureFlags;
+        private final BatteryController mBatteryController;
+
+        @Inject
+        public Factory(
+                UserTracker userTracker,
+                ConfigurationController configurationController,
+                TunerService tunerService,
+                @Main Handler mainHandler,
+                ContentResolver contentResolver,
+                FeatureFlags featureFlags,
+                BatteryController batteryController
+        ) {
+            mUserTracker = userTracker;
+            mConfigurationController = configurationController;
+            mTunerService = tunerService;
+            mMainHandler = mainHandler;
+            mContentResolver = contentResolver;
+            mFeatureFlags = featureFlags;
+            mBatteryController = batteryController;
+        }
+
+        /** */
+        public BatteryMeterViewController create(View view, StatusBarLocation location) {
+            return new BatteryMeterViewController(
+                    (BatteryMeterView) view,
+                    location,
+                    mUserTracker,
+                    mConfigurationController,
+                    mTunerService,
+                    mMainHandler,
+                    mContentResolver,
+                    mFeatureFlags,
+                    mBatteryController
+            );
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
index fc32f4c..9527f32 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
@@ -26,9 +26,8 @@
 import com.android.systemui.classifier.domain.interactor.FalsingInteractor
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
 import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlags
 import com.android.systemui.scene.shared.model.SceneKey
 import com.android.systemui.scene.shared.model.SceneModel
 import com.android.systemui.util.kotlin.pairwise
@@ -51,7 +50,7 @@
     private val repository: BouncerRepository,
     private val authenticationInteractor: AuthenticationInteractor,
     private val sceneInteractor: SceneInteractor,
-    featureFlags: FeatureFlags,
+    flags: SceneContainerFlags,
     private val falsingInteractor: FalsingInteractor,
 ) {
 
@@ -94,7 +93,7 @@
     val isPatternVisible: StateFlow<Boolean> = authenticationInteractor.isPatternVisible
 
     init {
-        if (featureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
+        if (flags.isEnabled()) {
             // Clear the message if moved from throttling to no-longer throttling.
             applicationScope.launch {
                 isThrottled.pairwise().collect { (wasThrottled, currentlyThrottled) ->
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
index 5b1998d..f6794d4 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
@@ -23,8 +23,7 @@
 import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
+import com.android.systemui.scene.shared.flag.SceneContainerFlags
 import javax.inject.Inject
 import kotlin.math.ceil
 import kotlinx.coroutines.CoroutineScope
@@ -47,7 +46,7 @@
     @Application private val applicationScope: CoroutineScope,
     private val bouncerInteractor: BouncerInteractor,
     private val authenticationInteractor: AuthenticationInteractor,
-    featureFlags: FeatureFlags,
+    flags: SceneContainerFlags,
 ) {
     private val isInputEnabled: StateFlow<Boolean> =
         bouncerInteractor.isThrottled
@@ -102,7 +101,7 @@
             )
 
     init {
-        if (featureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
+        if (flags.isEnabled()) {
             applicationScope.launch {
                 bouncerInteractor.isThrottled
                     .map { isThrottled ->
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java
index 3195d09..0a1aed6 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java
@@ -22,8 +22,7 @@
 import com.android.systemui.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.flags.FeatureFlagsClassic;
-import com.android.systemui.flags.Flags;
+import com.android.systemui.scene.shared.flag.SceneContainerFlags;
 import com.android.systemui.statusbar.phone.NotificationTapHelper;
 
 import dagger.Binds;
@@ -53,8 +52,8 @@
     static FalsingCollector providesFalsingCollectorLegacy(
             FalsingCollectorImpl impl,
             FalsingCollectorNoOp noOp,
-            FeatureFlagsClassic featureFlags) {
-        return featureFlags.isEnabled(Flags.SCENE_CONTAINER) ? noOp : impl;
+            SceneContainerFlags flags) {
+        return flags.isEnabled() ? noOp : impl;
     }
 
     /** Provides the actual {@link FalsingCollector}. */
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt
index 0b57e79..d011dd4 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt
@@ -22,6 +22,7 @@
 import android.graphics.drawable.LayerDrawable
 import android.view.View
 import android.service.controls.Control
+import android.service.controls.templates.TemperatureControlTemplate
 import android.service.controls.templates.ThumbnailTemplate
 import android.util.TypedValue
 
@@ -68,7 +69,9 @@
     override fun bind(cws: ControlWithState, colorOffset: Int) {
         this.control = cws.control!!
         cvh.setStatusText(control.getStatusText())
-        template = control.getControlTemplate() as ThumbnailTemplate
+        template = control.controlTemplate as? ThumbnailTemplate
+                ?: (control.controlTemplate as TemperatureControlTemplate).template
+                        as ThumbnailTemplate
 
         val ld = cvh.layout.getBackground() as LayerDrawable
         val clipLayer = ld.findDrawableByLayerId(R.id.clip_layer) as ClipDrawable
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 08d11c2..7ee0ff4 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -124,7 +124,6 @@
 import com.android.systemui.util.concurrency.SysUIConcurrencyModule;
 import com.android.systemui.util.dagger.UtilModule;
 import com.android.systemui.util.kotlin.CoroutinesModule;
-import com.android.systemui.util.leak.GarbageMonitorModule;
 import com.android.systemui.util.sensors.SensorModule;
 import com.android.systemui.util.settings.SettingsUtilModule;
 import com.android.systemui.util.time.SystemClock;
@@ -177,7 +176,6 @@
             FlagsModule.class,
             SystemPropertiesFlagsModule.class,
             FooterActionsModule.class,
-            GarbageMonitorModule.class,
             KeyboardModule.class,
             LetterboxModule.class,
             KeyguardBlueprintModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index ea2568d..59e30a1 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -115,7 +115,7 @@
     val BUILDER_EXTRAS_OVERRIDE =
         sysPropBooleanFlag(
             "persist.sysui.notification.builder_extras_override",
-            default = true
+            default = false
         )
 
     /** Only notify group expansion listeners when a change happens. */
@@ -215,7 +215,7 @@
     /** Inflate and bind views upon emitting a blueprint value . */
     // TODO(b/297365780): Tracking Bug
     @JvmField
-    val LAZY_INFLATE_KEYGUARD = unreleasedFlag("lazy_inflate_keyguard", teamfood = true)
+    val LAZY_INFLATE_KEYGUARD = releasedFlag("lazy_inflate_keyguard")
 
     /** Enables UI updates for AI wallpapers in the wallpaper picker. */
     // TODO(b/267722622): Tracking Bug
@@ -643,7 +643,22 @@
      */
     // TODO(b/283300105): Tracking Bug
     @JvmField val SCENE_CONTAINER_ENABLED = false
-    @JvmField val SCENE_CONTAINER = unreleasedFlag("scene_container")
+    @Deprecated(
+        message = """
+            Do not use this flag directly. Please use
+            [com.android.systemui.scene.shared.flag.SceneContainerFlags#isEnabled].
+
+            (Not really deprecated but using this as a simple way to bring attention to the above).
+        """,
+        replaceWith = ReplaceWith(
+            "com.android.systemui.scene.shared.flag.SceneContainerFlags#isEnabled",
+        ),
+        level = DeprecationLevel.WARNING,
+    )
+    @JvmField val SCENE_CONTAINER = resourceBooleanFlag(
+        R.bool.config_sceneContainerFrameworkEnabled,
+        "scene_container",
+    )
 
     // 1900
     @JvmField val NOTE_TASKS = releasedFlag("keycode_flag")
@@ -708,7 +723,7 @@
     @JvmField val KEYBOARD_BACKLIGHT_INDICATOR = releasedFlag("keyboard_backlight_indicator")
 
     // TODO(b/277192623): Tracking Bug
-    @JvmField val KEYBOARD_EDUCATION = unreleasedFlag("keyboard_education", teamfood = false)
+    @JvmField val KEYBOARD_EDUCATION = unreleasedFlag("keyboard_education", teamfood = true)
 
     // TODO(b/277201412): Tracking Bug
     @JvmField
@@ -774,11 +789,11 @@
 
     /** Enable the Compose implementation of the PeopleSpaceActivity. */
     @JvmField
-    val COMPOSE_PEOPLE_SPACE = releasedFlag("compose_people_space")
+    val COMPOSE_PEOPLE_SPACE = unreleasedFlag("compose_people_space", teamfood = true)
 
     /** Enable the Compose implementation of the Quick Settings footer actions. */
     @JvmField
-    val COMPOSE_QS_FOOTER_ACTIONS = unreleasedFlag("compose_qs_footer_actions")
+    val COMPOSE_QS_FOOTER_ACTIONS = unreleasedFlag("compose_qs_footer_actions", teamfood = true)
 
     /** Enable the share wifi button in Quick Settings internet dialog. */
     @JvmField
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index e374549..5727857 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -45,6 +45,7 @@
 import com.android.systemui.keyguard.shared.model.StatusBarState
 import com.android.systemui.keyguard.shared.model.WakefulnessModel
 import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlags
 import com.android.systemui.scene.shared.model.SceneKey
 import com.android.systemui.shade.data.repository.ShadeRepository
 import com.android.systemui.statusbar.CommandQueue
@@ -77,6 +78,7 @@
     private val repository: KeyguardRepository,
     private val commandQueue: CommandQueue,
     featureFlags: FeatureFlags,
+    sceneContainerFlags: SceneContainerFlags,
     bouncerRepository: KeyguardBouncerRepository,
     configurationRepository: ConfigurationRepository,
     shadeRepository: ShadeRepository,
@@ -249,7 +251,7 @@
 
     /** Whether to animate the next doze mode transition. */
     val animateDozingTransitions: Flow<Boolean> by lazy {
-        if (featureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
+        if (sceneContainerFlags.isEnabled()) {
             sceneInteractorProvider
                 .get()
                 .transitioningTo
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index d2eac45..37e750b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -235,11 +235,15 @@
                 quickStatusBarHeaderController.setContentMargins(mContentHorizontalPadding,
                         mContentHorizontalPadding);
             } else {
-                view.setPaddingRelative(
-                        mContentHorizontalPadding,
-                        view.getPaddingTop(),
-                        mContentHorizontalPadding,
-                        view.getPaddingBottom());
+                // Set the horizontal paddings unless the view is the Compose implementation of the
+                // footer actions.
+                if (view.getTag(R.id.tag_compose_qs_footer_actions) == null) {
+                    view.setPaddingRelative(
+                            mContentHorizontalPadding,
+                            view.getPaddingTop(),
+                            mContentHorizontalPadding,
+                            view.getPaddingBottom());
+                }
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index d801faa..596d024 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -303,6 +303,17 @@
         // to all views except for qs_footer_actions, so we set it to the Compose view.
         composeView.setId(R.id.qs_footer_actions);
 
+        // Set this tag so that QSContainerImpl does not add horizontal paddings to this Compose
+        // implementation of the footer actions. They will be set in Compose instead so that the
+        // background fills the full screen width.
+        composeView.setTag(R.id.tag_compose_qs_footer_actions, true);
+
+        // Set the same elevation as the View implementation, otherwise the footer actions will be
+        // drawn below the scroll view with QS grid and clicks won't get through on small devices
+        // where there isn't enough vertical space to show all the tiles and the footer actions.
+        composeView.setElevation(
+                composeView.getContext().getResources().getDimension(R.dimen.qs_panel_elevation));
+
         // Replace the View by the Compose provided one.
         ViewGroup parent = (ViewGroup) footerActionsView.getParent();
         ViewGroup.LayoutParams layoutParams = footerActionsView.getLayoutParams();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt
index 4c6281e..9edd2c6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt
@@ -18,13 +18,17 @@
 
 import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
 import javax.inject.Inject
 
 /** Models UI state and handles user input for the quick settings scene. */
 @SysUISingleton
 class QuickSettingsSceneViewModel
 @Inject
-constructor(private val bouncerInteractor: BouncerInteractor) {
+constructor(
+    private val bouncerInteractor: BouncerInteractor,
+    val shadeHeaderViewModel: ShadeHeaderViewModel,
+) {
     /** Notifies that some content in quick settings was clicked. */
     fun onContentClicked() {
         bouncerInteractor.showOrUnlockDevice()
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 3a64a6a..d23beda 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -85,7 +85,6 @@
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.model.SysUiState;
@@ -96,6 +95,7 @@
 import com.android.systemui.navigationbar.buttons.KeyButtonView;
 import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
 import com.android.systemui.scene.domain.interactor.SceneInteractor;
+import com.android.systemui.scene.shared.flag.SceneContainerFlags;
 import com.android.systemui.settings.DisplayTracker;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.shade.ShadeViewController;
@@ -143,6 +143,7 @@
 
     private final Context mContext;
     private final FeatureFlags mFeatureFlags;
+    private final SceneContainerFlags mSceneContainerFlags;
     private final Executor mMainExecutor;
     private final ShellInterface mShellInterface;
     private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
@@ -218,7 +219,7 @@
 
                             // If scene framework is enabled, set the scene container window to
                             // visible and let the touch "slip" into that window.
-                            if (mFeatureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
+                            if (mSceneContainerFlags.isEnabled()) {
                                 mSceneInteractor.get().setVisible(true, "swipe down on launcher");
                             } else {
                                 centralSurfaces.onInputFocusTransfer(
@@ -229,7 +230,7 @@
                         if (action == ACTION_UP || action == ACTION_CANCEL) {
                             mInputFocusTransferStarted = false;
 
-                            if (!mFeatureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
+                            if (!mSceneContainerFlags.isEnabled()) {
                                 float velocity = (event.getY() - mInputFocusTransferStartY)
                                         / (event.getEventTime() - mInputFocusTransferStartMillis);
                                 centralSurfaces.onInputFocusTransfer(mInputFocusTransferStarted,
@@ -582,6 +583,7 @@
             KeyguardUnlockAnimationController sysuiUnlockAnimationController,
             AssistUtils assistUtils,
             FeatureFlags featureFlags,
+            SceneContainerFlags sceneContainerFlags,
             DumpManager dumpManager,
             Optional<UnfoldTransitionProgressForwarder> unfoldTransitionProgressForwarder
     ) {
@@ -592,6 +594,7 @@
 
         mContext = context;
         mFeatureFlags = featureFlags;
+        mSceneContainerFlags = sceneContainerFlags;
         mMainExecutor = mainExecutor;
         mShellInterface = shellInterface;
         mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
diff --git a/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
index c5fbf7b9..fcbe9a6 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.scene
 
+import com.android.systemui.scene.shared.flag.SceneContainerFlagsModule
 import com.android.systemui.scene.shared.model.SceneContainerConfig
 import com.android.systemui.scene.shared.model.SceneKey
 import dagger.Module
@@ -28,6 +29,7 @@
             EmptySceneModule::class,
             GoneSceneModule::class,
             QuickSettingsSceneModule::class,
+            SceneContainerFlagsModule::class,
             ShadeSceneModule::class,
         ],
 )
diff --git a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
index 85ef21a..b36ec32 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
@@ -19,6 +19,7 @@
 import com.android.systemui.CoreStartable
 import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor
 import com.android.systemui.scene.domain.startable.SceneContainerStartable
+import com.android.systemui.scene.shared.flag.SceneContainerFlagsModule
 import com.android.systemui.scene.shared.model.SceneContainerConfig
 import com.android.systemui.scene.shared.model.SceneKey
 import dagger.Binds
@@ -36,6 +37,7 @@
             GoneSceneModule::class,
             LockscreenSceneModule::class,
             QuickSettingsSceneModule::class,
+            SceneContainerFlagsModule::class,
             ShadeSceneModule::class,
         ],
 )
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ShadelessSceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/ShadelessSceneContainerFrameworkModule.kt
index 5fda9b1..c10e51b 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ShadelessSceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ShadelessSceneContainerFrameworkModule.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.scene
 
+import com.android.systemui.scene.shared.flag.SceneContainerFlagsModule
 import com.android.systemui.scene.shared.model.SceneContainerConfig
 import com.android.systemui.scene.shared.model.SceneKey
 import dagger.Module
@@ -29,6 +30,7 @@
             EmptySceneModule::class,
             GoneSceneModule::class,
             LockscreenSceneModule::class,
+            SceneContainerFlagsModule::class,
         ],
 )
 object ShadelessSceneContainerFrameworkModule {
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
index 45ee7be..7353379 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
@@ -43,7 +43,7 @@
 class SceneInteractor
 @Inject
 constructor(
-    @Application applicationScope: CoroutineScope,
+    @Application private val applicationScope: CoroutineScope,
     private val repository: SceneContainerRepository,
     private val powerRepository: PowerRepository,
     private val logger: SceneLogger,
@@ -146,6 +146,28 @@
         return repository.setVisible(isVisible)
     }
 
+    /** True if there is a transition happening from and to the specified scenes. */
+    fun transitioning(from: SceneKey, to: SceneKey): StateFlow<Boolean> {
+        fun transitioning(
+            state: ObservableTransitionState,
+            from: SceneKey,
+            to: SceneKey,
+        ): Boolean {
+            return (state as? ObservableTransitionState.Transition)?.let {
+                it.fromScene == from && it.toScene == to
+            }
+                ?: false
+        }
+
+        return transitionState
+            .map { state -> transitioning(state, from, to) }
+            .stateIn(
+                scope = applicationScope,
+                started = SharingStarted.WhileSubscribed(),
+                initialValue = transitioning(transitionState.value, from, to),
+            )
+    }
+
     /**
      * Binds the given flow so the system remembers it.
      *
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
index 7f77acc..722d366 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
@@ -26,13 +26,12 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.DisplayId
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
 import com.android.systemui.keyguard.shared.model.WakefulnessState
 import com.android.systemui.model.SysUiState
 import com.android.systemui.model.updateFlags
 import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlags
 import com.android.systemui.scene.shared.logger.SceneLogger
 import com.android.systemui.scene.shared.model.ObservableTransitionState
 import com.android.systemui.scene.shared.model.SceneKey
@@ -66,7 +65,7 @@
     private val sceneInteractor: SceneInteractor,
     private val authenticationInteractor: AuthenticationInteractor,
     private val keyguardInteractor: KeyguardInteractor,
-    private val featureFlags: FeatureFlags,
+    private val flags: SceneContainerFlags,
     private val sysUiState: SysUiState,
     @DisplayId private val displayId: Int,
     private val sceneLogger: SceneLogger,
@@ -74,14 +73,17 @@
 ) : CoreStartable {
 
     override fun start() {
-        if (featureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
+        if (flags.isEnabled()) {
             sceneLogger.logFrameworkEnabled(isEnabled = true)
             hydrateVisibility()
             automaticallySwitchScenes()
             hydrateSystemUiState()
             collectFalsingSignals()
         } else {
-            sceneLogger.logFrameworkEnabled(isEnabled = false)
+            sceneLogger.logFrameworkEnabled(
+                isEnabled = false,
+                reason = flags.requirementDescription(),
+            )
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
new file mode 100644
index 0000000..83fb723
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
@@ -0,0 +1,136 @@
+/*
+ * 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.systemui.scene.shared.flag
+
+import androidx.annotation.VisibleForTesting
+import com.android.systemui.compose.ComposeFacade
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.flags.Flag
+import com.android.systemui.flags.Flags
+import com.android.systemui.flags.ReleasedFlag
+import com.android.systemui.flags.ResourceBooleanFlag
+import com.android.systemui.flags.UnreleasedFlag
+import dagger.Module
+import dagger.Provides
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+
+/**
+ * Defines interface for classes that can check whether the scene container framework feature is
+ * enabled.
+ */
+interface SceneContainerFlags {
+
+    /** Returns `true` if the Scene Container Framework is enabled; `false` otherwise. */
+    fun isEnabled(): Boolean
+
+    /** Returns a developer-readable string that describes the current requirement list. */
+    fun requirementDescription(): String
+}
+
+class SceneContainerFlagsImpl
+@AssistedInject
+constructor(
+    private val featureFlags: FeatureFlagsClassic,
+    @Assisted private val isComposeAvailable: Boolean,
+) : SceneContainerFlags {
+
+    companion object {
+        @VisibleForTesting
+        val flags: List<Flag<Boolean>> =
+            listOf(
+                Flags.SCENE_CONTAINER,
+                Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA,
+                Flags.MIGRATE_LOCK_ICON,
+                Flags.MIGRATE_NSSL,
+                Flags.MIGRATE_KEYGUARD_STATUS_VIEW,
+            )
+    }
+
+    /** The list of requirements, all must be met for the feature to be enabled. */
+    private val requirements =
+        flags.map { FlagMustBeEnabled(it) } +
+            listOf(ComposeMustBeAvailable(), CompileTimeFlagMustBeEnabled())
+
+    override fun isEnabled(): Boolean {
+        return requirements.all { it.isMet() }
+    }
+
+    override fun requirementDescription(): String {
+        return buildString {
+            requirements.forEach { requirement ->
+                append('\n')
+                append(if (requirement.isMet()) "    [MET]" else "[NOT MET]")
+                append(" ${requirement.name}")
+            }
+        }
+    }
+
+    private interface Requirement {
+        val name: String
+
+        fun isMet(): Boolean
+    }
+
+    private inner class ComposeMustBeAvailable : Requirement {
+        override val name = "Jetpack Compose must be available"
+
+        override fun isMet(): Boolean {
+            return isComposeAvailable
+        }
+    }
+
+    private inner class CompileTimeFlagMustBeEnabled : Requirement {
+        override val name = "Flags.SCENE_CONTAINER_ENABLED must be enabled in code"
+
+        override fun isMet(): Boolean {
+            return Flags.SCENE_CONTAINER_ENABLED
+        }
+    }
+
+    private inner class FlagMustBeEnabled<FlagType : Flag<*>>(
+        private val flag: FlagType,
+    ) : Requirement {
+        override val name = "Flag ${flag.name} must be enabled"
+
+        override fun isMet(): Boolean {
+            return when (flag) {
+                is ResourceBooleanFlag -> featureFlags.isEnabled(flag)
+                is ReleasedFlag -> featureFlags.isEnabled(flag)
+                is UnreleasedFlag -> featureFlags.isEnabled(flag)
+                else -> error("Unsupported flag type ${flag.javaClass}")
+            }
+        }
+    }
+
+    @AssistedFactory
+    interface Factory {
+        fun create(isComposeAvailable: Boolean): SceneContainerFlagsImpl
+    }
+}
+
+@Module
+object SceneContainerFlagsModule {
+
+    @Provides
+    @SysUISingleton
+    fun impl(factory: SceneContainerFlagsImpl.Factory): SceneContainerFlags {
+        return factory.create(ComposeFacade.isComposeAvailable())
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt
index 62136dc..c2c2e04 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt
@@ -24,16 +24,21 @@
 
 class SceneLogger @Inject constructor(@SceneFrameworkLog private val logBuffer: LogBuffer) {
 
-    fun logFrameworkEnabled(isEnabled: Boolean) {
+    fun logFrameworkEnabled(isEnabled: Boolean, reason: String? = null) {
         fun asWord(isEnabled: Boolean): String {
             return if (isEnabled) "enabled" else "disabled"
         }
 
         logBuffer.log(
             tag = TAG,
-            level = LogLevel.INFO,
-            messageInitializer = { bool1 = isEnabled },
-            messagePrinter = { "Scene framework is ${asWord(bool1)}" }
+            level = if (isEnabled) LogLevel.INFO else LogLevel.WARNING,
+            messageInitializer = {
+                bool1 = isEnabled
+                str1 = reason
+            },
+            messagePrinter = {
+                "Scene framework is ${asWord(bool1)}${if (str1 != null) " $str1" else ""}"
+            }
         )
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
index ed719a65..3f7512a 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
@@ -26,13 +26,13 @@
 import com.android.systemui.battery.BatteryMeterView
 import com.android.systemui.battery.BatteryMeterViewController
 import com.android.systemui.biometrics.AuthRippleView
-import com.android.systemui.compose.ComposeFacade
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.ui.view.KeyguardRootView
 import com.android.systemui.privacy.OngoingPrivacyChip
+import com.android.systemui.scene.shared.flag.SceneContainerFlags
 import com.android.systemui.scene.shared.model.Scene
 import com.android.systemui.scene.shared.model.SceneContainerConfig
 import com.android.systemui.scene.ui.view.SceneWindowRootView
@@ -70,17 +70,13 @@
         @SysUISingleton
         fun providesWindowRootView(
             layoutInflater: LayoutInflater,
-            featureFlags: FeatureFlags,
+            sceneContainerFlags: SceneContainerFlags,
             viewModelProvider: Provider<SceneContainerViewModel>,
             containerConfigProvider: Provider<SceneContainerConfig>,
             scenesProvider: Provider<Set<@JvmSuppressWildcards Scene>>,
             layoutInsetController: NotificationInsetsController,
         ): WindowRootView {
-            return if (
-                Flags.SCENE_CONTAINER_ENABLED &&
-                    featureFlags.isEnabled(Flags.SCENE_CONTAINER) &&
-                    ComposeFacade.isComposeAvailable()
-            ) {
+            return if (sceneContainerFlags.isEnabled()) {
                 val sceneWindowRootView =
                     layoutInflater.inflate(R.layout.scene_window_root, null) as SceneWindowRootView
                 sceneWindowRootView.init(
@@ -104,9 +100,9 @@
         @SysUISingleton
         fun providesNotificationShadeWindowView(
             root: WindowRootView,
-            featureFlags: FeatureFlags,
+            sceneContainerFlags: SceneContainerFlags,
         ): NotificationShadeWindowView {
-            if (featureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
+            if (sceneContainerFlags.isEnabled()) {
                 return root.requireViewById(R.id.legacy_window_root)
             }
             return root as NotificationShadeWindowView?
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt
new file mode 100644
index 0000000..c6c664d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt
@@ -0,0 +1,134 @@
+/*
+ * 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.shade.ui.viewmodel
+
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.icu.text.DateFormat
+import android.icu.text.DisplayContext
+import android.os.UserHandle
+import com.android.systemui.R
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
+import java.util.Date
+import java.util.Locale
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
+
+/** Models UI state for the shade header. */
+@SysUISingleton
+class ShadeHeaderViewModel
+@Inject
+constructor(
+    @Application private val applicationScope: CoroutineScope,
+    context: Context,
+    sceneInteractor: SceneInteractor,
+    mobileIconsInteractor: MobileIconsInteractor,
+    val mobileIconsViewModel: MobileIconsViewModel,
+    broadcastDispatcher: BroadcastDispatcher,
+) {
+    /** True if we are transitioning between Shade and QuickSettings scenes, in either direction. */
+    val isTransitioning =
+        combine(
+                sceneInteractor.transitioning(from = SceneKey.Shade, to = SceneKey.QuickSettings),
+                sceneInteractor.transitioning(from = SceneKey.QuickSettings, to = SceneKey.Shade)
+            ) { shadeToQuickSettings, quickSettingsToShade ->
+                shadeToQuickSettings || quickSettingsToShade
+            }
+            .stateIn(applicationScope, SharingStarted.WhileSubscribed(), false)
+
+    /** True if there is exactly one mobile connection. */
+    val isSingleCarrier: StateFlow<Boolean> = mobileIconsInteractor.isSingleCarrier
+
+    /** The list of subscription Ids for current mobile connections. */
+    val mobileSubIds =
+        mobileIconsInteractor.filteredSubscriptions
+            .map { list -> list.map { it.subscriptionId } }
+            .stateIn(applicationScope, SharingStarted.WhileSubscribed(), emptyList())
+
+    private val longerPattern = context.getString(R.string.abbrev_wday_month_day_no_year_alarm)
+    private val shorterPattern = context.getString(R.string.abbrev_month_day_no_year)
+    private val longerDateFormat = MutableStateFlow(getFormatFromPattern(longerPattern))
+    private val shorterDateFormat = MutableStateFlow(getFormatFromPattern(shorterPattern))
+
+    private val _shorterDateText: MutableStateFlow<String> = MutableStateFlow("")
+    val shorterDateText: StateFlow<String> = _shorterDateText.asStateFlow()
+
+    private val _longerDateText: MutableStateFlow<String> = MutableStateFlow("")
+    val longerDateText: StateFlow<String> = _longerDateText.asStateFlow()
+
+    init {
+        broadcastDispatcher
+            .broadcastFlow(
+                filter =
+                    IntentFilter().apply {
+                        addAction(Intent.ACTION_TIME_TICK)
+                        addAction(Intent.ACTION_TIME_CHANGED)
+                        addAction(Intent.ACTION_TIMEZONE_CHANGED)
+                        addAction(Intent.ACTION_LOCALE_CHANGED)
+                    },
+                user = UserHandle.SYSTEM,
+                map = { intent, _ ->
+                    intent.action == Intent.ACTION_TIMEZONE_CHANGED ||
+                        intent.action == Intent.ACTION_LOCALE_CHANGED
+                }
+            )
+            .onEach { invalidateFormats -> updateDateTexts(invalidateFormats) }
+            .launchIn(applicationScope)
+
+        applicationScope.launch { updateDateTexts(false) }
+    }
+
+    private fun updateDateTexts(invalidateFormats: Boolean) {
+        if (invalidateFormats) {
+            longerDateFormat.value = getFormatFromPattern(longerPattern)
+            shorterDateFormat.value = getFormatFromPattern(shorterPattern)
+        }
+
+        val currentTime = Date()
+
+        _longerDateText.value = longerDateFormat.value.format(currentTime)
+        _shorterDateText.value = shorterDateFormat.value.format(currentTime)
+    }
+
+    private fun getFormatFromPattern(pattern: String?): DateFormat {
+        val l = Locale.getDefault()
+        val format = DateFormat.getInstanceForSkeleton(pattern, l)
+        // The use of CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE instead of
+        // CAPITALIZATION_FOR_STANDALONE is to address
+        // https://unicode-org.atlassian.net/browse/ICU-21631
+        // TODO(b/229287642): Switch back to CAPITALIZATION_FOR_STANDALONE
+        format.setContext(DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE)
+        return format
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
index 8edc26d..068d5a5 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
@@ -36,6 +36,7 @@
     @Application private val applicationScope: CoroutineScope,
     authenticationInteractor: AuthenticationInteractor,
     private val bouncerInteractor: BouncerInteractor,
+    val shadeHeaderViewModel: ShadeHeaderViewModel,
 ) {
     /** The key of the scene we should switch to when swiping up. */
     val upDestinationSceneKey: StateFlow<SceneKey> =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 0277a36..b797c63 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -606,8 +606,8 @@
 
     private final ActivityLaunchAnimator mActivityLaunchAnimator;
     private final NotificationLaunchAnimatorControllerProvider mNotificationAnimationProvider;
-    private final NotificationPresenter mPresenter;
-    private final NotificationActivityStarter mNotificationActivityStarter;
+    private final Lazy<NotificationPresenter> mPresenterLazy;
+    private final Lazy<NotificationActivityStarter> mNotificationActivityStarterLazy;
     private final Lazy<NotificationShadeDepthController> mNotificationShadeDepthControllerLazy;
     private final Optional<Bubbles> mBubblesOptional;
     private final Lazy<NoteTaskController> mNoteTaskControllerLazy;
@@ -681,8 +681,9 @@
             Lazy<NotificationShadeWindowViewController> notificationShadeWindowViewControllerLazy,
             NotificationShelfController notificationShelfController,
             NotificationStackScrollLayoutController notificationStackScrollLayoutController,
-            NotificationPresenter notificationPresenter,
-            NotificationActivityStarter notificationActivityStarter,
+            // Lazys due to b/298099682.
+            Lazy<NotificationPresenter> notificationPresenterLazy,
+            Lazy<NotificationActivityStarter> notificationActivityStarterLazy,
             NotificationLaunchAnimatorControllerProvider notifLaunchAnimatorControllerProvider,
             NotificationExpansionRepository notificationExpansionRepository,
             DozeParameters dozeParameters,
@@ -791,8 +792,8 @@
         mStackScrollerController = notificationStackScrollLayoutController;
         mStackScroller = mStackScrollerController.getView();
         mNotifListContainer = mStackScrollerController.getNotificationListContainer();
-        mPresenter = notificationPresenter;
-        mNotificationActivityStarter = notificationActivityStarter;
+        mPresenterLazy = notificationPresenterLazy;
+        mNotificationActivityStarterLazy = notificationActivityStarterLazy;
         mNotificationAnimationProvider = notifLaunchAnimatorControllerProvider;
         mNotificationExpansionRepository = notificationExpansionRepository;
         mDozeServiceHost = dozeServiceHost;
@@ -1509,15 +1510,16 @@
         mActivityLaunchAnimator.setCallback(mActivityLaunchAnimatorCallback);
         mActivityLaunchAnimator.addListener(mActivityLaunchAnimatorListener);
         mRemoteInputManager.addControllerCallback(mNotificationShadeWindowController);
-        mStackScrollerController.setNotificationActivityStarter(mNotificationActivityStarter);
-        mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
-        mShadeController.setNotificationPresenter(mPresenter);
+        mStackScrollerController.setNotificationActivityStarter(
+                mNotificationActivityStarterLazy.get());
+        mGutsManager.setNotificationActivityStarter(mNotificationActivityStarterLazy.get());
+        mShadeController.setNotificationPresenter(mPresenterLazy.get());
         mNotificationsController.initialize(
-                mPresenter,
+                mPresenterLazy.get(),
                 mNotifListContainer,
                 mStackScrollerController.getNotifStackController(),
-                mNotificationActivityStarter);
-        mWindowRootViewVisibilityInteractor.setUp(mPresenter, mNotificationsController);
+                mNotificationActivityStarterLazy.get());
+        mWindowRootViewVisibilityInteractor.setUp(mPresenterLazy.get(), mNotificationsController);
     }
 
     /**
@@ -1710,7 +1712,7 @@
 
     private void onExpandedInvisible() {
         setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
-        if (!mNotificationActivityStarter.isCollapsingToShowActivityOverLockscreen()) {
+        if (!mNotificationActivityStarterLazy.get().isCollapsingToShowActivityOverLockscreen()) {
             showBouncerOrLockScreenIfKeyguard();
         } else if (DEBUG) {
             Log.d(TAG, "Not showing bouncer due to activity showing over lockscreen");
@@ -2036,7 +2038,7 @@
             String action = intent.getAction();
             if (ACTION_FAKE_ARTWORK.equals(action)) {
                 if (DEBUG_MEDIA_FAKE_ARTWORK) {
-                    mPresenter.updateMediaMetaData(true, true);
+                    mPresenterLazy.get().updateMediaMetaData(true, true);
                 }
             }
         }
@@ -2218,7 +2220,7 @@
         releaseGestureWakeLock();
         runLaunchTransitionEndRunnable();
         mKeyguardStateController.setLaunchTransitionFadingAway(false);
-        mPresenter.updateMediaMetaData(true /* metaDataChanged */, true);
+        mPresenterLazy.get().updateMediaMetaData(true /* metaDataChanged */, true);
     }
 
     /**
@@ -2242,7 +2244,7 @@
                 beforeFading.run();
             }
             updateScrimController();
-            mPresenter.updateMediaMetaData(false, true);
+            mPresenterLazy.get().updateMediaMetaData(false, true);
             mShadeSurface.resetAlpha();
             mShadeSurface.fadeOut(
                     FADE_KEYGUARD_START_DELAY, FADE_KEYGUARD_DURATION,
@@ -3343,7 +3345,8 @@
                     updateDozingState();
                     checkBarModes();
                     updateScrimController();
-                    mPresenter.updateMediaMetaData(false, mState != StatusBarState.KEYGUARD);
+                    mPresenterLazy.get()
+                            .updateMediaMetaData(false, mState != StatusBarState.KEYGUARD);
                     Trace.endSection();
                 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
index cc41bf8..23b0ee0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
@@ -27,6 +27,7 @@
 import com.android.systemui.R
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
+import com.android.systemui.scene.shared.flag.SceneContainerFlags
 import com.android.systemui.scene.ui.view.WindowRootView
 import com.android.systemui.shade.ShadeController
 import com.android.systemui.shade.ShadeLogger
@@ -48,8 +49,9 @@
 
 private const val TAG = "PhoneStatusBarViewController"
 
-/** Controller for [PhoneStatusBarView].  */
-class PhoneStatusBarViewController private constructor(
+/** Controller for [PhoneStatusBarView]. */
+class PhoneStatusBarViewController
+private constructor(
     view: PhoneStatusBarView,
     @Named(UNFOLD_STATUS_BAR) private val progressProvider: ScopedUnfoldTransitionProgressProvider?,
     private val centralSurfaces: CentralSurfaces,
@@ -61,42 +63,42 @@
     private val moveFromCenterAnimationController: StatusBarMoveFromCenterAnimationController?,
     private val userChipViewModel: StatusBarUserChipViewModel,
     private val viewUtil: ViewUtil,
-    private val featureFlags: FeatureFlags,
+    private val sceneContainerFlags: SceneContainerFlags,
     private val configurationController: ConfigurationController,
     private val statusOverlayHoverListenerFactory: StatusOverlayHoverListenerFactory,
 ) : ViewController<PhoneStatusBarView>(view) {
 
     private lateinit var statusContainer: View
 
-    private val configurationListener = object : ConfigurationController.ConfigurationListener {
-        override fun onConfigChanged(newConfig: Configuration?) {
-            mView.updateResources()
+    private val configurationListener =
+        object : ConfigurationController.ConfigurationListener {
+            override fun onConfigChanged(newConfig: Configuration?) {
+                mView.updateResources()
+            }
         }
-    }
 
     override fun onViewAttached() {
         statusContainer = mView.requireViewById(R.id.system_icons)
         statusContainer.setOnHoverListener(
-            statusOverlayHoverListenerFactory.createDarkAwareListener(statusContainer))
+            statusOverlayHoverListenerFactory.createDarkAwareListener(statusContainer)
+        )
         if (moveFromCenterAnimationController == null) return
 
         val statusBarLeftSide: View =
-                mView.requireViewById(R.id.status_bar_start_side_except_heads_up)
+            mView.requireViewById(R.id.status_bar_start_side_except_heads_up)
         val systemIconArea: ViewGroup = mView.requireViewById(R.id.status_bar_end_side_content)
 
-        val viewsToAnimate = arrayOf(
-            statusBarLeftSide,
-            systemIconArea
-        )
+        val viewsToAnimate = arrayOf(statusBarLeftSide, systemIconArea)
 
-        mView.viewTreeObserver.addOnPreDrawListener(object :
-            ViewTreeObserver.OnPreDrawListener {
-            override fun onPreDraw(): Boolean {
-                moveFromCenterAnimationController.onViewsReady(viewsToAnimate)
-                mView.viewTreeObserver.removeOnPreDrawListener(this)
-                return true
+        mView.viewTreeObserver.addOnPreDrawListener(
+            object : ViewTreeObserver.OnPreDrawListener {
+                override fun onPreDraw(): Boolean {
+                    moveFromCenterAnimationController.onViewsReady(viewsToAnimate)
+                    mView.viewTreeObserver.removeOnPreDrawListener(this)
+                    return true
+                }
             }
-        })
+        )
 
         mView.addOnLayoutChangeListener { _, left, _, right, _, oldLeft, _, oldRight, _ ->
             val widthChanged = right - left != oldRight - oldLeft
@@ -121,8 +123,7 @@
         mView.init(userChipViewModel)
     }
 
-    override fun onInit() {
-    }
+    override fun onInit() {}
 
     fun setImportantForAccessibility(mode: Int) {
         mView.importantForAccessibility = mode
@@ -151,10 +152,11 @@
     fun onTouch(event: MotionEvent) {
         if (statusBarWindowStateController.windowIsShowing()) {
             val upOrCancel =
-                event.action == MotionEvent.ACTION_UP ||
-                    event.action == MotionEvent.ACTION_CANCEL
-            centralSurfaces.setInteracting(WINDOW_STATUS_BAR,
-                !upOrCancel || shadeController.isExpandedVisible)
+                event.action == MotionEvent.ACTION_UP || event.action == MotionEvent.ACTION_CANCEL
+            centralSurfaces.setInteracting(
+                WINDOW_STATUS_BAR,
+                !upOrCancel || shadeController.isExpandedVisible
+            )
         }
     }
 
@@ -171,15 +173,20 @@
             // panel view.
             if (!centralSurfaces.commandQueuePanelsEnabled) {
                 if (event.action == MotionEvent.ACTION_DOWN) {
-                    Log.v(TAG, String.format("onTouchForwardedFromStatusBar: panel disabled, " +
-                        "ignoring touch at (${event.x.toInt()},${event.y.toInt()})"))
+                    Log.v(
+                        TAG,
+                        String.format(
+                            "onTouchForwardedFromStatusBar: panel disabled, " +
+                                "ignoring touch at (${event.x.toInt()},${event.y.toInt()})"
+                        )
+                    )
                 }
                 return false
             }
 
             // If scene framework is enabled, route the touch to it and
             // ignore the rest of the gesture.
-            if (featureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
+            if (sceneContainerFlags.isEnabled()) {
                 windowRootView.get().dispatchTouchEvent(event)
                 return true
             }
@@ -188,12 +195,13 @@
                 // If the view that would receive the touch is disabled, just have status
                 // bar eat the gesture.
                 if (!shadeViewController.isViewEnabled) {
-                    shadeLogger.logMotionEvent(event,
-                        "onTouchForwardedFromStatusBar: panel view disabled")
+                    shadeLogger.logMotionEvent(
+                        event,
+                        "onTouchForwardedFromStatusBar: panel view disabled"
+                    )
                     return true
                 }
-                if (shadeViewController.isFullyCollapsed &&
-                    event.y < 1f) {
+                if (shadeViewController.isFullyCollapsed && event.y < 1f) {
                     // b/235889526 Eat events on the top edge of the phone when collapsed
                     shadeLogger.logMotionEvent(event, "top edge touch ignored")
                     return true
@@ -218,9 +226,7 @@
                 else -> super.getViewCenter(view, outPoint)
             }
 
-        /**
-         * Returns start or end (based on [isStart]) center point of the view
-         */
+        /** Returns start or end (based on [isStart]) center point of the view */
         private fun getViewEdgeCenter(view: View, outPoint: Point, isStart: Boolean) {
             val isRtl = view.resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL
             val isLeftEdge = isRtl xor isStart
@@ -236,11 +242,14 @@
         }
     }
 
-    class Factory @Inject constructor(
+    class Factory
+    @Inject
+    constructor(
         private val unfoldComponent: Optional<SysUIUnfoldComponent>,
         @Named(UNFOLD_STATUS_BAR)
         private val progressProvider: Optional<ScopedUnfoldTransitionProgressProvider>,
         private val featureFlags: FeatureFlags,
+        private val sceneContainerFlags: SceneContainerFlags,
         private val userChipViewModel: StatusBarUserChipViewModel,
         private val centralSurfaces: CentralSurfaces,
         private val statusBarWindowStateController: StatusBarWindowStateController,
@@ -252,9 +261,7 @@
         private val configurationController: ConfigurationController,
         private val statusOverlayHoverListenerFactory: StatusOverlayHoverListenerFactory,
     ) {
-        fun create(
-            view: PhoneStatusBarView
-        ): PhoneStatusBarViewController {
+        fun create(view: PhoneStatusBarView): PhoneStatusBarViewController {
             val statusBarMoveFromCenterAnimationController =
                 if (featureFlags.isEnabled(Flags.ENABLE_UNFOLD_STATUS_BAR_ANIMATIONS)) {
                     unfoldComponent.getOrNull()?.getStatusBarMoveFromCenterAnimationController()
@@ -274,10 +281,10 @@
                 statusBarMoveFromCenterAnimationController,
                 userChipViewModel,
                 viewUtil,
-                featureFlags,
+                sceneContainerFlags,
                 configurationController,
                 statusOverlayHoverListenerFactory,
             )
         }
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
index fa9b9d2..5773612 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
@@ -34,9 +34,8 @@
 import com.android.systemui.R;
 import com.android.systemui.ScreenDecorations;
 import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
 import com.android.systemui.scene.domain.interactor.SceneInteractor;
+import com.android.systemui.scene.shared.flag.SceneContainerFlags;
 import com.android.systemui.shade.ShadeExpansionStateManager;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -85,7 +84,7 @@
             ShadeExpansionStateManager shadeExpansionStateManager,
             Provider<SceneInteractor> sceneInteractor,
             Provider<JavaAdapter> javaAdapter,
-            FeatureFlags featureFlags,
+            SceneContainerFlags sceneContainerFlags,
             UnlockedScreenOffAnimationController unlockedScreenOffAnimationController
     ) {
         mContext = context;
@@ -123,7 +122,7 @@
         mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
         shadeExpansionStateManager.addFullExpansionListener(this::onShadeExpansionFullyChanged);
 
-        if (featureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
+        if (sceneContainerFlags.isEnabled()) {
             javaAdapter.get().alwaysCollectFlow(
                     sceneInteractor.get().isVisible(),
                     this::onShadeExpansionFullyChanged);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
index a4ec3a3..0f55910 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
@@ -20,7 +20,6 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.statusbar.phone.StatusBarLocation
-import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
 import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractor
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
@@ -56,7 +55,6 @@
     private val airplaneModeInteractor: AirplaneModeInteractor,
     private val constants: ConnectivityConstants,
     @Application private val scope: CoroutineScope,
-    private val statusBarPipelineFlags: StatusBarPipelineFlags,
 ) {
     @VisibleForTesting val mobileIconSubIdCache = mutableMapOf<Int, MobileIconViewModel>()
     @VisibleForTesting
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
index 6bff4ce..5da919b 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
@@ -191,7 +191,6 @@
 
         featureFlags = FakeFeatureFlags()
         featureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true)
-        featureFlags.set(Flags.SCENE_CONTAINER, false)
         featureFlags.set(Flags.BOUNCER_USER_SWITCHER, false)
         featureFlags.set(Flags.KEYGUARD_WM_STATE_REFACTOR, false)
 
@@ -244,6 +243,7 @@
                 falsingManager,
                 userSwitcherController,
                 featureFlags,
+                sceneTestUtils.sceneContainerFlags,
                 globalSettings,
                 sessionTracker,
                 Optional.of(sideFpsController),
@@ -622,51 +622,6 @@
         configurationListenerArgumentCaptor.value.onUiModeChanged()
         verify(view).reloadColors()
     }
-    @Test
-    fun onOrientationChanged_landscapeKeyguardFlagDisabled_blockReinflate() {
-        featureFlags.set(Flags.LOCKSCREEN_ENABLE_LANDSCAPE, false)
-
-        // Run onOrientationChanged
-        val configurationListenerArgumentCaptor =
-            ArgumentCaptor.forClass(ConfigurationController.ConfigurationListener::class.java)
-        underTest.onViewAttached()
-        verify(configurationController).addCallback(configurationListenerArgumentCaptor.capture())
-        clearInvocations(viewFlipperController)
-        configurationListenerArgumentCaptor.value.onOrientationChanged(
-            Configuration.ORIENTATION_LANDSCAPE
-        )
-        // Verify view is reinflated when flag is on
-        verify(viewFlipperController, never()).clearViews()
-        verify(viewFlipperController, never())
-            .asynchronouslyInflateView(
-                eq(SecurityMode.PIN),
-                any(),
-                onViewInflatedCallbackArgumentCaptor.capture()
-            )
-    }
-
-    @Test
-    fun onOrientationChanged_landscapeKeyguardFlagEnabled_doesReinflate() {
-        featureFlags.set(Flags.LOCKSCREEN_ENABLE_LANDSCAPE, true)
-
-        // Run onOrientationChanged
-        val configurationListenerArgumentCaptor =
-            ArgumentCaptor.forClass(ConfigurationController.ConfigurationListener::class.java)
-        underTest.onViewAttached()
-        verify(configurationController).addCallback(configurationListenerArgumentCaptor.capture())
-        clearInvocations(viewFlipperController)
-        configurationListenerArgumentCaptor.value.onOrientationChanged(
-            Configuration.ORIENTATION_LANDSCAPE
-        )
-        // Verify view is reinflated when flag is on
-        verify(viewFlipperController).clearViews()
-        verify(viewFlipperController)
-            .asynchronouslyInflateView(
-                eq(SecurityMode.PIN),
-                any(),
-                onViewInflatedCallbackArgumentCaptor.capture()
-            )
-    }
 
     @Test
     fun hasDismissActions() {
@@ -802,8 +757,6 @@
     @Test
     fun dismissesKeyguard_whenSceneChangesToGone() =
         sceneTestUtils.testScope.runTest {
-            featureFlags.set(Flags.SCENE_CONTAINER, true)
-
             // Upon init, we have never dismisses the keyguard.
             underTest.onInit()
             runCurrent()
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java
index 68c2f59..19bc818 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java
@@ -140,11 +140,6 @@
 
     @Test
     public void asynchronouslyInflateView_setNeedsInput() {
-        when(mKeyguardSecurityViewControllerFactory.create(
-               any(), any(SecurityMode.class),
-                any(KeyguardSecurityCallback.class)))
-                .thenReturn(mKeyguardInputViewController);
-
         ArgumentCaptor<AsyncLayoutInflater.OnInflateFinishedListener> argumentCaptor =
                 ArgumentCaptor.forClass(AsyncLayoutInflater.OnInflateFinishedListener.class);
         mKeyguardSecurityViewFlipperController.asynchronouslyInflateView(SecurityMode.PIN,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/TemperatureControlBehaviorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/TemperatureControlBehaviorTest.kt
new file mode 100644
index 0000000..588e34d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/TemperatureControlBehaviorTest.kt
@@ -0,0 +1,98 @@
+package com.android.systemui.controls.ui
+
+import android.app.PendingIntent
+import android.content.ComponentName
+import android.content.Intent
+import android.graphics.drawable.Icon
+import android.service.controls.Control
+import android.service.controls.DeviceTypes
+import android.service.controls.templates.TemperatureControlTemplate
+import android.service.controls.templates.ThumbnailTemplate
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.controls.ControlsMetricsLogger
+import com.android.systemui.controls.controller.ControlInfo
+import com.android.systemui.controls.controller.ControlsController
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.time.FakeSystemClock
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+class TemperatureControlBehaviorTest : SysuiTestCase() {
+
+    @Mock lateinit var controlsMetricsLogger: ControlsMetricsLogger
+    @Mock lateinit var controlActionCoordinator: ControlActionCoordinator
+    @Mock lateinit var controlsController: ControlsController
+
+    private val fakeSystemClock = FakeSystemClock()
+    private val underTest = TemperatureControlBehavior()
+
+    private lateinit var viewHolder: ControlViewHolder
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+
+        viewHolder =
+            ControlViewHolder(
+                LayoutInflater.from(mContext).inflate(R.layout.controls_base_item, null, false)
+                    as ViewGroup,
+                controlsController,
+                FakeExecutor(fakeSystemClock),
+                FakeExecutor(fakeSystemClock),
+                controlActionCoordinator,
+                controlsMetricsLogger,
+                0,
+                0,
+            )
+    }
+
+    @Test
+    fun testBehaviourSupportsThumbnailSubBehaviour() {
+        val controlWithState =
+            ControlWithState(
+                ComponentName("test.pkg", "TestClass"),
+                ControlInfo(
+                    "test_id",
+                    "test title",
+                    "test subtitle",
+                    DeviceTypes.TYPE_AC_UNIT,
+                ),
+                Control.StatefulBuilder(
+                        "",
+                        PendingIntent.getActivity(
+                            context,
+                            0,
+                            Intent(),
+                            PendingIntent.FLAG_IMMUTABLE,
+                        ),
+                    )
+                    .setControlTemplate(
+                        TemperatureControlTemplate(
+                            "test id",
+                            ThumbnailTemplate(
+                                "test id",
+                                false,
+                                Icon.createWithContentUri(""),
+                                "test description",
+                            ),
+                            0,
+                            0,
+                            0
+                        )
+                    )
+                    .setStatus(Control.STATUS_OK)
+                    .build()
+            )
+        viewHolder.bindData(controlWithState, false)
+        underTest.initialize(viewHolder)
+
+        underTest.bind(controlWithState, 0) // no crash
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
index e2362f6..f62137c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
@@ -175,7 +175,6 @@
                 set(Flags.REVAMPED_WALLPAPER_UI, true)
                 set(Flags.WALLPAPER_FULLSCREEN_PREVIEW, true)
                 set(Flags.FACE_AUTH_REFACTOR, true)
-                set(Flags.SCENE_CONTAINER, false)
             }
         underTest.interactor =
             KeyguardQuickAffordanceInteractor(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
index ce280d7..14cdf2f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
@@ -29,7 +29,6 @@
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.flags.FakeFeatureFlags
 import com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR
-import com.android.systemui.flags.Flags.SCENE_CONTAINER
 import com.android.systemui.keyguard.data.repository.FakeCommandQueue
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.keyguard.shared.model.CameraLaunchSourceModel
@@ -70,11 +69,7 @@
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
-        featureFlags =
-            FakeFeatureFlags().apply {
-                set(FACE_AUTH_REFACTOR, true)
-                set(SCENE_CONTAINER, true)
-            }
+        featureFlags = FakeFeatureFlags().apply { set(FACE_AUTH_REFACTOR, true) }
         commandQueue = FakeCommandQueue()
         val sceneTestUtils = SceneTestUtils(this)
         testScope = sceneTestUtils.testScope
@@ -90,6 +85,7 @@
                 repository = repository,
                 commandQueue = commandQueue,
                 featureFlags = featureFlags,
+                sceneContainerFlags = sceneTestUtils.sceneContainerFlags,
                 bouncerRepository = bouncerRepository,
                 configurationRepository = configurationRepository,
                 shadeRepository = shadeRepository,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt
index 499a636..bdcb9ab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt
@@ -104,7 +104,6 @@
             FakeFeatureFlags().apply {
                 set(Flags.FACE_AUTH_REFACTOR, false)
                 set(Flags.DELAY_BOUNCER, false)
-                set(Flags.SCENE_CONTAINER, false)
             }
         trustRepository = FakeTrustRepository()
         powerRepository = FakePowerRepository()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt
index 7fecfc2..b935e1d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt
@@ -129,7 +129,6 @@
                 set(Flags.FACE_AUTH_REFACTOR, true)
                 set(Flags.LOCK_SCREEN_LONG_PRESS_ENABLED, false)
                 set(Flags.LOCK_SCREEN_LONG_PRESS_DIRECT_TO_WPP, false)
-                set(Flags.SCENE_CONTAINER, false)
             }
 
         val withDeps = KeyguardInteractorFactory.create(featureFlags = featureFlags)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
index 2cb0205..8ae8930 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
@@ -23,10 +23,19 @@
 import com.android.systemui.scene.SceneTestUtils
 import com.android.systemui.scene.shared.model.SceneKey
 import com.android.systemui.scene.shared.model.SceneModel
+import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
+import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
+import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
+import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.android.systemui.util.mockito.mock
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
+import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
@@ -44,15 +53,49 @@
             repository = utils.authenticationRepository(),
         )
 
-    private val underTest =
-        QuickSettingsSceneViewModel(
-            bouncerInteractor =
-                utils.bouncerInteractor(
-                    authenticationInteractor = authenticationInteractor,
-                    sceneInteractor = sceneInteractor,
+    private val mobileIconsInteractor = FakeMobileIconsInteractor(FakeMobileMappingsProxy(), mock())
+
+    private var mobileIconsViewModel: MobileIconsViewModel =
+        MobileIconsViewModel(
+            logger = mock(),
+            verboseLogger = mock(),
+            interactor = mobileIconsInteractor,
+            airplaneModeInteractor =
+                AirplaneModeInteractor(
+                    FakeAirplaneModeRepository(),
+                    FakeConnectivityRepository(),
                 ),
+            constants = mock(),
+            scope = testScope.backgroundScope,
         )
 
+    private lateinit var shadeHeaderViewModel: ShadeHeaderViewModel
+
+    private lateinit var underTest: QuickSettingsSceneViewModel
+
+    @Before
+    fun setUp() {
+        shadeHeaderViewModel =
+            ShadeHeaderViewModel(
+                applicationScope = testScope.backgroundScope,
+                context = context,
+                sceneInteractor = sceneInteractor,
+                mobileIconsInteractor = mobileIconsInteractor,
+                mobileIconsViewModel = mobileIconsViewModel,
+                broadcastDispatcher = fakeBroadcastDispatcher,
+            )
+
+        underTest =
+            QuickSettingsSceneViewModel(
+                bouncerInteractor =
+                    utils.bouncerInteractor(
+                        authenticationInteractor = authenticationInteractor,
+                        sceneInteractor = sceneInteractor,
+                    ),
+                shadeHeaderViewModel = shadeHeaderViewModel,
+            )
+    }
+
     @Test
     fun onContentClicked_deviceUnlocked_switchesToGone() =
         testScope.runTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
index ef07fab..e353a53 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
@@ -36,6 +36,7 @@
 import com.android.systemui.navigationbar.NavigationBarController
 import com.android.systemui.navigationbar.NavigationModeController
 import com.android.systemui.recents.OverviewProxyService.ACTION_QUICKSTEP
+import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags
 import com.android.systemui.settings.FakeDisplayTracker
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.shade.ShadeViewController
@@ -146,6 +147,7 @@
                 sysuiUnlockAnimationController,
                 assistUtils,
                 featureFlags,
+                FakeSceneContainerFlags(),
                 dumpManager,
                 unfoldTransitionProgressForwarder
             )
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
index 6006cd4..141fcbb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
@@ -25,8 +25,6 @@
 import com.android.systemui.authentication.domain.model.AuthenticationMethodModel
 import com.android.systemui.bouncer.ui.viewmodel.PinBouncerViewModel
 import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.shared.model.WakefulnessState
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel
 import com.android.systemui.keyguard.ui.viewmodel.LockscreenSceneViewModel
@@ -38,7 +36,14 @@
 import com.android.systemui.scene.shared.model.SceneModel
 import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
 import com.android.systemui.settings.FakeDisplayTracker
+import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
 import com.android.systemui.shade.ui.viewmodel.ShadeSceneViewModel
+import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
+import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
+import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
 import com.android.systemui.util.mockito.mock
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
@@ -125,13 +130,25 @@
                 ),
         )
 
-    private val shadeSceneViewModel =
-        ShadeSceneViewModel(
-            applicationScope = testScope.backgroundScope,
-            authenticationInteractor = authenticationInteractor,
-            bouncerInteractor = bouncerInteractor,
+    private val mobileIconsInteractor = FakeMobileIconsInteractor(FakeMobileMappingsProxy(), mock())
+
+    private var mobileIconsViewModel: MobileIconsViewModel =
+        MobileIconsViewModel(
+            logger = mock(),
+            verboseLogger = mock(),
+            interactor = mobileIconsInteractor,
+            airplaneModeInteractor =
+                AirplaneModeInteractor(
+                    FakeAirplaneModeRepository(),
+                    FakeConnectivityRepository(),
+                ),
+            constants = mock(),
+            scope = testScope.backgroundScope,
         )
 
+    private lateinit var shadeHeaderViewModel: ShadeHeaderViewModel
+    private lateinit var shadeSceneViewModel: ShadeSceneViewModel
+
     private val keyguardRepository = utils.keyguardRepository
     private val keyguardInteractor =
         utils.keyguardInteractor(
@@ -140,7 +157,23 @@
 
     @Before
     fun setUp() {
-        val featureFlags = FakeFeatureFlags().apply { set(Flags.SCENE_CONTAINER, true) }
+        shadeHeaderViewModel =
+            ShadeHeaderViewModel(
+                applicationScope = testScope.backgroundScope,
+                context = context,
+                sceneInteractor = sceneInteractor,
+                mobileIconsInteractor = mobileIconsInteractor,
+                mobileIconsViewModel = mobileIconsViewModel,
+                broadcastDispatcher = fakeBroadcastDispatcher,
+            )
+
+        shadeSceneViewModel =
+            ShadeSceneViewModel(
+                applicationScope = testScope.backgroundScope,
+                authenticationInteractor = authenticationInteractor,
+                bouncerInteractor = bouncerInteractor,
+                shadeHeaderViewModel = shadeHeaderViewModel,
+            )
 
         authenticationRepository.setUnlocked(false)
 
@@ -152,7 +185,7 @@
                 sceneInteractor = sceneInteractor,
                 authenticationInteractor = authenticationInteractor,
                 keyguardInteractor = keyguardInteractor,
-                featureFlags = featureFlags,
+                flags = utils.sceneContainerFlags,
                 sysUiState = sysUiState,
                 displayId = displayTracker.defaultDisplayId,
                 sceneLogger = mock(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
index 8620f61..ed716a9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
@@ -28,6 +28,7 @@
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.test.runTest
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -136,6 +137,97 @@
         }
 
     @Test
+    fun transitioning_idle_false() =
+        testScope.runTest {
+            val transitionState =
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Idle(SceneKey.Shade)
+                )
+            val transitioning by
+                collectLastValue(underTest.transitioning(SceneKey.Shade, SceneKey.Lockscreen))
+            underTest.setTransitionState(transitionState)
+
+            assertThat(transitioning).isFalse()
+        }
+
+    @Test
+    fun transitioning_wrongFromScene_false() =
+        testScope.runTest {
+            val transitionState =
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Transition(
+                        fromScene = SceneKey.Gone,
+                        toScene = SceneKey.Lockscreen,
+                        progress = flowOf(0.5f)
+                    )
+                )
+            val transitioning by
+                collectLastValue(underTest.transitioning(SceneKey.Shade, SceneKey.Lockscreen))
+            underTest.setTransitionState(transitionState)
+
+            assertThat(transitioning).isFalse()
+        }
+
+    @Test
+    fun transitioning_wrongToScene_false() =
+        testScope.runTest {
+            val transitionState =
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Transition(
+                        fromScene = SceneKey.Shade,
+                        toScene = SceneKey.QuickSettings,
+                        progress = flowOf(0.5f)
+                    )
+                )
+            underTest.setTransitionState(transitionState)
+
+            assertThat(underTest.transitioning(SceneKey.Shade, SceneKey.Lockscreen).value).isFalse()
+        }
+
+    @Test
+    fun transitioning_correctFromAndToScenes_true() =
+        testScope.runTest {
+            val transitionState =
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Transition(
+                        fromScene = SceneKey.Shade,
+                        toScene = SceneKey.Lockscreen,
+                        progress = flowOf(0.5f)
+                    )
+                )
+            val transitioning by
+                collectLastValue(underTest.transitioning(SceneKey.Shade, SceneKey.Lockscreen))
+            underTest.setTransitionState(transitionState)
+
+            assertThat(transitioning).isTrue()
+        }
+
+    @Test
+    fun transitioning_updates() =
+        testScope.runTest {
+            val transitionState =
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Idle(SceneKey.Shade)
+                )
+            val transitioning by
+                collectLastValue(underTest.transitioning(SceneKey.Shade, SceneKey.Lockscreen))
+            underTest.setTransitionState(transitionState)
+
+            assertThat(transitioning).isFalse()
+
+            transitionState.value =
+                ObservableTransitionState.Transition(
+                    fromScene = SceneKey.Shade,
+                    toScene = SceneKey.Lockscreen,
+                    progress = flowOf(0.5f)
+                )
+            assertThat(transitioning).isTrue()
+
+            transitionState.value = ObservableTransitionState.Idle(SceneKey.Lockscreen)
+            assertThat(transitioning).isFalse()
+        }
+
+    @Test
     fun isVisible() =
         testScope.runTest {
             val isVisible by collectLastValue(underTest.isVisible)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index 771c3e3..145629a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -42,6 +42,7 @@
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
+import org.junit.Assume.assumeTrue
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
@@ -57,7 +58,7 @@
     private val utils = SceneTestUtils(this)
     private val testScope = utils.testScope
     private val sceneInteractor = utils.sceneInteractor()
-    private val featureFlags = utils.featureFlags
+    private val sceneContainerFlags = utils.sceneContainerFlags
     private val authenticationRepository = utils.authenticationRepository()
     private val authenticationInteractor =
         utils.authenticationInteractor(
@@ -78,7 +79,7 @@
             sceneInteractor = sceneInteractor,
             authenticationInteractor = authenticationInteractor,
             keyguardInteractor = keyguardInteractor,
-            featureFlags = featureFlags,
+            flags = sceneContainerFlags,
             sysUiState = sysUiState,
             displayId = Display.DEFAULT_DISPLAY,
             sceneLogger = mock(),
@@ -516,7 +517,8 @@
         initialSceneKey: SceneKey? = null,
         authenticationMethod: AuthenticationMethodModel? = null,
     ): MutableStateFlow<ObservableTransitionState> {
-        featureFlags.set(Flags.SCENE_CONTAINER, true)
+        assumeTrue(Flags.SCENE_CONTAINER_ENABLED)
+        sceneContainerFlags.enabled = true
         authenticationRepository.setUnlocked(isDeviceUnlocked)
         keyguardRepository.setBypassEnabled(isBypassEnabled)
         val transitionStateFlow =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt
new file mode 100644
index 0000000..17ee3a1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt
@@ -0,0 +1,96 @@
+/*
+ * 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.systemui.scene.shared.flag
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FakeFeatureFlagsClassic
+import com.android.systemui.flags.Flags
+import com.android.systemui.flags.ReleasedFlag
+import com.android.systemui.flags.ResourceBooleanFlag
+import com.android.systemui.flags.UnreleasedFlag
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@SmallTest
+@RunWith(Parameterized::class)
+internal class SceneContainerFlagsTest(
+    private val testCase: TestCase,
+) : SysuiTestCase() {
+
+    private lateinit var underTest: SceneContainerFlags
+
+    @Before
+    fun setUp() {
+        val featureFlags =
+            FakeFeatureFlagsClassic().apply {
+                SceneContainerFlagsImpl.flags.forEach { flag ->
+                    when (flag) {
+                        is ResourceBooleanFlag -> set(flag, testCase.areAllFlagsSet)
+                        is ReleasedFlag -> set(flag, testCase.areAllFlagsSet)
+                        is UnreleasedFlag -> set(flag, testCase.areAllFlagsSet)
+                        else -> error("Unsupported flag type ${flag.javaClass}")
+                    }
+                }
+            }
+        underTest = SceneContainerFlagsImpl(featureFlags, testCase.isComposeAvailable)
+    }
+
+    @Test
+    fun isEnabled() {
+        assumeTrue(Flags.SCENE_CONTAINER_ENABLED)
+        assertThat(underTest.isEnabled()).isEqualTo(testCase.expectedEnabled)
+    }
+
+    internal data class TestCase(
+        val isComposeAvailable: Boolean,
+        val areAllFlagsSet: Boolean,
+        val expectedEnabled: Boolean,
+    ) {
+        override fun toString(): String {
+            return """
+                (compose=$isComposeAvailable + flags=$areAllFlagsSet) -> expected=$expectedEnabled
+            """
+                .trimIndent()
+        }
+    }
+
+    companion object {
+        @Parameterized.Parameters(name = "{0}")
+        @JvmStatic
+        fun testCases() = buildList {
+            repeat(4) { combination ->
+                val isComposeAvailable = combination and 0b100 != 0
+                val areAllFlagsSet = combination and 0b001 != 0
+
+                val expectedEnabled = isComposeAvailable && areAllFlagsSet
+
+                add(
+                    TestCase(
+                        isComposeAvailable = isComposeAvailable,
+                        areAllFlagsSet = areAllFlagsSet,
+                        expectedEnabled = expectedEnabled,
+                    )
+                )
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt
index ee61f57..587da2d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt
@@ -140,7 +140,7 @@
     private val pipTask = RootTaskInfo().apply {
         configuration.windowConfiguration.apply {
             windowingMode = WINDOWING_MODE_PINNED
-            bounds = Rect(628, 1885, 1038, 2295)
+            setBounds(Rect(628, 1885, 1038, 2295))
             activityType = ACTIVITY_TYPE_STANDARD
         }
         displayId = DISPLAY_ID
@@ -164,7 +164,7 @@
     private val fullScreenWorkProfileTask = RootTaskInfo().apply {
         configuration.windowConfiguration.apply {
             windowingMode = WINDOWING_MODE_FULLSCREEN
-            bounds = Rect(0, 0, 1080, 2400)
+            setBounds(Rect(0, 0, 1080, 2400))
             activityType = ACTIVITY_TYPE_STANDARD
         }
         displayId = DISPLAY_ID
@@ -188,7 +188,7 @@
     private val launcherTask = RootTaskInfo().apply {
         configuration.windowConfiguration.apply {
             windowingMode = WINDOWING_MODE_FULLSCREEN
-            bounds = Rect(0, 0, 1080, 2400)
+            setBounds(Rect(0, 0, 1080, 2400))
             activityType = ACTIVITY_TYPE_HOME
         }
         displayId = DISPLAY_ID
@@ -212,7 +212,7 @@
     private val emptyTask = RootTaskInfo().apply {
         configuration.windowConfiguration.apply {
             windowingMode = WINDOWING_MODE_FULLSCREEN
-            bounds = Rect(0, 0, 1080, 2400)
+            setBounds(Rect(0, 0, 1080, 2400))
             activityType = ACTIVITY_TYPE_UNDEFINED
         }
         displayId = DISPLAY_ID
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
new file mode 100644
index 0000000..a09e844
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
@@ -0,0 +1,155 @@
+package com.android.systemui.shade.ui.viewmodel
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.scene.SceneTestUtils
+import com.android.systemui.scene.shared.model.ObservableTransitionState
+import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
+import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
+import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.android.systemui.util.mockito.mock
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(JUnit4::class)
+class ShadeHeaderViewModelTest : SysuiTestCase() {
+    private val utils = SceneTestUtils(this)
+    private val testScope = utils.testScope
+    private val sceneInteractor = utils.sceneInteractor()
+
+    private val mobileIconsInteractor = FakeMobileIconsInteractor(FakeMobileMappingsProxy(), mock())
+
+    private var mobileIconsViewModel: MobileIconsViewModel =
+        MobileIconsViewModel(
+            logger = mock(),
+            verboseLogger = mock(),
+            interactor = mobileIconsInteractor,
+            airplaneModeInteractor =
+                AirplaneModeInteractor(
+                    FakeAirplaneModeRepository(),
+                    FakeConnectivityRepository(),
+                ),
+            constants = mock(),
+            scope = testScope.backgroundScope,
+        )
+
+    private lateinit var underTest: ShadeHeaderViewModel
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        underTest =
+            ShadeHeaderViewModel(
+                applicationScope = testScope.backgroundScope,
+                context = context,
+                sceneInteractor = sceneInteractor,
+                mobileIconsInteractor = mobileIconsInteractor,
+                mobileIconsViewModel = mobileIconsViewModel,
+                broadcastDispatcher = fakeBroadcastDispatcher,
+            )
+    }
+
+    @Test
+    fun isTransitioning_idle_false() =
+        testScope.runTest {
+            val isTransitioning by collectLastValue(underTest.isTransitioning)
+            sceneInteractor.setTransitionState(
+                MutableStateFlow(ObservableTransitionState.Idle(SceneKey.Shade))
+            )
+
+            assertThat(isTransitioning).isFalse()
+        }
+
+    @Test
+    fun isTransitioning_shadeToQs_true() =
+        testScope.runTest {
+            val isTransitioning by collectLastValue(underTest.isTransitioning)
+            sceneInteractor.setTransitionState(
+                MutableStateFlow(
+                    ObservableTransitionState.Transition(
+                        fromScene = SceneKey.Shade,
+                        toScene = SceneKey.QuickSettings,
+                        progress = MutableStateFlow(0.5f)
+                    )
+                )
+            )
+
+            assertThat(isTransitioning).isTrue()
+        }
+
+    @Test
+    fun isTransitioning_qsToShade_true() =
+        testScope.runTest {
+            val isTransitioning by collectLastValue(underTest.isTransitioning)
+            sceneInteractor.setTransitionState(
+                MutableStateFlow(
+                    ObservableTransitionState.Transition(
+                        fromScene = SceneKey.QuickSettings,
+                        toScene = SceneKey.Shade,
+                        progress = MutableStateFlow(0.5f)
+                    )
+                )
+            )
+
+            assertThat(isTransitioning).isTrue()
+        }
+
+    @Test
+    fun isTransitioning_otherTransition_false() =
+        testScope.runTest {
+            val isTransitioning by collectLastValue(underTest.isTransitioning)
+            sceneInteractor.setTransitionState(
+                MutableStateFlow(
+                    ObservableTransitionState.Transition(
+                        fromScene = SceneKey.Gone,
+                        toScene = SceneKey.Shade,
+                        progress = MutableStateFlow(0.5f)
+                    )
+                )
+            )
+
+            assertThat(isTransitioning).isFalse()
+        }
+
+    @Test
+    fun mobileSubIds_update() =
+        testScope.runTest {
+            val mobileSubIds by collectLastValue(underTest.mobileSubIds)
+            mobileIconsInteractor.filteredSubscriptions.value = listOf(SUB_1)
+
+            assertThat(mobileSubIds).isEqualTo(listOf(1))
+
+            mobileIconsInteractor.filteredSubscriptions.value = listOf(SUB_1, SUB_2)
+
+            assertThat(mobileSubIds).isEqualTo(listOf(1, 2))
+        }
+
+    companion object {
+        private val SUB_1 =
+            SubscriptionModel(
+                subscriptionId = 1,
+                isOpportunistic = false,
+                carrierName = "Carrier 1",
+            )
+        private val SUB_2 =
+            SubscriptionModel(
+                subscriptionId = 2,
+                isOpportunistic = false,
+                carrierName = "Carrier 2",
+            )
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
index 69b9525..5c75d9c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
@@ -23,10 +23,18 @@
 import com.android.systemui.scene.SceneTestUtils
 import com.android.systemui.scene.shared.model.SceneKey
 import com.android.systemui.scene.shared.model.SceneModel
+import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
+import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
+import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.android.systemui.util.mockito.mock
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
+import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
@@ -45,17 +53,51 @@
             sceneInteractor = sceneInteractor,
         )
 
-    private val underTest =
-        ShadeSceneViewModel(
-            applicationScope = testScope.backgroundScope,
-            authenticationInteractor = authenticationInteractor,
-            bouncerInteractor =
-                utils.bouncerInteractor(
-                    authenticationInteractor = authenticationInteractor,
-                    sceneInteractor = sceneInteractor,
+    private val mobileIconsInteractor = FakeMobileIconsInteractor(FakeMobileMappingsProxy(), mock())
+
+    private var mobileIconsViewModel: MobileIconsViewModel =
+        MobileIconsViewModel(
+            logger = mock(),
+            verboseLogger = mock(),
+            interactor = mobileIconsInteractor,
+            airplaneModeInteractor =
+                AirplaneModeInteractor(
+                    FakeAirplaneModeRepository(),
+                    FakeConnectivityRepository(),
                 ),
+            constants = mock(),
+            scope = testScope.backgroundScope,
         )
 
+    private lateinit var shadeHeaderViewModel: ShadeHeaderViewModel
+
+    private lateinit var underTest: ShadeSceneViewModel
+
+    @Before
+    fun setUp() {
+        shadeHeaderViewModel =
+            ShadeHeaderViewModel(
+                applicationScope = testScope.backgroundScope,
+                context = context,
+                sceneInteractor = sceneInteractor,
+                mobileIconsInteractor = mobileIconsInteractor,
+                mobileIconsViewModel = mobileIconsViewModel,
+                broadcastDispatcher = fakeBroadcastDispatcher,
+            )
+
+        underTest =
+            ShadeSceneViewModel(
+                applicationScope = testScope.backgroundScope,
+                authenticationInteractor = authenticationInteractor,
+                bouncerInteractor =
+                    utils.bouncerInteractor(
+                        authenticationInteractor = authenticationInteractor,
+                        sceneInteractor = sceneInteractor,
+                    ),
+                shadeHeaderViewModel = shadeHeaderViewModel,
+            )
+    }
+
     @Test
     fun upTransitionSceneKey_deviceLocked_lockScreen() =
         testScope.runTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 4e3690f..137566b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -136,6 +136,7 @@
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationShadeDepthController;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -491,8 +492,8 @@
                 mNotificationShadeWindowViewControllerLazy,
                 mNotificationShelfController,
                 mStackScrollerController,
-                mNotificationPresenter,
-                mNotificationActivityStarter,
+                (Lazy<NotificationPresenter>) () -> mNotificationPresenter,
+                (Lazy<NotificationActivityStarter>) () -> mNotificationActivityStarter,
                 mNotifLaunchAnimControllerProvider,
                 new NotificationExpansionRepository(),
                 mDozeParameters,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
index 4c3c3f9..4349d73 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
@@ -31,6 +31,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
+import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags
 import com.android.systemui.scene.ui.view.WindowRootView
 import com.android.systemui.shade.ShadeControllerImpl
 import com.android.systemui.shade.ShadeLogger
@@ -47,6 +48,8 @@
 import com.android.systemui.util.mockito.whenever
 import com.android.systemui.util.view.ViewUtil
 import com.google.common.truth.Truth.assertThat
+import java.util.Optional
+import javax.inject.Provider
 import org.junit.Before
 import org.junit.Test
 import org.mockito.ArgumentCaptor
@@ -57,40 +60,24 @@
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
-import java.util.Optional
-import javax.inject.Provider
 
 @SmallTest
 class PhoneStatusBarViewControllerTest : SysuiTestCase() {
 
-    @Mock
-    private lateinit var shadeViewController: ShadeViewController
-    @Mock
-    private lateinit var featureFlags: FeatureFlags
-    @Mock
-    private lateinit var moveFromCenterAnimation: StatusBarMoveFromCenterAnimationController
-    @Mock
-    private lateinit var sysuiUnfoldComponent: SysUIUnfoldComponent
-    @Mock
-    private lateinit var progressProvider: ScopedUnfoldTransitionProgressProvider
-    @Mock
-    private lateinit var configurationController: ConfigurationController
-    @Mock
-    private lateinit var mStatusOverlayHoverListenerFactory: StatusOverlayHoverListenerFactory
-    @Mock
-    private lateinit var userChipViewModel: StatusBarUserChipViewModel
-    @Mock
-    private lateinit var centralSurfacesImpl: CentralSurfacesImpl
-    @Mock
-    private lateinit var commandQueue: CommandQueue
-    @Mock
-    private lateinit var shadeControllerImpl: ShadeControllerImpl
-    @Mock
-    private lateinit var windowRootView: Provider<WindowRootView>
-    @Mock
-    private lateinit var shadeLogger: ShadeLogger
-    @Mock
-    private lateinit var viewUtil: ViewUtil
+    @Mock private lateinit var shadeViewController: ShadeViewController
+    @Mock private lateinit var featureFlags: FeatureFlags
+    @Mock private lateinit var moveFromCenterAnimation: StatusBarMoveFromCenterAnimationController
+    @Mock private lateinit var sysuiUnfoldComponent: SysUIUnfoldComponent
+    @Mock private lateinit var progressProvider: ScopedUnfoldTransitionProgressProvider
+    @Mock private lateinit var configurationController: ConfigurationController
+    @Mock private lateinit var mStatusOverlayHoverListenerFactory: StatusOverlayHoverListenerFactory
+    @Mock private lateinit var userChipViewModel: StatusBarUserChipViewModel
+    @Mock private lateinit var centralSurfacesImpl: CentralSurfacesImpl
+    @Mock private lateinit var commandQueue: CommandQueue
+    @Mock private lateinit var shadeControllerImpl: ShadeControllerImpl
+    @Mock private lateinit var windowRootView: Provider<WindowRootView>
+    @Mock private lateinit var shadeLogger: ShadeLogger
+    @Mock private lateinit var viewUtil: ViewUtil
     private lateinit var statusBarWindowStateController: StatusBarWindowStateController
 
     private lateinit var view: PhoneStatusBarView
@@ -109,16 +96,16 @@
         // create the view and controller on main thread as it requires main looper
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
             val parent = FrameLayout(mContext) // add parent to keep layout params
-            view = LayoutInflater.from(mContext)
-                .inflate(R.layout.status_bar, parent, false) as PhoneStatusBarView
+            view =
+                LayoutInflater.from(mContext).inflate(R.layout.status_bar, parent, false)
+                    as PhoneStatusBarView
             controller = createAndInitController(view)
         }
     }
 
     @Test
     fun onViewAttachedAndDrawn_moveFromCenterAnimationEnabled_moveFromCenterAnimationInitialized() {
-        whenever(featureFlags.isEnabled(Flags.ENABLE_UNFOLD_STATUS_BAR_ANIMATIONS))
-                .thenReturn(true)
+        whenever(featureFlags.isEnabled(Flags.ENABLE_UNFOLD_STATUS_BAR_ANIMATIONS)).thenReturn(true)
         val view = createViewMock()
         val argumentCaptor = ArgumentCaptor.forClass(OnPreDrawListener::class.java)
         unfoldConfig.isEnabled = true
@@ -136,7 +123,7 @@
     @Test
     fun onViewAttachedAndDrawn_statusBarAnimationDisabled_animationNotInitialized() {
         whenever(featureFlags.isEnabled(Flags.ENABLE_UNFOLD_STATUS_BAR_ANIMATIONS))
-                .thenReturn(false)
+            .thenReturn(false)
         val view = createViewMock()
         unfoldConfig.isEnabled = true
         // create the controller on main thread as it requires main looper
@@ -150,8 +137,8 @@
     @Test
     fun handleTouchEventFromStatusBar_panelsNotEnabled_returnsFalseAndNoViewEvent() {
         `when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(false)
-        val returnVal = view.onTouchEvent(
-                        MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0))
+        val returnVal =
+            view.onTouchEvent(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0))
         assertThat(returnVal).isFalse()
         verify(shadeViewController, never()).handleExternalTouch(any())
     }
@@ -160,8 +147,8 @@
     fun handleTouchEventFromStatusBar_viewNotEnabled_returnsTrueAndNoViewEvent() {
         `when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(true)
         `when`(shadeViewController.isViewEnabled).thenReturn(false)
-        val returnVal = view.onTouchEvent(
-                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0))
+        val returnVal =
+            view.onTouchEvent(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0))
         assertThat(returnVal).isTrue()
         verify(shadeViewController, never()).handleExternalTouch(any())
     }
@@ -245,22 +232,23 @@
 
     private fun createAndInitController(view: PhoneStatusBarView): PhoneStatusBarViewController {
         return PhoneStatusBarViewController.Factory(
-            Optional.of(sysuiUnfoldComponent),
-            Optional.of(progressProvider),
-            featureFlags,
-            userChipViewModel,
-            centralSurfacesImpl,
-            statusBarWindowStateController,
-            shadeControllerImpl,
-            shadeViewController,
-            windowRootView,
-            shadeLogger,
-            viewUtil,
-            configurationController,
-            mStatusOverlayHoverListenerFactory
-        ).create(view).also {
-            it.init()
-        }
+                Optional.of(sysuiUnfoldComponent),
+                Optional.of(progressProvider),
+                featureFlags,
+                FakeSceneContainerFlags(),
+                userChipViewModel,
+                centralSurfacesImpl,
+                statusBarWindowStateController,
+                shadeControllerImpl,
+                shadeViewController,
+                windowRootView,
+                shadeLogger,
+                viewUtil,
+                configurationController,
+                mStatusOverlayHoverListenerFactory
+            )
+            .create(view)
+            .also { it.init() }
     }
 
     private class UnfoldConfig : UnfoldTransitionConfig {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
index e42515e..eb6f2f8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
@@ -78,7 +78,6 @@
                 airplaneModeInteractor,
                 constants,
                 testScope.backgroundScope,
-                statusBarPipelineFlags,
             )
 
         interactor.filteredSubscriptions.value = listOf(SUB_1, SUB_2)
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 5256245..65cac6e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -84,7 +84,7 @@
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
 public class VolumeDialogImplTest extends SysuiTestCase {
     VolumeDialogImpl mDialog;
     View mActiveRinger;
@@ -141,6 +141,7 @@
         getContext().addMockSystemService(KeyguardManager.class, mKeyguard);
 
         mTestableLooper = TestableLooper.get(this);
+        allowTestableLooperAsMainThread();
 
         when(mPostureController.getDevicePosture())
                 .thenReturn(DevicePostureController.DEVICE_POSTURE_CLOSED);
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
index 28b7d41..aa88a46 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
@@ -166,7 +166,9 @@
         }
         disallowTestableLooperAsMainThread();
         mContext.cleanUpReceivers(this.getClass().getSimpleName());
-        mFakeBroadcastDispatcher.cleanUpReceivers(this.getClass().getSimpleName());
+        if (mFakeBroadcastDispatcher != null) {
+            mFakeBroadcastDispatcher.cleanUpReceivers(this.getClass().getSimpleName());
+        }
     }
 
     @AfterClass
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
index 11ea513..2e3bb2b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
@@ -24,6 +24,8 @@
 import com.android.systemui.keyguard.data.repository.FakeCommandQueue
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags
+import com.android.systemui.scene.shared.flag.SceneContainerFlags
 import com.android.systemui.shade.data.repository.FakeShadeRepository
 import com.android.systemui.util.mockito.mock
 
@@ -37,6 +39,7 @@
     @JvmStatic
     fun create(
         featureFlags: FakeFeatureFlags = createFakeFeatureFlags(),
+        sceneContainerFlags: SceneContainerFlags = FakeSceneContainerFlags(),
         repository: FakeKeyguardRepository = FakeKeyguardRepository(),
         commandQueue: FakeCommandQueue = FakeCommandQueue(),
         bouncerRepository: FakeKeyguardBouncerRepository = FakeKeyguardBouncerRepository(),
@@ -48,6 +51,7 @@
             repository = repository,
             commandQueue = commandQueue,
             featureFlags = featureFlags,
+            sceneContainerFlags = sceneContainerFlags,
             bouncerRepository = bouncerRepository,
             configurationRepository = configurationRepository,
             shadeRepository = shadeRepository,
@@ -55,6 +59,7 @@
                 repository = repository,
                 commandQueue = commandQueue,
                 featureFlags = featureFlags,
+                sceneContainerFlags = sceneContainerFlags,
                 bouncerRepository = bouncerRepository,
                 configurationRepository = configurationRepository,
                 shadeRepository = shadeRepository,
@@ -72,6 +77,7 @@
         val repository: FakeKeyguardRepository,
         val commandQueue: FakeCommandQueue,
         val featureFlags: FakeFeatureFlags,
+        val sceneContainerFlags: SceneContainerFlags,
         val bouncerRepository: FakeKeyguardBouncerRepository,
         val configurationRepository: FakeConfigurationRepository,
         val shadeRepository: FakeShadeRepository,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
index 282d798..9dea0a0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
@@ -31,7 +31,7 @@
 import com.android.systemui.classifier.FalsingCollectorFake
 import com.android.systemui.classifier.domain.interactor.FalsingInteractor
 import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
-import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.FakeFeatureFlagsClassic
 import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.data.repository.FakeCommandQueue
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
@@ -43,6 +43,7 @@
 import com.android.systemui.power.data.repository.FakePowerRepository
 import com.android.systemui.scene.data.repository.SceneContainerRepository
 import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags
 import com.android.systemui.scene.shared.model.SceneContainerConfig
 import com.android.systemui.scene.shared.model.SceneKey
 import com.android.systemui.shade.data.repository.FakeShadeRepository
@@ -67,11 +68,8 @@
 ) {
     val testDispatcher = StandardTestDispatcher()
     val testScope = TestScope(testDispatcher)
-    val featureFlags =
-        FakeFeatureFlags().apply {
-            set(Flags.SCENE_CONTAINER, true)
-            set(Flags.FACE_AUTH_REFACTOR, false)
-        }
+    val featureFlags = FakeFeatureFlagsClassic().apply { set(Flags.FACE_AUTH_REFACTOR, false) }
+    val sceneContainerFlags = FakeSceneContainerFlags().apply { enabled = true }
     private val userRepository: UserRepository by lazy {
         FakeUserRepository().apply {
             val users = listOf(UserInfo(/* id=  */ 0, "name", /* flags= */ 0))
@@ -164,6 +162,7 @@
             repository = repository,
             commandQueue = FakeCommandQueue(),
             featureFlags = featureFlags,
+            sceneContainerFlags = sceneContainerFlags,
             bouncerRepository = FakeKeyguardBouncerRepository(),
             configurationRepository = FakeConfigurationRepository(),
             shadeRepository = FakeShadeRepository(),
@@ -181,7 +180,7 @@
             repository = BouncerRepository(),
             authenticationInteractor = authenticationInteractor,
             sceneInteractor = sceneInteractor,
-            featureFlags = featureFlags,
+            flags = sceneContainerFlags,
             falsingInteractor = falsingInteractor(),
         )
     }
@@ -195,7 +194,7 @@
             applicationScope = applicationScope(),
             bouncerInteractor = bouncerInteractor,
             authenticationInteractor = authenticationInteractor,
-            featureFlags = featureFlags,
+            flags = sceneContainerFlags,
         )
     }
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/flag/FakeSceneContainerFlags.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/flag/FakeSceneContainerFlags.kt
new file mode 100644
index 0000000..01a1ece
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/flag/FakeSceneContainerFlags.kt
@@ -0,0 +1,30 @@
+/*
+ * 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.systemui.scene.shared.flag
+
+class FakeSceneContainerFlags(
+    var enabled: Boolean = false,
+) : SceneContainerFlags {
+
+    override fun isEnabled(): Boolean {
+        return enabled
+    }
+
+    override fun requirementDescription(): String {
+        return ""
+    }
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index cbf4cce..93ba362 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -63,6 +63,7 @@
 import android.app.RemoteAction;
 import android.app.admin.DevicePolicyManager;
 import android.appwidget.AppWidgetManagerInternal;
+import android.companion.virtual.VirtualDeviceManager;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -928,18 +929,32 @@
         mContext.registerReceiverAsUser(receiver, UserHandle.ALL, filter, null, mMainHandler,
                 Context.RECEIVER_EXPORTED);
 
-        final BroadcastReceiver virtualDeviceReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                final int deviceId = intent.getIntExtra(
-                        EXTRA_VIRTUAL_DEVICE_ID, DEVICE_ID_DEFAULT);
-                mProxyManager.clearConnections(deviceId);
+        if (android.companion.virtual.flags.Flags.vdmPublicApis()) {
+            VirtualDeviceManager vdm = mContext.getSystemService(VirtualDeviceManager.class);
+            if (vdm != null) {
+                vdm.registerVirtualDeviceListener(mContext.getMainExecutor(),
+                        new VirtualDeviceManager.VirtualDeviceListener() {
+                            @Override
+                            public void onVirtualDeviceClosed(int deviceId) {
+                                mProxyManager.clearConnections(deviceId);
+                            }
+                        });
             }
-        };
+        } else {
+            final BroadcastReceiver virtualDeviceReceiver = new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    final int deviceId = intent.getIntExtra(
+                            EXTRA_VIRTUAL_DEVICE_ID, DEVICE_ID_DEFAULT);
+                    mProxyManager.clearConnections(deviceId);
+                }
+            };
 
-        final IntentFilter virtualDeviceFilter = new IntentFilter(ACTION_VIRTUAL_DEVICE_REMOVED);
-        mContext.registerReceiver(virtualDeviceReceiver, virtualDeviceFilter,
-                Context.RECEIVER_NOT_EXPORTED);
+            final IntentFilter virtualDeviceFilter = new IntentFilter(
+                    ACTION_VIRTUAL_DEVICE_REMOVED);
+            mContext.registerReceiver(virtualDeviceReceiver, virtualDeviceFilter,
+                    Context.RECEIVER_NOT_EXPORTED);
+        }
     }
 
     /**
diff --git a/services/autofill/Android.bp b/services/autofill/Android.bp
index eb23f2f..d43a219 100644
--- a/services/autofill/Android.bp
+++ b/services/autofill/Android.bp
@@ -19,4 +19,19 @@
     defaults: ["platform_service_defaults"],
     srcs: [":services.autofill-sources"],
     libs: ["services.core"],
+    static_libs: ["autofill_flags_java_lib"],
+}
+
+aconfig_declarations {
+    name: "autofill_flags",
+    package: "android.service.autofill",
+    srcs: [
+        "bugfixes.aconfig",
+        "features.aconfig",
+    ],
+}
+
+java_aconfig_library {
+    name: "autofill_flags_java_lib",
+    aconfig_declarations: "autofill_flags",
 }
diff --git a/services/autofill/bugfixes.aconfig b/services/autofill/bugfixes.aconfig
new file mode 100644
index 0000000..ef23754
--- /dev/null
+++ b/services/autofill/bugfixes.aconfig
@@ -0,0 +1,8 @@
+package: "android.service.autofill"
+
+flag {
+  name: "test"
+  namespace: "autofill"
+  description: "Test flag "
+  bug: "297380045"
+}
\ No newline at end of file
diff --git a/services/autofill/features.aconfig b/services/autofill/features.aconfig
new file mode 100644
index 0000000..1e44de6
--- /dev/null
+++ b/services/autofill/features.aconfig
@@ -0,0 +1 @@
+package: "android.service.autofill"
\ No newline at end of file
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index ec4203e..cad8fcf 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -594,8 +594,6 @@
 
     // Called by Shell command.
     int getMaxPartitions() {
-        enforceCallingPermissionForManagement();
-
         synchronized (mLock) {
             return sPartitionMaxCount;
         }
@@ -628,8 +626,6 @@
 
     // Called by Shell command.
     int getMaxVisibleDatasets() {
-        enforceCallingPermissionForManagement();
-
         synchronized (sLock) {
             return sVisibleDatasetsMaxCount;
         }
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
index c66fb81..39756df 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
@@ -26,11 +26,14 @@
 import android.os.ShellCommand;
 import android.os.UserHandle;
 import android.service.autofill.AutofillFieldClassificationService.Scores;
+import android.service.autofill.Flags;
 import android.view.autofill.AutofillManager;
 
 import com.android.internal.os.IResultReceiver;
 
 import java.io.PrintWriter;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -60,6 +63,8 @@
                 return requestGet(pw);
             case "set":
                 return requestSet(pw);
+            case "flags":
+                return requestFlags(pw);
             default:
                 return handleDefaultCommands(cmd);
         }
@@ -67,7 +72,7 @@
 
     @Override
     public void onHelp() {
-        try (final PrintWriter pw = getOutPrintWriter();) {
+        try (final PrintWriter pw = getOutPrintWriter(); ) {
             pw.println("AutoFill Service (autofill) commands:");
             pw.println("  help");
             pw.println("    Prints this help text.");
@@ -109,21 +114,24 @@
             pw.println("    Sets whether binding to services provided by instant apps is allowed");
             pw.println("");
             pw.println("  set temporary-augmented-service USER_ID [COMPONENT_NAME DURATION]");
-            pw.println("    Temporarily (for DURATION ms) changes the augmented autofill service "
-                    + "implementation.");
+            pw.println(
+                    "    Temporarily (for DURATION ms) changes the augmented autofill service "
+                            + "implementation.");
             pw.println("    To reset, call with just the USER_ID argument.");
             pw.println("");
             pw.println("  set default-augmented-service-enabled USER_ID [true|false]");
             pw.println("    Enable / disable the default augmented autofill service for the user.");
             pw.println("");
             pw.println("  set temporary-detection-service USER_ID [COMPONENT_NAME DURATION]");
-            pw.println("    Temporarily (for DURATION ms) changes the autofill detection service "
-                    + "implementation.");
+            pw.println(
+                    "    Temporarily (for DURATION ms) changes the autofill detection service "
+                            + "implementation.");
             pw.println("    To reset, call with [COMPONENT_NAME 0].");
             pw.println("");
             pw.println("  get default-augmented-service-enabled USER_ID");
-            pw.println("    Checks whether the default augmented autofill service is enabled for "
-                    + "the user.");
+            pw.println(
+                    "    Checks whether the default augmented autofill service is enabled for "
+                            + "the user.");
             pw.println("");
             pw.println("  list sessions [--user USER_ID]");
             pw.println("    Lists all pending sessions.");
@@ -134,9 +142,36 @@
             pw.println("  reset");
             pw.println("    Resets all pending sessions and cached service connections.");
             pw.println("");
+            pw.println("  flags");
+            pw.println("    Prints out all autofill related flags.");
+            pw.println("");
         }
     }
 
+    private int requestFlags(PrintWriter pw) {
+
+        if (Flags.test()) {
+            pw.println("Hello Flag World!");
+            pw.println("");
+        }
+
+        try {
+            Method[] flagMethods = Flags.class.getMethods();
+            // For some reason, unreferenced flags do not show up here
+            // Maybe compiler optomized them out of bytecode?
+            for (Method method : flagMethods) {
+                if (Modifier.isPublic(method.getModifiers())) {
+                    pw.println(method.getName() + ": " + method.invoke(null));
+                }
+            }
+        } catch (Exception ex) {
+            pw.println(ex);
+            return -1;
+        }
+
+        return 0;
+    }
+
     private int requestGet(PrintWriter pw) {
         final String what = getNextArgRequired();
         switch(what) {
diff --git a/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java b/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java
index 3cb9ac8..e8839a2 100644
--- a/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java
+++ b/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java
@@ -340,7 +340,7 @@
             return;
         }
 
-        mRole = Role.Initiator;
+        mRole = Role.INITIATOR;
         mHandshakeContext = D2DHandshakeContext.forInitiator();
         mClientInit = mHandshakeContext.getNextHandshakeMessage();
 
@@ -412,7 +412,7 @@
 
         // Proceed with the rest of Ukey2 handshake
         if (mHandshakeContext == null) { // Server-side logic
-            mRole = Role.Responder;
+            mRole = Role.RESPONDER;
             mHandshakeContext = D2DHandshakeContext.forResponder();
 
             // Receive Client Init
@@ -479,9 +479,9 @@
         }
         sendMessage(MessageType.PRE_SHARED_KEY, constructToken(mRole, mPreSharedKey));
         byte[] receivedAuthToken = readMessage(MessageType.PRE_SHARED_KEY);
-        byte[] expectedAuthToken = constructToken(mRole == Role.Initiator
-                ? Role.Responder
-                : Role.Initiator,
+        byte[] expectedAuthToken = constructToken(mRole == Role.INITIATOR
+                ? Role.RESPONDER
+                : Role.INITIATOR,
                 mPreSharedKey);
         mPskVerified = Arrays.equals(receivedAuthToken, expectedAuthToken);
 
@@ -515,9 +515,9 @@
         byte[] remoteAttestation = readMessage(MessageType.ATTESTATION);
 
         // Verifying remote attestation with public key local binding param
-        byte[] expectedChallenge = constructToken(mRole == Role.Initiator
-                ? Role.Responder
-                : Role.Initiator,
+        byte[] expectedChallenge = constructToken(mRole == Role.INITIATOR
+                ? Role.RESPONDER
+                : Role.INITIATOR,
                 mConnectionContext.getSessionUnique());
         mVerificationResult = mVerifier.verifyAttestation(remoteAttestation, expectedChallenge);
 
@@ -554,7 +554,7 @@
     // This information is needed to help resolve potential role collision.
     private byte[] constructHandshakeInitMessage(byte[] message) {
         return ByteBuffer.allocate(1 + message.length)
-                .put((byte) (Role.Initiator.equals(mRole) ? 0 : 1))
+                .put((byte) (Role.INITIATOR.equals(mRole) ? 0 : 1))
                 .put(message)
                 .array();
     }
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 9e7b897..b07a0bb 100644
--- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
+++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
@@ -27,8 +27,6 @@
 import android.app.WindowConfiguration;
 import android.app.compat.CompatChanges;
 import android.companion.virtual.VirtualDeviceManager.ActivityListener;
-import android.companion.virtual.VirtualDeviceParams;
-import android.companion.virtual.VirtualDeviceParams.ActivityPolicy;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledSince;
 import android.content.ComponentName;
@@ -108,18 +106,14 @@
     public static final long ALLOW_SECURE_ACTIVITY_DISPLAY_ON_REMOTE_DEVICE = 201712607L;
     @NonNull
     private final ArraySet<UserHandle> mAllowedUsers;
-    @Nullable
-    private final ArraySet<ComponentName> mAllowedCrossTaskNavigations;
-    @Nullable
-    private final ArraySet<ComponentName> mBlockedCrossTaskNavigations;
-    @Nullable
-    private final ArraySet<ComponentName> mAllowedActivities;
-    @Nullable
-    private final ArraySet<ComponentName> mBlockedActivities;
+    private final boolean mActivityLaunchAllowedByDefault;
+    @NonNull
+    private final ArraySet<ComponentName> mActivityPolicyExceptions;
+    private final boolean mCrossTaskNavigationAllowedByDefault;
+    @NonNull
+    private final ArraySet<ComponentName> mCrossTaskNavigationExceptions;
     private final Object mGenericWindowPolicyControllerLock = new Object();
-    @ActivityPolicy
-    private final int mDefaultActivityPolicy;
-    private final ActivityBlockedCallback mActivityBlockedCallback;
+    @Nullable private final ActivityBlockedCallback mActivityBlockedCallback;
     private int mDisplayId = Display.INVALID_DISPLAY;
 
     @NonNull
@@ -134,7 +128,7 @@
     private final ArraySet<RunningAppsChangedListener> mRunningAppsChangedListeners =
             new ArraySet<>();
     @Nullable private final SecureWindowCallback mSecureWindowCallback;
-    @Nullable private final Set<String> mDisplayCategories;
+    @NonNull private final Set<String> mDisplayCategories;
 
     @GuardedBy("mGenericWindowPolicyControllerLock")
     private boolean mShowTasksInHostDeviceRecents;
@@ -146,18 +140,14 @@
      * @param windowFlags The window flags that this controller is interested in.
      * @param systemWindowFlags The system window flags that this controller is interested in.
      * @param allowedUsers The set of users that are allowed to stream in this display.
-     * @param allowedCrossTaskNavigations The set of components explicitly allowed to navigate
-     *   across tasks on this device.
-     * @param blockedCrossTaskNavigations The set of components explicitly blocked from
-     *   navigating across tasks on this device.
-     * @param allowedActivities The set of activities explicitly allowed to stream on this device.
-     *   Used only if the {@code activityPolicy} is
-     *   {@link VirtualDeviceParams#ACTIVITY_POLICY_DEFAULT_BLOCKED}.
-     * @param blockedActivities The set of activities explicitly blocked from streaming on this
-     *   device. Used only if the {@code activityPolicy} is
-     *   {@link VirtualDeviceParams#ACTIVITY_POLICY_DEFAULT_ALLOWED}
-     * @param defaultActivityPolicy Whether activities are default allowed to be displayed or
-     *   blocked.
+     * @param activityLaunchAllowedByDefault Whether activities are default allowed to be launched
+     *   or blocked.
+     * @param activityPolicyExceptions The set of activities explicitly exempt from the default
+     *   activity policy.
+     * @param crossTaskNavigationAllowedByDefault Whether cross task navigations are allowed by
+     *   default or not.
+     * @param crossTaskNavigationExceptions The set of components explicitly exempt from the default
+     *   navigation policy.
      * @param activityListener Activity listener to listen for activity changes.
      * @param activityBlockedCallback Callback that is called when an activity is blocked from
      *   launching.
@@ -169,25 +159,23 @@
      */
     public GenericWindowPolicyController(int windowFlags, int systemWindowFlags,
             @NonNull ArraySet<UserHandle> allowedUsers,
-            @NonNull Set<ComponentName> allowedCrossTaskNavigations,
-            @NonNull Set<ComponentName> blockedCrossTaskNavigations,
-            @NonNull Set<ComponentName> allowedActivities,
-            @NonNull Set<ComponentName> blockedActivities,
-            @ActivityPolicy int defaultActivityPolicy,
-            @NonNull ActivityListener activityListener,
-            @NonNull PipBlockedCallback pipBlockedCallback,
-            @NonNull ActivityBlockedCallback activityBlockedCallback,
-            @NonNull SecureWindowCallback secureWindowCallback,
-            @NonNull IntentListenerCallback intentListenerCallback,
+            boolean activityLaunchAllowedByDefault,
+            @NonNull Set<ComponentName> activityPolicyExceptions,
+            boolean crossTaskNavigationAllowedByDefault,
+            @NonNull Set<ComponentName> crossTaskNavigationExceptions,
+            @Nullable ActivityListener activityListener,
+            @Nullable PipBlockedCallback pipBlockedCallback,
+            @Nullable ActivityBlockedCallback activityBlockedCallback,
+            @Nullable SecureWindowCallback secureWindowCallback,
+            @Nullable IntentListenerCallback intentListenerCallback,
             @NonNull Set<String> displayCategories,
             boolean showTasksInHostDeviceRecents) {
         super();
         mAllowedUsers = allowedUsers;
-        mAllowedCrossTaskNavigations = new ArraySet<>(allowedCrossTaskNavigations);
-        mBlockedCrossTaskNavigations = new ArraySet<>(blockedCrossTaskNavigations);
-        mAllowedActivities = new ArraySet<>(allowedActivities);
-        mBlockedActivities = new ArraySet<>(blockedActivities);
-        mDefaultActivityPolicy = defaultActivityPolicy;
+        mActivityLaunchAllowedByDefault = activityLaunchAllowedByDefault;
+        mActivityPolicyExceptions = new ArraySet<>(activityPolicyExceptions);
+        mCrossTaskNavigationAllowedByDefault = crossTaskNavigationAllowedByDefault;
+        mCrossTaskNavigationExceptions = new ArraySet<>(crossTaskNavigationExceptions);
         mActivityBlockedCallback = activityBlockedCallback;
         setInterestedWindowFlags(windowFlags, systemWindowFlags);
         mActivityListener = activityListener;
@@ -233,7 +221,9 @@
             @Nullable Intent intent, @WindowConfiguration.WindowingMode int windowingMode,
             int launchingFromDisplayId, boolean isNewTask) {
         if (!canContainActivity(activityInfo, windowingMode, launchingFromDisplayId, isNewTask)) {
-            mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
+            if (mActivityBlockedCallback != null) {
+                mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
+            }
             return false;
         }
         if (mIntentListenerCallback != null && intent != null
@@ -275,22 +265,17 @@
                     + mDisplayCategories);
             return false;
         }
-        if ((mDefaultActivityPolicy == VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_ALLOWED
-                && mBlockedActivities.contains(activityComponent))
-                || (mDefaultActivityPolicy == VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_BLOCKED
-                && !mAllowedActivities.contains(activityComponent))) {
+        if (!isAllowedByPolicy(mActivityLaunchAllowedByDefault, mActivityPolicyExceptions,
+                activityComponent)) {
             Slog.d(TAG, "Virtual device launch disallowed by policy: " + activityComponent);
             return false;
         }
-        if (isNewTask && launchingFromDisplayId != DEFAULT_DISPLAY) {
-            if ((!mBlockedCrossTaskNavigations.isEmpty()
-                    && mBlockedCrossTaskNavigations.contains(activityComponent))
-                    || ((!mAllowedCrossTaskNavigations.isEmpty()
-                    && !mAllowedCrossTaskNavigations.contains(activityComponent)))) {
-                Slog.d(TAG, "Virtual device cross task navigation disallowed by policy: "
-                        + activityComponent);
-                return false;
-            }
+        if (isNewTask && launchingFromDisplayId != DEFAULT_DISPLAY
+                && !isAllowedByPolicy(mCrossTaskNavigationAllowedByDefault,
+                        mCrossTaskNavigationExceptions, activityComponent)) {
+            Slog.d(TAG, "Virtual device cross task navigation disallowed by policy: "
+                    + activityComponent);
+            return false;
         }
 
         return true;
@@ -302,7 +287,7 @@
             int systemWindowFlags) {
         // The callback is fired only when windowFlags are changed. To let VirtualDevice owner
         // aware that the virtual display has a secure window on top.
-        if ((windowFlags & FLAG_SECURE) != 0) {
+        if ((windowFlags & FLAG_SECURE) != 0 && mSecureWindowCallback != null) {
             // Post callback on the main thread, so it doesn't block activity launching.
             mHandler.post(() -> mSecureWindowCallback.onSecureWindowShown(mDisplayId,
                     activityInfo.applicationInfo.uid));
@@ -314,7 +299,9 @@
             // TODO(b/201712607): Add checks for the apps that use SurfaceView#setSecure.
             if ((windowFlags & FLAG_SECURE) != 0
                     || (systemWindowFlags & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) {
-                mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
+                if (mActivityBlockedCallback != null) {
+                    mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
+                }
                 return false;
             }
         }
@@ -367,9 +354,9 @@
         if (super.isEnteringPipAllowed(uid)) {
             return true;
         }
-        mHandler.post(() -> {
-            mPipBlockedCallback.onEnteringPipBlocked(uid);
-        });
+        if (mPipBlockedCallback != null) {
+            mHandler.post(() -> mPipBlockedCallback.onEnteringPipBlocked(uid));
+        }
         return false;
     }
 
@@ -389,7 +376,13 @@
         }
         return activityInfo.requiredDisplayCategory != null
                     && mDisplayCategories.contains(activityInfo.requiredDisplayCategory);
+    }
 
+    private boolean isAllowedByPolicy(boolean allowedByDefault, ArraySet<ComponentName> exceptions,
+            ComponentName component) {
+        // Either allowed and the exceptions do not contain the component,
+        // or disallowed and the exceptions contain the component.
+        return allowedByDefault != exceptions.contains(component);
     }
 
     @VisibleForTesting
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 56afeb1..8f765e4 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -19,7 +19,9 @@
 import static android.app.admin.DevicePolicyManager.NEARBY_STREAMING_ENABLED;
 import static android.app.admin.DevicePolicyManager.NEARBY_STREAMING_NOT_CONTROLLED_BY_POLICY;
 import static android.app.admin.DevicePolicyManager.NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY;
+import static android.companion.virtual.VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_ALLOWED;
 import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
+import static android.companion.virtual.VirtualDeviceParams.NAVIGATION_POLICY_DEFAULT_ALLOWED;
 import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_RECENTS;
 import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
@@ -39,6 +41,7 @@
 import android.companion.virtual.IVirtualDeviceActivityListener;
 import android.companion.virtual.IVirtualDeviceIntentInterceptor;
 import android.companion.virtual.IVirtualDeviceSoundEffectListener;
+import android.companion.virtual.VirtualDevice;
 import android.companion.virtual.VirtualDeviceManager;
 import android.companion.virtual.VirtualDeviceManager.ActivityListener;
 import android.companion.virtual.VirtualDeviceParams;
@@ -168,6 +171,9 @@
     @Nullable
     private LocaleList mLocaleList = null;
 
+    @NonNull
+    private final VirtualDevice mPublicVirtualDeviceObject;
+
     private ActivityListener createListenerAdapter() {
         return new ActivityListener() {
 
@@ -286,6 +292,9 @@
             throw e.rethrowFromSystemServer();
         }
         mVirtualDeviceLog.logCreated(deviceId, mOwnerUid);
+
+        mPublicVirtualDeviceObject = new VirtualDevice(
+                this, getDeviceId(), getPersistentDeviceId(), mParams.getName());
     }
 
     @VisibleForTesting
@@ -315,9 +324,9 @@
         return mAssociationInfo.getDisplayName();
     }
 
-    /** Returns the optional name of the device. */
-    String getDeviceName() {
-        return mParams.getName();
+    /** Returns the public representation of the device. */
+    VirtualDevice getPublicVirtualDeviceObject() {
+        return mPublicVirtualDeviceObject;
     }
 
     /** Returns the locale of the device. */
@@ -327,7 +336,7 @@
         }
     }
 
-    /** Returns the policy specified for this policy type */
+    @Override  // Binder call
     public @VirtualDeviceParams.DevicePolicy int getDevicePolicy(
             @VirtualDeviceParams.PolicyType int policyType) {
         if (Flags.dynamicPolicy()) {
@@ -754,8 +763,10 @@
             synchronized (mVirtualDeviceLock) {
                 mDefaultShowPointerIcon = showPointerIcon;
             }
-            getDisplayIds().forEach(
-                    displayId -> mInputController.setShowPointerIcon(showPointerIcon, displayId));
+            final int[] displayIds = getDisplayIds();
+            for (int i = 0; i < displayIds.length; ++i) {
+                mInputController.setShowPointerIcon(showPointerIcon, displayIds[i]);
+            }
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
@@ -831,22 +842,31 @@
 
     private GenericWindowPolicyController createWindowPolicyController(
             @NonNull Set<String> displayCategories) {
-        final GenericWindowPolicyController gwpc =
-                new GenericWindowPolicyController(FLAG_SECURE,
-                        SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
-                        getAllowedUserHandles(),
-                        mParams.getAllowedCrossTaskNavigations(),
-                        mParams.getBlockedCrossTaskNavigations(),
-                        mParams.getAllowedActivities(),
-                        mParams.getBlockedActivities(),
-                        mParams.getDefaultActivityPolicy(),
-                        createListenerAdapter(),
-                        this::onEnteringPipBlocked,
-                        this::onActivityBlocked,
-                        this::onSecureWindowShown,
-                        this::shouldInterceptIntent,
-                        displayCategories,
-                        mParams.getDevicePolicy(POLICY_TYPE_RECENTS) == DEVICE_POLICY_DEFAULT);
+        final boolean activityLaunchAllowedByDefault =
+                mParams.getDefaultActivityPolicy() == ACTIVITY_POLICY_DEFAULT_ALLOWED;
+        final boolean crossTaskNavigationAllowedByDefault =
+                mParams.getDefaultNavigationPolicy() == NAVIGATION_POLICY_DEFAULT_ALLOWED;
+        final boolean showTasksInHostDeviceRecents =
+                mParams.getDevicePolicy(POLICY_TYPE_RECENTS) == DEVICE_POLICY_DEFAULT;
+
+        final GenericWindowPolicyController gwpc = new GenericWindowPolicyController(
+                FLAG_SECURE,
+                SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
+                getAllowedUserHandles(),
+                activityLaunchAllowedByDefault,
+                /*activityPolicyExceptions=*/activityLaunchAllowedByDefault
+                        ? mParams.getBlockedActivities() : mParams.getAllowedActivities(),
+                crossTaskNavigationAllowedByDefault,
+                /*crossTaskNavigationExceptions=*/crossTaskNavigationAllowedByDefault
+                        ? mParams.getBlockedCrossTaskNavigations()
+                        : mParams.getAllowedCrossTaskNavigations(),
+                createListenerAdapter(),
+                this::onEnteringPipBlocked,
+                this::onActivityBlocked,
+                this::onSecureWindowShown,
+                this::shouldInterceptIntent,
+                displayCategories,
+                showTasksInHostDeviceRecents);
         gwpc.registerRunningAppsChangedListener(/* listener= */ this);
         return gwpc;
     }
@@ -1018,14 +1038,15 @@
         return mOwnerUid;
     }
 
-    ArraySet<Integer> getDisplayIds() {
+    @Override  // Binder call
+    public int[] getDisplayIds() {
         synchronized (mVirtualDeviceLock) {
             final int size = mVirtualDisplays.size();
-            ArraySet<Integer> arraySet = new ArraySet<>(size);
+            int[] displayIds = new int[size];
             for (int i = 0; i < size; i++) {
-                arraySet.append(mVirtualDisplays.keyAt(i));
+                displayIds[i] = mVirtualDisplays.keyAt(i);
             }
-            return arraySet;
+            return displayIds;
         }
     }
 
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
index 4da9298..cfe56e9 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -30,6 +30,7 @@
 import android.companion.CompanionDeviceManager;
 import android.companion.virtual.IVirtualDevice;
 import android.companion.virtual.IVirtualDeviceActivityListener;
+import android.companion.virtual.IVirtualDeviceListener;
 import android.companion.virtual.IVirtualDeviceManager;
 import android.companion.virtual.IVirtualDeviceSoundEffectListener;
 import android.companion.virtual.VirtualDevice;
@@ -49,6 +50,7 @@
 import android.os.Looper;
 import android.os.Parcel;
 import android.os.Process;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.ArraySet;
@@ -70,6 +72,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
@@ -77,6 +80,7 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Consumer;
+import java.util.stream.Collectors;
 
 
 @SuppressLint("LongLogTag")
@@ -103,6 +107,9 @@
                 }
             };
 
+    private final RemoteCallbackList<IVirtualDeviceListener> mVirtualDeviceListeners =
+            new RemoteCallbackList<>();
+
     /**
      * Mapping from device IDs to virtual devices.
      */
@@ -225,6 +232,17 @@
             mVirtualDevices.remove(deviceId);
         }
 
+        if (Flags.vdmPublicApis()) {
+            mVirtualDeviceListeners.broadcast(listener -> {
+                try {
+                    listener.onVirtualDeviceClosed(deviceId);
+                } catch (RemoteException e) {
+                    Slog.i(TAG, "Failed to invoke onVirtualDeviceClosed listener: "
+                            + e.getMessage());
+                }
+            });
+        }
+
         Intent i = new Intent(VirtualDeviceManager.ACTION_VIRTUAL_DEVICE_REMOVED);
         i.putExtra(VirtualDeviceManager.EXTRA_VIRTUAL_DEVICE_ID, deviceId);
         i.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
@@ -376,6 +394,17 @@
                 }
                 mVirtualDevices.put(deviceId, virtualDevice);
             }
+
+            if (Flags.vdmPublicApis()) {
+                mVirtualDeviceListeners.broadcast(listener -> {
+                    try {
+                        listener.onVirtualDeviceCreated(deviceId);
+                    } catch (RemoteException e) {
+                        Slog.i(TAG, "Failed to invoke onVirtualDeviceCreated listener: "
+                                + e.getMessage());
+                    }
+                });
+            }
             return virtualDevice;
         }
 
@@ -415,14 +444,31 @@
             synchronized (mVirtualDeviceManagerLock) {
                 for (int i = 0; i < mVirtualDevices.size(); i++) {
                     final VirtualDeviceImpl device = mVirtualDevices.valueAt(i);
-                    virtualDevices.add(
-                            new VirtualDevice(device.getDeviceId(), device.getPersistentDeviceId(),
-                                    device.getDeviceName()));
+                    virtualDevices.add(device.getPublicVirtualDeviceObject());
                 }
             }
             return virtualDevices;
         }
 
+        @Override // Binder call
+        public VirtualDevice getVirtualDevice(int deviceId) {
+            VirtualDeviceImpl device;
+            synchronized (mVirtualDeviceManagerLock) {
+                device = mVirtualDevices.get(deviceId);
+            }
+            return device == null ? null : device.getPublicVirtualDeviceObject();
+        }
+
+        @Override // Binder call
+        public void registerVirtualDeviceListener(IVirtualDeviceListener listener) {
+            mVirtualDeviceListeners.register(listener);
+        }
+
+        @Override // Binder call
+        public void unregisterVirtualDeviceListener(IVirtualDeviceListener listener) {
+            mVirtualDeviceListeners.unregister(listener);
+        }
+
         @Override // BinderCall
         @VirtualDeviceParams.DevicePolicy
         public int getDevicePolicy(int deviceId, @VirtualDeviceParams.PolicyType int policyType) {
@@ -705,7 +751,9 @@
             synchronized (mVirtualDeviceManagerLock) {
                 virtualDevice = mVirtualDevices.get(deviceId);
             }
-            return virtualDevice == null ? new ArraySet<>() : virtualDevice.getDisplayIds();
+            return virtualDevice == null ? new ArraySet<>()
+                    : Arrays.stream(virtualDevice.getDisplayIds()).boxed()
+                            .collect(Collectors.toCollection(ArraySet::new));
         }
 
         @Override
diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS
index ef15beb..bf7cc10 100644
--- a/services/core/java/com/android/server/am/OWNERS
+++ b/services/core/java/com/android/server/am/OWNERS
@@ -32,7 +32,7 @@
 per-file *Assist* = file:/core/java/android/service/voice/OWNERS
 per-file *Voice* = file:/core/java/android/service/voice/OWNERS
 
-per-file SettingsToPropertiesMapper.java = omakoto@google.com, yamasani@google.com
+per-file SettingsToPropertiesMapper.java = omakoto@google.com, yamasani@google.com, dzshen@google.com, zhidou@google.com, tedbauer@google.com
 
 per-file CarUserSwitchingDialog.java = file:platform/packages/services/Car:/OWNERS
 
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 38c6a52..906c66d 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -144,6 +144,7 @@
     private final VirtualDeviceManagerInternal mVdmInternal;
     private final VirtualDeviceManager mVdm;
     private BroadcastReceiver mVirtualDeviceRemovedReceiver;
+    private VirtualDeviceManager.VirtualDeviceListener mVirtualDeviceListener;
     private final IUserManager mUm;
     private final PackageManager mPm;
     private final AppOpsManager mAppOps;
@@ -216,12 +217,14 @@
     @Override
     public void onStart() {
         publishBinderService(Context.CLIPBOARD_SERVICE, new ClipboardImpl());
-        if (mVdmInternal != null) {
-            registerVirtualDeviceRemovedListener();
+        if (!android.companion.virtual.flags.Flags.vdmPublicApis() && mVdmInternal != null) {
+            registerVirtualDeviceBroadcastReceiver();
+        } else if (android.companion.virtual.flags.Flags.vdmPublicApis() && mVdm != null) {
+            registerVirtualDeviceListener();
         }
     }
 
-    private void registerVirtualDeviceRemovedListener() {
+    private void registerVirtualDeviceBroadcastReceiver() {
         if (mVirtualDeviceRemovedReceiver != null) {
             return;
         }
@@ -245,6 +248,23 @@
                 Context.RECEIVER_NOT_EXPORTED);
     }
 
+    private void registerVirtualDeviceListener() {
+        if (mVirtualDeviceListener != null) {
+            return;
+        }
+        mVirtualDeviceListener = new VirtualDeviceManager.VirtualDeviceListener() {
+            @Override
+            public void onVirtualDeviceClosed(int deviceId) {
+                synchronized (mLock) {
+                    for (int i = mClipboards.numMaps() - 1; i >= 0; i--) {
+                        mClipboards.delete(mClipboards.keyAt(i), deviceId);
+                    }
+                }
+            }
+        };
+        mVdm.registerVirtualDeviceListener(getContext().getMainExecutor(), mVirtualDeviceListener);
+    }
+
     @Override
     public void onUserStopped(@NonNull TargetUser user) {
         synchronized (mLock) {
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index df2a830..99a5398 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -25,6 +25,7 @@
 import android.hardware.display.BrightnessConfiguration;
 import android.hardware.display.BrightnessCorrection;
 import android.os.PowerManager;
+import android.util.LongArray;
 import android.util.MathUtils;
 import android.util.Pair;
 import android.util.Slog;
@@ -37,7 +38,11 @@
 import com.android.server.display.whitebalance.DisplayWhiteBalanceController;
 
 import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
 import java.util.Locale;
 import java.util.Objects;
 
@@ -840,6 +845,13 @@
         private final boolean mIsForIdleMode;
         private final DisplayWhiteBalanceController mDisplayWhiteBalanceController;
 
+        // Previous short-term models and the times that they were computed stored for debugging
+        // purposes
+        private List<Spline> mPreviousBrightnessSplines = new ArrayList<>();
+        private LongArray mBrightnessSplineChangeTimes = new LongArray();
+        private static final int NO_OF_PREVIOUS_CONFIGS_TO_LOG = 5;
+        private static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
+
         public PhysicalMappingStrategy(BrightnessConfiguration config, float[] nits,
                 float[] brightness, float maxGamma, boolean isForIdleMode,
                 DisplayWhiteBalanceController displayWhiteBalanceController) {
@@ -982,6 +994,13 @@
             mUserLux = lux;
             mUserBrightness = brightness;
             computeSpline();
+
+            if (mPreviousBrightnessSplines.size() == NO_OF_PREVIOUS_CONFIGS_TO_LOG) {
+                mPreviousBrightnessSplines.remove(0);
+                mBrightnessSplineChangeTimes.remove(0);
+            }
+            mPreviousBrightnessSplines.add(mBrightnessSpline);
+            mBrightnessSplineChangeTimes.add(System.currentTimeMillis());
         }
 
         @Override
@@ -1042,7 +1061,16 @@
             pw.println("  mDefaultConfig=" + mDefaultConfig);
             pw.println("  mBrightnessRangeAdjustmentApplied=" + mBrightnessRangeAdjustmentApplied);
 
-            dumpConfigDiff(pw, hbmTransition);
+            pw.println("  Previous short-term models (oldest to newest): ");
+            for (int i = 0; i < mPreviousBrightnessSplines.size(); i++) {
+                pw.println("  Computed at "
+                        + FORMAT.format(new Date(mBrightnessSplineChangeTimes.get(i))) + ": ");
+                dumpConfigDiff(pw, hbmTransition, mPreviousBrightnessSplines.get(i),
+                        /* shortTermModelOnly= */ true);
+            }
+
+            pw.println("  Difference between current config and default: ");
+            dumpConfigDiff(pw, hbmTransition, mBrightnessSpline, /* shortTermModelOnly= */ false);
         }
 
         @Override
@@ -1066,9 +1094,8 @@
          *
          * @param pw The print-writer to write to.
          */
-        private void dumpConfigDiff(PrintWriter pw, float hbmTransition) {
-            pw.println("  Difference between current config and default: ");
-
+        private void dumpConfigDiff(PrintWriter pw, float hbmTransition, Spline brightnessSpline,
+                boolean shortTermModelOnly) {
             Pair<float[], float[]> currentCurve = mConfig.getCurve();
             Spline currSpline = Spline.createSpline(currentCurve.first, currentCurve.second);
 
@@ -1107,7 +1134,7 @@
 
                 float defaultNits = defaultSpline.interpolate(lux);
                 float longTermNits = currSpline.interpolate(lux);
-                float shortTermNits = mBrightnessSpline.interpolate(lux);
+                float shortTermNits = brightnessSpline.interpolate(lux);
                 float brightness = mAdjustedNitsToBrightnessSpline.interpolate(shortTermNits);
 
                 String luxPrefix = (lux == mUserLux ? "^" : "");
@@ -1142,8 +1169,10 @@
                 // At 80 chars, start another row
                 if (sbLux.length() > 80 || (i == luxes.length - 1)) {
                     pw.println(sbLux);
-                    pw.println(sbNits);
-                    pw.println(sbLong);
+                    if (!shortTermModelOnly) {
+                        pw.println(sbNits);
+                        pw.println(sbLong);
+                    }
                     pw.println(sbShort);
                     pw.println(sbBrightness);
                     pw.println(sbPercent);
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index f3ad4b4..90c7ce7 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -146,6 +146,7 @@
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.SettingsWrapper;
 import com.android.server.AnimationThread;
 import com.android.server.DisplayThread;
 import com.android.server.LocalServices;
@@ -159,7 +160,7 @@
 import com.android.server.display.mode.DisplayModeDirector;
 import com.android.server.display.utils.SensorUtils;
 import com.android.server.input.InputManagerInternal;
-import com.android.server.utils.FoldSettingWrapper;
+import com.android.server.utils.FoldSettingProvider;
 import com.android.server.wm.SurfaceAnimationThread;
 import com.android.server.wm.WindowManagerInternal;
 
@@ -549,9 +550,9 @@
         mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper());
         mUiHandler = UiThread.getHandler();
         mDisplayDeviceRepo = new DisplayDeviceRepository(mSyncRoot, mPersistentDataStore);
-        mLogicalDisplayMapper = new LogicalDisplayMapper(mContext, mDisplayDeviceRepo,
-                new LogicalDisplayListener(), mSyncRoot, mHandler,
-                new FoldSettingWrapper(mContext.getContentResolver()), mFlags);
+        mLogicalDisplayMapper = new LogicalDisplayMapper(mContext,
+                new FoldSettingProvider(mContext, new SettingsWrapper()), mDisplayDeviceRepo,
+                new LogicalDisplayListener(), mSyncRoot, mHandler, mFlags);
         mDisplayModeDirector = new DisplayModeDirector(context, mHandler);
         mBrightnessSynchronizer = new BrightnessSynchronizer(mContext);
         Resources resources = mContext.getResources();
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index cbe0fc7..b3b16ad 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -43,7 +43,7 @@
 import com.android.server.display.feature.DisplayManagerFlags;
 import com.android.server.display.layout.DisplayIdProducer;
 import com.android.server.display.layout.Layout;
-import com.android.server.utils.FoldSettingWrapper;
+import com.android.server.utils.FoldSettingProvider;
 
 import java.io.PrintWriter;
 import java.util.Arrays;
@@ -149,7 +149,7 @@
     private final Listener mListener;
     private final DisplayManagerService.SyncRoot mSyncRoot;
     private final LogicalDisplayMapperHandler mHandler;
-    private final FoldSettingWrapper mFoldSettingWrapper;
+    private final FoldSettingProvider mFoldSettingProvider;
     private final PowerManager mPowerManager;
 
     /**
@@ -196,26 +196,27 @@
     private boolean mInteractive;
     private final DisplayManagerFlags mFlags;
 
-    LogicalDisplayMapper(@NonNull Context context, @NonNull DisplayDeviceRepository repo,
+    LogicalDisplayMapper(@NonNull Context context, FoldSettingProvider foldSettingProvider,
+            @NonNull DisplayDeviceRepository repo,
             @NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot,
-            @NonNull Handler handler, FoldSettingWrapper foldSettingWrapper,
-            DisplayManagerFlags flags) {
-        this(context, repo, listener, syncRoot, handler, new DeviceStateToLayoutMap(
-                (isDefault) -> isDefault ? DEFAULT_DISPLAY : sNextNonDefaultDisplayId++),
-                foldSettingWrapper, flags);
+            @NonNull Handler handler, DisplayManagerFlags flags) {
+        this(context, foldSettingProvider, repo, listener, syncRoot, handler,
+                new DeviceStateToLayoutMap((isDefault) -> isDefault ? DEFAULT_DISPLAY
+                        : sNextNonDefaultDisplayId++), flags);
     }
 
-    LogicalDisplayMapper(@NonNull Context context, @NonNull DisplayDeviceRepository repo,
+    LogicalDisplayMapper(@NonNull Context context, FoldSettingProvider foldSettingProvider,
+            @NonNull DisplayDeviceRepository repo,
             @NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot,
             @NonNull Handler handler, @NonNull DeviceStateToLayoutMap deviceStateToLayoutMap,
-            FoldSettingWrapper foldSettingWrapper, DisplayManagerFlags flags) {
+            DisplayManagerFlags flags) {
         mSyncRoot = syncRoot;
         mPowerManager = context.getSystemService(PowerManager.class);
         mInteractive = mPowerManager.isInteractive();
         mHandler = new LogicalDisplayMapperHandler(handler.getLooper());
         mDisplayDeviceRepo = repo;
         mListener = listener;
-        mFoldSettingWrapper = foldSettingWrapper;
+        mFoldSettingProvider = foldSettingProvider;
         mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);
         mSupportsConcurrentInternalDisplays = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_supportsConcurrentInternalDisplays);
@@ -488,10 +489,13 @@
                 });
             } else if (sleepDevice) {
                 // Send the device to sleep when required.
+                int goToSleepFlag =
+                        mFoldSettingProvider.shouldSleepOnFold() ? 0
+                                : PowerManager.GO_TO_SLEEP_FLAG_SOFT_SLEEP;
                 mHandler.post(() -> {
                     mPowerManager.goToSleep(SystemClock.uptimeMillis(),
                             PowerManager.GO_TO_SLEEP_REASON_DEVICE_FOLD,
-                            PowerManager.GO_TO_SLEEP_FLAG_SOFT_SLEEP);
+                            goToSleepFlag);
                 });
             }
         }
@@ -565,7 +569,8 @@
                 && mDeviceStatesOnWhichToSleep.get(pendingState)
                 && !mDeviceStatesOnWhichToSleep.get(currentState)
                 && !isOverrideActive
-                && isInteractive && isBootCompleted && !mFoldSettingWrapper.shouldStayAwakeOnFold();
+                && isInteractive && isBootCompleted
+                && !mFoldSettingProvider.shouldStayAwakeOnFold();
     }
 
     private boolean areAllTransitioningDisplaysOffLocked() {
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 1ec8b10..131eec3 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -116,6 +116,7 @@
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.proto.ProtoOutputStream;
+import android.view.IWindowManager;
 import android.view.InputChannel;
 import android.view.InputDevice;
 import android.view.MotionEvent;
@@ -123,6 +124,7 @@
 import android.view.WindowManager.DisplayImePolicy;
 import android.view.WindowManager.LayoutParams;
 import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
+import android.view.WindowManagerGlobal;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.ImeTracker;
 import android.view.inputmethod.InputBinding;
@@ -2988,7 +2990,8 @@
                     "Waiting for the lazy init of mImeDrawsImeNavBarRes");
         }
         final boolean canImeDrawsImeNavBar =
-                mImeDrawsImeNavBarRes != null && mImeDrawsImeNavBarRes.get();
+                mImeDrawsImeNavBarRes != null && mImeDrawsImeNavBarRes.get()
+                        && hasNavigationBarOnCurrentDisplay();
         final boolean shouldShowImeSwitcherWhenImeIsShown = shouldShowImeSwitcherLocked(
                 InputMethodService.IME_ACTIVE | InputMethodService.IME_VISIBLE);
         return (canImeDrawsImeNavBar ? InputMethodNavButtonFlags.IME_DRAWS_IME_NAV_BAR : 0)
@@ -2996,6 +2999,21 @@
                 ? InputMethodNavButtonFlags.SHOW_IME_SWITCHER_WHEN_IME_IS_SHOWN : 0);
     }
 
+    /**
+     * Whether the current display has a navigation bar. When this is {@code false} (e.g. emulator),
+     * the IME should <em>not</em> draw the IME navigation bar.
+     */
+    @GuardedBy("ImfLock.class")
+    private boolean hasNavigationBarOnCurrentDisplay() {
+        final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+        try {
+            return wm.hasNavigationBar(mCurTokenDisplayId != INVALID_DISPLAY
+                    ? mCurTokenDisplayId : DEFAULT_DISPLAY);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     @GuardedBy("ImfLock.class")
     private boolean shouldShowImeSwitcherLocked(int visibility) {
         if (!mShowOngoingImeSwitcherForPhones) return false;
diff --git a/services/core/java/com/android/server/notification/NotificationBitmapJobService.java b/services/core/java/com/android/server/notification/NotificationBitmapJobService.java
new file mode 100644
index 0000000..4335a1d
--- /dev/null
+++ b/services/core/java/com/android/server/notification/NotificationBitmapJobService.java
@@ -0,0 +1,123 @@
+/**
+ * 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.notification;
+
+import static android.app.job.JobScheduler.RESULT_SUCCESS;
+
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.CancellationSignal;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.LocalServices;
+
+import java.util.Calendar;
+
+/**
+ * This service runs everyday at 2am local time to remove expired bitmaps.
+ */
+public class NotificationBitmapJobService extends JobService {
+    static final String TAG = "NotificationBitmapJob";
+
+    static final int BASE_JOB_ID = 290381858; // Feature bug id
+
+    static void scheduleJob(Context context) {
+        if (context == null) {
+            return;
+        }
+        try {
+            JobScheduler jobScheduler =
+                    context.getSystemService(JobScheduler.class).forNamespace(TAG);
+
+            ComponentName component =
+                    new ComponentName(context, NotificationBitmapJobService.class);
+
+            JobInfo jobInfo = new JobInfo.Builder(BASE_JOB_ID, component)
+                    .setRequiresDeviceIdle(true)
+                    .setMinimumLatency(getRunAfterMs())
+                    .build();
+
+            final int result = jobScheduler.schedule(jobInfo);
+            if (result != RESULT_SUCCESS) {
+                Slog.e(TAG, "Failed to schedule bitmap removal job");
+            }
+
+        } catch (Throwable e) {
+            Slog.wtf(TAG, "Failed bitmap removal job", e);
+        }
+    }
+
+    /**
+     * @return Milliseconds until the next time the job should run.
+     */
+    private static long getRunAfterMs() {
+        Calendar cal = Calendar.getInstance();  // Uses local time zone
+        final long now = cal.getTimeInMillis();
+
+        cal.set(Calendar.HOUR_OF_DAY, 2);
+        cal.set(Calendar.MINUTE, 0);
+        cal.set(Calendar.MILLISECOND, 0);
+        final long today2AM = cal.getTimeInMillis();
+
+        cal.add(Calendar.DAY_OF_YEAR, 1);
+        final long tomorrow2AM = cal.getTimeInMillis();
+
+        return getTimeUntilRemoval(now, today2AM, tomorrow2AM);
+    }
+
+    @VisibleForTesting
+    static long getTimeUntilRemoval(long now, long today2AM, long tomorrow2AM) {
+        if (now < today2AM) {
+            return today2AM - now;
+        }
+        return tomorrow2AM - now;
+    }
+
+    @Override
+    public boolean onStartJob(JobParameters params) {
+        new Thread(() -> {
+            NotificationManagerInternal nmInternal =
+                    LocalServices.getService(NotificationManagerInternal.class);
+            nmInternal.removeBitmaps();
+
+            // Schedule the next job here, since we cannot use setPeriodic and setMinimumLatency
+            // together when creating JobInfo.
+            scheduleJob(/* context= */ this);
+
+            jobFinished(params, /* wantsReschedule= */ false);
+        }).start();
+
+        return true;  // This service continues to run in a separate thread.
+    }
+
+    @Override
+    public boolean onStopJob(JobParameters params) {
+        // No need to keep this job alive since the original thread is going to keep running and
+        // call scheduleJob at the end of its execution.
+        return false;
+    }
+
+    @Override
+    @VisibleForTesting
+    protected void attachBaseContext(Context base) {
+        super.attachBaseContext(base);
+    }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/notification/NotificationManagerInternal.java b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
index c240bcb..b12180b 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerInternal.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
@@ -52,4 +52,6 @@
     void sendReviewPermissionsNotification();
 
     void cleanupHistoryFiles();
+
+    void removeBitmaps();
 }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 69b9e25..ec071a7 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -132,6 +132,7 @@
 import static com.android.server.utils.PriorityDump.PRIORITY_ARG;
 import static com.android.server.utils.PriorityDump.PRIORITY_ARG_CRITICAL;
 import static com.android.server.utils.PriorityDump.PRIORITY_ARG_NORMAL;
+import static com.android.server.notification.Flags.expireBitmaps;
 
 import android.Manifest;
 import android.Manifest.permission;
@@ -203,6 +204,8 @@
 import android.content.pm.VersionedPackage;
 import android.content.res.Resources;
 import android.database.ContentObserver;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Icon;
 import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.AudioManagerInternal;
@@ -389,6 +392,8 @@
     static final int MESSAGE_FINISH_TOKEN_TIMEOUT = 7;
     static final int MESSAGE_ON_PACKAGE_CHANGED = 8;
 
+    static final long BITMAP_EXPIRATION_TIME_MS = TimeUnit.HOURS.toMillis(24);
+
     // ranking thread messages
     private static final int MESSAGE_RECONSIDER_RANKING = 1000;
     private static final int MESSAGE_RANKING_SORT = 1001;
@@ -2822,6 +2827,9 @@
             mAssistants.onBootPhaseAppsCanStart();
             mConditionProviders.onBootPhaseAppsCanStart();
             mHistoryManager.onBootPhaseAppsCanStart();
+            if (expireBitmaps()) {
+                NotificationBitmapJobService.scheduleJob(getContext());
+            }
             registerDeviceConfigChange();
             migrateDefaultNAS();
             maybeShowInitialReviewPermissionsNotification();
@@ -6604,8 +6612,72 @@
             checkCallerIsSystem();
             mHistoryManager.cleanupHistoryFiles();
         }
+
+        @Override
+        public void removeBitmaps() {
+            // Check all NotificationRecords, remove expired bitmaps and icon URIs, repost silently.
+            synchronized (mNotificationLock) {
+                for (NotificationRecord r: mNotificationList) {
+
+                    // System#currentTimeMillis when posted
+                    final long timePostedMs = r.getSbn().getPostTime();
+                    final long timeNowMs = System.currentTimeMillis();
+
+                    if (isBitmapExpired(timePostedMs, timeNowMs, BITMAP_EXPIRATION_TIME_MS)) {
+                        removeBitmapAndRepost(r);
+                    }
+                }
+            }
+        }
     };
 
+    @VisibleForTesting
+    static boolean isBigPictureWithBitmapOrIcon(Notification n) {
+        final boolean isBigPicture = n.isStyle(Notification.BigPictureStyle.class);
+        if (!isBigPicture) {
+            return false;
+        }
+
+        final boolean hasBitmap = n.extras.containsKey(Notification.EXTRA_PICTURE);
+        if (hasBitmap) {
+            return true;
+        }
+
+        final boolean hasIcon = n.extras.containsKey(Notification.EXTRA_PICTURE_ICON);
+        if (hasIcon) {
+            return true;
+        }
+        return false;
+    }
+
+    @VisibleForTesting
+    // TODO(b/298414239) Unit test via public API
+    static boolean isBitmapExpired(long timePostedMs, long timeNowMs, long timeToLiveMs) {
+        final long timeDiff = timeNowMs - timePostedMs;
+        return timeDiff > timeToLiveMs;
+    }
+
+    @VisibleForTesting
+    void removeBitmapAndRepost(NotificationRecord r) {
+        if (!isBigPictureWithBitmapOrIcon(r.getNotification())) {
+            return;
+        }
+        // Remove Notification object's reference to picture bitmap or URI
+        r.getNotification().extras.remove(Notification.EXTRA_PICTURE);
+        r.getNotification().extras.remove(Notification.EXTRA_PICTURE_ICON);
+
+        // Make Notification silent
+        r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE;
+
+        // Repost
+        enqueueNotificationInternal(r.getSbn().getPackageName(),
+                r.getSbn().getOpPkg(), r.getSbn().getUid(),
+                r.getSbn().getInitialPid(), r.getSbn().getTag(),
+                r.getSbn().getId(), r.getNotification(),
+                r.getSbn().getUserId(), /* postSilently= */ true,
+                /* byForegroundService= */ false);
+    }
+
     int getNumNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted) {
         return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted).getList()
                 .size();
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index b8feb4d..967998a 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -435,6 +435,12 @@
         }
 
         final int userId = user == null ? UserHandle.USER_ALL : user.getIdentifier();
+        if (outInfo != null) {
+            // Remember which users are affected, before the installed states are modified
+            outInfo.mRemovedUsers = (systemApp || userId == UserHandle.USER_ALL)
+                    ? ps.queryInstalledUsers(allUserHandles, /* installed= */true)
+                    : new int[]{userId};
+        }
 
         if ((!systemApp || (flags & PackageManager.DELETE_SYSTEM_APP) != 0)
                 && userId != UserHandle.USER_ALL) {
@@ -630,7 +636,6 @@
             // Preserve data by setting flag
             flags |= PackageManager.DELETE_KEEP_DATA;
         }
-
         synchronized (mPm.mInstallLock) {
             deleteInstalledPackageLIF(deletedPs, true, flags, allUserHandles, outInfo,
                     writeSettings);
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index dd04340..2712fa7 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -44,7 +44,6 @@
 import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
 import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
 import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL;
-
 import static com.android.server.pm.DexOptHelper.useArtService;
 import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
@@ -1144,8 +1143,7 @@
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
         final ParsedPackage parsedPackage;
         try (PackageParser2 pp = mPm.mInjector.getPreparingPackageParser()) {
-            if (request.getPackageLite() == null || !PackageInstallerSession.isArchivedInstallation(
-                    request.getInstallFlags())) {
+            if (request.getPackageLite() == null || !request.isArchived()) {
                 // TODO: pass packageLite from install request instead of reparsing the package
                 parsedPackage = pp.parsePackage(tmpPackageFile, parseFlags, false);
                 AndroidPackageUtils.validatePackageDexMetadata(parsedPackage);
@@ -3556,7 +3554,7 @@
                 logCriticalInfo(Log.WARN, "System package " + packageName
                         + " no longer exists; its data will be wiped");
                 mInjector.getHandler().post(
-                        () -> mRemovePackageHelper.removePackageData(ps, userIds, null, 0, false));
+                        () -> mRemovePackageHelper.removePackageData(ps, userIds));
                 expectingBetter.put(ps.getPackageName(), ps.getPath());
             } else {
                 // we still have a disabled system package, but, it still might have
@@ -3631,7 +3629,7 @@
             // partition], completely remove the package data.
             final PackageSetting ps = mPm.mSettings.getPackageLPr(packageName);
             if (ps != null && mPm.mPackages.get(packageName) == null) {
-                mRemovePackageHelper.removePackageData(ps, userIds, null, 0, false);
+                mRemovePackageHelper.removePackageData(ps, userIds);
             }
             logCriticalInfo(Log.WARN, msg);
         }
diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java
index fe7c086..e1cfc41 100644
--- a/services/core/java/com/android/server/pm/InstallRequest.java
+++ b/services/core/java/com/android/server/pm/InstallRequest.java
@@ -21,7 +21,6 @@
 import static android.content.pm.PackageManager.INSTALL_SCENARIO_DEFAULT;
 import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
 import static android.os.Process.INVALID_UID;
-
 import static com.android.server.pm.PackageManagerService.SCAN_AS_INSTANT_APP;
 import static com.android.server.pm.PackageManagerService.TAG;
 
@@ -327,6 +326,10 @@
         return mRemovedInfo != null && mRemovedInfo.mRemovedPackage != null;
     }
 
+    public boolean isArchived() {
+        return PackageInstallerSession.isArchivedInstallation(getInstallFlags());
+    }
+
     @Nullable
     public String getRemovedPackage() {
         return mRemovedInfo != null ? mRemovedInfo.mRemovedPackage : null;
diff --git a/services/core/java/com/android/server/pm/PackageArchiverService.java b/services/core/java/com/android/server/pm/PackageArchiverService.java
index 29f49c8..c7f067b 100644
--- a/services/core/java/com/android/server/pm/PackageArchiverService.java
+++ b/services/core/java/com/android/server/pm/PackageArchiverService.java
@@ -112,16 +112,15 @@
                 callerPackageName, DELETE_KEEP_DATA, intentSender, userId);
     }
 
-    private ArchiveState createArchiveState(String packageName, int userId)
+    /**
+     * Creates archived state for the package and user.
+     */
+    public ArchiveState createArchiveState(String packageName, int userId)
             throws PackageManager.NameNotFoundException {
         PackageStateInternal ps = getPackageState(packageName, mPm.snapshotComputer(),
                 Binder.getCallingUid(), userId);
         String responsibleInstallerPackage = getResponsibleInstallerPackage(ps);
-        if (responsibleInstallerPackage == null) {
-            throw new PackageManager.NameNotFoundException(
-                    TextUtils.formatSimple("No installer found to archive app %s.",
-                            packageName));
-        }
+        verifyInstaller(responsibleInstallerPackage);
 
         List<LauncherActivityInfo> mainActivities = getLauncherActivityInfos(ps, userId);
         List<ArchiveActivityInfo> archiveActivityInfos = new ArrayList<>();
@@ -136,6 +135,26 @@
         return new ArchiveState(archiveActivityInfos, responsibleInstallerPackage);
     }
 
+    private void verifyInstaller(String installerPackage)
+            throws PackageManager.NameNotFoundException {
+        if (TextUtils.isEmpty(installerPackage)) {
+            throw new PackageManager.NameNotFoundException("No installer found");
+        }
+        if (!verifySupportsUnarchival(installerPackage)) {
+            throw new PackageManager.NameNotFoundException("Installer does not support unarchival");
+        }
+    }
+
+    /**
+     * @return true if installerPackage support unarchival:
+     * - has an action Intent.ACTION_UNARCHIVE_PACKAGE,
+     * - has permissions to install packages.
+     */
+    public boolean verifySupportsUnarchival(String installerPackage) {
+        // TODO(b/278553670) Check if installerPackage supports unarchival.
+        return true;
+    }
+
     @Override
     public void requestUnarchive(
             @NonNull String packageName,
@@ -246,7 +265,7 @@
     }
 
     private String getResponsibleInstallerPackage(PackageStateInternal ps) {
-        return ps.getInstallSource().mUpdateOwnerPackageName == null
+        return TextUtils.isEmpty(ps.getInstallSource().mUpdateOwnerPackageName)
                 ? ps.getInstallSource().mInstallerPackageName
                 : ps.getInstallSource().mUpdateOwnerPackageName;
     }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 1bdade2..0dd4111ad 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -40,7 +40,6 @@
 import static android.system.OsConstants.O_CREAT;
 import static android.system.OsConstants.O_RDONLY;
 import static android.system.OsConstants.O_WRONLY;
-
 import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
 import static com.android.internal.util.XmlUtils.readBitmapAttribute;
 import static com.android.internal.util.XmlUtils.readByteArrayAttribute;
@@ -1166,6 +1165,11 @@
                 throw new IllegalArgumentException(
                         "Archived installation can only use Streaming System DataLoader.");
             }
+            if (!TextUtils.isEmpty(params.appPackageName) && !isArchivedInstallationAllowed(
+                    params.appPackageName)) {
+                throw new IllegalArgumentException(
+                        "Archived installation of this package is not allowed.");
+            }
         }
     }
 
@@ -2220,6 +2224,19 @@
     }
 
     /**
+     * Check if this package can be installed archived.
+     */
+    private static boolean isArchivedInstallationAllowed(String packageName) {
+        final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
+        final PackageStateInternal existingPkgSetting = pmi.getPackageStateInternal(packageName);
+        if (existingPkgSetting == null) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
      * Checks if the package can be installed on IncFs.
      */
     private static boolean isIncrementalInstallationAllowed(String packageName) {
@@ -3371,6 +3388,23 @@
             }
         }
 
+        if (isArchivedInstallation()) {
+            if (!isArchivedInstallationAllowed(mPackageName)) {
+                throw new PackageManagerException(
+                        PackageManager.INSTALL_FAILED_SESSION_INVALID,
+                        "Archived installation of this package is not allowed.");
+            }
+
+            if (!isInstalledByAdb(getInstallSource().mInitiatingPackageName)
+                    && !mPm.mArchiverService.verifySupportsUnarchival(
+                    getInstallSource().mInstallerPackageName)) {
+                throw new PackageManagerException(
+                        PackageManager.INSTALL_FAILED_SESSION_INVALID,
+                        "Installer has to support unarchival in order to install archived "
+                                + "packages.");
+            }
+        }
+
         if (isIncrementalInstallation()) {
             if (!isIncrementalInstallationAllowed(mPackageName)) {
                 throw new PackageManagerException(
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index bb4fd66..0c2f1ca 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -36,7 +36,6 @@
 import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
 import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL;
 import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE;
-
 import static com.android.internal.annotations.VisibleForTesting.Visibility;
 import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_INIT_TIME;
 import static com.android.server.pm.DexOptHelper.useArtService;
@@ -6323,7 +6322,6 @@
             archPkg.targetSdkVersion = apk.getTargetSdkVersion();
 
             // These get translated in flags important for user data management.
-            archPkg.clearUserDataAllowed = apk.isClearUserDataAllowed();
             archPkg.backupAllowed = apk.isBackupAllowed();
             archPkg.defaultToDeviceProtectedStorage =
                     apk.isDefaultToDeviceProtectedStorage();
diff --git a/services/core/java/com/android/server/pm/PackageMetrics.java b/services/core/java/com/android/server/pm/PackageMetrics.java
index c1580c4b..7ad336c 100644
--- a/services/core/java/com/android/server/pm/PackageMetrics.java
+++ b/services/core/java/com/android/server/pm/PackageMetrics.java
@@ -120,7 +120,7 @@
                     versionCode = ps.getVersionCode();
                     apksSize = getApksSize(ps.getPath());
                 }
-            } catch (IllegalStateException e) {
+            } catch (IllegalStateException | NullPointerException e) {
                 // no-op
             }
         }
diff --git a/services/core/java/com/android/server/pm/PackageRemovedInfo.java b/services/core/java/com/android/server/pm/PackageRemovedInfo.java
index c762fd3..5f44528 100644
--- a/services/core/java/com/android/server/pm/PackageRemovedInfo.java
+++ b/services/core/java/com/android/server/pm/PackageRemovedInfo.java
@@ -164,8 +164,7 @@
         }
     }
 
-    public void populateUsers(int[] userIds, PackageSetting deletedPackageSetting) {
-        mRemovedUsers = userIds;
+    public void populateBroadcastUsers(PackageSetting deletedPackageSetting) {
         if (mRemovedUsers == null) {
             mBroadcastUsers = null;
             return;
@@ -173,8 +172,8 @@
 
         mBroadcastUsers = EMPTY_INT_ARRAY;
         mInstantUserIds = EMPTY_INT_ARRAY;
-        for (int i = userIds.length - 1; i >= 0; --i) {
-            final int userId = userIds[i];
+        for (int i = mRemovedUsers.length - 1; i >= 0; --i) {
+            final int userId = mRemovedUsers[i];
             if (deletedPackageSetting.getInstantApp(userId)) {
                 mInstantUserIds = ArrayUtils.appendInt(mInstantUserIds, userId);
             } else {
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 7cac3e1..88184c0 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -818,7 +818,7 @@
             if (userState.isInstalled()) {
                 return true;
             }
-            if (userState.getCeDataInode() > 0) {
+            if (userState.dataExists()) {
                 return true;
             }
         }
diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java
index d4f30fe..2aedf0d 100644
--- a/services/core/java/com/android/server/pm/RemovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java
@@ -295,25 +295,24 @@
             outInfo.mInstallerPackageName = ps.getInstallSource().mInstallerPackageName;
             outInfo.mIsStaticSharedLib = pkg != null && pkg.getStaticSharedLibraryName() != null;
             outInfo.mRemovedAppId = ps.getAppId();
-            outInfo.mRemovedUsers = userIds;
-            outInfo.mBroadcastUsers = userIds;
+            outInfo.mBroadcastUsers = outInfo.mRemovedUsers;
             outInfo.mIsExternal = ps.isExternalStorage();
             outInfo.mRemovedPackageVersionCode = ps.getVersionCode();
         }
     }
 
     // Called to clean up disabled system packages
-    public void removePackageData(final PackageSetting deletedPs, @NonNull int[] allUserHandles,
-            PackageRemovedInfo outInfo, int flags, boolean writeSettings) {
+    public void removePackageData(final PackageSetting deletedPs, @NonNull int[] allUserHandles) {
         synchronized (mPm.mInstallLock) {
-            removePackageDataLIF(deletedPs, allUserHandles, outInfo, flags, writeSettings);
+            removePackageDataLIF(deletedPs, allUserHandles, /* outInfo= */ null,
+                    /* flags= */ 0, /* writeSettings= */ false);
         }
     }
 
     /*
      * This method deletes the package from internal data structures. If the DELETE_KEEP_DATA
      * flag is not set, the data directory is removed as well.
-     * make sure this flag is set for partially installed apps. If not its meaningless to
+     * make sure this flag is set for partially installed apps. If not it's meaningless to
      * delete a partially installed application.
      */
     @GuardedBy("mPm.mInstallLock")
@@ -328,8 +327,7 @@
             outInfo.mInstallerPackageName = deletedPs.getInstallSource().mInstallerPackageName;
             outInfo.mIsStaticSharedLib = deletedPkg != null
                     && deletedPkg.getStaticSharedLibraryName() != null;
-            outInfo.populateUsers(deletedPs.queryInstalledUsers(
-                    mUserManagerInternal.getUserIds(), true), deletedPs);
+            outInfo.populateBroadcastUsers(deletedPs);
             outInfo.mIsExternal = deletedPs.isExternalStorage();
             outInfo.mRemovedPackageVersionCode = deletedPs.getVersionCode();
         }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 6eace6a..1137681 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -27,7 +27,6 @@
 import static android.os.Process.INVALID_UID;
 import static android.os.Process.PACKAGE_INFO_GID;
 import static android.os.Process.SYSTEM_UID;
-
 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
 import static com.android.server.pm.PackageManagerService.WRITE_USER_PACKAGE_RESTRICTIONS;
 import static com.android.server.pm.SharedUidMigration.BEST_EFFORT;
@@ -4896,8 +4895,6 @@
             pw.print("]");
         }
         pw.println();
-        File dataDir = PackageInfoUtils.getDataDir(ps, UserHandle.myUserId());
-        pw.print(prefix); pw.print("  dataDir="); pw.println(dataDir.getAbsolutePath());
         if (pkg != null) {
             pw.print(prefix); pw.print("  versionName="); pw.println(pkg.getVersionName());
             pw.print(prefix); pw.print("  usesNonSdkApi="); pw.println(pkg.isNonSdkApiRequested());
@@ -5198,6 +5195,10 @@
             pw.print("      installReason=");
             pw.println(userState.getInstallReason());
 
+            File dataDir = PackageInfoUtils.getDataDir(ps, user.id);
+            pw.print("      dataDir=");
+            pw.println(dataDir.getAbsolutePath());
+
             final PackageUserStateInternal pus = ps.readUserState(user.id);
             pw.print("      firstInstallTime=");
             date.setTime(pus.getFirstInstallTimeMillis());
diff --git a/services/core/java/com/android/server/pm/flags.aconfig b/services/core/java/com/android/server/pm/flags.aconfig
index 368a843..7779c08 100644
--- a/services/core/java/com/android/server/pm/flags.aconfig
+++ b/services/core/java/com/android/server/pm/flags.aconfig
@@ -6,3 +6,11 @@
     description: "Feature flag for Quarantined state"
     bug: "269127435"
 }
+
+flag {
+    name: "new_match_uninstalled_enabled"
+    namespace: "package_manager_service"
+    description: "Feature flag for new MATCH_UNINSTALLED_PACKAGES behavior"
+    bug: "298681254"
+    is_fixed_read_only: true
+}
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserState.java b/services/core/java/com/android/server/pm/pkg/PackageUserState.java
index 7bc518c..c05b3c2 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserState.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserState.java
@@ -242,4 +242,11 @@
     @Nullable
     ArchiveState getArchiveState();
 
+    /**
+     * @return whether the data dir exists. True when the app is installed for the user, or when the
+     * app is uninstalled for the user with {@link PackageManager#DELETE_KEEP_DATA}.
+     *
+     * @hide
+     */
+    boolean dataExists();
 }
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
index 3534d75..fc4b686 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
@@ -196,4 +196,9 @@
     public ArchiveState getArchiveState() {
         return null;
     }
+
+    @Override
+    public boolean dataExists() {
+        return true;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
index 2349fbf..0b35d8a 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
@@ -685,6 +685,10 @@
         return false;
     }
 
+    @Override
+    public boolean dataExists() {
+        return getCeDataInode() > 0;
+    }
 
 
 
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateUtils.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateUtils.java
index 54f7ebc..9ab3060 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateUtils.java
@@ -27,6 +27,7 @@
 import android.util.DebugUtils;
 import android.util.Slog;
 
+import com.android.server.pm.Flags;
 import com.android.server.pm.pkg.component.ParsedMainComponent;
 
 /** @hide */
@@ -82,15 +83,38 @@
         return reportIfDebug(matchesUnaware || matchesAware, flags);
     }
 
+    /**
+     * @return true if any of the following conditions is met:
+     * <p><ul>
+     * <li> If it is installed and not hidden for this user;
+     * <li> If it is installed but hidden for this user, still return true if
+     * {@link PackageManager#MATCH_UNINSTALLED_PACKAGES} or
+     * {@link PackageManager#MATCH_ARCHIVED_PACKAGES} is requested;
+     * <li> If MATCH_ANY_USER is requested, always return true, because the fact that
+     * this object exists means that the package must be installed or has data on at least one user;
+     * <li> (When feature enabled) If it is not installed but still has data (i.e., it was
+     * previously uninstalled with {@link PackageManager#DELETE_KEEP_DATA}), return true if the
+     * caller requested {@link PackageManager#MATCH_UNINSTALLED_PACKAGES} or
+     * {@link PackageManager#MATCH_ARCHIVED_PACKAGES};
+     * </ul><p>
+     */
     public static boolean isAvailable(@NonNull PackageUserState state, long flags) {
-        // True if it is installed for this user and it is not hidden. If it is hidden,
-        // still return true if the caller requested MATCH_UNINSTALLED_PACKAGES
         final boolean matchAnyUser = (flags & PackageManager.MATCH_ANY_USER) != 0;
         final boolean matchUninstalled = (flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0;
         final boolean matchArchived = (flags & PackageManager.MATCH_ARCHIVED_PACKAGES) != 0;
-        return matchAnyUser
-                || (state.isInstalled()
-                && (!state.isHidden() || matchUninstalled || matchArchived));
+        final boolean matchDataExists = matchUninstalled || matchArchived;
+
+        if (matchAnyUser) {
+            return true;
+        }
+        if (state.isInstalled()) {
+            if (!state.isHidden()) {
+                return true;
+            } else return matchDataExists;
+        } else {
+            // not installed
+            return matchDataExists && Flags.newMatchUninstalledEnabled() && state.dataExists();
+        }
     }
 
     public static boolean reportIfDebug(boolean result, long flags) {
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index 2d55b9f..81c2f07 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -28,7 +28,6 @@
 import static android.os.Build.VERSION_CODES.DONUT;
 import static android.os.Build.VERSION_CODES.O;
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
-
 import static com.android.server.pm.pkg.parsing.ParsingUtils.parseKnownActivityEmbeddingCerts;
 
 import android.annotation.AnyRes;
@@ -514,7 +513,7 @@
         pkg
                 // Default true
                 .setBackupAllowed(lite.isBackupAllowed())
-                .setClearUserDataAllowed(lite.isClearUserDataAllowed())
+                .setClearUserDataAllowed(true)
                 .setClearUserDataOnFailedRestoreAllowed(
                         lite.isClearUserDataOnFailedRestoreAllowed())
                 .setAllowNativeHeapPointerTagging(true)
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 63794d5..4d38239 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -607,10 +607,10 @@
     DisplayPolicy mDefaultDisplayPolicy;
 
     // What we do when the user long presses on home
-    private int mLongPressOnHomeBehavior;
+    int mLongPressOnHomeBehavior;
 
     // What we do when the user double-taps on home
-    private int mDoubleTapOnHomeBehavior;
+    int mDoubleTapOnHomeBehavior;
 
     // Must match config_primaryShortPressTargetActivity in config.xml
     ComponentName mPrimaryShortPressTargetActivity;
@@ -1853,7 +1853,9 @@
                 Settings.Secure.TV_USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
     }
 
-    private void handleShortPressOnHome(int displayId) {
+    private void handleShortPressOnHome(KeyEvent event) {
+        logKeyboardSystemsEvent(event, KeyboardLogEvent.HOME);
+
         // Turn on the connected TV and switch HDMI input if we're a HDMI playback device.
         final HdmiControl hdmiControl = getHdmiControl();
         if (hdmiControl != null) {
@@ -1869,7 +1871,7 @@
         }
 
         // Go home!
-        launchHomeFromHotKey(displayId);
+        launchHomeFromHotKey(event.getDisplayId());
     }
 
     /**
@@ -1974,17 +1976,15 @@
     private class DisplayHomeButtonHandler {
 
         private final int mDisplayId;
-
-        private boolean mHomeDoubleTapPending;
         private boolean mHomePressed;
         private boolean mHomeConsumed;
-
+        private KeyEvent mPendingHomeKeyEvent;
         private final Runnable mHomeDoubleTapTimeoutRunnable = new Runnable() {
             @Override
             public void run() {
-                if (mHomeDoubleTapPending) {
-                    mHomeDoubleTapPending = false;
-                    handleShortPressOnHome(mDisplayId);
+                if (mPendingHomeKeyEvent != null) {
+                    handleShortPressOnHome(mPendingHomeKeyEvent);
+                    mPendingHomeKeyEvent = null;
                 }
             }
         };
@@ -2007,7 +2007,6 @@
             // If we have released the home key, and didn't do anything else
             // while it was pressed, then it is time to go home!
             if (!down) {
-                logKeyboardSystemsEvent(event, KeyboardLogEvent.HOME);
                 if (mDisplayId == DEFAULT_DISPLAY) {
                     cancelPreloadRecentApps();
                 }
@@ -2029,7 +2028,7 @@
                     if (mDoubleTapOnHomeBehavior != DOUBLE_TAP_HOME_PIP_MENU
                             || mPictureInPictureVisible) {
                         mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable); // just in case
-                        mHomeDoubleTapPending = true;
+                        mPendingHomeKeyEvent = event;
                         mHandler.postDelayed(mHomeDoubleTapTimeoutRunnable,
                                 ViewConfiguration.getDoubleTapTimeout());
                         return true;
@@ -2037,7 +2036,7 @@
                 }
 
                 // Post to main thread to avoid blocking input pipeline.
-                mHandler.post(() -> handleShortPressOnHome(mDisplayId));
+                mHandler.post(() -> handleShortPressOnHome(event));
                 return true;
             }
 
@@ -2063,10 +2062,10 @@
             // Remember that home is pressed and handle special actions.
             if (repeatCount == 0) {
                 mHomePressed = true;
-                if (mHomeDoubleTapPending) {
-                    mHomeDoubleTapPending = false;
+                if (mPendingHomeKeyEvent != null) {
+                    mPendingHomeKeyEvent = null;
                     mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable);
-                    mHandler.post(this::handleDoubleTapOnHome);
+                    mHandler.post(() -> handleDoubleTapOnHome(event));
                 // TODO(multi-display): Remove display id check once we support recents on
                 // multi-display
                 } else if (mDoubleTapOnHomeBehavior == DOUBLE_TAP_HOME_RECENT_SYSTEM_UI
@@ -2076,19 +2075,19 @@
             } else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
                 if (!keyguardOn) {
                     // Post to main thread to avoid blocking input pipeline.
-                    mHandler.post(() -> handleLongPressOnHome(event.getDeviceId(),
-                            event.getEventTime()));
+                    mHandler.post(() -> handleLongPressOnHome(event));
                 }
             }
             return true;
         }
 
-        private void handleDoubleTapOnHome() {
+        private void handleDoubleTapOnHome(KeyEvent event) {
             if (mHomeConsumed) {
                 return;
             }
             switch (mDoubleTapOnHomeBehavior) {
                 case DOUBLE_TAP_HOME_RECENT_SYSTEM_UI:
+                    logKeyboardSystemsEvent(event, KeyboardLogEvent.APP_SWITCH);
                     mHomeConsumed = true;
                     toggleRecentApps();
                     break;
@@ -2103,7 +2102,7 @@
             }
         }
 
-        private void handleLongPressOnHome(int deviceId, long eventTime) {
+        private void handleLongPressOnHome(KeyEvent event) {
             if (mHomeConsumed) {
                 return;
             }
@@ -2115,13 +2114,16 @@
                     "Home - Long Press");
             switch (mLongPressOnHomeBehavior) {
                 case LONG_PRESS_HOME_ALL_APPS:
+                    logKeyboardSystemsEvent(event, KeyboardLogEvent.ALL_APPS);
                     launchAllAppsAction();
                     break;
                 case LONG_PRESS_HOME_ASSIST:
-                    launchAssistAction(null, deviceId, eventTime,
+                    logKeyboardSystemsEvent(event, KeyboardLogEvent.LAUNCH_ASSISTANT);
+                    launchAssistAction(null, event.getDeviceId(), event.getEventTime(),
                             AssistUtils.INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS);
                     break;
                 case LONG_PRESS_HOME_NOTIFICATION_PANEL:
+                    logKeyboardSystemsEvent(event, KeyboardLogEvent.TOGGLE_NOTIFICATION_PANEL);
                     toggleNotificationPanel();
                     break;
                 default:
@@ -3269,7 +3271,7 @@
 
         switch (keyCode) {
             case KeyEvent.KEYCODE_HOME:
-                return handleHomeShortcuts(displayId, focusedToken, event);
+                return handleHomeShortcuts(focusedToken, event);
             case KeyEvent.KEYCODE_MENU:
                 // Hijack modified menu keys for debugging features
                 final int chordBug = KeyEvent.META_SHIFT_ON;
@@ -3311,7 +3313,7 @@
             case KeyEvent.KEYCODE_H:
             case KeyEvent.KEYCODE_ENTER:
                 if (event.isMetaPressed()) {
-                    return handleHomeShortcuts(displayId, focusedToken, event);
+                    return handleHomeShortcuts(focusedToken, event);
                 }
                 break;
             case KeyEvent.KEYCODE_I:
@@ -3661,15 +3663,15 @@
         upEvent.recycle();
     }
 
-    private boolean handleHomeShortcuts(int displayId, IBinder focusedToken, KeyEvent event) {
+    private boolean handleHomeShortcuts(IBinder focusedToken, KeyEvent event) {
         // First we always handle the home key here, so applications
         // can never break it, although if keyguard is on, we do let
         // it handle it, because that gives us the correct 5 second
         // timeout.
-        DisplayHomeButtonHandler handler = mDisplayHomeButtonHandlers.get(displayId);
+        DisplayHomeButtonHandler handler = mDisplayHomeButtonHandlers.get(event.getDisplayId());
         if (handler == null) {
-            handler = new DisplayHomeButtonHandler(displayId);
-            mDisplayHomeButtonHandlers.put(displayId, handler);
+            handler = new DisplayHomeButtonHandler(event.getDisplayId());
+            mDisplayHomeButtonHandlers.put(event.getDisplayId(), handler);
         }
         return handler.handleHomeButton(focusedToken, event);
     }
@@ -5333,11 +5335,6 @@
             return false;
         }
 
-        if (theaterModeEnabled) {
-            Settings.Global.putInt(mContext.getContentResolver(),
-                    Settings.Global.THEATER_MODE_ON, 0);
-        }
-
         mPowerManager.wakeUp(wakeTime, reason, details);
         return true;
     }
diff --git a/services/core/java/com/android/server/utils/FoldSettingProvider.java b/services/core/java/com/android/server/utils/FoldSettingProvider.java
new file mode 100644
index 0000000..d62628b
--- /dev/null
+++ b/services/core/java/com/android/server/utils/FoldSettingProvider.java
@@ -0,0 +1,102 @@
+/*
+ * 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.utils;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Log;
+
+import com.android.internal.R;
+import com.android.internal.util.SettingsWrapper;
+
+import java.util.Set;
+
+/**
+ * This class provides a convenient way to access the {@link Settings.System#FOLD_LOCK_BEHAVIOR}.
+ * The {@link Settings.System#FOLD_LOCK_BEHAVIOR} setting controls the behavior of the device when
+ * it is folded, and provides the user with three different options to choose from. Those are:
+ * 1. Stay awake on fold: The device will remain unlocked when it is folded.
+ * 2. Selective stay awake: The device will remain unlocked when it is folded only if there are
+ * apps with wakelocks running. This is also the set default behavior.
+ * 3. Sleep on fold: The device will lock when it is folded, regardless of which apps are running
+ * or whether any wakelocks are held.
+ *
+ * Keep the setting values in this class in sync with the values in
+ * {@link com.android.settings.display.FoldLockBehaviorSettings}
+ */
+public class FoldSettingProvider {
+
+    public static final String SETTING_VALUE_STAY_AWAKE_ON_FOLD = "stay_awake_on_fold_key";
+    public static final String SETTING_VALUE_SELECTIVE_STAY_AWAKE = "selective_stay_awake_key";
+    public static final String SETTING_VALUE_SLEEP_ON_FOLD = "sleep_on_fold_key";
+    private static final String SETTING_VALUE_DEFAULT = SETTING_VALUE_SELECTIVE_STAY_AWAKE;
+    private static final Set<String> SETTING_VALUES = Set.of(SETTING_VALUE_STAY_AWAKE_ON_FOLD,
+            SETTING_VALUE_SELECTIVE_STAY_AWAKE, SETTING_VALUE_SLEEP_ON_FOLD);
+    private static final String TAG = "FoldSettingProvider";
+
+    private final ContentResolver mContentResolver;
+    private final boolean mIsFoldLockBehaviorAvailable;
+    private final SettingsWrapper mSettingsWrapper;
+
+    public FoldSettingProvider(Context context, SettingsWrapper settingsWrapper) {
+        mContentResolver = context.getContentResolver();
+        mSettingsWrapper = settingsWrapper;
+        mIsFoldLockBehaviorAvailable = context.getResources().getBoolean(
+                R.bool.config_fold_lock_behavior);
+    }
+
+    /**
+     * Returns whether the device should remain awake after folding.
+     */
+    public boolean shouldStayAwakeOnFold() {
+        return getFoldSettingValue().equals(SETTING_VALUE_STAY_AWAKE_ON_FOLD);
+    }
+
+    /**
+     * Returns whether the device should selective remain awake after folding.
+     */
+    public boolean shouldSelectiveStayAwakeOnFold() {
+        return getFoldSettingValue().equals(SETTING_VALUE_SELECTIVE_STAY_AWAKE);
+    }
+
+    /**
+     * Returns whether the device should strictly sleep after folding.
+     */
+    public boolean shouldSleepOnFold() {
+        return getFoldSettingValue().equals(SETTING_VALUE_SLEEP_ON_FOLD);
+    }
+
+    private String getFoldSettingValue() {
+        if (!mIsFoldLockBehaviorAvailable) {
+            return SETTING_VALUE_DEFAULT;
+        }
+        String foldSettingValue = mSettingsWrapper.getStringForUser(
+                mContentResolver,
+                Settings.System.FOLD_LOCK_BEHAVIOR,
+                UserHandle.USER_CURRENT);
+        foldSettingValue = (foldSettingValue != null) ? foldSettingValue : SETTING_VALUE_DEFAULT;
+        if (!SETTING_VALUES.contains(foldSettingValue)) {
+            Log.e(TAG,
+                    "getFoldSettingValue: Invalid setting value, returning default setting value");
+            foldSettingValue = SETTING_VALUE_DEFAULT;
+        }
+
+        return foldSettingValue;
+    }
+}
diff --git a/services/core/java/com/android/server/utils/FoldSettingWrapper.java b/services/core/java/com/android/server/utils/FoldSettingWrapper.java
deleted file mode 100644
index 97a1ac0..0000000
--- a/services/core/java/com/android/server/utils/FoldSettingWrapper.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.utils;
-
-import android.content.ContentResolver;
-import android.provider.Settings;
-
-/**
- * A wrapper class for the {@link Settings.System#STAY_AWAKE_ON_FOLD} setting.
- *
- * This class provides a convenient way to access the {@link Settings.System#STAY_AWAKE_ON_FOLD}
- * setting for testing.
- */
-public class FoldSettingWrapper {
-    private final ContentResolver mContentResolver;
-
-    public FoldSettingWrapper(ContentResolver contentResolver) {
-        mContentResolver = contentResolver;
-    }
-
-    /**
-     * Returns whether the device should remain awake after folding.
-     */
-    public boolean shouldStayAwakeOnFold() {
-        try {
-            return (Settings.System.getIntForUser(
-                    mContentResolver,
-                    Settings.System.STAY_AWAKE_ON_FOLD,
-                    0) == 1);
-        } catch (Settings.SettingNotFoundException e) {
-            return false;
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index 4f3ab8b..ae29afa 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -22,6 +22,7 @@
 import static com.android.server.wm.AnimationSpecProto.ALPHA;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_DIMMER;
 
+import android.annotation.NonNull;
 import android.graphics.Rect;
 import android.util.Log;
 import android.util.proto.ProtoOutputStream;
@@ -178,6 +179,7 @@
         mSurfaceAnimatorStarter = surfaceAnimatorStarter;
     }
 
+    @NonNull
     WindowContainer<?> getHost() {
         return mHost;
     }
@@ -199,13 +201,6 @@
             try {
                 final SurfaceControl ctl = makeDimLayer();
                 mDimState = new DimState(ctl);
-                /**
-                 * See documentation on {@link #dimAbove} to understand lifecycle management of
-                 * Dim's via state resetting for Dim's with containers.
-                 */
-                if (container == null) {
-                    mDimState.mDontReset = true;
-                }
             } catch (Surface.OutOfResourcesException e) {
                 Log.w(TAG, "OutOfResourcesException creating dim surface");
             }
@@ -241,7 +236,7 @@
      * @param container The container which to dim above. Should be a child of our host.
      * @param alpha     The alpha at which to Dim.
      */
-    void dimAbove(WindowContainer container, float alpha) {
+    void dimAbove(@NonNull WindowContainer container, float alpha) {
         dim(container, 1, alpha, 0);
     }
 
@@ -253,7 +248,7 @@
      * @param blurRadius The amount of blur added to the Dim.
      */
 
-    void dimBelow(WindowContainer container, float alpha, int blurRadius) {
+    void dimBelow(@NonNull WindowContainer container, float alpha, int blurRadius) {
         dim(container, -1, alpha, blurRadius);
     }
 
@@ -316,7 +311,12 @@
             if (!mDimState.isVisible) {
                 mDimState.isVisible = true;
                 t.show(mDimState.mDimLayer);
-                startDimEnter(mLastRequestedDimContainer, mDimState.mSurfaceAnimator, t);
+                // Skip enter animation while starting window is on top of its activity
+                final WindowState ws = mLastRequestedDimContainer.asWindowState();
+                if (ws == null || ws.mActivityRecord == null
+                        || ws.mActivityRecord.mStartingData == null) {
+                    startDimEnter(mLastRequestedDimContainer, mDimState.mSurfaceAnimator, t);
+                }
             }
             return true;
         }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 334464c..daa73db 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -743,9 +743,6 @@
     /** Set of activities in foreground size compat mode. */
     private Set<ActivityRecord> mActiveSizeCompatActivities = new ArraySet<>();
 
-    // Used in updating the display size
-    private Point mTmpDisplaySize = new Point();
-
     // Used in updating override configurations
     private final Configuration mTempConfig = new Configuration();
 
@@ -4797,25 +4794,6 @@
         }, false /* traverseTopToBottom */);
     }
 
-    /**
-     * Starts the Keyguard exit animation on all windows that don't belong to an app token.
-     */
-    void startKeyguardExitOnNonAppWindows(boolean onWallpaper, boolean goingToShade,
-            boolean subtle) {
-        final WindowManagerPolicy policy = mWmService.mPolicy;
-        forAllWindows(w -> {
-            if (w.mActivityRecord == null && w.canBeHiddenByKeyguard()
-                    && w.wouldBeVisibleIfPolicyIgnored() && !w.isVisible()) {
-                w.startAnimation(policy.createHiddenByKeyguardExit(
-                        onWallpaper, goingToShade, subtle));
-            }
-        }, true /* traverseTopToBottom */);
-        for (int i = mShellRoots.size() - 1; i >= 0; --i) {
-            mShellRoots.valueAt(i).startAnimation(policy.createHiddenByKeyguardExit(
-                    onWallpaper, goingToShade, subtle));
-        }
-    }
-
     /** @return {@code true} if there is window to wait before enabling the screen. */
     boolean shouldWaitForSystemDecorWindowsOnBoot() {
         if (!isDefaultDisplay && !supportsSystemDecorations()) {
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 315c479..d461d1e 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -948,7 +948,7 @@
         mDisplayWindowSettings.setUserRotation(mDisplayContent, userRotationMode,
                 userRotation);
         if (changed) {
-            mService.updateRotation(true /* alwaysSendConfiguration */,
+            mService.updateRotation(false /* alwaysSendConfiguration */,
                     false /* forceRelayout */);
         }
     }
@@ -2127,7 +2127,7 @@
         @Override
         public void onChange(boolean selfChange) {
             if (updateSettings()) {
-                mService.updateRotation(true /* alwaysSendConfiguration */,
+                mService.updateRotation(false /* alwaysSendConfiguration */,
                         false /* forceRelayout */);
             }
         }
diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
index 97b3e32..45cf10b 100644
--- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java
+++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
@@ -80,10 +80,10 @@
 
     // Whether per-app user aspect ratio override settings is enabled
     private static final String KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS =
-            "enable_app_compat_user_aspect_ratio_settings";
+            "enable_app_compat_aspect_ratio_user_settings";
 
     // TODO(b/288142656): Enable user aspect ratio settings by default.
-    private static final boolean DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_SETTINGS = false;
+    private static final boolean DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_SETTINGS = true;
 
     // Whether per-app fullscreen user aspect ratio override option is enabled
     private static final String KEY_ENABLE_USER_ASPECT_RATIO_FULLSCREEN =
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index d56acaa..2fdfec0 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -258,10 +258,6 @@
      */
     final SparseArray<SleepToken> mSleepTokens = new SparseArray<>();
 
-    // The default minimal size that will be used if the activity doesn't specify its minimal size.
-    // It will be calculated when the default display gets added.
-    int mDefaultMinSizeOfResizeableTaskDp = -1;
-
     // Whether tasks have moved and we need to rank the tasks before next OOM scoring
     private boolean mTaskLayersChanged = true;
     private int mTmpTaskLayerRank;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 21a4fe8..21526e7 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3543,11 +3543,6 @@
                 ? null : new PictureInPictureParams(top.pictureInPictureArgs);
     }
 
-    private boolean shouldDockBigOverlays() {
-        final ActivityRecord topMostActivity = getTopMostActivity();
-        return topMostActivity != null && topMostActivity.shouldDockBigOverlays;
-    }
-
     Rect getDisplayCutoutInsets() {
         if (mDisplayContent == null || getDisplayInfo().displayCutout == null) return null;
         final WindowState w = getTopVisibleAppMainWindow();
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 81f91c7..a6c6491 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -440,10 +440,11 @@
     boolean canApplyDim(@NonNull Task task) {
         if (mTransientLaunches == null) return true;
         final Dimmer dimmer = task.getDimmer();
-        final WindowContainer<?> dimmerHost = dimmer != null ? dimmer.getHost() : null;
-        if (dimmerHost == null) return false;
-        if (isInTransientHide(dimmerHost)) {
-            // The layer of dimmer is inside transient-hide task, then allow to dim.
+        if (dimmer == null) {
+            return false;
+        }
+        if (dimmer.getHost().asTask() != null) {
+            // Always allow to dim if the host only affects its task.
             return true;
         }
         // The dimmer host of a translucent task can be a display, then it is not in transient-hide.
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index dae61da..4a0f44b 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1135,13 +1135,6 @@
         return parent != null && parent.isAttached();
     }
 
-    void setWaitingForDrawnIfResizingChanged() {
-        for (int i = mChildren.size() - 1; i >= 0; --i) {
-            final WindowContainer wc = mChildren.get(i);
-            wc.setWaitingForDrawnIfResizingChanged();
-        }
-    }
-
     void onResize() {
         if (mControllableInsetProvider != null) {
             mControllableInsetProvider.onWindowContainerBoundsChanged();
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 9c04e0a..b12cc0b 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1717,29 +1717,6 @@
     }
 
     /**
-     * This is a form of rectangle "difference". It cut off each dimension of rect by the amount
-     * that toRemove is "pushing into" it from the outside. Any dimension that fully contains
-     * toRemove won't change.
-     */
-    private void cutRect(Rect rect, Rect toRemove) {
-        if (toRemove.isEmpty()) return;
-        if (toRemove.top < rect.bottom && toRemove.bottom > rect.top) {
-            if (toRemove.right >= rect.right && toRemove.left >= rect.left) {
-                rect.right = toRemove.left;
-            } else if (toRemove.left <= rect.left && toRemove.right <= rect.right) {
-                rect.left = toRemove.right;
-            }
-        }
-        if (toRemove.left < rect.right && toRemove.right > rect.left) {
-            if (toRemove.bottom >= rect.bottom && toRemove.top >= rect.top) {
-                rect.bottom = toRemove.top;
-            } else if (toRemove.top <= rect.top && toRemove.bottom <= rect.bottom) {
-                rect.top = toRemove.bottom;
-            }
-        }
-    }
-
-    /**
      * Retrieves the visible bounds of the window.
      * @param bounds The rect which gets the bounds.
      */
@@ -3965,14 +3942,6 @@
         return mDragResizing != computeDragResizing();
     }
 
-    @Override
-    void setWaitingForDrawnIfResizingChanged() {
-        if (isDragResizeChanged()) {
-            mWmService.mRoot.mWaitingForDrawn.add(this);
-        }
-        super.setWaitingForDrawnIfResizingChanged();
-    }
-
     /**
      * Resets the state whether we reported a drag resize change to the app.
      */
@@ -5524,10 +5493,6 @@
         outRegion.translate(mWindowFrames.mFrame.left, mWindowFrames.mFrame.top);
     }
 
-    boolean hasTapExcludeRegion() {
-        return !mTapExcludeRegion.isEmpty();
-    }
-
     boolean isImeLayeringTarget() {
         return getDisplayContent().getImeTarget(IME_TARGET_LAYERING) == this;
     }
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 4d73358..e434f29 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -17,7 +17,6 @@
 package com.android.server.wm;
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
@@ -746,17 +745,6 @@
         return this;
     }
 
-    /**
-     * Return whether windows from this token can layer above the
-     * system bars, or in other words extend outside of the "Decor Frame"
-     */
-    boolean canLayerAboveSystemBars() {
-        int layer = getWindowLayerFromType();
-        int navLayer = mWmService.mPolicy.getWindowLayerFromTypeLw(TYPE_NAVIGATION_BAR,
-                mOwnerCanManageAppTokens);
-        return mOwnerCanManageAppTokens && (layer > navLayer);
-    }
-
     int getWindowLayerFromType() {
         return mWmService.mPolicy.getWindowLayerFromTypeLw(windowType, mOwnerCanManageAppTokens,
                 mRoundedCornerOverlay);
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 6e0d98c..55deb22 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -372,7 +372,7 @@
     virtual void onPointerDisplayIdChanged(int32_t displayId, const FloatPoint& position);
 
     /* --- PointerControllerPolicyInterface implementation --- */
-    virtual std::shared_ptr<PointerControllerInterface> createPointerController() override;
+    std::shared_ptr<PointerControllerInterface> createPointerController() override;
 
 private:
     sp<InputManagerInterface> mInputManager;
@@ -489,7 +489,7 @@
         dump += StringPrintf(INDENT "Pointer Capture: %s, seq=%" PRIu32 "\n",
                              mLocked.pointerCaptureRequest.enable ? "Enabled" : "Disabled",
                              mLocked.pointerCaptureRequest.seq);
-        forEachPointerControllerLocked([&dump](PointerController& pc) { pc.dump(dump); });
+        forEachPointerControllerLocked([&dump](PointerController& pc) { dump += pc.dump(); });
     } // release lock
     dump += "\n";
 
@@ -530,9 +530,8 @@
     { // acquire lock
         std::scoped_lock _l(mLock);
         mLocked.viewports = viewports;
-        forEachPointerControllerLocked([viewports = std::move(viewports)](PointerController& pc) {
-            pc.onDisplayViewportsUpdated(viewports);
-        });
+        forEachPointerControllerLocked(
+                [&viewports](PointerController& pc) { pc.onDisplayViewportsUpdated(viewports); });
     } // release lock
 
     mInputManager->getReader().requestRefreshConfiguration(
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
index 9a8e421..8684dbe 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
@@ -111,7 +111,7 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             final String action = intent.getAction();
-            mInjector.getNotificationManager().cancel(LOG_TAG, NOTIFICATION_ID);
+            cancelNotification();
             if (ACTION_BUGREPORT_SHARING_ACCEPTED.equals(action)) {
                 onBugreportSharingAccepted();
             } else if (ACTION_BUGREPORT_SHARING_DECLINED.equals(action)) {
@@ -213,8 +213,7 @@
             mRemoteBugreportServiceIsActive.set(true);
             mRemoteBugreportSharingAccepted.set(false);
             registerRemoteBugreportReceivers();
-            mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID,
-                    buildNotification(NOTIFICATION_BUGREPORT_STARTED), UserHandle.ALL);
+            notify(NOTIFICATION_BUGREPORT_STARTED);
             mHandler.postDelayed(mRemoteBugreportTimeoutRunnable, REMOTE_BUGREPORT_TIMEOUT_MILLIS);
             return true;
         } catch (RemoteException re) {
@@ -258,13 +257,10 @@
         final String bugreportHash = intent.getStringExtra(EXTRA_REMOTE_BUGREPORT_HASH);
         if (mRemoteBugreportSharingAccepted.get()) {
             shareBugreportWithDeviceOwnerIfExists(bugreportUriString, bugreportHash);
-            mInjector.getNotificationManager().cancel(LOG_TAG,
-                    NOTIFICATION_ID);
+            cancelNotification();
         } else {
             mService.setDeviceOwnerRemoteBugreportUriAndHash(bugreportUriString, bugreportHash);
-            mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID,
-                    buildNotification(NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED),
-                    UserHandle.ALL);
+            notify(NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED);
         }
         mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver);
     }
@@ -274,7 +270,7 @@
         mInjector.systemPropertiesSet(CTL_STOP, REMOTE_BUGREPORT_SERVICE);
         mRemoteBugreportSharingAccepted.set(false);
         mService.setDeviceOwnerRemoteBugreportUriAndHash(null, null);
-        mInjector.getNotificationManager().cancel(LOG_TAG, NOTIFICATION_ID);
+        cancelNotification();
         final Bundle extras = new Bundle();
         extras.putInt(DeviceAdminReceiver.EXTRA_BUGREPORT_FAILURE_REASON,
                 DeviceAdminReceiver.BUGREPORT_FAILURE_FAILED_COMPLETING);
@@ -289,9 +285,7 @@
         if (uriAndHash != null) {
             shareBugreportWithDeviceOwnerIfExists(uriAndHash.first, uriAndHash.second);
         } else if (mRemoteBugreportServiceIsActive.get()) {
-            mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID,
-                    buildNotification(NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED),
-                    UserHandle.ALL);
+            notify(NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED);
         }
     }
 
@@ -340,7 +334,16 @@
         filterConsent.addAction(ACTION_BUGREPORT_SHARING_DECLINED);
         filterConsent.addAction(ACTION_BUGREPORT_SHARING_ACCEPTED);
         mContext.registerReceiver(mRemoteBugreportConsentReceiver, filterConsent);
-        mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID,
-                buildNotification(NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED), UserHandle.ALL);
+        notify(NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED);
+    }
+
+    private void notify(@RemoteBugreportNotificationType int type) {
+        mInjector.getNotificationManager()
+                .notifyAsUser(LOG_TAG, NOTIFICATION_ID, buildNotification(type), UserHandle.ALL);
+    }
+
+    private void cancelNotification() {
+        mInjector.getNotificationManager()
+                .cancelAsUser(LOG_TAG, NOTIFICATION_ID, UserHandle.ALL);
     }
 }
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
index e8acb06..6ff7b26 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
@@ -16,15 +16,20 @@
 
 package com.android.inputmethodservice;
 
+import static android.view.WindowInsets.Type.captionBar;
+
 import static com.android.compatibility.common.util.SystemUtil.eventually;
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeFalse;
 
 import android.app.Instrumentation;
 import android.content.Context;
 import android.content.res.Configuration;
+import android.graphics.Insets;
 import android.os.RemoteException;
 import android.provider.Settings;
 import android.support.test.uiautomator.By;
@@ -32,6 +37,7 @@
 import android.support.test.uiautomator.UiObject2;
 import android.support.test.uiautomator.Until;
 import android.util.Log;
+import android.view.WindowManagerGlobal;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
 
@@ -592,6 +598,20 @@
                 false /* orientationPortrait */);
     }
 
+    /**
+     * This checks that when the system navigation bar is not created (e.g. emulator),
+     * then the IME caption bar is also not created.
+     */
+    @Test
+    public void testNoNavigationBar_thenImeNoCaptionBar() throws Exception {
+        boolean hasNavigationBar = WindowManagerGlobal.getWindowManagerService()
+                .hasNavigationBar(mInputMethodService.getDisplayId());
+        assumeFalse("Must not have a navigation bar", hasNavigationBar);
+
+        assertEquals(Insets.NONE, mInputMethodService.getWindow().getWindow().getDecorView()
+                .getRootWindowInsets().getInsetsIgnoringVisibility(captionBar()));
+    }
+
     private void verifyInputViewStatus(
             Runnable runnable, boolean expected, boolean inputViewStarted)
             throws InterruptedException {
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerServiceTest.java
index a805e5c..bea6543 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -125,7 +125,7 @@
         Assert.assertNull(pri.mBroadcastUsers);
 
         // populateUsers with nothing leaves nothing
-        pri.populateUsers(null, setting);
+        pri.populateBroadcastUsers(setting);
         Assert.assertNull(pri.mBroadcastUsers);
 
         // Create a real (non-null) PackageSetting and confirm that the removed
@@ -139,9 +139,10 @@
                 .setSecondaryCpuAbiString("secondaryCpuAbiString")
                 .setCpuAbiOverrideString("cpuAbiOverrideString")
                 .build();
-        pri.populateUsers(new int[]{
+        pri.mRemovedUsers = new int[]{
                 1, 2, 3, 4, 5
-        }, setting);
+        };
+        pri.populateBroadcastUsers(setting);
         Assert.assertNotNull(pri.mBroadcastUsers);
         Assert.assertEquals(5, pri.mBroadcastUsers.length);
         Assert.assertNotNull(pri.mInstantUserIds);
@@ -151,9 +152,10 @@
         pri.mBroadcastUsers = null;
         final int EXCLUDED_USER_ID = 4;
         setting.setInstantApp(true, EXCLUDED_USER_ID);
-        pri.populateUsers(new int[]{
+        pri.mRemovedUsers = new int[]{
                 1, 2, 3, EXCLUDED_USER_ID, 5
-        }, setting);
+        };
+        pri.populateBroadcastUsers(setting);
         Assert.assertNotNull(pri.mBroadcastUsers);
         Assert.assertEquals(4, pri.mBroadcastUsers.length);
         Assert.assertNotNull(pri.mInstantUserIds);
diff --git a/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
index d16c37a4..2bdebe2 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
@@ -267,7 +267,8 @@
                 /* shouldResetShortTermModel= */ true);
 
         // There should be a user data point added to the mapper.
-        verify(mBrightnessMappingStrategy).addUserDataPoint(1000f, 0.5f);
+        verify(mBrightnessMappingStrategy).addUserDataPoint(/* lux= */ 1000f,
+                /* brightness= */ 0.5f);
     }
 
     @Test
@@ -295,7 +296,8 @@
         mController.recalculateSplines(true, adjustments);
         verify(mBrightnessMappingStrategy).clearUserDataPoints();
         verify(mBrightnessMappingStrategy).recalculateSplines(true, adjustments);
-        verify(mBrightnessMappingStrategy, times(2)).addUserDataPoint(currentLux, 0.5f);
+        verify(mBrightnessMappingStrategy, times(2)).addUserDataPoint(currentLux,
+                /* brightness= */ 0.5f);
 
         clearInvocations(mBrightnessMappingStrategy);
 
@@ -342,7 +344,7 @@
         // Verify only happens on the first configure. (i.e. not again when switching back)
         // Intentionally using any() to ensure it's not called whatsoever.
         verify(mBrightnessMappingStrategy, times(1))
-                .addUserDataPoint(123.0f, 0.5f);
+                .addUserDataPoint(/* lux= */ 123.0f, /* brightness= */ 0.5f);
         verify(mBrightnessMappingStrategy, times(1))
                 .addUserDataPoint(anyFloat(), anyFloat());
     }
@@ -385,7 +387,7 @@
         // Verify that we add the data point once when the user sets it, and again when we return
         // interactive mode.
         verify(mBrightnessMappingStrategy, times(2))
-                .addUserDataPoint(123.0f, 0.51f);
+                .addUserDataPoint(/* lux= */ 123.0f, /* brightness= */ 0.51f);
     }
 
     @Test
@@ -428,7 +430,7 @@
         // Verify only happens on the first configure. (i.e. not again when switching back)
         // Intentionally using any() to ensure it's not called whatsoever.
         verify(mBrightnessMappingStrategy, times(1))
-                .addUserDataPoint(123.0f, 0.5f);
+                .addUserDataPoint(/* lux= */ 123.0f, /* brightness= */ 0.5f);
         verify(mBrightnessMappingStrategy, times(1))
                 .addUserDataPoint(anyFloat(), anyFloat());
     }
@@ -474,7 +476,7 @@
         // Verify this happens on the first configure and again when switching back
         // Intentionally using any() to ensure it's not called any other times whatsoever.
         verify(mBrightnessMappingStrategy, times(2))
-                .addUserDataPoint(123.0f, 0.5f);
+                .addUserDataPoint(/* lux= */ 123.0f, /* brightness= */ 0.5f);
         verify(mBrightnessMappingStrategy, times(2))
                 .addUserDataPoint(anyFloat(), anyFloat());
     }
@@ -533,7 +535,8 @@
                 /* shouldResetShortTermModel= */ true);
 
         // There should be a user data point added to the mapper.
-        verify(mBrightnessMappingStrategy, times(1)).addUserDataPoint(1000f, 0.5f);
+        verify(mBrightnessMappingStrategy, times(1)).addUserDataPoint(/* lux= */ 1000f,
+                /* brightness= */ 0.5f);
         verify(mBrightnessMappingStrategy, times(2)).setBrightnessConfiguration(any());
         verify(mBrightnessMappingStrategy, times(3)).getBrightness(anyFloat(), any(), anyInt());
 
@@ -559,7 +562,8 @@
                 /* shouldResetShortTermModel= */ true);
 
         // Ensure we use the correct mapping strategy
-        verify(mIdleBrightnessMappingStrategy, times(1)).addUserDataPoint(1000f, 0.5f);
+        verify(mIdleBrightnessMappingStrategy, times(1)).addUserDataPoint(/* lux= */ 1000f,
+                /* brightness= */ 0.5f);
     }
 
     @Test
diff --git a/services/tests/displayservicetests/src/com/android/server/display/BrightnessMappingStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/BrightnessMappingStrategyTest.java
index ee7826f..97e5826 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/BrightnessMappingStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/BrightnessMappingStrategyTest.java
@@ -445,7 +445,7 @@
 
         // Add a data point in the middle of the curve where the user has set the brightness max
         final int idx = LUX_LEVELS.length / 2;
-        strategy.addUserDataPoint(LUX_LEVELS[idx], 1.0f);
+        strategy.addUserDataPoint(LUX_LEVELS[idx], /* brightness= */ 1.0f);
 
         // Then make sure that all control points after the middle lux level are also set to max...
         for (int i = idx; i < LUX_LEVELS.length; i++) {
@@ -662,11 +662,11 @@
                 GAMMA_CORRECTION_NITS);
         BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc,
                 mMockDwbc);
-        assertEquals(0.0f, strategy.getAutoBrightnessAdjustment(), 0.0001f /* tolerance */);
-        strategy.addUserDataPoint(2500, 1.0f);
-        assertEquals(+1.0f, strategy.getAutoBrightnessAdjustment(), 0.0001f /* tolerance */);
-        strategy.addUserDataPoint(2500, 0.0f);
-        assertEquals(-1.0f, strategy.getAutoBrightnessAdjustment(), 0.0001f /* tolerance */);
+        assertEquals(0.0f, strategy.getAutoBrightnessAdjustment(), /* delta= */ 0.0001f);
+        strategy.addUserDataPoint(/* lux= */ 2500, /* brightness= */ 1.0f);
+        assertEquals(+1.0f, strategy.getAutoBrightnessAdjustment(), /* delta= */ 0.0001f);
+        strategy.addUserDataPoint(/* lux= */ 2500, /* brightness= */ 0.0f);
+        assertEquals(-1.0f, strategy.getAutoBrightnessAdjustment(), /* delta= */ 0.0001f);
     }
 
     @Test
@@ -701,7 +701,7 @@
         // Similarly, if we set a user data point at (x4, 1.0), the adjustment should be 1 - y4.
         adjustment = 1.0f - y4;
         gamma = (float) MathUtils.pow(MAXIMUM_GAMMA, -adjustment);
-        strategy.addUserDataPoint(x4, 1.0f);
+        strategy.addUserDataPoint(x4, /* brightness= */ 1.0f);
         assertEquals(MathUtils.pow(y0, gamma), strategy.getBrightness(x0), 0.0001f /* tolerance */);
         assertEquals(MathUtils.pow(y2, gamma), strategy.getBrightness(x2), 0.0001f /* tolerance */);
         assertEquals(1.0f, strategy.getBrightness(x4), 0.0001f /* tolerance */);
diff --git a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
index 6954435..065dd1f 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
@@ -44,9 +44,13 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -58,6 +62,7 @@
 import android.os.IThermalService;
 import android.os.PowerManager;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.test.TestLooper;
 import android.view.Display;
 import android.view.DisplayAddress;
@@ -69,7 +74,7 @@
 import com.android.server.display.feature.DisplayManagerFlags;
 import com.android.server.display.layout.DisplayIdProducer;
 import com.android.server.display.layout.Layout;
-import com.android.server.utils.FoldSettingWrapper;
+import com.android.server.utils.FoldSettingProvider;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -93,6 +98,7 @@
     private static int sUniqueTestDisplayId = 0;
     private static final int DEVICE_STATE_CLOSED = 0;
     private static final int DEVICE_STATE_OPEN = 2;
+    private static final int FLAG_GO_TO_SLEEP_ON_FOLD = 0;
     private static int sNextNonDefaultDisplayId = DEFAULT_DISPLAY + 1;
     private static final File NON_EXISTING_FILE = new File("/non_existing_folder/should_not_exist");
 
@@ -107,7 +113,7 @@
 
     @Mock LogicalDisplayMapper.Listener mListenerMock;
     @Mock Context mContextMock;
-    @Mock FoldSettingWrapper mFoldSettingWrapperMock;
+    @Mock FoldSettingProvider mFoldSettingProviderMock;
     @Mock Resources mResourcesMock;
     @Mock IPowerManager mIPowerManagerMock;
     @Mock IThermalService mIThermalServiceMock;
@@ -120,7 +126,7 @@
     @Captor ArgumentCaptor<Integer> mDisplayEventCaptor;
 
     @Before
-    public void setUp() {
+    public void setUp() throws RemoteException {
         // Share classloader to allow package private access.
         System.setProperty("dexmaker.share_classloader", "true");
         MockitoAnnotations.initMocks(this);
@@ -150,7 +156,9 @@
 
         when(mContextMock.getSystemServiceName(PowerManager.class))
                 .thenReturn(Context.POWER_SERVICE);
-        when(mFoldSettingWrapperMock.shouldStayAwakeOnFold()).thenReturn(false);
+        when(mFoldSettingProviderMock.shouldStayAwakeOnFold()).thenReturn(false);
+        when(mFoldSettingProviderMock.shouldSleepOnFold()).thenReturn(false);
+        when(mIPowerManagerMock.isInteractive()).thenReturn(true);
         when(mContextMock.getSystemService(PowerManager.class)).thenReturn(mPowerManager);
         when(mContextMock.getResources()).thenReturn(mResourcesMock);
         when(mResourcesMock.getBoolean(
@@ -166,9 +174,10 @@
         when(mFlagsMock.isConnectedDisplayManagementEnabled()).thenReturn(false);
         mLooper = new TestLooper();
         mHandler = new Handler(mLooper.getLooper());
-        mLogicalDisplayMapper = new LogicalDisplayMapper(mContextMock, mDisplayDeviceRepo,
+        mLogicalDisplayMapper = new LogicalDisplayMapper(mContextMock, mFoldSettingProviderMock,
+                mDisplayDeviceRepo,
                 mListenerMock, new DisplayManagerService.SyncRoot(), mHandler,
-                mDeviceStateToLayoutMapSpy, mFoldSettingWrapperMock, mFlagsMock);
+                mDeviceStateToLayoutMapSpy, mFlagsMock);
     }
 
 
@@ -645,8 +654,8 @@
     }
 
     @Test
-    public void testDeviceShouldNotSleepWhenFoldSettingTrue() {
-        when(mFoldSettingWrapperMock.shouldStayAwakeOnFold()).thenReturn(true);
+    public void testDeviceShouldNotSleepWhenStayAwakeSettingTrue() {
+        when(mFoldSettingProviderMock.shouldStayAwakeOnFold()).thenReturn(true);
 
         assertFalse(mLogicalDisplayMapper.shouldDeviceBePutToSleep(DEVICE_STATE_CLOSED,
                 DEVICE_STATE_OPEN,
@@ -679,6 +688,26 @@
     }
 
     @Test
+    public void testDeviceShouldPutToSleepWhenSleepSettingTrue() throws RemoteException {
+        when(mFoldSettingProviderMock.shouldSleepOnFold()).thenReturn(true);
+
+        finishBootAndFoldDevice();
+
+        verify(mIPowerManagerMock, atLeastOnce()).goToSleep(anyLong(), anyInt(),
+                eq(FLAG_GO_TO_SLEEP_ON_FOLD));
+    }
+
+    @Test
+    public void testDeviceShouldNotBePutToSleepWhenSleepSettingFalse() throws RemoteException {
+        when(mFoldSettingProviderMock.shouldSleepOnFold()).thenReturn(false);
+
+        finishBootAndFoldDevice();
+
+        verify(mIPowerManagerMock, never()).goToSleep(anyLong(), anyInt(),
+                eq(FLAG_GO_TO_SLEEP_ON_FOLD));
+    }
+
+    @Test
     public void testDeviceStateLocked() {
         DisplayDevice device1 = createDisplayDevice(TYPE_INTERNAL, 600, 800,
                 FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY);
@@ -930,6 +959,15 @@
     // Helper Methods
     /////////////////
 
+    private void finishBootAndFoldDevice() {
+        mLogicalDisplayMapper.setDeviceStateLocked(DEVICE_STATE_OPEN, false);
+        advanceTime(1000);
+        mLogicalDisplayMapper.onBootCompleted();
+        advanceTime(1000);
+        mLogicalDisplayMapper.setDeviceStateLocked(DEVICE_STATE_CLOSED, false);
+        advanceTime(1000);
+    }
+
     private void createDefaultDisplay(Layout layout, DisplayDevice device) {
         createDefaultDisplay(layout, info(device).address);
     }
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverServiceTest.java
index e58a234..80576a6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverServiceTest.java
@@ -18,9 +18,7 @@
 
 import static android.content.Intent.FLAG_RECEIVER_FOREGROUND;
 import static android.content.pm.PackageManager.DELETE_KEEP_DATA;
-
 import static com.google.common.truth.Truth.assertThat;
-
 import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -207,8 +205,7 @@
                 () -> mArchiveService.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender,
                         UserHandle.CURRENT));
         assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class);
-        assertThat(e.getCause()).hasMessageThat().isEqualTo(
-                String.format("No installer found to archive app %s.", PACKAGE));
+        assertThat(e.getCause()).hasMessageThat().isEqualTo("No installer found");
     }
 
     @Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/utils/FoldSettingProviderTest.java b/services/tests/mockingservicestests/src/com/android/server/utils/FoldSettingProviderTest.java
new file mode 100644
index 0000000..3514276
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/utils/FoldSettingProviderTest.java
@@ -0,0 +1,143 @@
+/*
+ * 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.utils;
+
+import static com.android.server.utils.FoldSettingProvider.SETTING_VALUE_SLEEP_ON_FOLD;
+import static com.android.server.utils.FoldSettingProvider.SETTING_VALUE_STAY_AWAKE_ON_FOLD;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.internal.R;
+import com.android.internal.util.SettingsWrapper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+public class FoldSettingProviderTest {
+
+    private static final String SETTING_VALUE_INVALID = "invalid_fold_lock_behavior";
+
+    @Mock
+    private Context mContext;
+    @Mock
+    private Resources mResources;
+    @Mock
+    private SettingsWrapper mSettingsWrapper;
+    private ContentResolver mContentResolver;
+    private FoldSettingProvider mFoldSettingProvider;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mContentResolver =
+                InstrumentationRegistry.getInstrumentation().getContext().getContentResolver();
+        when(mContext.getContentResolver()).thenReturn(mContentResolver);
+        when(mContext.getResources()).thenReturn(mResources);
+        setFoldLockBehaviorAvailability(true);
+
+        mFoldSettingProvider = new FoldSettingProvider(mContext, mSettingsWrapper);
+    }
+
+    @Test
+    public void foldSettingNotAvailable_returnDefaultSetting() {
+        setFoldLockBehaviorAvailability(false);
+        setFoldLockBehaviorSettingValue(SETTING_VALUE_STAY_AWAKE_ON_FOLD);
+        mFoldSettingProvider = new FoldSettingProvider(mContext, mSettingsWrapper);
+
+        boolean shouldSelectiveStayAwakeOnFold =
+                mFoldSettingProvider.shouldSelectiveStayAwakeOnFold();
+
+        assertThat(shouldSelectiveStayAwakeOnFold).isTrue();
+    }
+
+    @Test
+    public void foldSettingNotAvailable_notReturnStayAwakeOnFoldTrue() {
+        setFoldLockBehaviorAvailability(false);
+        setFoldLockBehaviorSettingValue(SETTING_VALUE_STAY_AWAKE_ON_FOLD);
+        mFoldSettingProvider = new FoldSettingProvider(mContext, mSettingsWrapper);
+
+        boolean shouldStayAwakeOnFold = mFoldSettingProvider.shouldStayAwakeOnFold();
+
+        assertThat(shouldStayAwakeOnFold).isFalse();
+    }
+
+    @Test
+    public void foldSettingNotAvailable_notReturnSleepOnFoldTrue() {
+        setFoldLockBehaviorAvailability(false);
+        setFoldLockBehaviorSettingValue(SETTING_VALUE_SLEEP_ON_FOLD);
+        mFoldSettingProvider = new FoldSettingProvider(mContext, mSettingsWrapper);
+
+        boolean shouldSleepOnFold = mFoldSettingProvider.shouldSleepOnFold();
+
+        assertThat(shouldSleepOnFold).isFalse();
+    }
+
+    @Test
+    public void foldSettingAvailable_returnCorrectFoldSetting() {
+        setFoldLockBehaviorSettingValue(SETTING_VALUE_STAY_AWAKE_ON_FOLD);
+
+        boolean shouldStayAwakeOnFold = mFoldSettingProvider.shouldStayAwakeOnFold();
+
+        assertThat(shouldStayAwakeOnFold).isTrue();
+    }
+
+    @Test
+    public void foldSettingInvalid_returnDefaultSetting() {
+        setFoldLockBehaviorSettingValue(SETTING_VALUE_INVALID);
+
+        boolean shouldSelectiveStayAwakeOnFold =
+                mFoldSettingProvider.shouldSelectiveStayAwakeOnFold();
+
+        assertThat(shouldSelectiveStayAwakeOnFold).isTrue();
+    }
+
+    @Test
+    public void foldSettingNotDefined_returnDefaultSetting() {
+        setFoldLockBehaviorSettingValue(null);
+
+        boolean shouldSelectiveStayAwakeOnFold =
+                mFoldSettingProvider.shouldSelectiveStayAwakeOnFold();
+
+        assertThat(shouldSelectiveStayAwakeOnFold).isTrue();
+    }
+
+    private void setFoldLockBehaviorAvailability(boolean isFoldLockBehaviorEnabled) {
+        when(mResources.getBoolean(R.bool.config_fold_lock_behavior)).thenReturn(
+                isFoldLockBehaviorEnabled);
+    }
+
+    private void setFoldLockBehaviorSettingValue(String foldLockBehaviorSettingValue) {
+        when(mSettingsWrapper.getStringForUser(any(),
+                eq(Settings.System.FOLD_LOCK_BEHAVIOR),
+                eq(UserHandle.USER_CURRENT))).thenReturn(foldLockBehaviorSettingValue);
+    }
+}
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 28df24c..c65452a 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
@@ -16,21 +16,31 @@
 
 package com.android.server.companion.virtual;
 
+import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM;
+import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
+import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_SENSORS;
 import static android.content.Context.DEVICE_ID_DEFAULT;
 import static android.content.Context.DEVICE_ID_INVALID;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.when;
 
+import android.companion.virtual.IVirtualDevice;
 import android.companion.virtual.VirtualDevice;
+import android.companion.virtual.flags.Flags;
 import android.os.Parcel;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsEnabled;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 @Presubmit
 @RunWith(AndroidJUnit4.class)
@@ -40,24 +50,35 @@
     private static final String PERSISTENT_ID = "persistentId";
     private static final String DEVICE_NAME = "VirtualDeviceName";
 
+    @Mock
+    private IVirtualDevice mVirtualDevice;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+    }
+
     @Test
     public void build_invalidId_shouldThrowIllegalArgumentException() {
         assertThrows(
                 IllegalArgumentException.class,
-                () -> new VirtualDevice(DEVICE_ID_INVALID, PERSISTENT_ID, DEVICE_NAME));
+                () -> new VirtualDevice(
+                        mVirtualDevice, DEVICE_ID_INVALID, PERSISTENT_ID, DEVICE_NAME));
     }
 
     @Test
     public void build_defaultId_shouldThrowIllegalArgumentException() {
         assertThrows(
                 IllegalArgumentException.class,
-                () -> new VirtualDevice(DEVICE_ID_DEFAULT, PERSISTENT_ID, DEVICE_NAME));
+                () -> new VirtualDevice(
+                        mVirtualDevice, DEVICE_ID_DEFAULT, PERSISTENT_ID, DEVICE_NAME));
     }
 
     @Test
     public void build_onlyRequiredFields() {
         VirtualDevice virtualDevice =
-                new VirtualDevice(VIRTUAL_DEVICE_ID, /*persistentId=*/null, /*name=*/null);
+                new VirtualDevice(
+                        mVirtualDevice, VIRTUAL_DEVICE_ID, /*persistentId=*/null, /*name=*/null);
         assertThat(virtualDevice.getDeviceId()).isEqualTo(VIRTUAL_DEVICE_ID);
         assertThat(virtualDevice.getPersistentDeviceId()).isNull();
         assertThat(virtualDevice.getName()).isNull();
@@ -66,15 +87,43 @@
     @Test
     public void parcelable_shouldRecreateSuccessfully() {
         VirtualDevice originalDevice =
-                new VirtualDevice(VIRTUAL_DEVICE_ID, PERSISTENT_ID, DEVICE_NAME);
+                new VirtualDevice(mVirtualDevice, VIRTUAL_DEVICE_ID, PERSISTENT_ID, DEVICE_NAME);
         Parcel parcel = Parcel.obtain();
         originalDevice.writeToParcel(parcel, 0);
         parcel.setDataPosition(0);
 
         VirtualDevice device = VirtualDevice.CREATOR.createFromParcel(parcel);
-        assertThat(device).isEqualTo(originalDevice);
         assertThat(device.getDeviceId()).isEqualTo(VIRTUAL_DEVICE_ID);
         assertThat(device.getPersistentDeviceId()).isEqualTo(PERSISTENT_ID);
         assertThat(device.getName()).isEqualTo(DEVICE_NAME);
     }
+
+    @RequiresFlagsEnabled(Flags.FLAG_VDM_PUBLIC_APIS)
+    @Test
+    public void virtualDevice_getDisplayIds() throws Exception {
+        VirtualDevice virtualDevice =
+                new VirtualDevice(
+                        mVirtualDevice, VIRTUAL_DEVICE_ID, /*persistentId=*/null, /*name=*/null);
+
+        when(mVirtualDevice.getDisplayIds()).thenReturn(new int[0]);
+        assertThat(virtualDevice.getDisplayIds()).hasLength(0);
+
+        final int[] displayIds = new int[]{7, 18};
+        when(mVirtualDevice.getDisplayIds()).thenReturn(displayIds);
+        assertThat(virtualDevice.getDisplayIds()).isEqualTo(displayIds);
+    }
+
+    @RequiresFlagsEnabled(Flags.FLAG_VDM_PUBLIC_APIS)
+    @Test
+    public void virtualDevice_hasCustomSensorSupport() throws Exception {
+        VirtualDevice virtualDevice =
+                new VirtualDevice(
+                        mVirtualDevice, VIRTUAL_DEVICE_ID, /*persistentId=*/null, /*name=*/null);
+
+        when(mVirtualDevice.getDevicePolicy(POLICY_TYPE_SENSORS)).thenReturn(DEVICE_POLICY_DEFAULT);
+        assertThat(virtualDevice.hasCustomSensorSupport()).isFalse();
+
+        when(mVirtualDevice.getDevicePolicy(POLICY_TYPE_SENSORS)).thenReturn(DEVICE_POLICY_CUSTOM);
+        assertThat(virtualDevice.hasCustomSensorSupport()).isTrue();
+    }
 }
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 2bfa44e..78655a5 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
@@ -25,7 +25,6 @@
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
-import android.companion.virtual.VirtualDeviceParams;
 import android.companion.virtual.audio.IAudioConfigChangedCallback;
 import android.companion.virtual.audio.IAudioRoutingCallback;
 import android.content.Context;
@@ -79,11 +78,10 @@
                         FLAG_SECURE,
                         SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
                         /* allowedUsers= */ new ArraySet<>(),
-                        /* allowedCrossTaskNavigations= */ new ArraySet<>(),
-                        /* blockedCrossTaskNavigations= */ new ArraySet<>(),
-                        /* allowedActivities= */ new ArraySet<>(),
-                        /* blockedActivities= */ new ArraySet<>(),
-                        VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_ALLOWED,
+                        /* activityLaunchAllowedByDefault= */ true,
+                        /* activityPolicyExceptions= */ new ArraySet<>(),
+                        /* crossTaskNavigationAllowedByDefault= */ true,
+                        /* crossTaskNavigationExceptions= */ new ArraySet<>(),
                         /* activityListener= */ null,
                         /* pipBlockedCallback= */ null,
                         /* activityBlockedCallback= */ null,
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationBitmapJobServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationBitmapJobServiceTest.java
new file mode 100644
index 0000000..312057ee
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationBitmapJobServiceTest.java
@@ -0,0 +1,119 @@
+/**
+ * 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.notification;
+
+import static com.google.common.truth.Truth.assertThat;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotSame;
+import static junit.framework.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.rule.ServiceTestRule;
+
+import com.android.server.LocalServices;
+import com.android.server.UiServiceTestCase;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+
+import java.lang.reflect.Field;
+
+@RunWith(AndroidTestingRunner.class)
+public class NotificationBitmapJobServiceTest extends UiServiceTestCase {
+    private NotificationBitmapJobService mJobService;
+
+    @Mock
+    private JobParameters mJobParams;
+
+    @Captor
+    ArgumentCaptor<JobInfo> mJobInfoCaptor;
+
+    @Mock
+    private JobScheduler mMockJobScheduler;
+
+    @Mock
+    private NotificationManagerInternal mMockNotificationManagerInternal;
+
+    @Rule
+    public final ServiceTestRule mServiceRule = new ServiceTestRule();
+
+    @Before
+    public void setUp() throws Exception {
+        // Set up JobScheduler mock
+        mJobService = new NotificationBitmapJobService();
+        mJobService.attachBaseContext(mContext);
+        mJobService.onCreate();
+        mJobService.onBind(/* intent= */ null);  // Create JobServiceEngine within JobService.
+
+        when(mMockJobScheduler.forNamespace(NotificationBitmapJobService.TAG))
+                .thenReturn(mMockJobScheduler);
+        mContext.addMockSystemService(JobScheduler.class, mMockJobScheduler);
+
+        // Add NotificationManagerInternal to LocalServices
+        LocalServices.removeServiceForTest(NotificationManagerInternal.class);
+        LocalServices.addService(NotificationManagerInternal.class,
+                mMockNotificationManagerInternal);
+    }
+
+    @Test
+    public void testScheduleJob_withCorrectJobInfo() {
+        when(mMockJobScheduler.getPendingJob(anyInt())).thenReturn(null);
+        mJobService.scheduleJob(mContext);
+
+        // Verify that the correct JobInfo was passed into JobScheduler
+        verify(mMockJobScheduler, times(1)).schedule(mJobInfoCaptor.capture());
+        JobInfo jobInfo = mJobInfoCaptor.getValue();
+
+        assertThat(jobInfo.getId()).isEqualTo(NotificationBitmapJobService.BASE_JOB_ID);
+        assertThat(jobInfo.isRequireDeviceIdle()).isTrue();
+        assertThat(jobInfo.getMinLatencyMillis()).isGreaterThan(0);
+    }
+
+    @Test
+    public void testOnStartJob_returnTrue() {
+        assertThat(mJobService.onStartJob(mJobParams)).isTrue();
+    }
+
+    @Test
+    public void testGetTimeUntilRemoval_beforeToday2am_returnTimeUntilToday2am() {
+        final long timeUntilRemoval = mJobService.getTimeUntilRemoval(/* now= */ 1,
+                /* today2AM= */ 2, /* tomorrow2AM= */ 26);
+
+        assertThat(timeUntilRemoval).isEqualTo(1);
+    }
+
+    @Test
+    public void testGetTimeUntilRemoval_afterToday2am_returnTimeUntilTomorrow2am() {
+        final long timeUntilRemoval = mJobService.getTimeUntilRemoval(/* now= */ 3,
+                /* today2AM= */ 2, /* tomorrow2AM= */ 26);
+
+        assertThat(timeUntilRemoval).isEqualTo(23);
+    }
+}
\ No newline at end of file
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 70e5c2e1..cb0a615 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -28,7 +28,9 @@
 import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
 import static android.app.Notification.FLAG_NO_CLEAR;
 import static android.app.Notification.FLAG_ONGOING_EVENT;
+import static android.app.Notification.FLAG_ONLY_ALERT_ONCE;
 import static android.app.Notification.FLAG_USER_INITIATED_JOB;
+import static android.app.Notification.GROUP_KEY_SILENT;
 import static android.app.NotificationChannel.USER_LOCKED_ALLOW_BUBBLE;
 import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED;
 import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL;
@@ -178,6 +180,7 @@
 import android.content.pm.UserInfo;
 import android.content.pm.VersionedPackage;
 import android.content.res.Resources;
+import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.graphics.drawable.Icon;
 import android.media.AudioManager;
@@ -230,6 +233,7 @@
 
 import androidx.test.InstrumentationRegistry;
 
+import com.android.internal.R;
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
 import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.Flag;
 import com.android.internal.config.sysui.TestableFlagResolver;
@@ -11282,6 +11286,116 @@
     }
 
     @Test
+    public void testIsBigPictureWithBitmapOrIcon_notBigPicture_false() {
+        Notification n = new Notification.Builder(mContext).build();
+
+        assertThat(mService.isBigPictureWithBitmapOrIcon(n)).isFalse();
+    }
+
+    @Test
+    public void testIsBigPictureWithBitmapOrIcon_bigPictureWithBitmap_true() {
+        Bitmap bitmap = Bitmap.createBitmap(400, 400, Bitmap.Config.ARGB_8888);
+
+        Notification n = new Notification.Builder(mContext)
+                .setStyle(new Notification.BigPictureStyle().bigPicture(bitmap))
+                .build();
+
+        assertThat(mService.isBigPictureWithBitmapOrIcon(n)).isTrue();
+    }
+
+    @Test
+    public void testIsBigPictureWithBitmapOrIcon_bigPictureWithIcon_true() {
+        Icon icon = Icon.createWithResource(mContext, R.drawable.btn_plus);
+
+        Notification n = new Notification.Builder(mContext)
+                .setStyle(new Notification.BigPictureStyle().bigPicture(icon))
+                .build();
+
+        assertThat(mService.isBigPictureWithBitmapOrIcon(n)).isTrue();
+    }
+
+    @Test
+    public void testIsBitmapExpired_notExpired_false() {
+        final boolean result = mService.isBitmapExpired(
+                /* timePosted= */ 0,
+                /* timeNow= */ 1,
+                /* timeToLive= */ 2);
+        assertThat(result).isFalse();
+    }
+
+    @Test
+    public void testIsBitmapExpired_expired_true() {
+        final boolean result = mService.isBitmapExpired(
+                /* timePosted= */ 0,
+                /* timeNow= */ 2,
+                /* timeToLive= */ 1);
+        assertThat(result).isTrue();
+    }
+
+    @Test
+    public void testRemoveBitmapAndRepost_removeBitmapFromExtras() {
+        // Create big picture NotificationRecord with bitmap
+        Bitmap bitmap = Bitmap.createBitmap(400, 400, Bitmap.Config.ARGB_8888);
+
+        Notification n = new Notification.Builder(mContext, "test")
+                .setStyle(new android.app.Notification.BigPictureStyle().bigPicture(bitmap))
+                .build();
+
+        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
+                n, UserHandle.getUserHandleForUid(mUid), null, 0);
+
+        NotificationRecord bigPictureRecord =
+                new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+        mService.removeBitmapAndRepost(bigPictureRecord);
+
+        Bitmap bitmapExtra = bigPictureRecord.getNotification().extras.getParcelable(
+                Notification.EXTRA_PICTURE, Bitmap.class);
+        assertThat(bitmapExtra).isNull();
+    }
+
+    @Test
+    public void testRemoveBitmapAndRepost_removeIconFromExtras() {
+        // Create big picture NotificationRecord with Icon
+        Icon icon = Icon.createWithResource(mContext, R.drawable.btn_plus);
+
+        Notification n = new Notification.Builder(mContext, "test")
+                .setStyle(new android.app.Notification.BigPictureStyle().bigPicture(icon))
+                .build();
+
+        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
+                n, UserHandle.getUserHandleForUid(mUid), null, 0);
+
+        NotificationRecord bigPictureRecord =
+                new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+        mService.removeBitmapAndRepost(bigPictureRecord);
+
+        Icon iconExtra = bigPictureRecord.getNotification().extras.getParcelable(
+                Notification.EXTRA_PICTURE_ICON, Icon.class);
+        assertThat(iconExtra).isNull();
+    }
+
+    @Test
+    public void testRemoveBitmapAndRepost_flagOnlyAlertOnce() {
+        Bitmap bitmap = Bitmap.createBitmap(400, 400, Bitmap.Config.ARGB_8888);
+
+        Notification n = new Notification.Builder(mContext, "test")
+                .setStyle(new android.app.Notification.BigPictureStyle().bigPicture(bitmap))
+                .build();
+
+        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
+                n, UserHandle.getUserHandleForUid(mUid), null, 0);
+
+        NotificationRecord bigPictureRecord =
+                new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+        mService.removeBitmapAndRepost(bigPictureRecord);
+
+        assertThat(n.flags & FLAG_ONLY_ALERT_ONCE).isNotEqualTo(0);
+    }
+
+    @Test
     public void checkCallStyleNotification_allowedForByForegroundService() throws Exception {
         Person person = new Person.Builder().setName("caller").build();
         Notification n = new Notification.Builder(mContext, "test")
diff --git a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
index f83aecb..8db09f9 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
@@ -115,43 +115,61 @@
         }
     }
 
-    void sendKeyCombination(int[] keyCodes, long duration) {
+    void sendKeyCombination(int[] keyCodes, long duration, boolean longPress) {
         final long downTime = SystemClock.uptimeMillis();
         final int count = keyCodes.length;
-        final KeyEvent[] events = new KeyEvent[count];
         int metaState = 0;
+
         for (int i = 0; i < count; i++) {
             final int keyCode = keyCodes[i];
             final KeyEvent event = new KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode,
                     0 /*repeat*/, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/,
                     0 /*flags*/, InputDevice.SOURCE_KEYBOARD);
             event.setDisplayId(DEFAULT_DISPLAY);
-            events[i] = event;
+            interceptKey(event);
             // The order is important here, metaState could be updated and applied to the next key.
             metaState |= MODIFIER.getOrDefault(keyCode, 0);
         }
 
-        for (KeyEvent event: events) {
-            interceptKey(event);
-        }
-
         try {
             Thread.sleep(duration);
         } catch (InterruptedException e) {
             throw new RuntimeException(e);
         }
 
+        if (longPress) {
+            final long nextDownTime = SystemClock.uptimeMillis();
+            for (int i = 0; i < count; i++) {
+                final int keyCode = keyCodes[i];
+                final KeyEvent nextDownEvent = new KeyEvent(downTime, nextDownTime,
+                        KeyEvent.ACTION_DOWN, keyCode, 1 /*repeat*/, metaState,
+                        KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/,
+                        KeyEvent.FLAG_LONG_PRESS /*flags*/, InputDevice.SOURCE_KEYBOARD);
+                nextDownEvent.setDisplayId(DEFAULT_DISPLAY);
+                interceptKey(nextDownEvent);
+            }
+        }
+
+        final long eventTime = SystemClock.uptimeMillis();
         for (int i = count - 1; i >= 0; i--) {
-            final long eventTime = SystemClock.uptimeMillis();
             final int keyCode = keyCodes[i];
             final KeyEvent upEvent = new KeyEvent(downTime, eventTime, KeyEvent.ACTION_UP, keyCode,
                     0, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0 /*flags*/,
                     InputDevice.SOURCE_KEYBOARD);
+            upEvent.setDisplayId(DEFAULT_DISPLAY);
             interceptKey(upEvent);
             metaState &= ~MODIFIER.getOrDefault(keyCode, 0);
         }
     }
 
+    void sendKeyCombination(int[] keyCodes, long duration) {
+        sendKeyCombination(keyCodes, duration, false /* longPress */);
+    }
+
+    void sendLongPressKeyCombination(int[] keyCodes) {
+        sendKeyCombination(keyCodes, ViewConfiguration.getLongPressTimeout(), true /* longPress */);
+    }
+
     void sendKey(int keyCode) {
         sendKey(keyCode, false);
     }
@@ -179,6 +197,7 @@
         final KeyEvent upEvent = new KeyEvent(downTime, eventTime, KeyEvent.ACTION_UP, keyCode,
                 0 /*repeat*/, 0 /*metaState*/, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/,
                 0 /*flags*/, InputDevice.SOURCE_KEYBOARD);
+        upEvent.setDisplayId(DEFAULT_DISPLAY);
         interceptKey(upEvent);
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java b/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java
index e13dc3e..4791946 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java
@@ -16,6 +16,11 @@
 
 package com.android.server.policy;
 
+import static com.android.server.policy.PhoneWindowManager.DOUBLE_TAP_HOME_RECENT_SYSTEM_UI;
+import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_HOME_ALL_APPS;
+import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_HOME_ASSIST;
+import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_HOME_NOTIFICATION_PANEL;
+
 import android.platform.test.annotations.Presubmit;
 import android.view.KeyEvent;
 
@@ -226,6 +231,59 @@
                         KeyboardLogEvent.LAUNCH_DEFAULT_MESSAGING, KeyEvent.KEYCODE_S, META_ON}};
     }
 
+    @Keep
+    private static Object[][] longPressOnHomeTestArguments() {
+        // testName, testKeys, longPressOnHomeBehavior, expectedLogEvent, expectedKey,
+        // expectedModifierState
+        return new Object[][]{
+                {"Long press HOME key -> Toggle Notification panel",
+                        new int[]{KeyEvent.KEYCODE_HOME}, LONG_PRESS_HOME_NOTIFICATION_PANEL,
+                        KeyboardLogEvent.TOGGLE_NOTIFICATION_PANEL, KeyEvent.KEYCODE_HOME, 0},
+                {"Long press META + ENTER -> Toggle Notification panel",
+                        new int[]{META_KEY, KeyEvent.KEYCODE_ENTER},
+                        LONG_PRESS_HOME_NOTIFICATION_PANEL,
+                        KeyboardLogEvent.TOGGLE_NOTIFICATION_PANEL, KeyEvent.KEYCODE_ENTER,
+                        META_ON},
+                {"Long press META + H -> Toggle Notification panel",
+                        new int[]{META_KEY, KeyEvent.KEYCODE_H}, LONG_PRESS_HOME_NOTIFICATION_PANEL,
+                        KeyboardLogEvent.TOGGLE_NOTIFICATION_PANEL, KeyEvent.KEYCODE_H, META_ON},
+                {"Long press HOME key -> Launch assistant",
+                        new int[]{KeyEvent.KEYCODE_HOME}, LONG_PRESS_HOME_ASSIST,
+                        KeyboardLogEvent.LAUNCH_ASSISTANT, KeyEvent.KEYCODE_HOME, 0},
+                {"Long press META + ENTER -> Launch assistant",
+                        new int[]{META_KEY, KeyEvent.KEYCODE_ENTER}, LONG_PRESS_HOME_ASSIST,
+                        KeyboardLogEvent.LAUNCH_ASSISTANT, KeyEvent.KEYCODE_ENTER, META_ON},
+                {"Long press META + H -> Launch assistant",
+                        new int[]{META_KEY, KeyEvent.KEYCODE_H}, LONG_PRESS_HOME_ASSIST,
+                        KeyboardLogEvent.LAUNCH_ASSISTANT, KeyEvent.KEYCODE_H, META_ON},
+                {"Long press HOME key -> Open App Drawer",
+                        new int[]{KeyEvent.KEYCODE_HOME}, LONG_PRESS_HOME_ALL_APPS,
+                        KeyboardLogEvent.ALL_APPS, KeyEvent.KEYCODE_HOME, 0},
+                {"Long press META + ENTER -> Open App Drawer",
+                        new int[]{META_KEY, KeyEvent.KEYCODE_ENTER}, LONG_PRESS_HOME_ALL_APPS,
+                        KeyboardLogEvent.ALL_APPS, KeyEvent.KEYCODE_ENTER, META_ON},
+                {"Long press META + H -> Open App Drawer", new int[]{META_KEY, KeyEvent.KEYCODE_H},
+                        LONG_PRESS_HOME_ALL_APPS, KeyboardLogEvent.ALL_APPS,
+                        KeyEvent.KEYCODE_H, META_ON}};
+    }
+
+    @Keep
+    private static Object[][] doubleTapOnHomeTestArguments() {
+        // testName, testKeys, doubleTapOnHomeBehavior, expectedLogEvent, expectedKey,
+        // expectedModifierState
+        return new Object[][]{
+                {"Double tap HOME -> Open App switcher",
+                        new int[]{KeyEvent.KEYCODE_HOME}, DOUBLE_TAP_HOME_RECENT_SYSTEM_UI,
+                        KeyboardLogEvent.APP_SWITCH, KeyEvent.KEYCODE_HOME, 0},
+                {"Double tap META + ENTER -> Open App switcher",
+                        new int[]{META_KEY, KeyEvent.KEYCODE_ENTER},
+                        DOUBLE_TAP_HOME_RECENT_SYSTEM_UI, KeyboardLogEvent.APP_SWITCH,
+                        KeyEvent.KEYCODE_ENTER, META_ON},
+                {"Double tap META + H -> Open App switcher",
+                        new int[]{META_KEY, KeyEvent.KEYCODE_H}, DOUBLE_TAP_HOME_RECENT_SYSTEM_UI,
+                        KeyboardLogEvent.APP_SWITCH, KeyEvent.KEYCODE_H, META_ON}};
+    }
+
     @Before
     public void setUp() {
         setUpPhoneWindowManager(/*supportSettingsUpdate*/ true);
@@ -237,13 +295,37 @@
         mPhoneWindowManager.overrideStatusBarManagerInternal();
         mPhoneWindowManager.overrideStartActivity();
         mPhoneWindowManager.overrideUserSetupComplete();
+        mPhoneWindowManager.setupAssistForLaunch();
+        mPhoneWindowManager.overrideTogglePanel();
     }
 
     @Test
     @Parameters(method = "shortcutTestArguments")
     public void testShortcuts(String testName, int[] testKeys, KeyboardLogEvent expectedLogEvent,
             int expectedKey, int expectedModifierState) {
-        sendKeyCombination(testKeys, 0);
+        sendKeyCombination(testKeys, 0 /* duration */);
+        mPhoneWindowManager.assertShortcutLogged(VENDOR_ID, PRODUCT_ID, expectedLogEvent,
+                expectedKey, expectedModifierState, "Failed while executing " + testName);
+    }
+
+    @Test
+    @Parameters(method = "longPressOnHomeTestArguments")
+    public void testLongPressOnHome(String testName, int[] testKeys, int longPressOnHomeBehavior,
+            KeyboardLogEvent expectedLogEvent, int expectedKey, int expectedModifierState) {
+        mPhoneWindowManager.overrideLongPressOnHomeBehavior(longPressOnHomeBehavior);
+        sendLongPressKeyCombination(testKeys);
+        mPhoneWindowManager.assertShortcutLogged(VENDOR_ID, PRODUCT_ID, expectedLogEvent,
+                expectedKey, expectedModifierState, "Failed while executing " + testName);
+    }
+
+    @Test
+    @Parameters(method = "doubleTapOnHomeTestArguments")
+    public void testDoubleTapOnHomeBehavior(String testName, int[] testKeys,
+            int doubleTapOnHomeBehavior, KeyboardLogEvent expectedLogEvent, int expectedKey,
+            int expectedModifierState) {
+        mPhoneWindowManager.overriderDoubleTapOnHomeBehavior(doubleTapOnHomeBehavior);
+        sendKeyCombination(testKeys, 0 /* duration */);
+        sendKeyCombination(testKeys, 0 /* duration */);
         mPhoneWindowManager.assertShortcutLogged(VENDOR_ID, PRODUCT_ID, expectedLogEvent,
                 expectedKey, expectedModifierState, "Failed while executing " + testName);
     }
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index bc8f06a..e301da7 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -364,6 +364,14 @@
         }
     }
 
+    void overrideLongPressOnHomeBehavior(int behavior) {
+        mPhoneWindowManager.mLongPressOnHomeBehavior = behavior;
+    }
+
+    void overriderDoubleTapOnHomeBehavior(int behavior) {
+        mPhoneWindowManager.mDoubleTapOnHomeBehavior = behavior;
+    }
+
     void overrideCanStartDreaming(boolean canDream) {
         doReturn(canDream).when(mDreamManagerInternal).canStartDreaming(anyBoolean());
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index 6b50492..915b387 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -583,6 +583,7 @@
 
         enableOrientationSensor();
 
+        clearInvocations(sMockWm);
         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90));
         assertTrue(waitForUiHandler());
 
@@ -627,6 +628,7 @@
         when(mDisplayRotationImmersiveAppCompatPolicyMock.isRotationLockEnforced(
                 Surface.ROTATION_90)).thenReturn(false);
 
+        clearInvocations(sMockWm);
         // And then ActivityRecord.setRequestedOrientation calls onSetRequestedOrientation.
         mTarget.onSetRequestedOrientation();
 
@@ -864,6 +866,7 @@
         assertEquals(Surface.ROTATION_270, mTarget.rotationForOrientation(
                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
 
+        clearInvocations(sMockWm);
         // ... until half-fold
         mTarget.foldStateChanged(DeviceStateController.DeviceState.HALF_FOLDED);
         assertTrue(waitForUiHandler());
@@ -899,6 +902,7 @@
         assertEquals(Surface.ROTATION_270, mTarget.rotationForOrientation(
                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
 
+        clearInvocations(sMockWm);
         // ... half-fold -> still no rotation
         mTarget.foldStateChanged(DeviceStateController.DeviceState.HALF_FOLDED);
         assertTrue(waitForUiHandler());
diff --git a/telecomm/java/android/telecom/CallEndpoint.java b/telecomm/java/android/telecom/CallEndpoint.java
index ed4bf40..a557caf 100644
--- a/telecomm/java/android/telecom/CallEndpoint.java
+++ b/telecomm/java/android/telecom/CallEndpoint.java
@@ -127,7 +127,7 @@
             return false;
         }
         CallEndpoint endpoint = (CallEndpoint) obj;
-        return getEndpointName().toString().contentEquals(endpoint.getEndpointName())
+        return Objects.equals(getEndpointName(), endpoint.getEndpointName())
                 && getEndpointType() == endpoint.getEndpointType()
                 && getIdentifier().equals(endpoint.getIdentifier());
     }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index ac8200a..0c8603b3 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -9894,9 +9894,15 @@
         sDefaults.putBoolean(KEY_USE_ONLY_DIALED_SIM_ECC_LIST_BOOL, false);
         sDefaults.putString(KEY_CARRIER_NETWORK_SERVICE_WWAN_PACKAGE_OVERRIDE_STRING, "");
         sDefaults.putString(KEY_CARRIER_NETWORK_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING, "");
+        sDefaults.putString(KEY_CARRIER_NETWORK_SERVICE_WLAN_CLASS_OVERRIDE_STRING, "");
+        sDefaults.putString(KEY_CARRIER_NETWORK_SERVICE_WWAN_CLASS_OVERRIDE_STRING, "");
         sDefaults.putString(KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_PACKAGE_OVERRIDE_STRING, "");
+        sDefaults.putString(KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_CLASS_OVERRIDE_STRING, "");
         sDefaults.putString(KEY_CARRIER_DATA_SERVICE_WWAN_PACKAGE_OVERRIDE_STRING, "");
         sDefaults.putString(KEY_CARRIER_DATA_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING, "");
+        sDefaults.putString(KEY_CARRIER_DATA_SERVICE_WWAN_CLASS_OVERRIDE_STRING, "");
+        sDefaults.putString(KEY_CARRIER_DATA_SERVICE_WLAN_CLASS_OVERRIDE_STRING, "");
+        sDefaults.putString(KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING, "");
         sDefaults.putString(KEY_CARRIER_INSTANT_LETTERING_INVALID_CHARS_STRING, "");
         sDefaults.putString(KEY_CARRIER_INSTANT_LETTERING_ESCAPED_CHARS_STRING, "");
         sDefaults.putString(KEY_CARRIER_INSTANT_LETTERING_ENCODING_STRING, "");
diff --git a/tests/TrustTests/src/android/trust/test/CanUnlockWithActiveUnlockTest.kt b/tests/TrustTests/src/android/trust/test/IsActiveUnlockRunningTest.kt
similarity index 100%
rename from tests/TrustTests/src/android/trust/test/CanUnlockWithActiveUnlockTest.kt
rename to tests/TrustTests/src/android/trust/test/IsActiveUnlockRunningTest.kt
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index 0fc2617..0aaf3e8 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -7,7 +7,9 @@
 #include "AaptUtil.h"
 #include "Main.h"
 #include "ResourceFilter.h"
+#include "Utils.h"
 
+#include <androidfw/PathUtils.h>
 #include <utils/misc.h>
 #include <utils/SortedVector.h>
 
@@ -96,7 +98,7 @@
     char *matchedPattern = NULL;
 
     String8 fullPath(root);
-    fullPath.appendPath(path);
+    appendPath(fullPath, String8(path));
     FileType type = getFileType(fullPath);
 
     int plen = strlen(path);
@@ -508,7 +510,7 @@
 {
     if (hasData()) {
         String8 name(mGroupEntry.toDirName(String8()));
-        name.appendPath(mPath);
+        appendPath(name, mPath);
         name.append(" #generated");
         return name;
     }
@@ -615,7 +617,7 @@
     String8 remain = path;
 
     sp<AaptDir> subdir = this;
-    while (name = remain.walkPath(&remain), remain != "") {
+    while (name = walkPath(remain, &remain), remain != "") {
         subdir = subdir->makeDir(name);
     }
 
@@ -623,7 +625,7 @@
     if (i >= 0) {
         return subdir->mDirs.valueAt(i);
     }
-    sp<AaptDir> dir = new AaptDir(name, subdir->mPath.appendPathCopy(name));
+    sp<AaptDir> dir = new AaptDir(name, appendPathCopy(subdir->mPath, name));
     subdir->mDirs.add(name, dir);
     return dir;
 }
@@ -645,7 +647,7 @@
     if (mFiles.indexOfKey(leafName) >= 0) {
         group = mFiles.valueFor(leafName);
     } else {
-        group = new AaptGroup(leafName, mPath.appendPathCopy(leafName));
+        group = new AaptGroup(leafName, appendPathCopy(mPath, leafName));
         mFiles.add(leafName, group);
     }
 
@@ -684,7 +686,7 @@
             // Add fully qualified path for dependency purposes
             // if we're collecting them
             if (fullResPaths != NULL) {
-                fullResPaths->add(srcDir.appendPathCopy(name));
+                fullResPaths->add(appendPathCopy(srcDir, name));
             }
         }
         closedir(dir);
@@ -701,7 +703,7 @@
         String8 pathName(srcDir);
         FileType type;
 
-        pathName.appendPath(fileNames[i].c_str());
+        appendPath(pathName, fileNames[i]);
         type = getFileType(pathName.c_str());
         if (type == kFileTypeDirectory) {
             sp<AaptDir> subdir;
@@ -709,7 +711,7 @@
             if (mDirs.indexOfKey(fileNames[i]) >= 0) {
                 subdir = mDirs.valueFor(fileNames[i]);
             } else {
-                subdir = new AaptDir(fileNames[i], mPath.appendPathCopy(fileNames[i]));
+                subdir = new AaptDir(fileNames[i], appendPathCopy(mPath, fileNames[i]));
                 notAdded = true;
             }
             ssize_t res = subdir->slurpFullTree(bundle, pathName, kind,
@@ -821,11 +823,11 @@
 {
     if (mFiles.size() > 0) {
         // Arbitrarily pull the first file out of the list as the source dir.
-        return mFiles.valueAt(0)->getPrintableSource().getPathDir();
+        return getPathDir(mFiles.valueAt(0)->getPrintableSource());
     }
     if (mDirs.size() > 0) {
         // Or arbitrarily pull the first dir out of the list as the source dir.
-        return mDirs.valueAt(0)->getPrintableSource().getPathDir();
+        return getPathDir(mDirs.valueAt(0)->getPrintableSource());
     }
 
     // Should never hit this case, but to be safe...
@@ -908,8 +910,8 @@
     sp<AaptFile> file;
     String8 root, remain(filePath), partialPath;
     while (remain.length() > 0) {
-        root = remain.walkPath(&remain);
-        partialPath.appendPath(root);
+        root = walkPath(remain, &remain);
+        appendPath(partialPath, root);
 
         const String8 rootStr(root);
 
@@ -924,7 +926,7 @@
                     return NULL;
                 }
             }
-            file = new AaptFile(srcDir.appendPathCopy(filePath), entry, resType);
+            file = new AaptFile(appendPathCopy(srcDir, filePath), entry, resType);
             status_t res = group->addFile(file);
             if (res != NO_ERROR) {
                 return NULL;
@@ -981,7 +983,7 @@
     if (bundle->getAndroidManifestFile() != NULL) {
         // place at root of zip.
         String8 srcFile(bundle->getAndroidManifestFile());
-        addFile(srcFile.getPathLeaf(), AaptGroupEntry(), srcFile.getPathDir(),
+        addFile(getPathLeaf(srcFile), AaptGroupEntry(), getPathDir(srcFile),
                 NULL, String8());
         totalCount++;
     }
@@ -1154,7 +1156,7 @@
         }
 
         String8 subdirName(srcDir);
-        subdirName.appendPath(entry->d_name);
+        appendPath(subdirName, entry->d_name);
 
         AaptGroupEntry group;
         String8 resType;
@@ -1239,16 +1241,16 @@
 
         String8 entryName(entry->getFileName());
 
-        String8 dirName = entryName.getPathDir();
+        String8 dirName = getPathDir(entryName);
         sp<AaptDir> dir = dirName == "" ? this : makeDir(dirName);
 
         String8 resType;
         AaptGroupEntry kind;
 
         String8 remain;
-        if (entryName.walkPath(&remain) == kResourceDir) {
+        if (walkPath(entryName, &remain) == kResourceDir) {
             // these are the resources, pull their type out of the directory name
-            kind.initFromDirName(remain.walkPath().c_str(), &resType);
+            kind.initFromDirName(walkPath(remain).c_str(), &resType);
         } else {
             // these are untyped and don't have an AaptGroupEntry
         }
@@ -1258,10 +1260,10 @@
         }
 
         // use the one from the zip file if they both exist.
-        dir->removeFile(entryName.getPathLeaf());
+        dir->removeFile(getPathLeaf(entryName));
 
         sp<AaptFile> file = new AaptFile(entryName, kind, resType);
-        status_t err = dir->addLeafFile(entryName.getPathLeaf(), file);
+        status_t err = dir->addLeafFile(getPathLeaf(entryName), file);
         if (err != NO_ERROR) {
             fprintf(stderr, "err=%s entryName=%s\n", strerror(err), entryName.c_str());
             count = err;
@@ -1374,7 +1376,7 @@
                     // containing no entries.
                     continue;
                 }
-                if (file->getPath().getPathExtension() == ".xml") {
+                if (getPathExtension(file->getPath()) == ".xml") {
                     // We can't remove .xml files at this point, because when
                     // we parse them they may add identifier resources, so
                     // removing them can cause our resource identifiers to
@@ -1411,7 +1413,7 @@
                     // containing no entries.
                     continue;
                 }
-                if (file->getPath().getPathExtension() == ".xml") {
+                if (getPathExtension(file->getPath()) == ".xml") {
                     // We can't remove .xml files at this point, because when
                     // we parse them they may add identifier resources, so
                     // removing them can cause our resource identifiers to
diff --git a/tools/aapt/Android.bp b/tools/aapt/Android.bp
index cecd95a..68db56d 100644
--- a/tools/aapt/Android.bp
+++ b/tools/aapt/Android.bp
@@ -51,6 +51,10 @@
         "libz",
     ],
 
+    whole_static_libs: [
+        "libandroidfw_pathutils",
+    ],
+
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/tools/aapt/CacheUpdater.h b/tools/aapt/CacheUpdater.h
index 2dc143c..dc5493f 100644
--- a/tools/aapt/CacheUpdater.h
+++ b/tools/aapt/CacheUpdater.h
@@ -7,6 +7,7 @@
 #ifndef CACHE_UPDATER_H
 #define CACHE_UPDATER_H
 
+#include <androidfw/PathUtils.h>
 #include <utils/String8.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -16,6 +17,8 @@
 #include <direct.h>
 #endif
 
+#include "Utils.h"
+
 using namespace android;
 
 /** CacheUpdater
@@ -72,14 +75,14 @@
             do {
                 // As we remove the end of existsPath add it to
                 // the string of paths to create.
-                toCreate = existsPath.getPathLeaf().appendPath(toCreate);
-                existsPath = existsPath.getPathDir();
+                toCreate = appendPathCopy(getPathLeaf(existsPath), toCreate);
+                existsPath = getPathDir(existsPath);
             } while (stat(existsPath.c_str(),&s) == -1);
 
             // Walk forwards and build directories as we go
             do {
                 // Advance to the next segment of the path
-                existsPath.appendPath(toCreate.walkPath(&remains));
+                appendPath(existsPath, walkPath(toCreate, &remains));
                 toCreate = remains;
 #ifdef _WIN32
                 _mkdir(existsPath.c_str());
@@ -101,7 +104,7 @@
     virtual void processImage(String8 source, String8 dest)
     {
         // Make sure we're trying to write to a directory that is extant
-        ensureDirectoriesExist(dest.getPathDir());
+        ensureDirectoriesExist(getPathDir(dest));
 
         preProcessImageToCache(bundle, source, dest);
     };
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 60f3f27..800466a 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -12,6 +12,7 @@
 #include "ResourceTable.h"
 #include "XMLNode.h"
 
+#include <androidfw/PathUtils.h>
 #include <utils/Errors.h>
 #include <utils/KeyedVector.h>
 #include <utils/List.h>
@@ -2486,12 +2487,12 @@
     for (int i = 1; i < bundle->getFileSpecCount(); i++) {
         const char* fileName = bundle->getFileSpecEntry(i);
 
-        if (strcasecmp(String8(fileName).getPathExtension().c_str(), ".gz") == 0) {
+        if (strcasecmp(getPathExtension(String8(fileName)).c_str(), ".gz") == 0) {
             printf(" '%s'... (from gzip)\n", fileName);
-            result = zip->addGzip(fileName, String8(fileName).getBasePath().c_str(), NULL);
+            result = zip->addGzip(fileName, getBasePath(String8(fileName)).c_str(), NULL);
         } else {
             if (bundle->getJunkPath()) {
-                String8 storageName = String8(fileName).getPathLeaf();
+                String8 storageName = getPathLeaf(String8(fileName));
                 printf(" '%s' as '%s'...\n", fileName,
                         ResTable::normalizeForOutput(storageName.c_str()).c_str());
                 result = zip->add(fileName, storageName.c_str(),
@@ -2617,10 +2618,10 @@
         return original;
     }
 
-    String8 ext(original.getPathExtension());
+    String8 ext(getPathExtension(original));
     if (ext == String8(".apk")) {
         return String8::format("%s_%s%s",
-                original.getBasePath().c_str(),
+                getBasePath(original).c_str(),
                 split->getDirectorySafeName().c_str(),
                 ext.c_str());
     }
@@ -2756,7 +2757,7 @@
             // generate the dependency file in the R.java package subdirectory
             // e.g. gen/com/foo/app/R.java.d
             dependencyFile = String8(bundle->getRClassDir());
-            dependencyFile.appendPath("R.java.d");
+            appendPath(dependencyFile, "R.java.d");
         }
         // Make sure we have a clean dependency file to start with
         fp = fopen(dependencyFile, "w");
diff --git a/tools/aapt/CrunchCache.cpp b/tools/aapt/CrunchCache.cpp
index 1f2febe..e731ce0 100644
--- a/tools/aapt/CrunchCache.cpp
+++ b/tools/aapt/CrunchCache.cpp
@@ -5,6 +5,7 @@
 // This file defines functions laid out and documented in
 // CrunchCache.h
 
+#include <androidfw/PathUtils.h>
 #include <utils/Compat.h>
 #include <utils/Vector.h>
 #include <utils/String8.h>
@@ -52,15 +53,15 @@
         relativePath = String8(rPathPtr + offset);
 
         if (forceOverwrite || needsUpdating(relativePath)) {
-            cu->processImage(mSourcePath.appendPathCopy(relativePath),
-                             mDestPath.appendPathCopy(relativePath));
+            cu->processImage(appendPathCopy(mSourcePath, relativePath),
+                             appendPathCopy(mDestPath, relativePath));
             numFilesUpdated++;
             // crunchFile(relativePath);
         }
         // Delete this file from the source files and (if it exists) from the
         // dest files.
         mSourceFiles.removeItemsAt(0);
-        mDestFiles.removeItem(mDestPath.appendPathCopy(relativePath));
+        mDestFiles.removeItem(appendPathCopy(mDestPath, relativePath));
     }
 
     // Iterate through what's left of destFiles and delete leftovers
@@ -99,7 +100,7 @@
     // Retrieve modification dates for this file entry under the source and
     // cache directory trees. The vectors will return a modification date of 0
     // if the file doesn't exist.
-    time_t sourceDate = mSourceFiles.valueFor(mSourcePath.appendPathCopy(relativePath));
-    time_t destDate = mDestFiles.valueFor(mDestPath.appendPathCopy(relativePath));
+    time_t sourceDate = mSourceFiles.valueFor(appendPathCopy(mSourcePath, relativePath));
+    time_t destDate = mDestFiles.valueFor(appendPathCopy(mDestPath, relativePath));
     return sourceDate > destDate;
 }
diff --git a/tools/aapt/DirectoryWalker.h b/tools/aapt/DirectoryWalker.h
index cea3a6e..7f60d4d 100644
--- a/tools/aapt/DirectoryWalker.h
+++ b/tools/aapt/DirectoryWalker.h
@@ -7,6 +7,7 @@
 #ifndef DIRECTORYWALKER_H
 #define DIRECTORYWALKER_H
 
+#include <androidfw/PathUtils.h>
 #include <dirent.h>
 #include <sys/types.h>
 #include <sys/param.h>
@@ -77,7 +78,7 @@
 
         mEntry = *entryPtr;
         // Get stats
-        String8 fullPath = mBasePath.appendPathCopy(mEntry.d_name);
+        String8 fullPath = appendPathCopy(mBasePath, mEntry.d_name);
         stat(fullPath.c_str(),&mStats);
         return &mEntry;
     };
diff --git a/tools/aapt/FileFinder.cpp b/tools/aapt/FileFinder.cpp
index a5c19806..69a8fa9 100644
--- a/tools/aapt/FileFinder.cpp
+++ b/tools/aapt/FileFinder.cpp
@@ -5,6 +5,7 @@
 // File Finder implementation.
 // Implementation for the functions declared and documented in FileFinder.h
 
+#include <androidfw/PathUtils.h>
 #include <utils/Vector.h>
 #include <utils/String8.h>
 #include <utils/KeyedVector.h>
@@ -57,7 +58,7 @@
         if (entry->d_name[0] == '.') // Skip hidden files and directories
             continue;
 
-        String8 fullPath = basePath.appendPathCopy(entryName);
+        String8 fullPath = appendPathCopy(basePath, entryName);
         // If this entry is a directory we'll recurse into it
         if (isDirectory(fullPath.c_str()) ) {
             DirectoryWalker* copy = dw->clone();
@@ -83,10 +84,10 @@
 {
     // Loop over the extensions, checking for a match
     bool done = false;
-    String8 ext(path.getPathExtension());
+    String8 ext(getPathExtension(path));
     ext.toLower();
     for (size_t i = 0; i < extensions.size() && !done; ++i) {
-        String8 ext2 = extensions[i].getPathExtension();
+        String8 ext2 = getPathExtension(extensions[i]);
         ext2.toLower();
         // Compare the extensions. If a match is found, add to storage.
         if (ext == ext2) {
diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp
index c6c7e96..cd4de90 100644
--- a/tools/aapt/Images.cpp
+++ b/tools/aapt/Images.cpp
@@ -8,6 +8,7 @@
 
 #include "Images.h"
 
+#include <androidfw/PathUtils.h>
 #include <androidfw/ResourceTypes.h>
 #include <utils/ByteOrder.h>
 
@@ -1357,7 +1358,7 @@
 status_t preProcessImage(const Bundle* bundle, const sp<AaptAssets>& /* assets */,
                          const sp<AaptFile>& file, String8* /* outNewLeafName */)
 {
-    String8 ext(file->getPath().getPathExtension());
+    String8 ext(getPathExtension(file->getPath()));
 
     // We currently only process PNG images.
     if (strcmp(ext.c_str(), ".png") != 0) {
@@ -1518,7 +1519,7 @@
 
     // Check to see if we're dealing with a 9-patch
     // If we are, process appropriately
-    if (source.getBasePath().getPathExtension() == ".9")  {
+    if (getPathExtension(getBasePath(source)) == ".9")  {
         if (do_9patch(source.c_str(), &imageInfo) != NO_ERROR) {
             return error;
         }
@@ -1584,12 +1585,12 @@
 status_t postProcessImage(const Bundle* bundle, const sp<AaptAssets>& assets,
                           ResourceTable* table, const sp<AaptFile>& file)
 {
-    String8 ext(file->getPath().getPathExtension());
+    String8 ext(getPathExtension(file->getPath()));
 
     // At this point, now that we have all the resource data, all we need to
     // do is compile XML files.
     if (strcmp(ext.c_str(), ".xml") == 0) {
-        String16 resourceName(parseResourceName(file->getSourceFile().getPathLeaf()));
+        String16 resourceName(parseResourceName(getPathLeaf(file->getSourceFile())));
         return compileXmlFile(bundle, assets, resourceName, file, table);
     }
 
diff --git a/tools/aapt/Package.cpp b/tools/aapt/Package.cpp
index a7ff5fa..5e0f87f 100644
--- a/tools/aapt/Package.cpp
+++ b/tools/aapt/Package.cpp
@@ -10,6 +10,7 @@
 #include "ResourceFilter.h"
 #include "Utils.h"
 
+#include <androidfw/PathUtils.h>
 #include <androidfw/misc.h>
 
 #include <utils/Log.h>
@@ -170,7 +171,7 @@
     /* anything here? */
     if (zip->getNumEntries() == 0) {
         if (bundle->getVerbose()) {
-            printf("Archive is empty -- removing %s\n", outputFile.getPathLeaf().c_str());
+            printf("Archive is empty -- removing %s\n", getPathLeaf(outputFile).c_str());
         }
         delete zip;        // close the file so we can remove it in Win32
         zip = NULL;
@@ -274,9 +275,9 @@
         return true;
     }
 
-    if (strcasecmp(storageName.getPathExtension().c_str(), ".gz") == 0) {
+    if (strcasecmp(getPathExtension(storageName).c_str(), ".gz") == 0) {
         fromGzip = true;
-        storageName = storageName.getBasePath();
+        storageName = getBasePath(storageName);
     }
 
     if (bundle->getUpdate()) {
@@ -366,7 +367,7 @@
  */
 bool okayToCompress(Bundle* bundle, const String8& pathName)
 {
-    String8 ext = pathName.getPathExtension();
+    String8 ext = getPathExtension(pathName);
     int i;
 
     if (ext.length() == 0)
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 4a360ed..3a198fd 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -19,6 +19,8 @@
 #include "WorkQueue.h"
 #include "XMLNode.h"
 
+#include <androidfw/PathUtils.h>
+
 #include <algorithm>
 
 // STATUST: mingw does seem to redefine UNKNOWN_ERROR from our enum value, so a cast is necessary.
@@ -143,8 +145,8 @@
                         mParams.inputFlags, mParams.navigation);
             }
             mPath = "res";
-            mPath.appendPath(file->getGroupEntry().toDirName(mResType));
-            mPath.appendPath(leaf);
+            appendPath(mPath, file->getGroupEntry().toDirName(mResType));
+            appendPath(mPath, leaf);
             mBaseName = parseResourceName(leaf);
             if (mBaseName == "") {
                 fprintf(stderr, "Error: malformed resource filename %s\n",
@@ -779,7 +781,7 @@
         if (kIsDebug) {
             printf("Qualifying class '%s' to '%s'", name.c_str(), className.c_str());
         }
-        attr->string.setTo(String16(className));
+        attr->string = String16(className);
     }
 }
 
@@ -969,7 +971,7 @@
             return UNKNOWN_ERROR;
         }
         String8 origPackage(attr->string);
-        attr->string.setTo(String16(manifestPackageNameOverride));
+        attr->string = String16(manifestPackageNameOverride);
         if (kIsDebug) {
             printf("Overriding package '%s' to be '%s'\n", origPackage.c_str(),
                     manifestPackageNameOverride);
@@ -1007,7 +1009,7 @@
                 XMLNode::attribute_entry* attr = child->editAttribute(
                         String16(RESOURCES_ANDROID_NAMESPACE), String16("targetPackage"));
                 if (attr != NULL) {
-                    attr->string.setTo(String16(instrumentationPackageNameOverride));
+                    attr->string = String16(instrumentationPackageNameOverride);
                 }
             }
         }
@@ -1686,7 +1688,7 @@
         ResourceDirIterator it(fonts, String8("font"));
         while ((err=it.next()) == NO_ERROR) {
             // fonts can be resources other than xml.
-            if (it.getFile()->getPath().getPathExtension() == ".xml") {
+            if (getPathExtension(it.getFile()->getPath()) == ".xml") {
                 String8 src = it.getFile()->getPrintableSource();
                 err = compileXmlFile(bundle, assets, String16(it.getBaseName()),
                         it.getFile(), &table, xmlFlags);
@@ -1716,7 +1718,7 @@
                              workItem.file, &table, xmlCompilationFlags);
 
         if (err == NO_ERROR && workItem.file->hasData()) {
-            assets->addResource(workItem.resPath.getPathLeaf(),
+            assets->addResource(getPathLeaf(workItem.resPath),
                                 workItem.resPath,
                                 workItem.file,
                                 workItem.file->getResourceType());
@@ -2851,7 +2853,7 @@
                 s++;
                 if (s > last && (*s == '.' || *s == 0)) {
                     String8 part(last, s-last);
-                    dest.appendPath(part);
+                    appendPath(dest, part);
 #ifdef _WIN32
                     _mkdir(dest.c_str());
 #else
@@ -2861,7 +2863,7 @@
                 }
             } while (*s);
         }
-        dest.appendPath(className);
+        appendPath(dest, className);
         dest.append(".java");
         FILE* fp = fopen(dest.c_str(), "w+");
         if (fp == NULL) {
@@ -2892,7 +2894,7 @@
 
         if (textSymbolsDest != NULL && R == className) {
             String8 textDest(textSymbolsDest);
-            textDest.appendPath(className);
+            appendPath(textDest, className);
             textDest.append(".txt");
 
             FILE* fp = fopen(textDest.c_str(), "w+");
@@ -2918,7 +2920,7 @@
         if (bundle->getGenDependencies() && R == className) {
             // Add this R.java to the dependency file
             String8 dependencyFile(bundle->getRClassDir());
-            dependencyFile.appendPath("R.java.d");
+            appendPath(dependencyFile, "R.java.d");
 
             FILE *fp = fopen(dependencyFile.c_str(), "a");
             fprintf(fp,"%s \\\n", dest.c_str());
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index bc252cf..9fb7319 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -14,6 +14,7 @@
 #include "Utils.h"
 
 #include <algorithm>
+#include <androidfw/PathUtils.h>
 #include <androidfw/ResourceTypes.h>
 #include <utils/ByteOrder.h>
 #include <utils/TypeHelpers.h>
@@ -83,7 +84,7 @@
         sp<AaptDir> resDir = assets->getDirs().valueFor(String8("res"));
         sp<AaptDir> dir = resDir->getDirs().valueFor(target->getGroupEntry().toDirName(
                 target->getResourceType()));
-        dir->removeFile(target->getPath().getPathLeaf());
+        dir->removeFile(getPathLeaf(target->getPath()));
         return NO_ERROR;
     }
 
@@ -1363,11 +1364,11 @@
                     size_t length;
                     const char16_t* attr = block.getAttributeName(i, &length);
                     if (strcmp16(attr, name16.c_str()) == 0) {
-                        name.setTo(block.getAttributeStringValue(i, &length));
+                        name = String16(block.getAttributeStringValue(i, &length));
                     } else if (strcmp16(attr, translatable16.c_str()) == 0) {
-                        translatable.setTo(block.getAttributeStringValue(i, &length));
+                        translatable = String16(block.getAttributeStringValue(i, &length));
                     } else if (strcmp16(attr, formatted16.c_str()) == 0) {
-                        formatted.setTo(block.getAttributeStringValue(i, &length));
+                        formatted = String16(block.getAttributeStringValue(i, &length));
                     }
                 }
                 
@@ -1541,7 +1542,7 @@
                 } else {
                     ssize_t sep = ident.findLast('.');
                     if (sep >= 0) {
-                        parentIdent.setTo(ident, sep);
+                        parentIdent = String16(ident, sep);
                     }
                 }
 
@@ -2831,10 +2832,10 @@
                 String8 config;
                 comma = strchr(start, ',');
                 if (comma != NULL) {
-                    config.setTo(start, comma - start);
+                    config = String8(start, comma - start);
                     start = comma + 1;
                 } else {
-                    config.setTo(start);
+                    config = start;
                 }
 
                 if (!locale.initFromFilterString(config)) {
diff --git a/tools/aapt/Utils.cpp b/tools/aapt/Utils.cpp
index 36b018e..946916a 100644
--- a/tools/aapt/Utils.cpp
+++ b/tools/aapt/Utils.cpp
@@ -36,3 +36,26 @@
     }
 #endif
 }
+
+String8 walkPath(const String8& path, String8* outRemains) {
+    const char* cp;
+    const char* const str = path.c_str();
+    const char* buf = str;
+
+    cp = strchr(buf, OS_PATH_SEPARATOR);
+    if (cp == buf) {
+        // don't include a leading '/'.
+        buf = buf + 1;
+        cp = strchr(buf, OS_PATH_SEPARATOR);
+    }
+
+    if (cp == nullptr) {
+        String8 res = buf != str ? String8(buf) : path;
+        if (outRemains) *outRemains = String8();
+        return res;
+    }
+
+    String8 res(buf, cp - buf);
+    if (outRemains) *outRemains = String8(cp + 1);
+    return res;
+}
diff --git a/tools/aapt/Utils.h b/tools/aapt/Utils.h
index 8eb5941..f0d6979 100644
--- a/tools/aapt/Utils.h
+++ b/tools/aapt/Utils.h
@@ -26,3 +26,13 @@
 // If the default OS separator is backslash, this converts all
 // backslashes to slashes, in-place. Otherwise it does nothing.
 void convertToResPath(android::String8&);
+
+/**
+ * Retrieve the front (root dir) component.  Optionally also return the
+ * remaining components.
+ *
+ * "/tmp/foo/bar.c" --> "tmp" (remain = "foo/bar.c")
+ * "/tmp" --> "tmp" (remain = "")
+ * "bar.c" --> "bar.c" (remain = "")
+ */
+android::String8 walkPath(const android::String8& path, android::String8* outRemains = nullptr);
diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp
index e270a73..a887ac9 100644
--- a/tools/aapt/XMLNode.cpp
+++ b/tools/aapt/XMLNode.cpp
@@ -334,9 +334,9 @@
             String16 spanTag;
             ssize_t semi = span.name.findFirst(';');
             if (semi >= 0) {
-                spanTag.setTo(span.name.c_str(), semi);
+                spanTag = String16(span.name.c_str(), semi);
             } else {
-                spanTag.setTo(span.name);
+                spanTag = span.name;
             }
             if (strcmp16(inXml->getElementName(&len), spanTag.c_str()) != 0) {
                 SourcePos(String8(fileName), inXml->getLineNumber()).error(
@@ -393,7 +393,7 @@
         // later as part of the overall type conversion.  Return to the
         // client the raw unprocessed text.
         rawString.append(curString);
-        outString->setTo(rawString);
+        *outString = rawString;
     }
 
     return NO_ERROR;
diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp
index 6bf265d..a2b4818 100644
--- a/tools/aapt2/dump/DumpManifest.cpp
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -216,9 +216,7 @@
 
 class ManifestExtractor {
  public:
-
-  explicit ManifestExtractor(LoadedApk* apk, DumpManifestOptions& options)
-      : apk_(apk), options_(options) { }
+  explicit ManifestExtractor(LoadedApk* apk, DumpManifestOptions& options);
 
   class Element {
    public:
@@ -509,7 +507,7 @@
 
  private:
   std::unique_ptr<xml::XmlResource> doc_;
-  std::unique_ptr<CommonFeatureGroup> commonFeatureGroup_ = util::make_unique<CommonFeatureGroup>();
+  std::unique_ptr<CommonFeatureGroup> commonFeatureGroup_;
   std::map<std::string, ConfigDescription> locales_;
   std::map<uint16_t, ConfigDescription> densities_;
   std::vector<Element*> parent_stack_;
@@ -2471,6 +2469,12 @@
   }
 }
 
+// Define this constructor after the CommonFeatureGroup class definition to avoid errors with using
+// std::unique_ptr on an incomplete type.
+ManifestExtractor::ManifestExtractor(LoadedApk* apk, DumpManifestOptions& options)
+    : apk_(apk), options_(options), commonFeatureGroup_(util::make_unique<CommonFeatureGroup>()) {
+}
+
 bool ManifestExtractor::Extract(android::IDiagnostics* diag) {
   // Load the manifest
   doc_ = apk_->LoadXml("AndroidManifest.xml", diag);
diff --git a/tools/hoststubgen/.gitignore b/tools/hoststubgen/.gitignore
new file mode 100644
index 0000000..6453bde
--- /dev/null
+++ b/tools/hoststubgen/.gitignore
@@ -0,0 +1,3 @@
+out/
+*-out/
+*.log
diff --git a/tools/hoststubgen/README.md b/tools/hoststubgen/README.md
new file mode 100644
index 0000000..b0a1262
--- /dev/null
+++ b/tools/hoststubgen/README.md
@@ -0,0 +1,76 @@
+# HostStubGen
+
+## Overview
+
+This directory contains tools / sample code / investigation for host side test support.
+
+
+## Directories and files
+
+- `hoststubgen/`
+  Contains source code of the "hoststubgen" tool and relevant code
+
+  - `framework-policy-override.txt`
+    This file contains "policy overrides", which allows to control what goes to stub/impl without
+    having to touch the target java files. This allows quicker iteration, because you can skip
+    having to rebuild framework.jar.
+
+  - `src/`
+
+    HostStubGen tool source code.
+
+  - `annotations-src/` See `Android.bp`.
+  - `helper-framework-buildtime-src/` See `Android.bp`.
+  - `helper-framework-runtime-src/` See `Android.bp`.
+  - `helper-runtime-src/` See `Android.bp`.
+
+  - `test-tiny-framework/` See `README.md` in it.
+
+  - `test-framework` See `README.md` in it.
+
+- `scripts`
+  - `run-host-test.sh`
+
+    Run a host side test. Use it instead of `atest` for now. (`atest` works "mostly" but it has
+    problems.)
+
+  - `dump-jar.sh`
+
+    A script to dump the content of `*.class` and `*.jar` files.
+
+  - `run-all-tests.sh`
+
+    Run all tests. Many tests may fail, but at least this should run til the end.
+    (It should print `run-all-tests.sh finished` at the end)
+
+## Build and run
+
+### Building `HostStubGen` binary
+
+```
+m hoststubgen
+```
+
+### Run the tests
+
+- Run all relevant tests and test scripts. Some of thests are still expected to fail,
+  but this should print "finished, with no unexpected failures" at the end.
+
+  However, because some of the script it executes depend on internal file paths to Soong's
+  intermediate directory, some of it might fail when something changes in the build system.
+
+  We need proper build system integration to fix them.
+```
+$ ./scripts/run-all-tests.sh
+```
+
+- See also `README.md` in `test-*` directories.
+
+## TODOs, etc
+
+ - Make sure the parent's visibility is not smaller than the member's.
+
+- @HostSideTestNativeSubstitutionClass should automatically add class-keep to the substitute class.
+  (or at least check it.)
+
+ - The `HostStubGenTest-framework-test-host-test-lib` jar somehow contain all ASM classes? Figure out where the dependency is coming from.
diff --git a/tools/hoststubgen/TEST_MAPPING b/tools/hoststubgen/TEST_MAPPING
new file mode 100644
index 0000000..9703626
--- /dev/null
+++ b/tools/hoststubgen/TEST_MAPPING
@@ -0,0 +1,6 @@
+{
+    // TODO: Change to presubmit.
+    "postsubmit": [
+        { "name": "tiny-framework-dump-test" }
+    ]
+}
diff --git a/tools/hoststubgen/common.sh b/tools/hoststubgen/common.sh
new file mode 100644
index 0000000..b49ee39
--- /dev/null
+++ b/tools/hoststubgen/common.sh
@@ -0,0 +1,116 @@
+# 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.
+
+set -e # Exit at failure
+shopt -s globstar # Enable double-star wildcards (**)
+
+cd "${0%/*}" # Move to the script dir
+
+fail() {
+  echo "Error: $*" 1>&2
+  exit 1
+}
+
+# Print the arguments and then execute.
+run() {
+  echo "Running: $*" 1>&2
+  "$@"
+}
+
+# Concatenate the second and subsequent args with the first arg as a separator.
+# e.g. `join : a b c` -> prints `a:b:c`
+join() {
+  local IFS="$1"
+  shift
+  echo "$*"
+}
+
+abspath() {
+  for name in "${@}"; do
+    readlink -f $name
+  done
+}
+
+m() {
+  if (( $SKIP_BUILD )) ; then
+    echo "Skipping build: $*" 1>&2
+    return 0
+  fi
+  run ${ANDROID_BUILD_TOP}/build/soong/soong_ui.bash --make-mode "$@"
+}
+
+# Extract given jar files
+extract() {
+  for f in "${@}"; do
+    local out=$f.ext
+    run rm -fr $out
+    run mkdir -p $out
+
+    # It's too noisy, so only show the first few lines.
+    {
+      # Hmm unzipping kotlin jar files may produce a warning? Let's just add `|| true`...
+      run unzip $f -d $out || true
+    } |& sed -e '5,$d'
+    echo '  (omitting remaining output)'
+
+  done
+}
+
+# Find all *.java files in $1, and print them as Java class names.
+# For example, if there's a file `src/com/android/test/Test.java`, and you run
+# `list_all_classes_under_dir src`, then it'll print `com.android.test.Test`.
+list_all_classes_under_dir() {
+  local dir="$1"
+  ( # Use a subshell, so we won't change the current directory on the caller side.
+    cd "$dir"
+
+    # List the java files, but replace the slashes with dots, and remove the `.java` suffix.
+    ls **/*.java | sed -e 's!/!.!g' -e 's!.java$!!'
+  )
+}
+
+checkenv() {
+  # Make sure $ANDROID_BUILD_TOP is set.
+  : ${ANDROID_BUILD_TOP:?}
+
+  # Make sure ANDROID_BUILD_TOP doesn't contain whitespace.
+  set ${ANDROID_BUILD_TOP}
+  if [[ $# != 1 ]] ; then
+    fail "\$ANDROID_BUILD_TOP cannot contain whitespace."
+  fi
+}
+
+checkenv
+
+JAVAC=${JAVAC:-javac}
+JAVA=${JAVA:-java}
+JAR=${JAR:-jar}
+
+JAVAC_OPTS=${JAVAC_OPTS:--Xmaxerrs 99999 -Xlint:none}
+
+SOONG_INT=$ANDROID_BUILD_TOP/out/soong/.intermediates
+
+JUNIT_TEST_MAIN_CLASS=com.android.hoststubgen.hosthelper.HostTestSuite
+
+run_junit_test_jar() {
+  local jar="$1"
+  echo "Starting test: $jar ..."
+  run cd "${jar%/*}"
+
+  run $JAVA $JAVA_OPTS \
+      -cp $jar \
+      org.junit.runner.JUnitCore \
+      $main_class || return 1
+  return 0
+}
diff --git a/tools/hoststubgen/hoststubgen/.gitignore b/tools/hoststubgen/hoststubgen/.gitignore
new file mode 100644
index 0000000..0f38407
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/.gitignore
@@ -0,0 +1 @@
+framework-all-stub-out
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/Android.bp b/tools/hoststubgen/hoststubgen/Android.bp
new file mode 100644
index 0000000..a617876
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/Android.bp
@@ -0,0 +1,303 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+// This library contains the standard hoststubgen annotations.
+java_library {
+    name: "hoststubgen-annotations",
+    srcs: [
+        "annotations-src/**/*.java",
+    ],
+    host_supported: true,
+
+    // Seems like we need it to avoid circular deps.
+    // Copied it from "app-compat-annotations".
+    sdk_version: "core_current",
+    visibility: ["//visibility:public"],
+}
+
+// This library contains helper classes used in the host side test environment at runtime.
+// This library is _not_ specific to Android APIs.
+java_library_host {
+    name: "hoststubgen-helper-runtime",
+    srcs: [
+        "helper-runtime-src/**/*.java",
+    ],
+    libs: [
+        "junit",
+        "ow2-asm",
+        "ow2-asm-analysis",
+        "ow2-asm-commons",
+        "ow2-asm-tree",
+        "ow2-asm-util",
+    ],
+    static_libs: [
+        "guava",
+    ],
+    jarjar_rules: "jarjar-rules.txt",
+    visibility: ["//visibility:public"],
+}
+
+// Host-side stub generator tool.
+java_binary_host {
+    name: "hoststubgen",
+    main_class: "com.android.hoststubgen.Main",
+    srcs: ["src/**/*.kt"],
+    static_libs: [
+        "hoststubgen-helper-runtime",
+        "ow2-asm",
+        "ow2-asm-analysis",
+        "ow2-asm-commons",
+        "ow2-asm-tree",
+        "ow2-asm-util",
+    ],
+    visibility: ["//visibility:public"],
+}
+
+// File that contains the standard command line argumetns to hoststubgen.
+filegroup {
+    name: "hoststubgen-standard-options",
+    srcs: [
+        "hoststubgen-standard-options.txt",
+    ],
+    visibility: ["//visibility:public"],
+}
+
+hoststubgen_common_options = "$(location hoststubgen) " +
+    // "--in-jar $(location :framework-all) " +
+    // "--policy-override-file $(location framework-policy-override.txt) " +
+    "@$(location :hoststubgen-standard-options) " +
+
+    "--out-stub-jar $(location host_stub.jar) " +
+    "--out-impl-jar $(location host_impl.jar) " +
+
+    // "--keep-all-classes " + // Used it for an experiment. See KeepAllClassesFilter.
+    "--gen-keep-all-file $(location hoststubgen_keep_all.txt) " +
+    "--gen-input-dump-file $(location hoststubgen_dump.txt) " +
+    ""
+
+// Common defaults for stub generation.
+// This one is not specific to Android APIs.
+genrule_defaults {
+    name: "hoststubgen-command-defaults",
+    tools: ["hoststubgen"],
+    srcs: [
+        ":hoststubgen-standard-options",
+    ],
+    // Create two jar files.
+    out: [
+        "host_stub.jar",
+        "host_impl.jar",
+
+        // Following files are created just as FYI.
+        "hoststubgen_keep_all.txt",
+        "hoststubgen_dump.txt",
+    ],
+    // visibility:  ["//visibility:public"],
+}
+
+// Generate the stub/impl from framework-all, with hidden APIs.
+java_genrule_host {
+    name: "framework-all-hidden-api-host",
+    defaults: ["hoststubgen-command-defaults"],
+    cmd: hoststubgen_common_options +
+        "--in-jar $(location :framework-all) " +
+        "--policy-override-file $(location framework-policy-override.txt) ",
+    srcs: [
+        ":framework-all",
+        "framework-policy-override.txt",
+    ],
+    visibility: ["//visibility:private"],
+}
+
+// Extract the stub jar from "framework-all-host" for subsequent build rules.
+java_genrule_host {
+    name: "framework-all-hidden-api-host-stub",
+    cmd: "cp $(in) $(out)",
+    srcs: [
+        ":framework-all-hidden-api-host{host_stub.jar}",
+    ],
+    out: [
+        "host_stub.jar",
+    ],
+    visibility: ["//visibility:public"],
+}
+
+// Extract the impl jar from "framework-all-host" for subsequent build rules.
+java_genrule_host {
+    name: "framework-all-hidden-api-host-impl",
+    cmd: "cp $(in) $(out)",
+    srcs: [
+        ":framework-all-hidden-api-host{host_impl.jar}",
+    ],
+    out: [
+        "host_impl.jar",
+    ],
+    visibility: ["//visibility:public"],
+}
+
+// Generate the stub/impl from framework-all, with only public/system/test APIs, without
+// hidden APIs.
+java_genrule_host {
+    name: "framework-all-test-api-host",
+    defaults: ["hoststubgen-command-defaults"],
+    cmd: hoststubgen_common_options +
+        "--intersect-stub-jar $(location :android_test_stubs_current{.jar}) " +
+        "--in-jar $(location :framework-all) " +
+        "--policy-override-file $(location framework-policy-override.txt) ",
+    srcs: [
+        ":framework-all",
+        ":android_test_stubs_current{.jar}",
+        "framework-policy-override.txt",
+    ],
+    visibility: ["//visibility:private"],
+}
+
+// Extract the stub jar from "framework-all-test-api-host" for subsequent build rules.
+java_genrule_host {
+    name: "framework-all-test-api-host-stub",
+    cmd: "cp $(in) $(out)",
+    srcs: [
+        ":framework-all-test-api-host{host_stub.jar}",
+    ],
+    out: [
+        "host_stub.jar",
+    ],
+    visibility: ["//visibility:public"],
+}
+
+// Extract the impl jar from "framework-all-test-api-host" for subsequent build rules.
+java_genrule_host {
+    name: "framework-all-test-api-host-impl",
+    cmd: "cp $(in) $(out)",
+    srcs: [
+        ":framework-all-test-api-host{host_impl.jar}",
+    ],
+    out: [
+        "host_impl.jar",
+    ],
+    visibility: ["//visibility:public"],
+}
+
+// This library contains helper classes to build hostside tests/targets.
+// This essentially contains dependencies from tests that we can't actually use the real ones.
+// For example, the actual AndroidTestCase and AndroidJUnit4 don't run on the host side (yet),
+// so we pup "fake" implementations here.
+// Ideally this library should be empty.
+java_library_host {
+    name: "hoststubgen-helper-framework-buildtime",
+    srcs: [
+        "helper-framework-buildtime-src/**/*.java",
+    ],
+    libs: [
+        // We need it to pull in some of the framework classes used in this library,
+        // such as Context.java.
+        "framework-all-hidden-api-host-impl",
+        "junit",
+    ],
+    visibility: ["//visibility:public"],
+}
+
+// This module contains "fake" libcore/dalvik classes, framework native substitution, etc,
+// that are needed at runtime.
+java_library_host {
+    name: "hoststubgen-helper-framework-runtime",
+    srcs: [
+        "helper-framework-runtime-src/**/*.java",
+    ],
+    libs: [
+        "hoststubgen-helper-runtime",
+        "framework-all-hidden-api-host-impl",
+    ],
+    visibility: ["//visibility:public"],
+}
+
+// Defaults for host side test modules.
+// We need two rules for each test.
+// 1. A "-test-lib" jar, which compiles the test against the stub jar.
+//    This one is only used by the second rule, so it should be "private.
+// 2. A "-test" jar, which includes 1 + the runtime (impl) jars.
+
+// This and next ones are for tests using framework-app, with hidden APIs.
+java_defaults {
+    name: "hosttest-with-framework-all-hidden-api-test-lib-defaults",
+    installable: false,
+    libs: [
+        "framework-all-hidden-api-host-stub",
+    ],
+    static_libs: [
+        "hoststubgen-helper-framework-buildtime",
+        "framework-annotations-lib",
+    ],
+    visibility: ["//visibility:private"],
+}
+
+// Default rules to include `libandroid_runtime`. For now, it's empty, but we'll use it
+// once we start using JNI.
+java_defaults {
+    name: "hosttest-with-libandroid_runtime",
+    jni_libs: [
+        // "libandroid_runtime",
+
+        // TODO: Figure out how to build them automatically.
+        // Following ones are depended by libandroid_runtime.
+        // Without listing them here, not only we won't get them under
+        // $ANDROID_HOST_OUT/testcases/*/lib64, but also not under
+        // $ANDROID_HOST_OUT/lib64, so we'd fail to load them at runtime.
+        // ($ANDROID_HOST_OUT/lib/ gets all of them though.)
+        // "libcutils",
+        // "libharfbuzz_ng",
+        // "libminikin",
+        // "libz",
+        // "libbinder",
+        // "libhidlbase",
+        // "libvintf",
+        // "libicu",
+        // "libutils",
+        // "libtinyxml2",
+    ],
+}
+
+java_defaults {
+    name: "hosttest-with-framework-all-hidden-api-test-defaults",
+    defaults: ["hosttest-with-libandroid_runtime"],
+    installable: false,
+    test_config: "AndroidTest-host.xml",
+    static_libs: [
+        "hoststubgen-helper-runtime",
+        "hoststubgen-helper-framework-runtime",
+        "framework-all-hidden-api-host-impl",
+    ],
+}
+
+// This and next ones are for tests using framework-app, with public/system/test APIs,
+// without hidden APIs.
+java_defaults {
+    name: "hosttest-with-framework-all-test-api-test-lib-defaults",
+    installable: false,
+    libs: [
+        "framework-all-test-api-host-stub",
+    ],
+    static_libs: [
+        "hoststubgen-helper-framework-buildtime",
+        "framework-annotations-lib",
+    ],
+    visibility: ["//visibility:private"],
+}
+
+java_defaults {
+    name: "hosttest-with-framework-all-test-api-test-defaults",
+    defaults: ["hosttest-with-libandroid_runtime"],
+    installable: false,
+    test_config: "AndroidTest-host.xml",
+    static_libs: [
+        "hoststubgen-helper-runtime",
+        "hoststubgen-helper-framework-runtime",
+        "framework-all-test-api-host-impl",
+    ],
+}
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestClassLoadHook.java b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestClassLoadHook.java
new file mode 100644
index 0000000..a774336
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestClassLoadHook.java
@@ -0,0 +1,38 @@
+/*
+ * 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.hosttest.annotation;
+
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * Add this with a fully-specified method name (e.g. {@code "com.package.Class.methodName"})
+ * of a callback to get a callback at the class load time.
+ *
+ * The method must be {@code public static} with a single argument that takes
+ * {@link java.lang.Class}.
+ */
+@Target({TYPE})
+@Retention(RetentionPolicy.CLASS)
+public @interface HostSideTestClassLoadHook {
+    String value();
+}
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestKeep.java b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestKeep.java
new file mode 100644
index 0000000..06ad1c2
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestKeep.java
@@ -0,0 +1,43 @@
+/*
+ * 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.hosttest.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * Mark a class, field or a method as "Stub", meaning tests can _not_ see the APIs, but they
+ * can indirectly be used on the host side.
+ * When applied to a class, it will _not_ affect the visibility of its members. They need to be
+ * individually marked.
+ *
+ * <p>In order to expose a class and all its members, use {@link HostSideTestWholeClassStub}
+ * instead.
+ * @hide
+ */
+@Target({TYPE, FIELD, METHOD, CONSTRUCTOR})
+@Retention(RetentionPolicy.CLASS)
+public @interface HostSideTestKeep {
+}
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestNativeSubstitutionClass.java b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestNativeSubstitutionClass.java
new file mode 100644
index 0000000..9c81383
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestNativeSubstitutionClass.java
@@ -0,0 +1,35 @@
+/*
+ * 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.hosttest.annotation;
+
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * If a class has this annotation, all its native methods will be delegated to another class.
+ * (See {@link android.os.Parcel} as an example.)
+ */
+@Target({TYPE})
+@Retention(RetentionPolicy.CLASS)
+public @interface HostSideTestNativeSubstitutionClass {
+    String value();
+}
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestRemove.java b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestRemove.java
new file mode 100644
index 0000000..46e5078
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestRemove.java
@@ -0,0 +1,39 @@
+/*
+ * 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.hosttest.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * Mark an item as "remove", so this cannot be used on the host side even indirectly.
+ * This is the default behavior.
+ *
+ * @hide
+ */
+@Target({TYPE, FIELD, METHOD, CONSTRUCTOR})
+@Retention(RetentionPolicy.CLASS)
+public @interface HostSideTestRemove {
+}
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestStub.java b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestStub.java
new file mode 100644
index 0000000..cabdfe0
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestStub.java
@@ -0,0 +1,43 @@
+/*
+ * 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.hosttest.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * Mark a class, field or a method as "Stub", meaning tests can see the APIs.
+ * When applied to a class, it will _not_ affect the visibility of its members. They need to be
+ * individually marked.
+ *
+ * <p>In order to expose a class and all its members, use {@link HostSideTestWholeClassStub}
+ * instead.
+ *
+ * @hide
+ */
+@Target({TYPE, FIELD, METHOD, CONSTRUCTOR})
+@Retention(RetentionPolicy.CLASS)
+public @interface HostSideTestStub {
+}
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestSubstitute.java b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestSubstitute.java
new file mode 100644
index 0000000..510a67e
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestSubstitute.java
@@ -0,0 +1,40 @@
+/*
+ * 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.hosttest.annotation;
+
+import static java.lang.annotation.ElementType.METHOD;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * If a method has this annotation, we'll replace it with another method on the host side.
+ *
+ * See {@link android.util.LruCache#getEldest()} and its substitution.
+ *
+ * @hide
+ */
+@Target({METHOD})
+@Retention(RetentionPolicy.CLASS)
+public @interface HostSideTestSubstitute {
+    // TODO We should add "_host" as default. We're not doing it yet, because extractign the default
+    // value with ASM doesn't seem trivial. (? not sure.)
+    String suffix();
+}
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestThrow.java b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestThrow.java
new file mode 100644
index 0000000..cd1bef4
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestThrow.java
@@ -0,0 +1,36 @@
+/*
+ * 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.hosttest.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.METHOD;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * If a method has this annotation, it will throw on the host side.
+ *
+ * @hide
+ */
+@Target({METHOD, CONSTRUCTOR})
+@Retention(RetentionPolicy.CLASS)
+public @interface HostSideTestThrow {
+}
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestWholeClassKeep.java b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestWholeClassKeep.java
new file mode 100644
index 0000000..3d1ddea
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestWholeClassKeep.java
@@ -0,0 +1,34 @@
+/*
+ * 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.hosttest.annotation;
+
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * Same as {@link HostSideTestKeep} but it'll change the visibility of all its members too.
+ * @hide
+ */
+@Target({TYPE})
+@Retention(RetentionPolicy.CLASS)
+public @interface HostSideTestWholeClassKeep {
+}
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestWholeClassStub.java b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestWholeClassStub.java
new file mode 100644
index 0000000..1824f6f
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestWholeClassStub.java
@@ -0,0 +1,35 @@
+/*
+ * 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.hosttest.annotation;
+
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * Same as {@link HostSideTestStub} but it'll change the visibility of all its members too.
+ *
+ * @hide
+ */
+@Target({TYPE})
+@Retention(RetentionPolicy.CLASS)
+public @interface HostSideTestWholeClassStub {
+}
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/tests/HostSideTestSuppress.java b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/tests/HostSideTestSuppress.java
new file mode 100644
index 0000000..b10f0ff
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/tests/HostSideTestSuppress.java
@@ -0,0 +1,31 @@
+/*
+ * 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.hosttest.annotation.tests;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Target;
+
+/**
+ * Use this annotation to skip certain tests for host side tests.
+ *
+ * TODO: Actually use it in the test runner.
+ */
+@Target({TYPE, FIELD, METHOD})
+public @interface HostSideTestSuppress {
+}
diff --git a/tools/hoststubgen/hoststubgen/framework-policy-override.txt b/tools/hoststubgen/hoststubgen/framework-policy-override.txt
new file mode 100644
index 0000000..295498d
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/framework-policy-override.txt
@@ -0,0 +1,98 @@
+# --------------------------------------------------------------------------------------------------
+# This file contains rules to process `framework-all.jar` to generate the host side test "stub" and
+# "impl" jars, without using Java annotations.
+#
+# Useful when:
+# - The class is auto-generated and annotations can't be added.
+#   (We need to figure out what to do on auto-generated classes.)
+# - Want to quickly change filter rules without having to rebuild framework.jar.
+#
+# Using this file, one can control the visibility of APIs on a per-class, per-field and per-method
+# basis, but in most cases, per-class directives would be sufficient. That is:
+#
+# - To put the entire class, including its members and nested classes, in the "stub" jar,
+#   so that the test / target code can use the API, use `stubclass`.
+#
+# class package.class	stubclass
+#
+# - To put the entire class, including its members and nested classes, in the "impl" jar,
+#   but not in the "stub" jar, use `keepclass`. Use this when you don't want to expose an API to
+#   tests/target directly, but it's still needed at runtime, because it's used by other "stub" APIs
+#   directly or indirectly.
+#
+# class package.class	keepclass
+#
+# All other classes will be removed from both the stub jar and impl jar.
+#
+# --------------------------------------------------------------------------------------------------
+
+# --------------------------------------------------------------------------------------------------
+# Directions on auto-generated classes, where we can't use Java annotations (yet).
+# --------------------------------------------------------------------------------------------------
+class android.Manifest stubclass
+class android.R        stubclass
+class android.os.PersistableBundleProto	keepclass
+
+# This is in module-utils, where using a HostStubGen annotation would be complicated, so we
+# add a direction here rather than using a java annotation.
+# The build file says it's deprecated, anyway...? Figure out what to do with it.
+class com.android.internal.util.Preconditions keepclass
+
+# --------------------------------------------------------------------------------------------------
+# Actual framework classes
+# --------------------------------------------------------------------------------------------------
+
+# Put basic exception classes in the "impl" jar.
+# We don't put them in stub yet (until something actually needs them).
+class android.os.DeadObjectException          keepclass
+class android.os.DeadSystemRuntimeException   keepclass
+class android.os.NetworkOnMainThreadException keepclass
+class android.os.RemoteException              keepclass
+class android.os.ServiceSpecificException     keepclass
+class android.util.AndroidException           keepclass
+class android.util.AndroidRuntimeException    keepclass
+class android.os.DeadSystemException          keepclass
+
+
+# For now, we only want to expose ArrayMap and Log, but they and their tests depend on
+# more classes.
+
+class android.util.ArrayMap             stubclass
+
+# Used by ArrayMap. No need to put them in the stub, but we need them in impl.
+class android.util.MapCollections         keepclass
+class android.util.ContainerHelpers       keepclass
+class com.android.internal.util.XmlUtils  keepclass
+class com.android.internal.util.FastMath  keepclass
+class android.util.MathUtils              keepclass
+
+
+class android.util.Log          stubclass
+class android.util.Slog         stubclass
+# We don't use Log's native code, yet. Instead, the following line enables the Java substitution.
+# Comment it out to disable Java substitution of Log's native methods.
+class android.util.Log	!com.android.hoststubgen.nativesubstitution.Log_host
+
+# Used by log
+class com.android.internal.util.FastPrintWriter         keepclass
+class com.android.internal.util.LineBreakBufferedWriter keepclass
+
+
+# Expose Context because it's referred to by AndroidTestCase, but don't need to expose any of
+# its members.
+class android.content.Context        keep
+
+# Expose Parcel, Parcel and there relevant classes, which are used by ArrayMapTets.
+class android.os.Parcelable     StubClass
+class android.os.Parcel         StubClass
+class android.os.Parcel         !com.android.hoststubgen.nativesubstitution.Parcel_host
+
+class android.os.IBinder        stubClass
+class android.os.IInterface     stubclass
+
+class android.os.BadParcelableException     stubclass
+class android.os.BadTypeParcelableException stubclass
+
+class android.os.BaseBundle        stubclass
+class android.os.Bundle            stubclass
+class android.os.PersistableBundle stubclass
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/android/test/AndroidTestCase.java b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/android/test/AndroidTestCase.java
new file mode 100644
index 0000000..e6d3866
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/android/test/AndroidTestCase.java
@@ -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 android.test;
+
+import android.content.Context;
+
+import junit.framework.TestCase;
+
+public class AndroidTestCase extends TestCase {
+    protected Context mContext;
+    public Context getContext() {
+        throw new RuntimeException("[ravenwood] Class Context is not supported yet.");
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/annotation/NonNull.java b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/annotation/NonNull.java
new file mode 100644
index 0000000..51c5d9a
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/annotation/NonNull.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2013 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 androidx.annotation;
+
+// [ravenwood] TODO: Find the actual androidx jar containing it.s
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Denotes that a parameter, field or method return value can never be null.
+ * <p>
+ * This is a marker annotation and it has no specific attributes.
+ *
+ * @paramDoc This value cannot be {@code null}.
+ * @returnDoc This value cannot be {@code null}.
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD, PARAMETER, FIELD})
+public @interface NonNull {
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/annotation/Nullable.java b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/annotation/Nullable.java
new file mode 100644
index 0000000..f1f0e8b
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/annotation/Nullable.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2013 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 androidx.annotation;
+
+// [ravenwood] TODO: Find the actual androidx jar containing it.s
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Denotes that a parameter, field or method return value can be null.
+ * <p>
+ * When decorating a method call parameter, this denotes that the parameter can
+ * legitimately be null and the method will gracefully deal with it. Typically
+ * used on optional parameters.
+ * <p>
+ * When decorating a method, this denotes the method might legitimately return
+ * null.
+ * <p>
+ * This is a marker annotation and it has no specific attributes.
+ *
+ * @paramDoc This value may be {@code null}.
+ * @returnDoc This value may be {@code null}.
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD, PARAMETER, FIELD})
+public @interface Nullable {
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/ext/junit/runners/AndroidJUnit4.java b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/ext/junit/runners/AndroidJUnit4.java
new file mode 100644
index 0000000..0c82e4e
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/ext/junit/runners/AndroidJUnit4.java
@@ -0,0 +1,30 @@
+/*
+ * 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 androidx.test.ext.junit.runners;
+
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.InitializationError;
+
+// TODO: We need to simulate the androidx test runner.
+// https://source.corp.google.com/piper///depot/google3/third_party/android/androidx_test/ext/junit/java/androidx/test/ext/junit/runners/AndroidJUnit4.java
+// https://source.corp.google.com/piper///depot/google3/third_party/android/androidx_test/runner/android_junit_runner/java/androidx/test/internal/runner/junit4/AndroidJUnit4ClassRunner.java
+
+public class AndroidJUnit4 extends BlockJUnit4ClassRunner {
+    public AndroidJUnit4(Class<?> testClass) throws InitializationError {
+        super(testClass);
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/FlakyTest.java b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/FlakyTest.java
new file mode 100644
index 0000000..2470d839
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/FlakyTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2014 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 androidx.test.filters;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Designates a test as being flaky (non-deterministic).
+ *
+ * <p>Can then be used to filter tests on execution using -e annotation or -e notAnnotation as
+ * desired.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface FlakyTest {
+  /**
+   * An optional bug number associated with the test. -1 Means that no bug number is associated with
+   * the flaky annotation.
+   *
+   * @return int
+   */
+  int bugId() default -1;
+
+  /**
+   * Details, such as the reason of why the test is flaky.
+   *
+   * @return String
+   */
+  String detail() default "";
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/LargeTest.java b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/LargeTest.java
new file mode 100644
index 0000000..578d7dc
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/LargeTest.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 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 androidx.test.filters;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to assign a large test size qualifier to a test. This annotation can be used at a
+ * method or class level.
+ *
+ * <p>Test size qualifiers are a great way to structure test code and are used to assign a test to a
+ * test suite of similar run time.
+ *
+ * <p>Execution time: &gt;1000ms
+ *
+ * <p>Large tests should be focused on testing integration of all application components. These
+ * tests fully participate in the system and may make use of all resources such as databases, file
+ * systems and network. As a rule of thumb most functional UI tests are large tests.
+ *
+ * <p>Note: This class replaces the deprecated Android platform size qualifier <a
+ * href="{@docRoot}reference/android/test/suitebuilder/annotation/LargeTest.html"><code>
+ * android.test.suitebuilder.annotation.LargeTest</code></a> and is the recommended way to annotate
+ * tests written with the AndroidX Test Library.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface LargeTest {}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/MediumTest.java b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/MediumTest.java
new file mode 100644
index 0000000..dfdaa53
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/MediumTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 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 androidx.test.filters;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to assign a medium test size qualifier to a test. This annotation can be used at a
+ * method or class level.
+ *
+ * <p>Test size qualifiers are a great way to structure test code and are used to assign a test to a
+ * test suite of similar run time.
+ *
+ * <p>Execution time: &lt;1000ms
+ *
+ * <p>Medium tests should be focused on a very limited subset of components or a single component.
+ * Resource access to the file system through well defined interfaces like databases,
+ * ContentProviders, or Context is permitted. Network access should be restricted, (long-running)
+ * blocking operations should be avoided and use mock objects instead.
+ *
+ * <p>Note: This class replaces the deprecated Android platform size qualifier <a
+ * href="{@docRoot}reference/android/test/suitebuilder/annotation/MediumTest.html"><code>
+ * android.test.suitebuilder.annotation.MediumTest</code></a> and is the recommended way to annotate
+ * tests written with the AndroidX Test Library.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface MediumTest {}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/RequiresDevice.java b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/RequiresDevice.java
new file mode 100644
index 0000000..3d3ee33
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/RequiresDevice.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 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 androidx.test.filters;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates that a specific test should not be run on emulator.
+ *
+ * <p>It will be executed only if the test is running on the physical android device.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface RequiresDevice {}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/SdkSuppress.java b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/SdkSuppress.java
new file mode 100644
index 0000000..dd65ddb
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/SdkSuppress.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 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 androidx.test.filters;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates that a specific test or class requires a minimum or maximum API Level to execute.
+ *
+ * <p>Test(s) will be skipped when executed on android platforms less/more than specified level
+ * (inclusive).
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface SdkSuppress {
+  /** The minimum API level to execute (inclusive) */
+  int minSdkVersion() default 1;
+  /** The maximum API level to execute (inclusive) */
+  int maxSdkVersion() default Integer.MAX_VALUE;
+  /**
+   * The {@link android.os.Build.VERSION.CODENAME} to execute on. This is intended to be used to run
+   * on a pre-release SDK, where the {@link android.os.Build.VERSION.SDK_INT} has not yet been
+   * finalized. This is treated as an OR operation with respect to the minSdkVersion and
+   * maxSdkVersion attributes.
+   *
+   * <p>For example, to filter a test so it runs on only the prerelease R SDK: <code>
+   * {@literal @}SdkSuppress(minSdkVersion = Build.VERSION_CODES.R, codeName = "R")
+   * </code>
+   */
+  String codeName() default "unset";
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/SmallTest.java b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/SmallTest.java
new file mode 100644
index 0000000..dd32df4
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/SmallTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2016 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 androidx.test.filters;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to assign a small test size qualifier to a test. This annotation can be used at a
+ * method or class level.
+ *
+ * <p>Test size qualifiers are a great way to structure test code and are used to assign a test to a
+ * test suite of similar run time.
+ *
+ * <p>Execution time: &lt;200ms
+ *
+ * <p>Small tests should be run very frequently. Focused on units of code to verify specific logical
+ * conditions. These tests should runs in an isolated environment and use mock objects for external
+ * dependencies. Resource access (such as file system, network, or databases) are not permitted.
+ * Tests that interact with hardware, make binder calls, or that facilitate android instrumentation
+ * should not use this annotation.
+ *
+ * <p>Note: This class replaces the deprecated Android platform size qualifier <a
+ * href="http://developer.android.com/reference/android/test/suitebuilder/annotation/SmallTest.html">
+ * android.test.suitebuilder.annotation.SmallTest</a> and is the recommended way to annotate tests
+ * written with the AndroidX Test Library.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface SmallTest {}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/Suppress.java b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/Suppress.java
new file mode 100644
index 0000000..88e636c
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/Suppress.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 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 androidx.test.filters;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Use this annotation on test classes or test methods that should not be included in a test suite.
+ * If the annotation appears on the class then no tests in that class will be included. If the
+ * annotation appears only on a test method then only that method will be excluded.
+ *
+ * <p>Note: This class replaces the deprecated Android platform annotation <a
+ * href="http://developer.android.com/reference/android/test/suitebuilder/annotation/Suppress.html">
+ * android.test.suitebuilder.annotation.Suppress</a> and is the recommended way to suppress tests
+ * written with the AndroidX Test Library.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface Suppress {}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/runner/AndroidJUnit4.java b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/runner/AndroidJUnit4.java
new file mode 100644
index 0000000..e137939
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/runner/AndroidJUnit4.java
@@ -0,0 +1,24 @@
+/*
+ * 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 androidx.test.runner;
+
+import org.junit.runners.model.InitializationError;
+
+public class AndroidJUnit4 extends androidx.test.ext.junit.runners.AndroidJUnit4 {
+    public AndroidJUnit4(Class<?> testClass) throws InitializationError {
+        super(testClass);
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Log_host.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Log_host.java
new file mode 100644
index 0000000..ee55c7a
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Log_host.java
@@ -0,0 +1,61 @@
+/*
+ * 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.nativesubstitution;
+
+import android.util.Log;
+import android.util.Log.Level;
+
+import java.io.PrintStream;
+
+public class Log_host {
+
+    public static boolean isLoggable(String tag, @Level int level) {
+        return true;
+    }
+
+    public static int println_native(int bufID, int priority, String tag, String msg) {
+        final PrintStream out = System.out;
+        final String buffer;
+        switch (bufID) {
+            case Log.LOG_ID_MAIN: buffer = "main"; break;
+            case Log.LOG_ID_RADIO: buffer = "radio"; break;
+            case Log.LOG_ID_EVENTS: buffer = "event"; break;
+            case Log.LOG_ID_SYSTEM: buffer = "system"; break;
+            case Log.LOG_ID_CRASH: buffer = "crash"; break;
+            default: buffer = "buf:" + bufID; break;
+        };
+
+        final String prio;
+        switch (priority) {
+            case Log.VERBOSE: prio = "V"; break;
+            case Log.DEBUG: prio = "D"; break;
+            case Log.INFO: prio = "I"; break;
+            case Log.WARN: prio = "W"; break;
+            case Log.ERROR: prio = "E"; break;
+            case Log.ASSERT: prio = "A"; break;
+            default: prio = "prio:" + priority; break;
+        };
+
+        for (String s : msg.split("\\n")) {
+            out.println(String.format("logd: [%s] %s %s: %s", buffer, prio, tag, s));
+        }
+        return msg.length();
+    }
+
+    public static int logger_entry_max_payload_native() {
+        return 4068; // [ravenwood] This is what people use in various places.
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java
new file mode 100644
index 0000000..d749f07
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java
@@ -0,0 +1,404 @@
+/*
+ * 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.nativesubstitution;
+
+import android.os.IBinder;
+
+import java.io.FileDescriptor;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Tentative, partial implementation of the Parcel native methods, using Java's
+ * {@link ByteBuffer}. It turned out there's enough semantics differences between Parcel
+ * and {@link ByteBuffer}, so it didn't actually work.
+ * (e.g. Parcel seems to allow moving the data position to be beyond its size? Which
+ * {@link ByteBuffer} wouldn't allow...)
+ */
+public class Parcel_host {
+    private Parcel_host() {
+    }
+
+    private static final AtomicLong sNextId = new AtomicLong(0);
+
+    private static final Map<Long, Parcel_host> sInstances = new ConcurrentHashMap<>();
+
+    private boolean mDeleted = false;
+
+    private byte[] mBuffer;
+    private int mSize;
+    private int mPos;
+
+    private boolean mSensitive;
+    private boolean mAllowFds;
+
+    // TODO Use the actual value from Parcel.java.
+    private static final int OK = 0;
+
+    private void validate() {
+        if (mDeleted) {
+            // TODO: Put more info
+            throw new RuntimeException("Parcel already destroyed");
+        }
+    }
+
+    private static Parcel_host getInstance(long id) {
+        Parcel_host p = sInstances.get(id);
+        if (p == null) {
+            // TODO: Put more info
+            throw new RuntimeException("Parcel doesn't exist with id=" + id);
+        }
+        p.validate();
+        return p;
+    }
+
+    public static long nativeCreate() {
+        final long id = sNextId.getAndIncrement();
+        final Parcel_host p = new Parcel_host();
+        sInstances.put(id, p);
+        p.init();
+        return id;
+    }
+
+    private void init() {
+        mBuffer = new byte[0];
+        mSize = 0;
+        mPos = 0;
+        mSensitive = false;
+        mAllowFds = false;
+    }
+
+    private void updateSize() {
+        if (mSize < mPos) {
+            mSize = mPos;
+        }
+    }
+
+    public static void nativeDestroy(long nativePtr) {
+        getInstance(nativePtr).mDeleted = true;
+        sInstances.remove(nativePtr);
+    }
+
+    public static void nativeFreeBuffer(long nativePtr) {
+        getInstance(nativePtr).freeBuffer();
+    }
+
+    public void freeBuffer() {
+        init();
+    }
+
+    private int getCapacity() {
+        return mBuffer.length;
+    }
+
+    private void ensureMoreCapacity(int size) {
+        ensureCapacity(mPos + size);
+    }
+
+    private void ensureCapacity(int targetSize) {
+        if (targetSize <= getCapacity()) {
+            return;
+        }
+        var newSize = getCapacity() * 2;
+        if (newSize < targetSize) {
+            newSize = targetSize;
+        }
+        forceSetCapacity(newSize);
+    }
+
+    private void forceSetCapacity(int newSize) {
+        var newBuf = new byte[newSize];
+
+        // Copy
+        System.arraycopy(mBuffer, 0, newBuf, 0, Math.min(newSize, getCapacity()));
+
+        this.mBuffer = newBuf;
+    }
+
+    private void ensureDataAvailable(int requestSize) {
+        if (mSize - mPos < requestSize) {
+            throw new RuntimeException(String.format(
+                    "Pacel data underflow. size=%d, pos=%d, request=%d", mSize, mPos, requestSize));
+        }
+    }
+
+    public static void nativeMarkSensitive(long nativePtr) {
+        getInstance(nativePtr).mSensitive = true;
+    }
+    public static void nativeMarkForBinder(long nativePtr, IBinder binder) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static boolean nativeIsForRpc(long nativePtr) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static int nativeDataSize(long nativePtr) {
+        return getInstance(nativePtr).mSize;
+    }
+    public static int nativeDataAvail(long nativePtr) {
+        var p = getInstance(nativePtr);
+        return p.mSize - p.mPos;
+    }
+    public static int nativeDataPosition(long nativePtr) {
+        return getInstance(nativePtr).mPos;
+    }
+    public static int nativeDataCapacity(long nativePtr) {
+        return getInstance(nativePtr).mBuffer.length;
+    }
+    public static void nativeSetDataSize(long nativePtr, int size) {
+        var p = getInstance(nativePtr);
+        p.ensureCapacity(size);
+        getInstance(nativePtr).mSize = size;
+    }
+    public static void nativeSetDataPosition(long nativePtr, int pos) {
+        var p = getInstance(nativePtr);
+        // TODO: Should this change the size or the capacity??
+        p.mPos = pos;
+    }
+    public static void nativeSetDataCapacity(long nativePtr, int size) {
+        var p = getInstance(nativePtr);
+        if (p.getCapacity() < size) {
+            p.forceSetCapacity(size);
+        }
+    }
+
+    public static boolean nativePushAllowFds(long nativePtr, boolean allowFds) {
+        var p = getInstance(nativePtr);
+        var prev = p.mAllowFds;
+        p.mAllowFds = allowFds;
+        return prev;
+    }
+    public static void nativeRestoreAllowFds(long nativePtr, boolean lastValue) {
+        getInstance(nativePtr).mAllowFds = lastValue;
+    }
+
+    public static void nativeWriteByteArray(long nativePtr, byte[] b, int offset, int len) {
+        nativeWriteBlob(nativePtr, b, offset, len);
+    }
+
+    public static void nativeWriteBlob(long nativePtr, byte[] b, int offset, int len) {
+        var p = getInstance(nativePtr);
+
+        if (b == null) {
+            nativeWriteInt(nativePtr, -1);
+        } else {
+            final var alignedSize = align4(b.length);
+
+            nativeWriteInt(nativePtr, b.length);
+
+            p.ensureMoreCapacity(alignedSize);
+
+            System.arraycopy(b, offset, p.mBuffer,  p.mPos, len);
+            p.mPos += alignedSize;
+            p.updateSize();
+        }
+    }
+
+    public static int nativeWriteInt(long nativePtr, int value) {
+        var p = getInstance(nativePtr);
+        p.ensureMoreCapacity(Integer.BYTES);
+
+        p.mBuffer[p.mPos++] = (byte) ((value >> 24) & 0xff);
+        p.mBuffer[p.mPos++] = (byte) ((value >> 16) & 0xff);
+        p.mBuffer[p.mPos++] = (byte) ((value >>  8) & 0xff);
+        p.mBuffer[p.mPos++] = (byte) ((value >>  0) & 0xff);
+
+        p.updateSize();
+
+        return OK;
+    }
+
+    public static int nativeWriteLong(long nativePtr, long value) {
+        nativeWriteInt(nativePtr, (int) (value >>> 32));
+        nativeWriteInt(nativePtr, (int) (value));
+        return OK;
+    }
+    public static int nativeWriteFloat(long nativePtr, float val) {
+        return nativeWriteInt(nativePtr, Float.floatToIntBits(val));
+    }
+    public static int nativeWriteDouble(long nativePtr, double val) {
+        return nativeWriteLong(nativePtr, Double.doubleToLongBits(val));
+    }
+    public static void nativeSignalExceptionForError(int error) {
+        throw new RuntimeException("Not implemented yet");
+    }
+
+    private static int align4(int val) {
+        return ((val + 3) / 4) * 4;
+    }
+
+    public static void nativeWriteString8(long nativePtr, String val) {
+        if (val == null) {
+            nativeWriteBlob(nativePtr, null, 0, 0);
+        } else {
+            var bytes = val.getBytes(StandardCharsets.UTF_8);
+            nativeWriteBlob(nativePtr, bytes, 0, bytes.length);
+        }
+    }
+    public static void nativeWriteString16(long nativePtr, String val) {
+        // Just reuse String8
+        nativeWriteString8(nativePtr, val);
+    }
+    public static void nativeWriteStrongBinder(long nativePtr, IBinder val) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static void nativeWriteFileDescriptor(long nativePtr, FileDescriptor val) {
+        throw new RuntimeException("Not implemented yet");
+    }
+
+    public static byte[] nativeCreateByteArray(long nativePtr) {
+        return nativeReadBlob(nativePtr);
+    }
+
+    public static boolean nativeReadByteArray(long nativePtr, byte[] dest, int destLen) {
+        if (dest == null) {
+            return false;
+        }
+        var data = nativeReadBlob(nativePtr);
+        if (data == null) {
+            System.err.println("Percel has NULL, which is unexpected."); // TODO: Is this correct?
+            return false;
+        }
+        // TODO: Make sure the check logic is correct.
+        if (data.length != destLen) {
+            System.err.println("Byte array size mismatch: expected="
+                    + data.length + " given=" + destLen);
+            return false;
+        }
+        return true;
+    }
+
+    public static byte[] nativeReadBlob(long nativePtr) {
+        final var size = nativeReadInt(nativePtr);
+        if (size == -1) {
+            return null;
+        }
+        var p = getInstance(nativePtr);
+        p.ensureDataAvailable(size);
+
+        var bytes = new byte[size];
+        System.arraycopy(p.mBuffer, p.mPos, bytes, 0, size);
+
+        p.mPos += align4(size);
+
+        return bytes;
+    }
+    public static int nativeReadInt(long nativePtr) {
+        var p = getInstance(nativePtr);
+
+        p.ensureDataAvailable(Integer.BYTES);
+
+        var ret = (((p.mBuffer[p.mPos++] & 0xff) << 24)
+                | ((p.mBuffer[p.mPos++] & 0xff) << 16)
+                | ((p.mBuffer[p.mPos++] & 0xff) <<  8)
+                | ((p.mBuffer[p.mPos++] & 0xff) <<  0));
+
+        return ret;
+    }
+    public static long nativeReadLong(long nativePtr) {
+        return (((long) nativeReadInt(nativePtr)) << 32)
+                | (((long) nativeReadInt(nativePtr)) & 0xffff_ffffL);
+    }
+
+    public static float nativeReadFloat(long nativePtr) {
+        return Float.intBitsToFloat(nativeReadInt(nativePtr));
+    }
+
+    public static double nativeReadDouble(long nativePtr) {
+        return Double.longBitsToDouble(nativeReadLong(nativePtr));
+    }
+
+    public static String nativeReadString8(long nativePtr) {
+        final var bytes = nativeReadBlob(nativePtr);
+        if (bytes == null) {
+            return null;
+        }
+        return new String(bytes, StandardCharsets.UTF_8);
+    }
+    public static String nativeReadString16(long nativePtr) {
+        return nativeReadString8(nativePtr);
+    }
+    public static IBinder nativeReadStrongBinder(long nativePtr) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static FileDescriptor nativeReadFileDescriptor(long nativePtr) {
+        throw new RuntimeException("Not implemented yet");
+    }
+
+    public static byte[] nativeMarshall(long nativePtr) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static void nativeUnmarshall(
+            long nativePtr, byte[] data, int offset, int length) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static int nativeCompareData(long thisNativePtr, long otherNativePtr) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static boolean nativeCompareDataInRange(
+            long ptrA, int offsetA, long ptrB, int offsetB, int length) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static void nativeAppendFrom(
+            long thisNativePtr, long otherNativePtr, int srcOffset, int length) {
+        var dst = getInstance(thisNativePtr);
+        var src = getInstance(otherNativePtr);
+
+        dst.ensureMoreCapacity(length);
+
+        System.arraycopy(src.mBuffer, srcOffset, dst.mBuffer, dst.mPos, length);
+        dst.mPos += length; // TODO: 4 byte align?
+        dst.updateSize();
+
+        // TODO: Update the other's position?
+    }
+
+    public static boolean nativeHasFileDescriptors(long nativePtr) {
+        // Assume false for now, because we don't support writing FDs yet.
+        return false;
+    }
+    public static boolean nativeHasFileDescriptorsInRange(
+            long nativePtr, int offset, int length) {
+        // Assume false for now, because we don't support writing FDs yet.
+        return false;
+    }
+    public static void nativeWriteInterfaceToken(long nativePtr, String interfaceName) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static void nativeEnforceInterface(long nativePtr, String interfaceName) {
+        throw new RuntimeException("Not implemented yet");
+    }
+
+    public static boolean nativeReplaceCallingWorkSourceUid(
+            long nativePtr, int workSourceUid) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static int nativeReadCallingWorkSourceUid(long nativePtr) {
+        throw new RuntimeException("Not implemented yet");
+    }
+
+    public static long nativeGetOpenAshmemSize(long nativePtr) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static long getGlobalAllocSize() {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static long getGlobalAllocCount() {
+        throw new RuntimeException("Not implemented yet");
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/SystemProperties_host.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/SystemProperties_host.java
new file mode 100644
index 0000000..1ec1d5f
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/SystemProperties_host.java
@@ -0,0 +1,56 @@
+/*
+ * 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.nativesubstitution;
+
+public class SystemProperties_host {
+    public static String native_get(String key, String def) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static int native_get_int(String key, int def) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static long native_get_long(String key, long def) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static boolean native_get_boolean(String key, boolean def) {
+        throw new RuntimeException("Not implemented yet");
+    }
+
+    public static long native_find(String name) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static String native_get(long handle) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static int native_get_int(long handle, int def) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static long native_get_long(long handle, long def) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static boolean native_get_boolean(long handle, boolean def) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static void native_set(String key, String def) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static void native_add_change_callback() {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static void native_report_sysprop_change() {
+        throw new RuntimeException("Not implemented yet");
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/runtimehelper/ClassLoadHook.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/runtimehelper/ClassLoadHook.java
new file mode 100644
index 0000000..fbcc648
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/runtimehelper/ClassLoadHook.java
@@ -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.hoststubgen.runtimehelper;
+
+import com.android.hoststubgen.hosthelper.HostTestException;
+
+import java.io.File;
+import java.io.PrintStream;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+
+/**
+ * Standard class loader hook.
+ *
+ * Currently, we use this class to load libandroid_runtime (if needed). In the future, we may
+ * load other JNI or do other set up here.
+ */
+public class ClassLoadHook {
+    private static PrintStream sOut = System.out;
+
+    /**
+     * If true, we won't load `libandroid_runtime`
+     *
+     * <p>Looks like there's some complexity in running a host test with JNI with `atest`,
+     * so we need a way to remove the dependency.
+     */
+    private static final boolean SKIP_LOADING_LIBANDROID = "1".equals(System.getenv(
+            "HOSTTEST_SKIP_LOADING_LIBANDROID"));
+
+    public static final String CORE_NATIVE_CLASSES = "core_native_classes";
+    public static final String ICU_DATA_PATH = "icu.data.path";
+    public static final String KEYBOARD_PATHS = "keyboard_paths";
+    public static final String GRAPHICS_NATIVE_CLASSES = "graphics_native_classes";
+
+    public static final String VALUE_N_A = "**n/a**";
+    public static final String LIBANDROID_RUNTIME_NAME = "libandroid_runtime";
+
+    private static String sInitialDir = new File("").getAbsolutePath();
+
+    static {
+        log("Initialized. Current dir=" + sInitialDir);
+    }
+
+    private ClassLoadHook() {
+    }
+
+    /**
+     * Called when classes with
+     * {@code @HostSideTestClassLoadHook(
+     * "com.android.hoststubgen.runtimehelper.LibandroidLoadingHook.onClassLoaded") }
+     * are loaded.
+     */
+    public static void onClassLoaded(Class<?> clazz) {
+        System.out.println("Framework class loaded: " + clazz.getCanonicalName());
+
+        loadFrameworkNativeCode();
+    }
+
+    private static void log(String message) {
+        sOut.println("ClassLoadHook: " + message);
+    }
+
+    private static void log(String fmt, Object... args) {
+        log(String.format(fmt, args));
+    }
+
+    private static void ensurePropertyNotSet(String key) {
+        if (System.getProperty(key) != null) {
+            throw new HostTestException("System property \"" + key + "\" is set unexpectedly");
+        }
+    }
+
+    private static void setProperty(String key, String value) {
+        System.setProperty(key, value);
+        log("Property set: %s=\"%s\"", key, value);
+    }
+
+    private static void dumpSystemProperties() {
+        for (var prop : System.getProperties().entrySet()) {
+            log("  %s=\"%s\"", prop.getKey(), prop.getValue());
+        }
+    }
+
+    private static void loadJniLibrary(String name) {
+        final String path = sInitialDir + "/lib64/" + name + ".so";
+        System.out.println("Loading " + path + " ...");
+        System.load(path);
+        System.out.println("Done loading " + path);
+    }
+
+    private static boolean sLoadFrameworkNativeCodeCalled = false;
+
+    /**
+     * Load `libandroid_runtime` if needed.
+     */
+    private static void loadFrameworkNativeCode() {
+        // This is called from class-initializers, so no synchronization is needed.
+        if (sLoadFrameworkNativeCodeCalled) {
+            // This method has already been called before.s
+            return;
+        }
+        sLoadFrameworkNativeCodeCalled = true;
+
+        // libandroid_runtime uses Java's system properties to decide what JNI methods to set up.
+        // Set up these properties for host-side tests.
+
+        if ("1".equals(System.getenv("HOSTTEST_DUMP_PROPERTIES"))) {
+            log("Java system properties:");
+            dumpSystemProperties();
+        }
+
+        if (SKIP_LOADING_LIBANDROID) {
+            log("Skip loading " + LIBANDROID_RUNTIME_NAME);
+        }
+
+        // Make sure these properties are not set.
+        ensurePropertyNotSet(CORE_NATIVE_CLASSES);
+        ensurePropertyNotSet(ICU_DATA_PATH);
+        ensurePropertyNotSet(KEYBOARD_PATHS);
+        ensurePropertyNotSet(GRAPHICS_NATIVE_CLASSES);
+
+        // Tell libandroid what JNI to use.
+        final var jniClasses = getCoreNativeClassesToUse();
+        if (jniClasses.isEmpty()) {
+            log("No classes require JNI methods, skip loading " + LIBANDROID_RUNTIME_NAME);
+            return;
+        }
+        setProperty(CORE_NATIVE_CLASSES, jniClasses);
+        setProperty(GRAPHICS_NATIVE_CLASSES, "");
+        setProperty(ICU_DATA_PATH, VALUE_N_A);
+        setProperty(KEYBOARD_PATHS, VALUE_N_A);
+
+        loadJniLibrary(LIBANDROID_RUNTIME_NAME);
+    }
+
+    /**
+     * Classes with native methods that are backed by `libandroid_runtime`.
+     *
+     * At runtime, we check if these classes have any methods, and if so, we'll have
+     * `libandroid_runtime` register the native functions.
+     */
+    private static final Class<?>[] sClassesWithLibandroidNativeMethods = {
+            android.util.Log.class,
+            android.os.Parcel.class,
+    };
+
+    /**
+     * @return if a given method is a native method or not.
+     */
+    private static boolean hasNativeMethod(Class<?> clazz) {
+        for (var method : clazz.getDeclaredMethods()) {
+            if (Modifier.isNative(method.getModifiers())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Create a list of classes as comma-separated that require JNI methods to be set up.
+     *
+     * <p>This list is used by frameworks/base/core/jni/LayoutlibLoader.cpp to decide
+     * what JNI methods to set up.
+     */
+    private static String getCoreNativeClassesToUse() {
+        final var coreNativeClassesToLoad = new ArrayList<String>();
+
+        for (var clazz : sClassesWithLibandroidNativeMethods) {
+            if (hasNativeMethod(clazz)) {
+                log("Class %s has native methods", clazz);
+                coreNativeClassesToLoad.add(clazz.getName());
+            }
+        }
+
+        return String.join(",", coreNativeClassesToLoad);
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/dalvik/system/VMRuntime.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/dalvik/system/VMRuntime.java
new file mode 100644
index 0000000..7d2b00d
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/dalvik/system/VMRuntime.java
@@ -0,0 +1,45 @@
+/*
+ * 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 dalvik.system;
+
+// [ravenwood] It's in libart, so until we get ART to work, we need to use a fake.
+// The original is here:
+// $ANDROID_BUILD_TOP/libcore/libart/src/main/java/dalvik/system/VMRuntime.java
+
+import java.lang.reflect.Array;
+
+public class VMRuntime {
+    private static final VMRuntime THE_ONE = new VMRuntime();
+
+    private VMRuntime() {
+    }
+
+    public static VMRuntime getRuntime() {
+        return THE_ONE;
+    }
+
+    public boolean is64Bit() {
+        return true;
+    }
+
+    public static boolean is64BitAbi(String abi) {
+        return true;
+    }
+
+    public Object newUnpaddedArray(Class<?> componentType, int minLength) {
+        return Array.newInstance(componentType, minLength);
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/util/EmptyArray.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/util/EmptyArray.java
new file mode 100644
index 0000000..a1ae35a
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/util/EmptyArray.java
@@ -0,0 +1,54 @@
+/*
+ * 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 libcore.util;
+
+import java.lang.annotation.Annotation;
+
+// [ravenwood] Copied from libcore. TODO: Figure out what to do with libcore.
+public class EmptyArray {
+    private EmptyArray() {}
+
+    public static final boolean[] BOOLEAN = new boolean[0];
+
+    public static final byte[] BYTE = new byte[0];
+
+    public static final char[] CHAR = new char[0];
+
+    public static final double[] DOUBLE = new double[0];
+
+    public static final float[] FLOAT = new float[0];
+
+    public static final int[] INT = new int[0];
+
+    public static final long[] LONG = new long[0];
+
+    public static final Class<?>[] CLASS = new Class[0];
+
+    public static final Object[] OBJECT = new Object[0];
+
+    public static final String[] STRING = new String[0];
+
+    public static final Throwable[] THROWABLE = new Throwable[0];
+
+    public static final StackTraceElement[] STACK_TRACE_ELEMENT = new StackTraceElement[0];
+
+    public static final java.lang.reflect.Type[] TYPE = new java.lang.reflect.Type[0];
+
+    public static final java.lang.reflect.TypeVariable[] TYPE_VARIABLE =
+            new java.lang.reflect.TypeVariable[0];
+    public static final Annotation[] ANNOTATION = new Annotation[0];
+
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/util/SneakyThrow.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/util/SneakyThrow.java
new file mode 100644
index 0000000..e142c46
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/util/SneakyThrow.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 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 libcore.util;
+
+// [ravenwood] Copied from libcore. TODO: Figure out what to do with libcore.
+
+public class SneakyThrow {
+
+    private SneakyThrow() {
+    }
+
+    public static void sneakyThrow(Throwable t) {
+        SneakyThrow.<RuntimeException>sneakyThrow_(t);
+    }
+
+    private static <T extends Throwable> void sneakyThrow_(Throwable t) throws T {
+       throw (T) t;
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedKeepClass.java b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedKeepClass.java
new file mode 100644
index 0000000..4c37579
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedKeepClass.java
@@ -0,0 +1,34 @@
+/*
+ * 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.hosthelper;
+
+import static java.lang.annotation.ElementType.TYPE;
+
+import org.objectweb.asm.Type;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation added to all "stub" classes generated by HostStubGen.
+ */
+@Target({TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HostStubGenProcessedKeepClass {
+    String CLASS_INTERNAL_NAME = Type.getInternalName(HostStubGenProcessedKeepClass.class);
+    String CLASS_DESCRIPTOR = "L" + CLASS_INTERNAL_NAME + ";";
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedStubClass.java b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedStubClass.java
new file mode 100644
index 0000000..34e0030
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedStubClass.java
@@ -0,0 +1,34 @@
+/*
+ * 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.hosthelper;
+
+import static java.lang.annotation.ElementType.TYPE;
+
+import org.objectweb.asm.Type;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation added to all "stub" classes generated by HostStubGen.
+ */
+@Target({TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HostStubGenProcessedStubClass {
+    String CLASS_INTERNAL_NAME = Type.getInternalName(HostStubGenProcessedStubClass.class);
+    String CLASS_DESCRIPTOR = "L" + CLASS_INTERNAL_NAME + ";";
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestException.java b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestException.java
new file mode 100644
index 0000000..c54c2c1
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestException.java
@@ -0,0 +1,26 @@
+/*
+ * 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.hosthelper;
+
+public class HostTestException extends RuntimeException {
+    public HostTestException(String message) {
+        super(message);
+    }
+
+    public HostTestException(String message, Throwable inner) {
+        super(message, inner);
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestSuite.java b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestSuite.java
new file mode 100644
index 0000000..29f7be0
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestSuite.java
@@ -0,0 +1,102 @@
+/*
+ * 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.hosthelper;
+
+import com.google.common.reflect.ClassPath;
+import com.google.common.reflect.ClassPath.ClassInfo;
+
+import junit.framework.JUnit4TestAdapter;
+import junit.framework.TestSuite;
+
+import java.util.regex.Pattern;
+
+/**
+ * A very simple Junit {@link TestSuite} builder that finds all classes that look like test classes.
+ *
+ * We use it to run ravenwood test jars from the command line.
+ */
+public class HostTestSuite {
+    private static final String CLASS_NAME_REGEX_ENV = "HOST_TEST_CLASS_NAME_REGEX";
+
+    /**
+     * Called by junit, and return all test-looking classes as a suite.
+     */
+    public static TestSuite suite() {
+        TestSuite suite = new TestSuite();
+
+        final Pattern classNamePattern;
+        final var filterRegex = System.getenv(CLASS_NAME_REGEX_ENV);
+        if (filterRegex == null) {
+            classNamePattern = Pattern.compile("");
+        } else {
+            classNamePattern = Pattern.compile(filterRegex);
+        }
+        try {
+            // We use guava to list all classes.
+            ClassPath cp = ClassPath.from(HostTestSuite.class.getClassLoader());
+
+            for (var classInfo : cp.getAllClasses()) {
+                Class<?> clazz = asTestClass(classInfo);
+                if (clazz != null) {
+                    if (classNamePattern.matcher(clazz.getSimpleName()).find()) {
+                        System.out.println("Test class found " + clazz.getName());
+                    } else {
+                        System.out.println("Skipping test class (for $"
+                                + CLASS_NAME_REGEX_ENV + "): " + clazz.getName());
+                    }
+                    suite.addTest(new JUnit4TestAdapter(clazz));
+                }
+            }
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        return suite;
+    }
+
+    /**
+     * Decide whether a class looks like a test class or not, and if so, return it as a Class
+     * instance.
+     */
+    private static Class<?> asTestClass(ClassInfo classInfo) {
+        try {
+            final Class<?> clazz = classInfo.load();
+
+            // Does it extend junit.framework.TestCase?
+            if (junit.framework.TestCase.class.isAssignableFrom(clazz)) {
+                // Ignore classes in JUnit itself, or the android(x) test lib.
+                if (classInfo.getName().startsWith("junit.")
+                        || classInfo.getName().startsWith("org.junit.")
+                        || classInfo.getName().startsWith("android.test.")
+                        || classInfo.getName().startsWith("androidx.test.")) {
+                    return null; // Ignore junit classes.
+                }
+                return clazz;
+            }
+            // Does it have any "@Test" method?
+            for (var method : clazz.getMethods()) {
+                for (var an : method.getAnnotations()) {
+                    if (an.annotationType() == org.junit.Test.class) {
+                        return clazz;
+                    }
+                }
+            }
+            return null;
+        } catch (java.lang.NoClassDefFoundError e) {
+            // Ignore unloadable classes.
+            return null;
+        }
+    }
+}
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
new file mode 100644
index 0000000..f7719a6
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java
@@ -0,0 +1,197 @@
+/*
+ * 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.hosthelper;
+
+import org.objectweb.asm.Type;
+
+import java.io.PrintStream;
+import java.lang.StackWalker.Option;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+
+import javax.annotation.concurrent.GuardedBy;
+
+/**
+ * Utilities used in the host side test environment.
+ */
+public class HostTestUtils {
+    private HostTestUtils() {
+    }
+
+    public static final String CLASS_INTERNAL_NAME = Type.getInternalName(HostTestUtils.class);
+
+    /** If true, we won't print method call log. */
+    private static final boolean SKIP_METHOD_LOG = "1".equals(System.getenv(
+            "HOSTTEST_SKIP_METHOD_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"));
+
+
+    /**
+     * Method call log will be printed to it.
+     */
+    public static PrintStream logPrintStream = System.out;
+
+    /**
+     * Called from methods with FilterPolicy.Throw.
+     */
+    public static void onThrowMethodCalled() {
+        // TODO: Maybe add call tracking?
+        throw new RuntimeException("This method is not supported on the host side");
+    }
+
+    /**
+     * Called from methods with FilterPolicy.Log.
+     */
+    public static void logMethodCall(
+            String methodClass,
+            String methodName,
+            String methodDescriptor
+    ) {
+        if (SKIP_METHOD_LOG) {
+            return;
+        }
+        logPrintStream.println("# " + methodClass + "." + methodName + methodDescriptor);
+    }
+
+    private static final StackWalker sStackWalker =
+            StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE);
+
+    /**
+     * Return a {@link StackWalker} that supports {@link StackWalker#getCallerClass()}.
+     */
+    public static StackWalker getStackWalker() {
+        return sStackWalker;
+    }
+
+    /**
+     * Cache used by {@link #isClassAllowedToCallNonStubMethods}.
+     */
+    @GuardedBy("sAllowedClasses")
+    private static final HashMap<Class, Boolean> sAllowedClasses = new HashMap();
+
+    /**
+     * Return true if a given class is allowed to access non-stub methods -- that is, if the class
+     * is in the hoststubgen generated JARs. (not in the test jar.)
+     */
+    private static boolean isClassAllowedToCallNonStubMethods(Class<?> clazz) {
+        synchronized (sAllowedClasses) {
+            var cached = sAllowedClasses.get(clazz);
+            if (cached != null) {
+                return cached;
+            }
+        }
+        // All processed classes have this annotation.
+        var allowed = clazz.getAnnotation(HostStubGenProcessedKeepClass.class) != null;
+
+        // Java classes should be able to access any methods. (via callbacks, etc.)
+        if (!allowed) {
+            if (clazz.getPackageName().startsWith("java.")
+                    || clazz.getPackageName().startsWith("javax.")) {
+                allowed = true;
+            }
+        }
+        synchronized (sAllowedClasses) {
+            sAllowedClasses.put(clazz, allowed);
+        }
+        return allowed;
+    }
+
+    /**
+     * Called when non-stub methods are called. We do a host-unsupported method direct call check
+     * in here.
+     */
+    public static void onNonStubMethodCalled(
+            String methodClass,
+            String methodName,
+            String methodDescriptor,
+            Class<?> callerClass) {
+        if (SKIP_NON_STUB_METHOD_CHECK) {
+            return;
+        }
+        if (isClassAllowedToCallNonStubMethods(callerClass)) {
+            return; // Generated class is allowed to call framework class.
+        }
+        logPrintStream.println("! " + methodClass + "." + methodName + methodDescriptor
+                + " called by " + callerClass.getCanonicalName());
+    }
+
+    /**
+     * Called when any top level class (not nested classes) in the impl jar is loaded.
+     *
+     * When HostStubGen inject a class-load hook, it's always a call to this method, with the
+     * actual method name as the second argument.
+     *
+     * This method discovers the hook method with reflections and call it.
+     *
+     * TODO: Add a unit test.
+     */
+    public static void onClassLoaded(Class<?> loadedClass, String callbackMethod) {
+        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);
+
+        if (lastPeriod < 0 || className.isEmpty() || methodName.isEmpty()) {
+            throw new HostTestException(String.format(
+                    "Unable to find class load hook: malformed method name \"%s\"",
+                    callbackMethod));
+        }
+
+        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);
+        }
+        if (!Modifier.isPublic(clazz.getModifiers())) {
+            throw new HostTestException(String.format(
+                    "Unable to find class load hook: Class %s must be public", className));
+        }
+
+        Method method = null;
+        try {
+            method = clazz.getMethod(methodName, Class.class);
+        } 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);
+        }
+        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));
+        }
+        try {
+            method.invoke(null, loadedClass);
+        } catch (Exception e) {
+            throw new HostTestException(String.format(
+                    "Unable to invoke class load hook %s.%s",
+                    className,
+                    methodName), e);
+        }
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt b/tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt
new file mode 100644
index 0000000..828d2a3
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt
@@ -0,0 +1,39 @@
+# File containing standard options to HostStubGen
+
+--debug
+
+# Uncomment below lines to enable each feature.
+--enable-non-stub-method-check
+# --no-non-stub-method-check
+
+# --enable-method-logging
+
+
+# Standard annotations.
+# Note, each line is a single argument, so we need newlines after each `--xxx-annotation`.
+--stub-annotation
+    android.hosttest.annotation.HostSideTestStub
+
+--keep-annotation
+    android.hosttest.annotation.HostSideTestKeep
+
+--stub-class-annotation
+    android.hosttest.annotation.HostSideTestWholeClassStub
+
+--keep-class-annotation
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+
+--throw-annotation
+    android.hosttest.annotation.HostSideTestThrow
+
+--remove-annotation
+    android.hosttest.annotation.HostSideTestRemove
+
+--substitute-annotation
+    android.hosttest.annotation.HostSideTestSubstitute
+
+--native-substitute-annotation
+    android.hosttest.annotation.HostSideTestNativeSubstitutionClass
+
+--class-load-hook-annotation
+    android.hosttest.annotation.HostSideTestClassLoadHook
diff --git a/tools/hoststubgen/hoststubgen/jarjar-rules.txt b/tools/hoststubgen/hoststubgen/jarjar-rules.txt
new file mode 100644
index 0000000..4e61ba6
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/jarjar-rules.txt
@@ -0,0 +1,2 @@
+# Rename guava
+rule com.google.common.** com.android.hoststubgen.x.@0
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Exceptions.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Exceptions.kt
new file mode 100644
index 0000000..207ba52
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Exceptions.kt
@@ -0,0 +1,48 @@
+/*
+ * 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
+
+/**
+ * We will not print the stack trace for exceptions implementing it.
+ */
+interface UserErrorException
+
+/**
+ * Exceptions about parsing class files.
+ */
+class ClassParseException(message: String) : Exception(message)
+
+/**
+ * Use it for internal exception that really shouldn't happen.
+ */
+class HostStubGenInternalException(message: String) : Exception(message)
+
+/**
+ * Exceptions about the content in a jar file.
+ */
+class InvalidJarFileException(message: String) : Exception(message), UserErrorException
+
+/**
+ * Exceptions missing classes, fields, methods, etc.
+ */
+class UnknownApiException(message: String) : Exception(message), UserErrorException
+
+/**
+ * Exceptions related to invalid annotations -- e.g. more than one visibility annotation
+ * on a single API.
+ */
+class InvalidAnnotationException(message: String) : Exception(message), UserErrorException
+
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
new file mode 100644
index 0000000..8db4b69
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
@@ -0,0 +1,402 @@
+/*
+ * 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
+
+import com.android.hoststubgen.asm.ClassNodes
+import com.android.hoststubgen.filters.AnnotationBasedFilter
+import com.android.hoststubgen.filters.ClassWidePolicyPropagatingFilter
+import com.android.hoststubgen.filters.ConstantFilter
+import com.android.hoststubgen.filters.FilterPolicy
+import com.android.hoststubgen.filters.ImplicitOutputFilter
+import com.android.hoststubgen.filters.KeepAllClassesFilter
+import com.android.hoststubgen.filters.OutputFilter
+import com.android.hoststubgen.filters.StubIntersectingFilter
+import com.android.hoststubgen.filters.createFilterFromTextPolicyFile
+import com.android.hoststubgen.filters.printAsTextPolicy
+import com.android.hoststubgen.visitors.BaseAdapter
+import org.objectweb.asm.ClassReader
+import org.objectweb.asm.ClassVisitor
+import org.objectweb.asm.ClassWriter
+import org.objectweb.asm.tree.ClassNode
+import org.objectweb.asm.util.CheckClassAdapter
+import java.io.BufferedInputStream
+import java.io.FileOutputStream
+import java.io.InputStream
+import java.io.OutputStream
+import java.io.PrintWriter
+import java.util.zip.ZipEntry
+import java.util.zip.ZipFile
+import java.util.zip.ZipOutputStream
+
+/**
+ * Actual main class.
+ */
+class HostStubGen(val options: HostStubGenOptions) {
+    fun run() {
+        val errors = HostStubGenErrors()
+
+        // Load all classes.
+        val allClasses = loadClassStructures(options.inJar)
+
+        // Dump the classes, if specified.
+        options.inputJarDumpFile?.let {
+            PrintWriter(it).use { pw -> allClasses.dump(pw) }
+            log.i("Dump file created at $it")
+        }
+
+        options.inputJarAsKeepAllFile?.let {
+            PrintWriter(it).use {
+                pw -> allClasses.forEach {
+                    classNode -> printAsTextPolicy(pw, classNode)
+                }
+            }
+            log.i("Dump file created at $it")
+        }
+
+        // Build the filters.
+        val filter = buildFilter(errors, allClasses, options)
+
+        // Transform the jar.
+        convert(
+                options.inJar,
+                options.outStubJar,
+                options.outImplJar,
+                filter,
+                options.enableClassChecker,
+                allClasses,
+                errors,
+        )
+    }
+
+    /**
+     * Load all the classes, without code.
+     */
+    private fun loadClassStructures(inJar: String): ClassNodes {
+        log.i("Reading class structure from $inJar ...")
+        val start = System.currentTimeMillis()
+
+        val allClasses = ClassNodes()
+
+        log.withIndent {
+            ZipFile(inJar).use { inZip ->
+                val inEntries = inZip.entries()
+
+                while (inEntries.hasMoreElements()) {
+                    val entry = inEntries.nextElement()
+
+                    BufferedInputStream(inZip.getInputStream(entry)).use { bis ->
+                        if (entry.name.endsWith(".class")) {
+                            val cr = ClassReader(bis)
+                            val cn = ClassNode()
+                            cr.accept(cn, ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG
+                                    or ClassReader.SKIP_FRAMES)
+                            if (!allClasses.addClass(cn)) {
+                                log.w("Duplicate class found: ${cn.name}")
+                            }
+                        } else if (entry.name.endsWith(".dex")) {
+                            // Seems like it's an ART jar file. We can't process it.
+                            // It's a fatal error.
+                            throw InvalidJarFileException(
+                                    "$inJar is not a desktop jar file. It contains a *.dex file.")
+                        } else {
+                            // Unknown file type. Skip.
+                            while (bis.available() > 0) {
+                                bis.skip((1024 * 1024).toLong())
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        if (allClasses.size == 0) {
+            log.w("$inJar contains no *.class files.")
+        }
+
+        val end = System.currentTimeMillis()
+        log.v("Done reading class structure in %.1f second(s).", (end - start) / 1000.0)
+        return allClasses
+    }
+
+    /**
+     * Build the filter, which decides what classes/methods/fields should be put in stub or impl
+     * jars, and "how". (e.g. with substitution?)
+     */
+    private fun buildFilter(
+            errors: HostStubGenErrors,
+            allClasses: ClassNodes,
+            options: HostStubGenOptions,
+            ): OutputFilter {
+        // We build a "chain" of multiple filters here.
+        //
+        // The filters are build in from "inside", meaning the first filter created here is
+        // the last filter used, so it has the least precedence.
+        //
+        // So, for example, the "remove" annotation, which is handled by AnnotationBasedFilter,
+        // can override a class-wide annotation, which is handled by
+        // ClassWidePolicyPropagatingFilter, and any annotations can be overridden by the
+        // text-file based filter, which is handled by parseTextFilterPolicyFile.
+
+        // The first filter is for the default policy from the command line options.
+        var filter: OutputFilter = ConstantFilter(options.defaultPolicy, "default-by-options")
+
+        // Next, we need a filter that resolves "class-wide" policies.
+        // 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)
+
+        // 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
+        )
+
+        // Next, "text based" filter, which allows to override polices without touching
+        // the target code.
+        options.policyOverrideFile?.let {
+            filter = createFilterFromTextPolicyFile(it, allClasses, filter)
+        }
+
+        // If `--intersect-stub-jar` is provided, load from these jar files too.
+        // We use this to restrict stub APIs to public/system/test APIs,
+        // by intersecting with a stub jar file created by metalava.
+        if (options.intersectStubJars.size > 0) {
+            val intersectingJars = loadIntersectingJars(options.intersectStubJars)
+
+            filter = StubIntersectingFilter(errors, intersectingJars, filter)
+        }
+
+        // Apply the implicit filter.
+        filter = ImplicitOutputFilter(errors, allClasses, filter)
+
+        // Optionally keep all classes.
+        if (options.keepAllClasses) {
+            filter = KeepAllClassesFilter(filter)
+        }
+
+        return filter
+    }
+
+    /**
+     * Load jar files specified with "--intersect-stub-jar".
+     */
+    private fun loadIntersectingJars(filenames: Set<String>): Map<String, ClassNodes> {
+        val intersectingJars = mutableMapOf<String, ClassNodes>()
+
+        filenames.forEach { filename ->
+            intersectingJars[filename] = loadClassStructures(filename)
+        }
+        return intersectingJars
+    }
+
+    /**
+     * Convert a JAR file into "stub" and "impl" JAR files.
+     */
+    private fun convert(
+            inJar: String,
+            outStubJar: String,
+            outImplJar: String,
+            filter: OutputFilter,
+            enableChecker: Boolean,
+            classes: ClassNodes,
+            errors: HostStubGenErrors,
+            ) {
+        log.i("Converting %s into [stub: %s, impl: %s] ...", inJar, outStubJar, outImplJar)
+        log.i("Checker is %s", if (enableChecker) "enabled" else "disabled")
+
+        val start = System.currentTimeMillis()
+
+        log.withIndent {
+            // Open the input jar file and process each entry.
+            ZipFile(inJar).use { inZip ->
+                ZipOutputStream(FileOutputStream(outStubJar)).use { stubOutStream ->
+                    ZipOutputStream(FileOutputStream(outImplJar)).use { implOutStream ->
+                        val inEntries = inZip.entries()
+                        while (inEntries.hasMoreElements()) {
+                            val entry = inEntries.nextElement()
+                            convertSingleEntry(inZip, entry, stubOutStream, implOutStream,
+                                    filter, enableChecker, classes, errors)
+                        }
+                        log.i("Converted all entries.")
+                    }
+                }
+                log.i("Created stub: $outStubJar")
+                log.i("Created impl: $outImplJar")
+            }
+        }
+        val end = System.currentTimeMillis()
+        log.v("Done transforming the jar in %.1f second(s).", (end - start) / 1000.0)
+    }
+
+    /**
+     * Convert a single ZIP entry, which may or may not be a class file.
+     */
+    private fun convertSingleEntry(
+            inZip: ZipFile,
+            entry: ZipEntry,
+            stubOutStream: ZipOutputStream,
+            implOutStream: ZipOutputStream,
+            filter: OutputFilter,
+            enableChecker: Boolean,
+            classes: ClassNodes,
+            errors: HostStubGenErrors,
+            ) {
+        log.d("Entry: %s", entry.name)
+        log.withIndent {
+            val name = entry.name
+
+            // Just ignore all the directories. (TODO: make sure it's okay)
+            if (name.endsWith("/")) {
+                return
+            }
+
+            // If it's a class, convert it.
+            if (name.endsWith(".class")) {
+                processSingleClass(inZip, entry, stubOutStream, implOutStream, filter,
+                        enableChecker, classes, errors)
+                return
+            }
+
+            // Handle other file types...
+
+            // - *.uau seems to contain hidden API information.
+            // -  *_compat_config.xml is also about compat-framework.
+            if (name.endsWith(".uau") ||
+                    name.endsWith("_compat_config.xml")) {
+                log.d("Not needed: %s", entry.name)
+                return
+            }
+
+            // Unknown type, we just copy it to both output zip files.
+            // TODO: We probably shouldn't do it for stub jar?
+            log.v("Copying: %s", entry.name)
+            copyZipEntry(inZip, entry, stubOutStream)
+            copyZipEntry(inZip, entry, implOutStream)
+        }
+    }
+
+    /**
+     * Copy a single ZIP entry to the output.
+     */
+    private fun copyZipEntry(
+            inZip: ZipFile,
+            entry: ZipEntry,
+            out: ZipOutputStream,
+            ) {
+        BufferedInputStream(inZip.getInputStream(entry)).use { bis ->
+            // Copy unknown entries as is to the impl out. (but not to the stub out.)
+            val outEntry = ZipEntry(entry.name)
+            out.putNextEntry(outEntry)
+            while (bis.available() > 0) {
+                out.write(bis.read())
+            }
+            out.closeEntry()
+        }
+    }
+
+    /**
+     * Convert a single class to "stub" and "impl".
+     */
+    private fun processSingleClass(
+            inZip: ZipFile,
+            entry: ZipEntry,
+            stubOutStream: ZipOutputStream,
+            implOutStream: ZipOutputStream,
+            filter: OutputFilter,
+            enableChecker: Boolean,
+            classes: ClassNodes,
+            errors: HostStubGenErrors,
+            ) {
+        val className = entry.name.replaceFirst("\\.class$".toRegex(), "")
+        val classPolicy = filter.getPolicyForClass(className)
+        if (classPolicy.policy == FilterPolicy.Remove) {
+            log.d("Removing class: %s %s", className, classPolicy)
+            return
+        }
+        // Generate stub first.
+        if (classPolicy.policy.needsInStub) {
+            log.v("Creating stub class: %s Policy: %s", className, classPolicy)
+            log.withIndent {
+                BufferedInputStream(inZip.getInputStream(entry)).use { bis ->
+                    val newEntry = ZipEntry(entry.name)
+                    stubOutStream.putNextEntry(newEntry)
+                    convertClass(/*forImpl=*/false, bis, stubOutStream, filter, enableChecker,
+                            classes, errors)
+                    stubOutStream.closeEntry()
+                }
+            }
+        }
+        log.v("Creating impl class: %s Policy: %s", className, classPolicy)
+        if (classPolicy.policy.needsInImpl) {
+            log.withIndent {
+                BufferedInputStream(inZip.getInputStream(entry)).use { bis ->
+                    val newEntry = ZipEntry(entry.name)
+                    implOutStream.putNextEntry(newEntry)
+                    convertClass(/*forImpl=*/true, bis, implOutStream, filter, enableChecker,
+                            classes, errors)
+                    implOutStream.closeEntry()
+                }
+            }
+        }
+    }
+
+    /**
+     * Convert a single class to either "stub" or "impl".
+     */
+    private fun convertClass(
+        forImpl: Boolean,
+        input: InputStream,
+        out: OutputStream,
+        filter: OutputFilter,
+        enableChecker: Boolean,
+        classes: ClassNodes,
+        errors: HostStubGenErrors,
+        ) {
+        val cr = ClassReader(input)
+
+        // COMPUTE_FRAMES wouldn't be happy if code uses
+        val flags = ClassWriter.COMPUTE_MAXS // or ClassWriter.COMPUTE_FRAMES
+        val cw = ClassWriter(flags)
+
+        // Connect to the class writer
+        var outVisitor: ClassVisitor = cw
+        if (enableChecker) {
+            outVisitor = CheckClassAdapter(outVisitor)
+        }
+        val visitorOptions = BaseAdapter.Options(
+                enablePreTrace = options.enablePreTrace,
+                enablePostTrace = options.enablePostTrace,
+                enableMethodLogging = options.enablePreTrace,
+                enableNonStubMethodCallDetection = options.enableNonStubMethodCallDetection,
+                errors = errors,
+        )
+        outVisitor = BaseAdapter.getVisitor(classes, outVisitor, filter, forImpl, visitorOptions)
+
+        cr.accept(outVisitor, ClassReader.EXPAND_FRAMES)
+        val data = cw.toByteArray()
+        out.write(data)
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenErrors.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenErrors.kt
new file mode 100644
index 0000000..9df0489
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenErrors.kt
@@ -0,0 +1,24 @@
+/*
+ * 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
+
+class HostStubGenErrors {
+    fun onErrorFound(message: String) {
+        // For now, we just throw as soon as any error is found, but eventually we should keep
+        // all errors and print them at the end.
+        throw RuntimeException(message)
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenLogger.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenLogger.kt
new file mode 100644
index 0000000..5e71a36
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenLogger.kt
@@ -0,0 +1,198 @@
+/*
+ * 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
+
+import java.io.OutputStream
+import java.io.PrintStream
+
+val log: HostStubGenLogger = HostStubGenLogger()
+
+/** Logging level */
+enum class LogLevel {
+    None,
+    Error,
+    Warn,
+    Info,
+    Verbose,
+    Debug,
+}
+
+/** Simple logging class. */
+class HostStubGenLogger(
+        private var out: PrintStream = System.out!!,
+        var level: LogLevel = LogLevel.Info,
+) {
+    companion object {
+        private val sNullPrintStream: PrintStream = PrintStream(OutputStream.nullOutputStream())
+    }
+
+    private var indentLevel: Int = 0
+        get() = field
+        set(value) {
+            field = value
+            indent = "  ".repeat(value)
+        }
+    private var indent: String = ""
+
+    fun indent() {
+        indentLevel++
+    }
+
+    fun unindent() {
+        if (indentLevel <= 0) {
+            throw IllegalStateException("Unbalanced unindent() call.")
+        }
+        indentLevel--
+    }
+
+    inline fun <T> withIndent(block: () -> T): T {
+        try {
+            indent()
+            return block()
+        } finally {
+            unindent()
+        }
+    }
+
+    fun isEnabled(level: LogLevel): Boolean {
+        return level.ordinal <= this.level.ordinal
+    }
+
+    private fun println(message: String) {
+        out.print(indent)
+        out.println(message)
+    }
+
+    /** Log an error. */
+    fun e(message: String) {
+        if (level.ordinal < LogLevel.Error.ordinal) {
+            return
+        }
+        println(message)
+    }
+
+    /** Log an error. */
+    fun e(format: String, vararg args: Any?) {
+        if (level.ordinal < LogLevel.Error.ordinal) {
+            return
+        }
+        e(String.format(format, *args))
+    }
+
+    /** Log a warning. */
+    fun w(message: String) {
+        if (level.ordinal < LogLevel.Warn.ordinal) {
+            return
+        }
+        println(message)
+    }
+
+    /** Log a warning. */
+    fun w(format: String, vararg args: Any?) {
+        if (level.ordinal < LogLevel.Warn.ordinal) {
+            return
+        }
+        w(String.format(format, *args))
+    }
+
+    /** Log an info message. */
+    fun i(message: String) {
+        if (level.ordinal < LogLevel.Info.ordinal) {
+            return
+        }
+        println(message)
+    }
+
+    /** Log a debug message. */
+    fun i(format: String, vararg args: Any?) {
+        if (level.ordinal < LogLevel.Warn.ordinal) {
+            return
+        }
+        i(String.format(format, *args))
+    }
+
+    /** Log a verbose message. */
+    fun v(message: String) {
+        if (level.ordinal < LogLevel.Verbose.ordinal) {
+            return
+        }
+        println(message)
+    }
+
+    /** Log a verbose message. */
+    fun v(format: String, vararg args: Any?) {
+        if (level.ordinal < LogLevel.Verbose.ordinal) {
+            return
+        }
+        v(String.format(format, *args))
+    }
+
+    /** Log a debug message. */
+    fun d(message: String) {
+        if (level.ordinal < LogLevel.Debug.ordinal) {
+            return
+        }
+        println(message)
+    }
+
+    /** Log a debug message. */
+    fun d(format: String, vararg args: Any?) {
+        if (level.ordinal < LogLevel.Warn.ordinal) {
+            return
+        }
+        d(String.format(format, *args))
+    }
+
+    inline fun forVerbose(block: () -> Unit) {
+        if (isEnabled(LogLevel.Verbose)) {
+            block()
+        }
+    }
+
+    inline fun forDebug(block: () -> Unit) {
+        if (isEnabled(LogLevel.Debug)) {
+            block()
+        }
+    }
+
+    /** Return a stream for error. */
+    fun getErrorPrintStream(): PrintStream {
+        if (level.ordinal < LogLevel.Error.ordinal) {
+            return sNullPrintStream
+        }
+
+        // TODO Apply indent
+        return PrintStream(out)
+    }
+
+    /** Return a stream for verbose messages. */
+    fun getVerbosePrintStream(): PrintStream {
+        if (level.ordinal < LogLevel.Verbose.ordinal) {
+            return sNullPrintStream
+        }
+        // TODO Apply indent
+        return PrintStream(out)
+    }
+
+    /** Return a stream for debug messages. */
+    fun getInfoPrintStream(): PrintStream {
+        if (level.ordinal < LogLevel.Info.ordinal) {
+            return sNullPrintStream
+        }
+        // TODO Apply indent
+        return PrintStream(out)
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
new file mode 100644
index 0000000..9a54ecf
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
@@ -0,0 +1,307 @@
+/*
+ * 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
+
+import com.android.hoststubgen.filters.FilterPolicy
+import java.io.BufferedReader
+import java.io.File
+import java.io.FileReader
+
+/**
+ * Options that can be set from command line arguments.
+ */
+class HostStubGenOptions(
+        /** Input jar file*/
+        var inJar: String = "",
+
+        /** Output stub jar file */
+        var outStubJar: String = "",
+
+        /** Output implementation jar file */
+        var outImplJar: String = "",
+
+        var inputJarDumpFile: String? = null,
+
+        var inputJarAsKeepAllFile: String? = null,
+
+        var stubAnnotations: MutableSet<String> = mutableSetOf(),
+        var keepAnnotations: MutableSet<String> = mutableSetOf(),
+        var throwAnnotations: MutableSet<String> = mutableSetOf(),
+        var removeAnnotations: MutableSet<String> = mutableSetOf(),
+        var stubClassAnnotations: MutableSet<String> = mutableSetOf(),
+        var keepClassAnnotations: MutableSet<String> = mutableSetOf(),
+
+        var substituteAnnotations: MutableSet<String> = mutableSetOf(),
+        var nativeSubstituteAnnotations: MutableSet<String> = mutableSetOf(),
+        var classLoadHookAnnotations: MutableSet<String> = mutableSetOf(),
+
+        var intersectStubJars: MutableSet<String> = mutableSetOf(),
+
+        var policyOverrideFile: String? = null,
+
+        var defaultPolicy: FilterPolicy = FilterPolicy.Remove,
+        var keepAllClasses: Boolean = false,
+
+        var logLevel: LogLevel = LogLevel.Info,
+
+        var cleanUpOnError: Boolean = false,
+
+        var enableClassChecker: Boolean = false,
+        var enablePreTrace: Boolean = false,
+        var enablePostTrace: Boolean = false,
+
+        var enableMethodLogging: Boolean = false,
+
+        var enableNonStubMethodCallDetection: Boolean = true,
+) {
+    companion object {
+
+        private fun String.ensureFileExists(): String {
+            if (!File(this).exists()) {
+                throw InputFileNotFoundException(this)
+            }
+            return this
+        }
+
+        fun parseArgs(args: Array<String>): HostStubGenOptions {
+            val ret = HostStubGenOptions()
+
+            val ai = ArgIterator(expandAtFiles(args))
+
+            var allAnnotations = mutableSetOf<String>()
+
+            fun ensureUniqueAnnotation(name: String): String {
+                if (!allAnnotations.add(name)) {
+                    throw DuplicateAnnotationException(ai.current)
+                }
+                return name
+            }
+
+            while (true) {
+                val arg = ai.nextArgOptional()
+                if (arg == null) {
+                    break
+                }
+
+                when (arg) {
+                    // TODO: Write help
+                    "-h", "--h" -> TODO("Help is not implemented yet")
+
+                    "-v", "--verbose" -> ret.logLevel = LogLevel.Verbose
+                    "-d", "--debug" -> ret.logLevel = LogLevel.Debug
+                    "-q", "--quiet" -> ret.logLevel = LogLevel.None
+
+                    "--in-jar" -> ret.inJar = ai.nextArgRequired(arg).ensureFileExists()
+                    "--out-stub-jar" -> ret.outStubJar = ai.nextArgRequired(arg)
+                    "--out-impl-jar" -> ret.outImplJar = ai.nextArgRequired(arg)
+
+                    "--policy-override-file" ->
+                        ret.policyOverrideFile = ai.nextArgRequired(arg).ensureFileExists()
+
+                    "--clean-up-on-error" -> ret.cleanUpOnError = true
+                    "--no-clean-up-on-error" -> ret.cleanUpOnError = false
+
+                    "--default-remove" -> ret.defaultPolicy = FilterPolicy.Remove
+                    "--default-throw" -> ret.defaultPolicy = FilterPolicy.Throw
+                    "--default-keep" -> ret.defaultPolicy = FilterPolicy.Keep
+                    "--default-stub" -> ret.defaultPolicy = FilterPolicy.Stub
+
+                    "--keep-all-classes" -> ret.keepAllClasses = true
+                    "--no-keep-all-classes" -> ret.keepAllClasses = false
+
+                    "--stub-annotation" ->
+                        ret.stubAnnotations += ensureUniqueAnnotation(ai.nextArgRequired(arg))
+
+                    "--keep-annotation" ->
+                        ret.keepAnnotations += ensureUniqueAnnotation(ai.nextArgRequired(arg))
+
+                    "--stub-class-annotation" ->
+                        ret.stubClassAnnotations += ensureUniqueAnnotation(ai.nextArgRequired(arg))
+
+                    "--keep-class-annotation" ->
+                        ret.keepClassAnnotations += ensureUniqueAnnotation(ai.nextArgRequired(arg))
+
+                    "--throw-annotation" ->
+                        ret.throwAnnotations += ensureUniqueAnnotation(ai.nextArgRequired(arg))
+
+                    "--remove-annotation" ->
+                        ret.removeAnnotations += ensureUniqueAnnotation(ai.nextArgRequired(arg))
+
+                    "--substitute-annotation" ->
+                        ret.substituteAnnotations += ensureUniqueAnnotation(ai.nextArgRequired(arg))
+
+                    "--native-substitute-annotation" ->
+                        ret.nativeSubstituteAnnotations +=
+                                ensureUniqueAnnotation(ai.nextArgRequired(arg))
+
+                    "--class-load-hook-annotation" ->
+                        ret.classLoadHookAnnotations +=
+                            ensureUniqueAnnotation(ai.nextArgRequired(arg))
+
+                    "--intersect-stub-jar" ->
+                        ret.intersectStubJars += ai.nextArgRequired(arg).ensureFileExists()
+
+                    "--gen-keep-all-file" ->
+                        ret.inputJarAsKeepAllFile = ai.nextArgRequired(arg)
+
+                    // Following options are for debugging.
+                    "--enable-class-checker" -> ret.enableClassChecker = true
+                    "--no-class-checker" -> ret.enableClassChecker = false
+
+                    "--enable-pre-trace" -> ret.enablePreTrace = true
+                    "--no-pre-trace" -> ret.enablePreTrace = false
+
+                    "--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
+
+                    "--gen-input-dump-file" -> ret.inputJarDumpFile = ai.nextArgRequired(arg)
+
+                    else -> throw ArgumentsException("Unknown option: $arg")
+                }
+            }
+            if (ret.inJar.isEmpty()) {
+                throw ArgumentsException("Required option missing: --in-jar")
+            }
+            if (ret.outStubJar.isEmpty()) {
+                throw ArgumentsException("Required option missing: --out-stub-jar")
+            }
+            if (ret.outImplJar.isEmpty()) {
+                throw ArgumentsException("Required option missing: --out-impl-jar")
+            }
+
+            return ret
+        }
+
+        /**
+         * Scan the arguments, and if any of them starts with an `@`, then load from the file
+         * and use its content as arguments.
+         *
+         * In this file, each line is treated as a single argument.
+         *
+         * The file can contain '#' as comments.
+         */
+        private fun expandAtFiles(args: Array<String>): List<String> {
+            val ret = mutableListOf<String>()
+
+            args.forEach { arg ->
+                if (!arg.startsWith('@')) {
+                    ret += arg
+                    return@forEach
+                }
+                // Read from the file, and add each line to the result.
+                val filename = arg.substring(1).ensureFileExists()
+
+                log.v("Expanding options file $filename")
+
+                BufferedReader(FileReader(filename)).use { reader ->
+                    while (true) {
+                        var line = reader.readLine()
+                        if (line == null) {
+                            break // EOF
+                        }
+
+                        line = normalizeTextLine(line)
+                        if (line.isNotEmpty()) {
+                            ret += line
+                        }
+                    }
+                }
+            }
+            return ret
+        }
+    }
+
+    open class ArgumentsException(message: String?) : Exception(message), UserErrorException
+
+    /** Thrown when the same annotation is used with different annotation arguments. */
+    class DuplicateAnnotationException(annotationName: String?) :
+            ArgumentsException("Duplicate annotation specified: '$annotationName'")
+
+    /** Thrown when an input file does not exist. */
+    class InputFileNotFoundException(filename: String) :
+            ArgumentsException("File '$filename' not found")
+
+    private class ArgIterator(
+            private val args: List<String>,
+            private var currentIndex: Int = -1
+    ) {
+        val current: String
+            get() = args.get(currentIndex)
+
+        /**
+         * Get the next argument, or [null] if there's no more arguments.
+         */
+        fun nextArgOptional(): String? {
+            if ((currentIndex + 1) >= args.size) {
+                return null
+            }
+            return args.get(++currentIndex)
+        }
+
+        /**
+         * Get the next argument, or throw if
+         */
+        fun nextArgRequired(argName: String): String {
+            nextArgOptional().let {
+                if (it == null) {
+                    throw ArgumentsException("Missing parameter for option $argName")
+                }
+                if (it.isEmpty()) {
+                    throw ArgumentsException("Parameter can't be empty for option $argName")
+                }
+                return it
+            }
+        }
+    }
+
+    override fun toString(): String {
+        return """
+            HostStubGenOptions{
+              inJar='$inJar',
+              outStubJar='$outStubJar',
+              outImplJar='$outImplJar',
+              inputJarDumpFile=$inputJarDumpFile,
+              inputJarAsKeepAllFile=$inputJarAsKeepAllFile,
+              stubAnnotations=$stubAnnotations,
+              keepAnnotations=$keepAnnotations,
+              throwAnnotations=$throwAnnotations,
+              removeAnnotations=$removeAnnotations,
+              stubClassAnnotations=$stubClassAnnotations,
+              keepClassAnnotations=$keepClassAnnotations,
+              substituteAnnotations=$substituteAnnotations,
+              nativeSubstituteAnnotations=$nativeSubstituteAnnotations,
+              classLoadHookAnnotations=$classLoadHookAnnotations,
+              intersectStubJars=$intersectStubJars,
+              policyOverrideFile=$policyOverrideFile,
+              defaultPolicy=$defaultPolicy,
+              keepAllClasses=$keepAllClasses,
+              logLevel=$logLevel,
+              cleanUpOnError=$cleanUpOnError,
+              enableClassChecker=$enableClassChecker,
+              enablePreTrace=$enablePreTrace,
+              enablePostTrace=$enablePostTrace,
+              enableMethodLogging=$enableMethodLogging,
+              enableNonStubMethodCallDetection=$enableNonStubMethodCallDetection,
+            }
+            """.trimIndent()
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Main.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Main.kt
new file mode 100644
index 0000000..0321d9d
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Main.kt
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+@file:JvmName("Main")
+
+package com.android.hoststubgen
+
+const val COMMAND_NAME = "HostStubGen"
+
+/**
+ * Entry point.
+ */
+fun main(args: Array<String>) {
+    var success = false
+    var clanupOnError = false
+    try {
+        // Parse the command line arguments.
+        val options = HostStubGenOptions.parseArgs(args)
+        clanupOnError = options.cleanUpOnError
+
+        log.level = options.logLevel
+
+        log.v("HostStubGen started")
+        log.v("Options: $options")
+
+        // Run.
+        HostStubGen(options).run()
+
+        success = true
+    } catch (e: Exception) {
+        log.e("$COMMAND_NAME: Error: ${e.message}")
+        if (e !is UserErrorException) {
+            e.printStackTrace(log.getErrorPrintStream())
+        }
+        if (clanupOnError) {
+            TODO("clanupOnError is not implemented yet")
+        }
+    }
+
+    log.v("HostStubGen finished")
+
+    System.exit(if (success) 0 else 1 )
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt
new file mode 100644
index 0000000..9fbd6d0
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt
@@ -0,0 +1,33 @@
+/*
+ * 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
+
+/**
+ * A regex that maches whitespate.
+ */
+val whitespaceRegex = """\s+""".toRegex()
+
+/**
+ * Remove the comment ('#' and following) and surrounding whitespace from a line.
+ */
+fun normalizeTextLine(s: String): String {
+    // Remove # and after. (comment)
+    val pos = s.indexOf('#')
+    val uncommented = if (pos < 0) s else s.substring(0, pos)
+
+    // Remove surrounding whitespace.
+    return uncommented.trim()
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt
new file mode 100644
index 0000000..a51bdcf
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt
@@ -0,0 +1,177 @@
+/*
+ * 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.asm
+
+import com.android.hoststubgen.ClassParseException
+import com.android.hoststubgen.HostStubGenInternalException
+import org.objectweb.asm.MethodVisitor
+import org.objectweb.asm.Opcodes
+import org.objectweb.asm.Type
+import org.objectweb.asm.tree.AnnotationNode
+import org.objectweb.asm.tree.ClassNode
+
+
+/** Name of the class initializer method. */
+val CLASS_INITIALIZER_NAME = "<clinit>"
+
+/** Descriptor of the class initializer method. */
+val CLASS_INITIALIZER_DESC = "()V"
+
+/**
+ * Find any of [anyAnnotations] from the list of visible / invisible annotations.
+ */
+fun findAnyAnnotation(
+        anyAnnotations: Set<String>,
+        visibleAnnotations: List<AnnotationNode>?,
+        invisibleAnnotations: List<AnnotationNode>?,
+    ): AnnotationNode? {
+    for (an in visibleAnnotations ?: emptyList()) {
+        if (anyAnnotations.contains(an.desc)) {
+            return an
+        }
+    }
+    for (an in invisibleAnnotations ?: emptyList()) {
+        if (anyAnnotations.contains(an.desc)) {
+            return an
+        }
+    }
+    return null
+}
+
+fun findAnnotationValueAsString(an: AnnotationNode, propertyName: String): String? {
+    for (i in 0..(an.values?.size ?: 0) - 2 step 2) {
+        val name = an.values[i]
+
+        if (name != propertyName) {
+            continue
+        }
+        val value = an.values[i + 1]
+        if (value is String) {
+            return value
+        }
+        throw ClassParseException(
+                "The type of '$name' in annotation \"${an.desc}\" must be String" +
+                        ", but is ${value?.javaClass?.canonicalName}")
+    }
+    return null
+}
+
+private val removeLastElement = """[./][^./]*$""".toRegex()
+
+fun getPackageNameFromClassName(className: String): String {
+    return className.replace(removeLastElement, "")
+}
+
+fun resolveClassName(className: String, packageName: String): String {
+    if (className.contains('.') || className.contains('/')) {
+        return className
+    }
+    return "$packageName.$className"
+}
+
+fun String.toJvmClassName(): String {
+    return this.replace('.', '/')
+}
+
+fun String.toHumanReadableClassName(): String {
+    return this.replace('/', '.')
+}
+
+fun String.toHumanReadableMethodName(): String {
+    return this.replace('/', '.')
+}
+
+private val numericalInnerClassName = """.*\$\d+$""".toRegex()
+
+fun isAnonymousInnerClass(cn: ClassNode): Boolean {
+    // TODO: Is there a better way?
+    return cn.name.matches(numericalInnerClassName)
+}
+
+/**
+ * Take a class name. If it's a nested class, then return the name of its direct outer class name.
+ * Otherwise, return null.
+ */
+fun getDirectOuterClassName(className: String): String? {
+    val pos = className.indexOf('$')
+    if (pos < 0) {
+        return null
+    }
+    return className.substring(0, pos)
+}
+
+/**
+ * Write bytecode to push all the method arguments to the stack.
+ * The number of arguments and their type are taken from [methodDescriptor].
+ */
+fun writeByteCodeToPushArguments(methodDescriptor: String, writer: MethodVisitor) {
+    var i = -1
+    Type.getArgumentTypes(methodDescriptor).forEach { type ->
+        i++
+
+        // See https://en.wikipedia.org/wiki/List_of_Java_bytecode_instructions
+
+        // Note, long and double will consume two local variable spaces, so the extra `i++`.
+        when (type) {
+            Type.VOID_TYPE -> throw HostStubGenInternalException("VOID_TYPE not expected")
+            Type.BOOLEAN_TYPE, Type.INT_TYPE, Type.SHORT_TYPE, Type.CHAR_TYPE
+                -> writer.visitVarInsn(Opcodes.ILOAD, i)
+            Type.LONG_TYPE -> writer.visitVarInsn(Opcodes.LLOAD, i++)
+            Type.FLOAT_TYPE -> writer.visitVarInsn(Opcodes.FLOAD, i)
+            Type.DOUBLE_TYPE -> writer.visitVarInsn(Opcodes.DLOAD, i++)
+            else -> writer.visitVarInsn(Opcodes.ALOAD, i)
+        }
+    }
+}
+
+/**
+ * Write bytecode to "RETURN" that matches the method's return type, according to
+ * [methodDescriptor].
+ */
+fun writeByteCodeToReturn(methodDescriptor: String, writer: MethodVisitor) {
+    Type.getReturnType(methodDescriptor).let { type ->
+        // See https://en.wikipedia.org/wiki/List_of_Java_bytecode_instructions
+        when (type) {
+            Type.VOID_TYPE -> writer.visitInsn(Opcodes.RETURN)
+            Type.BOOLEAN_TYPE, Type.INT_TYPE, Type.SHORT_TYPE, Type.CHAR_TYPE
+                -> writer.visitInsn(Opcodes.IRETURN)
+            Type.LONG_TYPE -> writer.visitInsn(Opcodes.LRETURN)
+            Type.FLOAT_TYPE -> writer.visitInsn(Opcodes.FRETURN)
+            Type.DOUBLE_TYPE -> writer.visitInsn(Opcodes.DRETURN)
+            else -> writer.visitInsn(Opcodes.ARETURN)
+        }
+    }
+}
+
+/**
+ * Return the "visibility" modifier from an `access` integer.
+ *
+ * (see https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.1-200-E.1)
+ */
+fun getVisibilityModifier(access: Int): Int {
+    return access and (Opcodes.ACC_PUBLIC or Opcodes.ACC_PRIVATE or Opcodes.ACC_PROTECTED)
+}
+
+/**
+ * Return true if an `access` integer is "private" or "package private".
+ */
+fun isVisibilityPrivateOrPackagePrivate(access: Int): Boolean {
+    return when (getVisibilityModifier(access)) {
+        0 -> true // Package private.
+        Opcodes.ACC_PRIVATE -> true
+        else -> false
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt
new file mode 100644
index 0000000..4df0bfc
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt
@@ -0,0 +1,149 @@
+package com.android.hoststubgen.asm
+
+import com.android.hoststubgen.ClassParseException
+import org.objectweb.asm.tree.AnnotationNode
+import org.objectweb.asm.tree.ClassNode
+import org.objectweb.asm.tree.FieldNode
+import org.objectweb.asm.tree.MethodNode
+import org.objectweb.asm.tree.TypeAnnotationNode
+import java.io.PrintWriter
+import java.util.Arrays
+
+/**
+ * Stores all classes loaded from a jar file, in a form of [ClassNode]
+ */
+class ClassNodes {
+    val mAllClasses: MutableMap<String, ClassNode> = HashMap()
+
+    /**
+     * Total number of classes registered.
+     */
+    val size: Int
+        get() = mAllClasses.size
+
+    /** Add a [ClassNode] */
+    fun addClass(cn: ClassNode): Boolean {
+        if (mAllClasses.containsKey(cn.name)) {
+            return false
+        }
+        mAllClasses[cn.name.toJvmClassName()] = cn
+        return true
+    }
+
+    /** Get a class's [ClassNodes] (which may not exist) */
+    fun findClass(name: String): ClassNode? {
+        return mAllClasses[name.toJvmClassName()]
+    }
+
+    /** Get a class's [ClassNodes] (which must exists) */
+    fun getClass(name: String): ClassNode {
+        return findClass(name) ?: throw ClassParseException("Class $name not found")
+    }
+
+    /** Find a field, which may not exist. */
+    fun findField(
+            className: String,
+            fieldName: String,
+    ): FieldNode? {
+        return findClass(className)?.fields?.firstOrNull { it.name == fieldName }?.let { fn ->
+            return fn
+        }
+    }
+
+    /** Find a method, which may not exist. */
+    fun findMethod(
+            className: String,
+            methodName: String,
+            descriptor: String,
+    ): MethodNode? {
+        return findClass(className)?.methods
+                ?.firstOrNull { it.name == methodName && it.desc == descriptor }?.let { mn ->
+            return mn
+        }
+    }
+
+    /** @return true if a class has a class initializer. */
+    fun hasClassInitializer(className: String): Boolean {
+        return findMethod(className, CLASS_INITIALIZER_NAME, CLASS_INITIALIZER_DESC) != null
+    }
+
+    /** Run the lambda on each class in alphabetical order. */
+    fun forEach(consumer: (classNode: ClassNode) -> Unit) {
+        val keys = mAllClasses.keys.toTypedArray()
+        Arrays.sort(keys)
+
+        for (name in keys) {
+            consumer(mAllClasses[name]!!)
+        }
+    }
+
+    /**
+     * Dump all classes.
+     */
+    fun dump(pw: PrintWriter) {
+        forEach { classNode -> dumpClass(pw, classNode) }
+    }
+
+    private fun dumpClass(pw: PrintWriter, cn: ClassNode) {
+        pw.printf("Class: %s [access: %x]\n", cn.name, cn.access)
+        dumpAnnotations(pw, "  ",
+                cn.visibleTypeAnnotations, cn.invisibleTypeAnnotations,
+                cn.visibleAnnotations, cn.invisibleAnnotations,
+                )
+
+        for (f in cn.fields ?: emptyList()) {
+            pw.printf("  Field: %s [sig: %s] [desc: %s] [access: %x]\n",
+                    f.name, f.signature, f.desc, f.access)
+            dumpAnnotations(pw, "    ",
+                    f.visibleTypeAnnotations, f.invisibleTypeAnnotations,
+                    f.visibleAnnotations, f.invisibleAnnotations,
+                    )
+        }
+        for (m in cn.methods ?: emptyList()) {
+            pw.printf("  Method: %s [sig: %s] [desc: %s] [access: %x]\n",
+                    m.name, m.signature, m.desc, m.access)
+            dumpAnnotations(pw, "    ",
+                    m.visibleTypeAnnotations, m.invisibleTypeAnnotations,
+                    m.visibleAnnotations, m.invisibleAnnotations,
+                    )
+        }
+    }
+
+    private fun dumpAnnotations(
+        pw: PrintWriter,
+        prefix: String,
+        visibleTypeAnnotations: List<TypeAnnotationNode>?,
+        invisibleTypeAnnotations: List<TypeAnnotationNode>?,
+        visibleAnnotations: List<AnnotationNode>?,
+        invisibleAnnotations: List<AnnotationNode>?,
+        ) {
+        for (an in visibleTypeAnnotations ?: emptyList()) {
+            pw.printf("%sTypeAnnotation(vis): %s\n", prefix, an.desc)
+        }
+        for (an in invisibleTypeAnnotations ?: emptyList()) {
+            pw.printf("%sTypeAnnotation(inv): %s\n", prefix, an.desc)
+        }
+        for (an in visibleAnnotations ?: emptyList()) {
+            pw.printf("%sAnnotation(vis): %s\n", prefix, an.desc)
+            if (an.values == null) {
+                continue
+            }
+            var i = 0
+            while (i < an.values.size - 1) {
+                pw.printf("%s  - %s -> %s \n", prefix, an.values[i], an.values[i + 1])
+                i += 2
+            }
+        }
+        for (an in invisibleAnnotations ?: emptyList()) {
+            pw.printf("%sAnnotation(inv): %s\n", prefix, an.desc)
+            if (an.values == null) {
+                continue
+            }
+            var i = 0
+            while (i < an.values.size - 1) {
+                pw.printf("%s  - %s -> %s \n", prefix, an.values[i], an.values[i + 1])
+                i += 2
+            }
+        }
+    }
+}
\ 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
new file mode 100644
index 0000000..454569d
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt
@@ -0,0 +1,401 @@
+/*
+ * 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.ClassParseException
+import com.android.hoststubgen.HostStubGenErrors
+import com.android.hoststubgen.HostStubGenInternalException
+import com.android.hoststubgen.InvalidAnnotationException
+import com.android.hoststubgen.asm.ClassNodes
+import com.android.hoststubgen.asm.findAnnotationValueAsString
+import com.android.hoststubgen.asm.findAnyAnnotation
+import com.android.hoststubgen.asm.toHumanReadableMethodName
+import com.android.hoststubgen.asm.toJvmClassName
+import com.android.hoststubgen.log
+import org.objectweb.asm.tree.AnnotationNode
+import org.objectweb.asm.tree.ClassNode
+
+// TODO: Detect invalid cases, such as...
+// - Class's visibility is lower than the members'.
+// - HostSideTestSubstituteWith is set, but it doesn't have @Stub or @Keep
+
+/**
+ * [OutputFilter] using Java annotations.
+ */
+class AnnotationBasedFilter(
+        private val errors: HostStubGenErrors,
+        private val classes: ClassNodes,
+        stubAnnotations_: Set<String>,
+        keepAnnotations_: Set<String>,
+        stubClassAnnotations_: Set<String>,
+        keepClassAnnotations_: Set<String>,
+        throwAnnotations_: Set<String>,
+        removeAnnotations_: Set<String>,
+        substituteAnnotations_: Set<String>,
+        nativeSubstituteAnnotations_: Set<String>,
+        classLoadHookAnnotations_: Set<String>,
+        fallback: OutputFilter,
+) : DelegatingFilter(fallback) {
+    private var stubAnnotations = convertToInternalNames(stubAnnotations_)
+    private var keepAnnotations = convertToInternalNames(keepAnnotations_)
+    private var stubClassAnnotations = convertToInternalNames(stubClassAnnotations_)
+    private var keepClassAnnotations = convertToInternalNames(keepClassAnnotations_)
+    private var throwAnnotations = convertToInternalNames(throwAnnotations_)
+    private var removeAnnotations = convertToInternalNames(removeAnnotations_)
+    private var substituteAnnotations = convertToInternalNames(substituteAnnotations_)
+    private var nativeSubstituteAnnotations = convertToInternalNames(nativeSubstituteAnnotations_)
+    private var classLoadHookAnnotations = convertToInternalNames(classLoadHookAnnotations_)
+
+    /** Annotations that control API visibility. */
+    private var visibilityAnnotations: Set<String> = convertToInternalNames(
+        stubAnnotations_ +
+        keepAnnotations_ +
+        stubClassAnnotations_ +
+        keepClassAnnotations_ +
+        throwAnnotations_ +
+        removeAnnotations_)
+
+    /**
+     * All the annotations we use. Note, this one is in a [convertToJvmNames] format unlike
+     * other ones, because of how it's used.
+     */
+    private var allAnnotations: Set<String> = convertToJvmNames(
+        stubAnnotations_ +
+                keepAnnotations_ +
+                stubClassAnnotations_ +
+                keepClassAnnotations_ +
+                throwAnnotations_ +
+                removeAnnotations_ +
+                substituteAnnotations_ +
+                nativeSubstituteAnnotations_ +
+                classLoadHookAnnotations_)
+
+    private val substitutionHelper = SubstitutionHelper()
+
+    private val reasonAnnotation = "annotation"
+    private val reasonClassAnnotation = "class-annotation"
+
+    /**
+     * Throw if an item has more than one visibility annotations.
+     *
+     * name1 - 4 are only used in exception messages. We take them as separate strings
+     * to avoid unnecessary string concatenations.
+     */
+    private fun detectInvalidAnnotations(
+        visibles: List<AnnotationNode>?,
+        invisibles: List<AnnotationNode>?,
+        type: String,
+        name1: String,
+        name2: String,
+        name3: String,
+    ) {
+        var count = 0
+        for (an in visibles ?: emptyList()) {
+            if (visibilityAnnotations.contains(an.desc)) {
+                count++
+            }
+        }
+        for (an in invisibles ?: emptyList()) {
+            if (visibilityAnnotations.contains(an.desc)) {
+                count++
+            }
+        }
+        if (count > 1) {
+            val description = if (name2 == "" && name3 == "") {
+                "$type $name1"
+            } else {
+                "$type $name1.$name2$name3"
+            }
+            throw InvalidAnnotationException(
+                "Found more than one visibility annotations on $description")
+        }
+    }
+
+    /**
+     * Find a visibility annotation.
+     *
+     * name1 - 4 are only used in exception messages.
+     */
+    private fun findAnnotation(
+        visibles: List<AnnotationNode>?,
+        invisibles: List<AnnotationNode>?,
+        type: String,
+        name1: String,
+        name2: String = "",
+        name3: String = "",
+    ): FilterPolicyWithReason? {
+        detectInvalidAnnotations(visibles, invisibles, type, name1, name2, name3)
+
+        findAnyAnnotation(stubAnnotations, visibles, invisibles)?.let {
+            return FilterPolicy.Stub.withReason(reasonAnnotation)
+        }
+        findAnyAnnotation(stubClassAnnotations, visibles, invisibles)?.let {
+            return FilterPolicy.StubClass.withReason(reasonClassAnnotation)
+        }
+        findAnyAnnotation(keepAnnotations, visibles, invisibles)?.let {
+            return FilterPolicy.Keep.withReason(reasonAnnotation)
+        }
+        findAnyAnnotation(keepClassAnnotations, visibles, invisibles)?.let {
+            return FilterPolicy.KeepClass.withReason(reasonClassAnnotation)
+        }
+        findAnyAnnotation(throwAnnotations, visibles, invisibles)?.let {
+            return FilterPolicy.Throw.withReason(reasonAnnotation)
+        }
+        findAnyAnnotation(removeAnnotations, visibles, invisibles)?.let {
+            return FilterPolicy.Remove.withReason(reasonAnnotation)
+        }
+        return null
+    }
+
+    override fun getPolicyForClass(className: String): FilterPolicyWithReason {
+        val cn = classes.getClass(className)
+
+        findAnnotation(
+            cn.visibleAnnotations,
+            cn.invisibleAnnotations,
+            "class",
+            className)?.let {
+            return it
+        }
+
+        // If it's any of the annotations, then always keep it.
+        if (allAnnotations.contains(className)) {
+            return FilterPolicy.KeepClass.withReason("HostStubGen Annotation")
+        }
+
+        return super.getPolicyForClass(className)
+    }
+
+    override fun getPolicyForField(
+            className: String,
+            fieldName: String
+    ): FilterPolicyWithReason {
+        val cn = classes.getClass(className)
+
+        cn.fields?.firstOrNull { it.name == fieldName }?.let {fn ->
+            findAnnotation(
+                fn.visibleAnnotations,
+                fn.invisibleAnnotations,
+                "field",
+                className,
+                fieldName
+                )?.let { policy ->
+                // If the item has an annotation, then use it.
+                return policy
+            }
+        }
+        return super.getPolicyForField(className, fieldName)
+    }
+
+    override fun getPolicyForMethod(
+            className: String,
+            methodName: String,
+            descriptor: String
+    ): FilterPolicyWithReason {
+        val cn = classes.getClass(className)
+
+        cn.methods?.firstOrNull { it.name == methodName && it.desc == descriptor }?.let { mn ->
+            // @SubstituteWith is going to complicate the policy here, so we ask helper
+            // what to do.
+            substitutionHelper.getPolicyFromSubstitution(cn, mn.name, mn.desc)?.let {
+                return it
+            }
+
+            // If there's no substitution, then we check the annotation.
+            findAnnotation(
+                mn.visibleAnnotations,
+                mn.invisibleAnnotations,
+                "method",
+                className,
+                methodName,
+                descriptor
+            )?.let { policy ->
+                return policy
+            }
+        }
+        return super.getPolicyForMethod(className, methodName, descriptor)
+    }
+
+    override fun getRenameTo(
+            className: String,
+            methodName: String,
+            descriptor: String
+    ): String? {
+        val cn = classes.getClass(className)
+
+        // If the method has a "substitute with" annotation, then return its "value" parameter.
+        cn.methods?.firstOrNull { it.name == methodName && it.desc == descriptor }?.let { mn ->
+            return substitutionHelper.getRenameTo(cn, mn.name, mn.desc)
+        }
+        return null
+    }
+
+    override fun getNativeSubstitutionClass(className: String): String? {
+        classes.getClass(className).let { cn ->
+            findAnyAnnotation(nativeSubstituteAnnotations,
+                    cn.visibleAnnotations, cn.invisibleAnnotations)?.let { an ->
+                return getAnnotationField(an, "value")?.toJvmClassName()
+            }
+        }
+        return null
+    }
+
+    override fun getClassLoadHook(className: String): String? {
+        classes.getClass(className).let { cn ->
+            findAnyAnnotation(classLoadHookAnnotations,
+                cn.visibleAnnotations, cn.invisibleAnnotations)?.let { an ->
+                return getAnnotationField(an, "value")?.toHumanReadableMethodName()
+            }
+        }
+        return null
+    }
+
+    private data class MethodKey(val name: String, val desc: String)
+
+    /**
+     * In order to handle substitution, we need to build a reverse mapping of substitution
+     * methods.
+     *
+     * This class automatically builds such a map internally that the above methods can
+     * take advantage of.
+     */
+    private inner class SubstitutionHelper {
+        private var currentClass: ClassNode? = null
+
+        private var policiesFromSubstitution = mutableMapOf<MethodKey, FilterPolicyWithReason>()
+        private var substituteToMethods = mutableMapOf<MethodKey, String>()
+
+        fun getPolicyFromSubstitution(cn: ClassNode, methodName: String, descriptor: String):
+                FilterPolicyWithReason? {
+            setClass(cn)
+            return policiesFromSubstitution[MethodKey(methodName, descriptor)]
+        }
+
+        fun getRenameTo(cn: ClassNode, methodName: String, descriptor: String): String? {
+            setClass(cn)
+            return substituteToMethods[MethodKey(methodName, descriptor)]
+        }
+
+        /**
+         * Every time we see a different class, we scan all its methods for substitution attributes,
+         * and compute (implicit) policies caused by them.
+         *
+         * For example, for the following methods:
+         *
+         *   @Stub
+         *   @Substitute(suffix = "_host")
+         *   private void foo() {
+         *      // This isn't supported on the host side.
+         *   }
+         *   private void foo_host() {
+         *      // Host side implementation
+         *   }
+         *
+         * We internally handle them as:
+         *
+         *   foo() -> Remove
+         *   foo_host() -> Stub, and then rename it to foo().
+         */
+        private fun setClass(cn: ClassNode) {
+            if (currentClass == cn) {
+                return
+            }
+            // If the class is changing, we'll rebuild the internal structure.
+            currentClass = cn
+
+            policiesFromSubstitution.clear()
+            substituteToMethods.clear()
+
+            for (mn in cn.methods ?: emptyList()) {
+                findAnyAnnotation(substituteAnnotations,
+                        mn.visibleAnnotations,
+                        mn.invisibleAnnotations)?.let { an ->
+
+                    // Find the policy for this method.
+                    val policy = outermostFilter.getPolicyForMethod(cn.name, mn.name, mn.desc)
+                            .policy.resolveClassWidePolicy()
+                    // Make sure it's either Stub or Keep.
+                    if (!(policy.needsInStub || policy.needsInImpl)) {
+                        // TODO: Use the real annotation names in the message
+                        errors.onErrorFound("@SubstituteWith must have either @Stub or @Keep")
+                        return@let
+                    }
+                    if (!policy.isUsableWithMethods) {
+                        throw HostStubGenInternalException("Policy $policy shouldn't show up here")
+                    }
+
+                    val suffix = getAnnotationField(an, "suffix") ?: return@let
+                    val renameFrom = mn.name + suffix
+                    val renameTo = mn.name
+
+                    if (renameFrom == renameTo) {
+                        errors.onErrorFound("@SubstituteWith have a different name")
+                        return@let
+                    }
+
+                    // This mn has "SubstituteWith". This means,
+                        // 1. Re move the "rename-to" method, so add it to substitutedMethods.
+                    policiesFromSubstitution[MethodKey(renameTo, mn.desc)] =
+                            FilterPolicy.Remove.withReason("substitute-to")
+
+                    // 2. We also keep the from-to in the map.
+                    policiesFromSubstitution[MethodKey(renameFrom, mn.desc)] =
+                            policy.withReason("substitute-from")
+                    substituteToMethods[MethodKey(renameFrom, mn.desc)] = renameTo
+
+                    log.v("Substitution found: %s%s -> %s", renameFrom, mn.desc, renameTo)
+                }
+            }
+        }
+    }
+
+    /**
+     * Return the (String) value of 'value' parameter from an annotation.
+     */
+    private fun getAnnotationField(an: AnnotationNode, name: String): String? {
+        try {
+            val suffix = findAnnotationValueAsString(an, name)
+            if (suffix == null) {
+                errors.onErrorFound("Annotation \"${an.desc}\" must have field $name")
+            }
+            return suffix
+        } catch (e: ClassParseException) {
+            errors.onErrorFound(e.message!!)
+            return null
+        }
+    }
+
+    companion object {
+        /**
+         * Convert from human-readable type names (e.g. "com.android.TypeName") to the internal type
+         * names (e.g. "Lcom/android/TypeName).
+         */
+        private fun convertToInternalNames(input: Set<String>): Set<String> {
+            val ret = mutableSetOf<String>()
+            input.forEach { ret.add("L" + it.toJvmClassName() + ";") }
+            return ret
+        }
+
+        /**
+         * Convert from human-readable type names to JVM type names.
+         */
+        private fun convertToJvmNames(input: Set<String>): Set<String> {
+            val ret = mutableSetOf<String>()
+            input.forEach { ret.add(it.toJvmClassName()) }
+            return ret
+        }
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt
new file mode 100644
index 0000000..6aac3d8
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt
@@ -0,0 +1,80 @@
+/*
+ * 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.asm.getDirectOuterClassName
+
+/**
+ * This is used as the second last fallback filter. This filter propagates the class-wide policy
+ * (obtained from [outermostFilter]) to the fields and methods.
+ */
+class ClassWidePolicyPropagatingFilter(
+        fallback: OutputFilter,
+    ) : DelegatingFilter(fallback) {
+
+    private fun getClassWidePolicy(className: String, resolve: Boolean): FilterPolicyWithReason? {
+        var currentClass = className
+
+        while (true) {
+            outermostFilter.getPolicyForClass(className).let { policy ->
+                if (policy.policy.isClassWidePolicy) {
+                    val p = if (resolve) policy.policy.resolveClassWidePolicy() else policy.policy
+
+                    return p.withReason(policy.reason).wrapReason("class-wide in $currentClass")
+                }
+                // If the class's policy is remove, then remove it.
+                if (policy.policy == FilterPolicy.Remove) {
+                    return FilterPolicy.Remove.withReason("class-wide in $currentClass")
+                }
+            }
+
+            // Next, look at the outer class...
+            val outer = getDirectOuterClassName(currentClass)
+            if (outer == null) {
+                return null
+            }
+            currentClass = outer
+        }
+    }
+
+    override fun getPolicyForClass(className: String): FilterPolicyWithReason {
+        // If it's a nested class, use the outer class's policy.
+        getDirectOuterClassName(className)?.let { outerName ->
+            getClassWidePolicy(outerName, resolve = false)?.let { policy ->
+                return policy
+            }
+        }
+
+        return super.getPolicyForClass(className)
+    }
+
+    override fun getPolicyForField(
+            className: String,
+            fieldName: String
+    ): FilterPolicyWithReason {
+        return getClassWidePolicy(className, resolve = true)
+                ?: super.getPolicyForField(className, fieldName)
+    }
+
+    override fun getPolicyForMethod(
+            className: String,
+            methodName: String,
+            descriptor: String
+    ): FilterPolicyWithReason {
+        return getClassWidePolicy(className, resolve = true)
+                ?: super.getPolicyForMethod(className, methodName, descriptor)
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ConstantFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ConstantFilter.kt
new file mode 100644
index 0000000..33010ba
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ConstantFilter.kt
@@ -0,0 +1,69 @@
+/*
+ * 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.HostStubGenInternalException
+
+
+/**
+ * [OutputFilter] with a given policy. Used to represent the default policy.
+ *
+ * This is used as the last fallback filter.
+ *
+ * @param policy the policy. Cannot be a "substitute" policy.
+ */
+class ConstantFilter(
+        policy: FilterPolicy,
+        val reason: String
+) : OutputFilter() {
+    val classPolicy: FilterPolicy
+    val fieldPolicy: FilterPolicy
+    val methodPolicy: FilterPolicy
+
+    init {
+        if (policy.isSubstitute) {
+            throw HostStubGenInternalException(
+                    "ConstantFilter doesn't allow substitution policies.")
+        }
+        if (policy.isClassWidePolicy) {
+            // We prevent it, because there's no point in using class-wide policies because
+            // all members get othe same policy too anyway.
+            throw HostStubGenInternalException(
+                    "ConstantFilter doesn't allow class-wide policies.")
+        }
+        methodPolicy = policy
+
+        // TODO: Need to think about the realistic default behavior.
+        classPolicy = if (policy != FilterPolicy.Throw) policy else FilterPolicy.Remove
+        fieldPolicy = classPolicy
+    }
+
+    override fun getPolicyForClass(className: String): FilterPolicyWithReason {
+        return classPolicy.withReason(reason)
+    }
+
+    override fun getPolicyForField(className: String, fieldName: String): FilterPolicyWithReason {
+        return fieldPolicy.withReason(reason)
+    }
+
+    override fun getPolicyForMethod(
+            className: String,
+            methodName: String,
+            descriptor: String,
+            ): FilterPolicyWithReason {
+        return methodPolicy.withReason(reason)
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt
new file mode 100644
index 0000000..f0763c4
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt
@@ -0,0 +1,72 @@
+/*
+ * 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
+
+/**
+ * Base class for an [OutputFilter] that uses another filter as a fallback.
+ */
+abstract class DelegatingFilter(
+        // fallback shouldn't be used by subclasses, so make it private.
+        // They should instead be calling into `super` or `outermostFilter`.
+        private val fallback: OutputFilter
+) : OutputFilter() {
+    init {
+        fallback.outermostFilter = this
+    }
+
+    override var outermostFilter: OutputFilter = this
+        get() = field
+        set(value) {
+            field = value
+            // Propagate the inner filters.
+            fallback.outermostFilter = value
+        }
+
+    override fun getPolicyForClass(className: String): FilterPolicyWithReason {
+        return fallback.getPolicyForClass(className)
+    }
+
+    override fun getPolicyForField(
+            className: String,
+            fieldName: String
+    ): FilterPolicyWithReason {
+        return fallback.getPolicyForField(className, fieldName)
+    }
+
+    override fun getPolicyForMethod(
+            className: String,
+            methodName: String,
+            descriptor: String
+    ): FilterPolicyWithReason {
+        return fallback.getPolicyForMethod(className, methodName, descriptor)
+    }
+
+    override fun getRenameTo(
+            className: String,
+            methodName: String,
+            descriptor: String
+    ): String? {
+        return fallback.getRenameTo(className, methodName, descriptor)
+    }
+
+    override fun getNativeSubstitutionClass(className: String): String? {
+        return fallback.getNativeSubstitutionClass(className)
+    }
+
+    override fun getClassLoadHook(className: String): String? {
+        return fallback.getClassLoadHook(className)
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicy.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicy.kt
new file mode 100644
index 0000000..f11ac2f
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicy.kt
@@ -0,0 +1,133 @@
+/*
+ * 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
+
+enum class FilterPolicy {
+    /**
+     * Keep the item in the stub jar file, so tests can use it.
+     */
+    Stub,
+
+    /**
+     * Keep the item in the impl jar file, but not in the stub file. Tests cannot use it directly,
+     * but indirectly.
+     */
+    Keep,
+
+    /**
+     * Only used for types. Keep the class in the stub, and also all its members.
+     * But each member can have another annotations to override it.
+     */
+    StubClass,
+
+    /**
+     * Only used for types. Keep the class in the impl, not in the stub, and also all its members.
+     * But each member can have another annotations to override it.
+     */
+    KeepClass,
+
+    /**
+     * Same as [Stub], but replace it with a "substitution" method. Only usable with methods.
+     */
+    SubstituteAndStub,
+
+    /**
+     * Same as [Keep], but replace it with a "substitution" method. Only usable with methods.
+     */
+    SubstituteAndKeep,
+
+    /**
+     * Only usable with methods. The item will be kept in the impl jar file, but when called,
+     * it'll throw.
+     */
+    Throw,
+
+    /**
+     * Remove the item completely.
+     */
+    Remove;
+
+    val isSubstitute: Boolean
+        get() = this == SubstituteAndStub || this == SubstituteAndKeep
+
+    val needsInStub: Boolean
+        get() = this == Stub || this == StubClass || this == SubstituteAndStub
+
+    val needsInImpl: Boolean
+        get() = this != Remove
+
+    /** Returns whether a policy can be used with classes */
+    val isUsableWithClasses: Boolean
+        get() {
+            return when (this) {
+                Stub, StubClass, Keep, KeepClass, Remove -> true
+                else -> false
+            }
+        }
+
+    /** Returns whether a policy can be used with fields. */
+    val isUsableWithFields: Boolean
+        get() {
+            return when (this) {
+                Stub, Keep, Remove -> true
+                else -> false
+            }
+        }
+
+    /** Returns whether a policy can be used with methods */
+    val isUsableWithMethods: Boolean
+        get() {
+            return when (this) {
+                StubClass, KeepClass -> false
+                else -> true
+            }
+        }
+
+    /** Returns whether a policy is a class-wide one. */
+    val isClassWidePolicy: Boolean
+        get() {
+            return when (this) {
+                StubClass, KeepClass -> true
+                else -> false
+            }
+        }
+
+    fun getSubstitutionBasePolicy(): FilterPolicy {
+        return when (this) {
+            SubstituteAndKeep -> Keep
+            SubstituteAndStub -> Stub
+            else -> this
+        }
+    }
+
+    /**
+     * Convert {Stub,Keep}Class to the corresponding Stub or Keep.
+     */
+    fun resolveClassWidePolicy(): FilterPolicy {
+        return when (this) {
+            StubClass -> Stub
+            KeepClass -> Keep
+            else -> this
+        }
+    }
+
+    /**
+     * Create a [FilterPolicyWithReason] with a given reason.
+     */
+    fun withReason(reason: String): FilterPolicyWithReason {
+        return FilterPolicyWithReason(this, reason)
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicyWithReason.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicyWithReason.kt
new file mode 100644
index 0000000..b64a2f5
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicyWithReason.kt
@@ -0,0 +1,66 @@
+/*
+ * 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
+
+/**
+ * Captures a [FilterPolicy] with a human-readable reason.
+ */
+data class FilterPolicyWithReason (
+        val policy: FilterPolicy,
+        val reason: String = "",
+) {
+    /**
+     * Return a new [FilterPolicy] with an updated reason, while keeping the original reason
+     * as an "inner-reason".
+     */
+    fun wrapReason(reason: String): FilterPolicyWithReason {
+        return FilterPolicyWithReason(policy, "$reason [inner-reason: ${this.reason}]")
+    }
+
+    /**
+     * If the visibility is lower than "Keep" (meaning if it's "remove"),
+     * then return a new [FilterPolicy] with "Keep".
+     * Otherwise, return itself
+     */
+    fun promoteToKeep(promotionReason: String): FilterPolicyWithReason {
+        if (policy.needsInImpl) {
+            return this
+        }
+        val newPolicy = if (policy.isClassWidePolicy) FilterPolicy.KeepClass else FilterPolicy.Keep
+
+        return FilterPolicyWithReason(newPolicy,
+                "$promotionReason [original remove reason: ${this.reason}]")
+    }
+
+    /**
+     * If the visibility is above "Keep" (meaning if it's "stub"),
+     * then return a new [FilterPolicy] with "Keep".
+     * Otherwise, return itself
+     */
+    fun demoteToKeep(promotionReason: String): FilterPolicyWithReason {
+        if (!policy.needsInStub) {
+            return this
+        }
+        val newPolicy = if (policy.isClassWidePolicy) FilterPolicy.KeepClass else FilterPolicy.Keep
+
+        return FilterPolicyWithReason(newPolicy,
+                "$promotionReason [original stub reason: ${this.reason}]")
+    }
+
+    override fun toString(): String {
+        return "[$policy - reason: $reason]"
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt
new file mode 100644
index 0000000..9c372ff
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt
@@ -0,0 +1,86 @@
+/*
+ * 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.HostStubGenErrors
+import com.android.hoststubgen.HostStubGenInternalException
+import com.android.hoststubgen.asm.isAnonymousInnerClass
+import com.android.hoststubgen.log
+import com.android.hoststubgen.asm.ClassNodes
+import com.android.hoststubgen.asm.isVisibilityPrivateOrPackagePrivate
+
+/**
+ * Filter implementing "implicit" rules, such as:
+ * - "keep all anonymous inner classes if the outer class is keep".
+ *   (But anonymous inner classes should never be in "stub")
+ * - For classes in stub, make sure private parameterless constructors are also in stub, if any.
+ */
+class ImplicitOutputFilter(
+        private val errors: HostStubGenErrors,
+        private val classes: ClassNodes,
+        fallback: OutputFilter
+) : DelegatingFilter(fallback) {
+    private fun getClassImplicitPolicy(className: String): FilterPolicyWithReason? {
+        // TODO: This check should be cached.
+        val cn = classes.getClass(className)
+
+        if (isAnonymousInnerClass(cn)) {
+            log.forDebug {
+//                log.d("  anon-inner class: ${className} outer: ${cn.outerClass}  ")
+            }
+            if (cn.outerClass == null) {
+                throw HostStubGenInternalException(
+                        "outerClass is null for anonymous inner class")
+            }
+            // If the outer class needs to be in impl, it should be in impl too.
+            val outerPolicy = outermostFilter.getPolicyForClass(cn.outerClass)
+            if (outerPolicy.policy.needsInImpl) {
+                return FilterPolicy.KeepClass.withReason("anonymous-inner-class")
+            }
+        }
+        return null
+    }
+
+    override fun getPolicyForClass(className: String): FilterPolicyWithReason {
+        // Use the implicit policy, if any.
+        getClassImplicitPolicy(className)?.let { return it }
+
+        return super.getPolicyForClass(className)
+    }
+
+    override fun getPolicyForMethod(
+            className: String,
+            methodName: String,
+            descriptor: String
+    ): FilterPolicyWithReason {
+        val fallback = super.getPolicyForMethod(className, methodName, descriptor)
+
+        // If the class is in the stub, then we need to put the private constructor in the stub too,
+        // to prevent the class from getting instantiated.
+        if (outermostFilter.getPolicyForClass(className).policy.needsInStub &&
+                !fallback.policy.needsInStub &&
+                (methodName == "<init>") && // Constructor?
+                (descriptor == "()V")) { // Has zero parameters?
+            classes.findMethod(className, methodName, descriptor)?.let { mn ->
+                if (isVisibilityPrivateOrPackagePrivate(mn.access)) {
+                    return FilterPolicy.Stub.withReason("private constructor in stub class")
+                }
+            }
+        }
+
+        return fallback
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt
new file mode 100644
index 0000000..f3551d4
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt
@@ -0,0 +1,138 @@
+/*
+ * 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.UnknownApiException
+import com.android.hoststubgen.asm.ClassNodes
+import com.android.hoststubgen.asm.toHumanReadableClassName
+import com.android.hoststubgen.asm.toHumanReadableMethodName
+
+// TODO: Validate all input names.
+
+class InMemoryOutputFilter(
+    private val classes: ClassNodes,
+    fallback: OutputFilter,
+) : DelegatingFilter(fallback) {
+    private val mPolicies: MutableMap<String, FilterPolicyWithReason> = mutableMapOf()
+    private val mRenames: MutableMap<String, String> = mutableMapOf()
+    private val mNativeSubstitutionClasses: MutableMap<String, String> = mutableMapOf()
+    private val mClassLoadHooks: MutableMap<String, String> = mutableMapOf()
+
+    private fun getClassKey(className: String): String {
+        return className.toHumanReadableClassName()
+    }
+
+    private fun getFieldKey(className: String, fieldName: String): String {
+        return getClassKey(className) + "." + fieldName
+    }
+
+    private fun getMethodKey(className: String, methodName: String, signature: String): String {
+        return getClassKey(className) + "." + methodName + ";" + signature
+    }
+
+    override fun getPolicyForClass(className: String): FilterPolicyWithReason {
+        return mPolicies[getClassKey(className)] ?: super.getPolicyForClass(className)
+    }
+
+    private fun ensureClassExists(className: String) {
+        if (classes.findClass(className) == null) {
+            throw UnknownApiException("Unknown class $className")
+        }
+    }
+
+    private fun ensureFieldExists(className: String, fieldName: String) {
+        if (classes.findField(className, fieldName) == null) {
+            throw UnknownApiException("Unknown field $className.$fieldName")
+        }
+    }
+
+    private fun ensureMethodExists(
+        className: String,
+        methodName: String,
+        descriptor: String
+    ) {
+        if (classes.findMethod(className, methodName, descriptor) == null) {
+            throw UnknownApiException("Unknown method $className.$methodName$descriptor")
+        }
+    }
+
+    fun setPolicyForClass(className: String, policy: FilterPolicyWithReason) {
+        ensureClassExists(className)
+        mPolicies[getClassKey(className)] = policy
+    }
+
+    override fun getPolicyForField(className: String, fieldName: String): FilterPolicyWithReason {
+        return mPolicies[getFieldKey(className, fieldName)]
+                ?: super.getPolicyForField(className, fieldName)
+    }
+
+    fun setPolicyForField(className: String, fieldName: String, policy: FilterPolicyWithReason) {
+        ensureFieldExists(className, fieldName)
+        mPolicies[getFieldKey(className, fieldName)] = policy
+    }
+
+    override fun getPolicyForMethod(
+            className: String,
+            methodName: String,
+            descriptor: String,
+            ): FilterPolicyWithReason {
+        return mPolicies[getMethodKey(className, methodName, descriptor)]
+                ?: super.getPolicyForMethod(className, methodName, descriptor)
+    }
+
+    fun setPolicyForMethod(
+            className: String,
+            methodName: String,
+            descriptor: String,
+            policy: FilterPolicyWithReason,
+            ) {
+        ensureMethodExists(className, methodName, descriptor)
+        mPolicies[getMethodKey(className, methodName, descriptor)] = policy
+    }
+
+    override fun getRenameTo(className: String, methodName: String, descriptor: String): String? {
+        return mRenames[getMethodKey(className, methodName, descriptor)]
+                ?: super.getRenameTo(className, methodName, descriptor)
+    }
+
+    fun setRenameTo(className: String, methodName: String, descriptor: String, toName: String) {
+        ensureMethodExists(className, methodName, descriptor)
+        ensureMethodExists(className, toName, descriptor)
+        mRenames[getMethodKey(className, methodName, descriptor)] = toName
+    }
+
+    override fun getNativeSubstitutionClass(className: String): String? {
+        return mNativeSubstitutionClasses[getClassKey(className)]
+                ?: super.getNativeSubstitutionClass(className)
+    }
+
+    fun setNativeSubstitutionClass(from: String, to: String) {
+        ensureClassExists(from)
+
+        // Native substitute classes may be provided from other jars, so we can't do this check.
+        // ensureClassExists(to)
+        mNativeSubstitutionClasses[getClassKey(from)] = to.toHumanReadableClassName()
+    }
+
+    override fun getClassLoadHook(className: String): String? {
+        return mClassLoadHooks[getClassKey(className)]
+            ?: super.getClassLoadHook(className)
+    }
+
+    fun setClassLoadHook(className: String, methodName: String) {
+        mClassLoadHooks[getClassKey(className)] = methodName.toHumanReadableMethodName()
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/KeepAllClassesFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/KeepAllClassesFilter.kt
new file mode 100644
index 0000000..45dd38d1
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/KeepAllClassesFilter.kt
@@ -0,0 +1,30 @@
+/*
+ * 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
+
+/**
+ * An [OutputFilter] that keeps all classes by default. (but none of its members)
+ *
+ * We're not currently using it, but using it *might* make certain things easier. For example, with
+ * this, all classes would at least be loadable.
+ */
+class KeepAllClassesFilter(fallback: OutputFilter) : DelegatingFilter(fallback) {
+    override fun getPolicyForClass(className: String): FilterPolicyWithReason {
+        // If the default visibility wouldn't keep it, change it to "keep".
+        val f = super.getPolicyForClass(className)
+        return f.promoteToKeep("keep-all-classes")
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt
new file mode 100644
index 0000000..392ee4b
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt
@@ -0,0 +1,81 @@
+/*
+ * 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
+
+/**
+ * Base class for "filters", which decides what APIs should go to the stub / impl jars.
+ */
+abstract class OutputFilter {
+    /**
+     * Filters are stacked over one another. This fields contains the "outermost" filter in a
+     * filter stack chain.
+     *
+     * Subclasses must use this filter to get a policy, when they need to infer a policy
+     * from the policy of another API.
+     *
+     * For example, [ClassWidePolicyPropagatingFilter] needs to check the policy of the enclosing
+     * class to propagate "class-wide" policies, but when it does so, it can't just use
+     * `this.getPolicyForClass()` because that wouldn't return policies decided by "outer"
+     * filters. Instead, it uses [outermostFilter.getPolicyForClass()].
+     *
+     * Note, [outermostFilter] can be itself, so make sure not to cause infinity recursions when
+     * using it.
+     */
+    open var outermostFilter: OutputFilter = this
+        get() = field
+        set(value) {
+            field = value
+        }
+
+    abstract fun getPolicyForClass(className: String): FilterPolicyWithReason
+
+    abstract fun getPolicyForField(className: String, fieldName: String): FilterPolicyWithReason
+
+    abstract fun getPolicyForMethod(
+            className: String,
+            methodName: String,
+            descriptor: String,
+            ): FilterPolicyWithReason
+
+    /**
+     * If a given method is a substitute-from method, return the substitute-to method name.
+     *
+     * The substitute-to and from methods must have the same signature, in the same class.
+     */
+    open fun getRenameTo(className: String, methodName: String, descriptor: String): String? {
+        return null
+    }
+
+    /**
+     * Return a "native substitution class" name for a given class.
+     *
+     * The result will be in a "human readable" form. (e.g. uses '.'s instead of '/'s)
+     *
+     * (which corresponds to @HostSideTestNativeSubstitutionClass of the standard annotations.)
+     */
+    open fun getNativeSubstitutionClass(className: String): String? {
+        return null
+    }
+
+    /**
+     * Return a "class load hook" method name for a given class.
+     *
+     * (which corresponds to @HostSideTestClassLoadHook of the standard annotations.)
+     */
+    open fun getClassLoadHook(className: String): String? {
+        return null
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/StubIntersectingFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/StubIntersectingFilter.kt
new file mode 100644
index 0000000..f92a027
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/StubIntersectingFilter.kt
@@ -0,0 +1,91 @@
+/*
+ * 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.HostStubGenErrors
+import com.android.hoststubgen.asm.ClassNodes
+
+private const val REASON = "demoted, not in intersect jars"
+
+/**
+ * An [OutputFilter] that will restrict what to put in stub to only what shows up in "intersecting
+ * jar" files.
+ *
+ * For example, if the Android public API stub jar is provided, then the HostStubGen's output
+ * stub will be restricted to public APIs.
+ */
+class StubIntersectingFilter(
+        private val errors: HostStubGenErrors,
+        /**
+         * If a class / field / method is not in any of these jars, then we will not put it in
+         * stub.
+         */
+        private val intersectingJars: Map<String, ClassNodes>,
+        fallback: OutputFilter,
+) : DelegatingFilter(fallback) {
+    private inline fun exists(predicate: (ClassNodes) -> Boolean): Boolean {
+        intersectingJars.forEach { entry ->
+            if (predicate(entry.value)) {
+                return true
+            }
+        }
+        return false
+    }
+
+    /**
+     * If [origPolicy] is less than "Stub", then return it as-is.
+     *
+     * Otherwise, call [inStubChecker] to see if the API is in any of [intersectingJars].
+     * If yes, then return [origPolicy] as-is. Otherwise, demote to "Keep".
+     */
+    private fun intersectWithStub(
+            origPolicy: FilterPolicyWithReason,
+            inStubChecker: () -> Boolean,
+    ): FilterPolicyWithReason {
+        if (origPolicy.policy.needsInStub) {
+            // Only check the stub jars, when the class is supposed to be in stub otherwise.
+            if (!inStubChecker()) {
+                return origPolicy.demoteToKeep(REASON)
+            }
+        }
+        return origPolicy
+    }
+
+    override fun getPolicyForClass(className: String): FilterPolicyWithReason {
+        return intersectWithStub(super.getPolicyForClass(className)) {
+            exists { classes -> classes.findClass(className) != null }
+        }
+    }
+
+    override fun getPolicyForField(
+            className: String,
+            fieldName: String
+    ): FilterPolicyWithReason {
+        return intersectWithStub(super.getPolicyForField(className, fieldName)) {
+            exists { classes -> classes.findField(className, fieldName) != null }
+        }
+    }
+
+    override fun getPolicyForMethod(
+            className: String,
+            methodName: String,
+            descriptor: String
+    ): FilterPolicyWithReason {
+        return intersectWithStub(super.getPolicyForMethod(className, methodName, descriptor)) {
+            exists { classes -> classes.findMethod(className, methodName, descriptor) != null }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
new file mode 100644
index 0000000..46546e8
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
@@ -0,0 +1,213 @@
+/*
+ * 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.UserErrorException
+import com.android.hoststubgen.asm.ClassNodes
+import com.android.hoststubgen.log
+import com.android.hoststubgen.normalizeTextLine
+import com.android.hoststubgen.whitespaceRegex
+import org.objectweb.asm.Opcodes
+import org.objectweb.asm.tree.ClassNode
+import java.io.BufferedReader
+import java.io.FileReader
+import java.io.PrintWriter
+import java.util.Objects
+
+/**
+ * Print a class node as a "keep" policy.
+ */
+fun printAsTextPolicy(pw: PrintWriter, cn: ClassNode) {
+    pw.printf("class %s\t%s\n", cn.name, "keep")
+
+    for (f in cn.fields ?: emptyList()) {
+        pw.printf("  field %s\t%s\n", f.name, "keep")
+    }
+    for (m in cn.methods ?: emptyList()) {
+        pw.printf("  method %s\t%s\t%s\n", m.name, m.desc, "keep")
+    }
+}
+
+/** Return true if [access] is either public or protected. */
+private fun isVisible(access: Int): Boolean {
+    return (access and (Opcodes.ACC_PUBLIC or Opcodes.ACC_PROTECTED)) != 0
+}
+
+/**
+ * Exception for a parse error.
+ */
+private class ParseException : Exception, UserErrorException {
+    val hasSourceInfo: Boolean
+
+    constructor(message: String) : super(message) {
+        hasSourceInfo = false
+    }
+
+    constructor(message: String, file: String, line: Int) :
+            super("$message in file $file line $line") {
+        hasSourceInfo = true
+    }
+
+    fun withSourceInfo(filename: String, lineNo: Int): ParseException {
+        if (hasSourceInfo) {
+            return this // Already has source information.
+        } else {
+            return ParseException(this.message ?: "", filename, lineNo)
+        }
+    }
+}
+
+private const val FILTER_REASON = "file-override"
+
+/**
+ * Read a given "policy" file and return as an [OutputFilter]
+ */
+fun createFilterFromTextPolicyFile(
+        filename: String,
+        classes: ClassNodes,
+        fallback: OutputFilter,
+        ): OutputFilter {
+    log.i("Loading offloaded annotations from $filename ...")
+    log.withIndent {
+        val ret = InMemoryOutputFilter(classes, fallback)
+
+        var lineNo = 0
+
+        try {
+            BufferedReader(FileReader(filename)).use { reader ->
+                var className = ""
+
+                while (true) {
+                    var line = reader.readLine()
+                    if (line == null) {
+                        break
+                    }
+                    lineNo++
+
+                    line = normalizeTextLine(line)
+
+                    if (line.isEmpty()) {
+                        continue // skip empty lines.
+                    }
+
+                    val fields = line.split(whitespaceRegex).toTypedArray()
+                    when (fields[0].lowercase()) {
+                        "c", "class" -> {
+                            if (fields.size < 3) {
+                                throw ParseException("Class ('c') expects 2 fields.")
+                            }
+                            className = fields[1]
+                            if (fields[2].startsWith("!")) {
+                                // It's a native-substitution.
+                                val toClass = fields[2].substring(1)
+                                ret.setNativeSubstitutionClass(className, toClass)
+                            } else if (fields[2].startsWith("~")) {
+                                // It's a class-load hook
+                                val callback = fields[2].substring(1)
+                                ret.setClassLoadHook(className, callback)
+                            } else {
+                                val policy = parsePolicy(fields[2])
+                                if (!policy.isUsableWithClasses) {
+                                    throw ParseException("Class can't have policy '$policy'")
+                                }
+                                Objects.requireNonNull(className)
+
+                                // TODO: Duplicate check, etc
+                                ret.setPolicyForClass(className, policy.withReason(FILTER_REASON))
+                            }
+                        }
+
+                        "f", "field" -> {
+                            if (fields.size < 3) {
+                                throw ParseException("Field ('f') expects 2 fields.")
+                            }
+                            val name = fields[1]
+                            val policy = parsePolicy(fields[2])
+                            if (!policy.isUsableWithFields) {
+                                throw ParseException("Field can't have policy '$policy'")
+                            }
+                            Objects.requireNonNull(className)
+
+                            // TODO: Duplicate check, etc
+                            ret.setPolicyForField(className, name, policy.withReason(FILTER_REASON))
+                        }
+
+                        "m", "method" -> {
+                            if (fields.size < 4) {
+                                throw ParseException("Method ('m') expects 3 fields.")
+                            }
+                            val name = fields[1]
+                            val signature = fields[2]
+                            val policy = parsePolicy(fields[3])
+
+                            if (!policy.isUsableWithMethods) {
+                                throw ParseException("Method can't have policy '$policy'")
+                            }
+
+                            Objects.requireNonNull(className)
+
+                            ret.setPolicyForMethod(className, name, signature,
+                                    policy.withReason(FILTER_REASON))
+                            if (policy.isSubstitute) {
+                                val fromName = fields[3].substring(1)
+
+                                if (fromName == name) {
+                                    throw ParseException(
+                                            "Substitution must have a different name")
+                                }
+
+                                // Set the policy  for the "from" method.
+                                ret.setPolicyForMethod(className, fromName, signature,
+                                        policy.getSubstitutionBasePolicy()
+                                                .withReason(FILTER_REASON))
+
+                                // Keep "from" -> "to" mapping.
+                                ret.setRenameTo(className, fromName, signature, name)
+                            }
+                        }
+
+                        else -> {
+                            throw ParseException("Unknown directive \"${fields[0]}\"")
+                        }
+                    }
+                }
+            }
+        } catch (e: ParseException) {
+            throw e.withSourceInfo(filename, lineNo)
+        }
+        return ret
+    }
+}
+
+private fun parsePolicy(s: String): FilterPolicy {
+    return when (s.lowercase()) {
+        "s", "stub" -> FilterPolicy.Stub
+        "k", "keep" -> FilterPolicy.Keep
+        "t", "throw" -> FilterPolicy.Throw
+        "r", "remove" -> FilterPolicy.Remove
+        "sc", "stubclass" -> FilterPolicy.StubClass
+        "kc", "keepclass" -> FilterPolicy.KeepClass
+        else -> {
+            if (s.startsWith("@")) {
+                FilterPolicy.SubstituteAndStub
+            } else if (s.startsWith("%")) {
+                FilterPolicy.SubstituteAndKeep
+            } else {
+                throw ParseException("Invalid policy \"$s\"")
+            }
+        }
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt
new file mode 100644
index 0000000..3cf9a1d
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt
@@ -0,0 +1,252 @@
+/*
+ * 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.visitors
+
+import com.android.hoststubgen.HostStubGenErrors
+import com.android.hoststubgen.asm.ClassNodes
+import com.android.hoststubgen.asm.getPackageNameFromClassName
+import com.android.hoststubgen.asm.resolveClassName
+import com.android.hoststubgen.asm.toJvmClassName
+import com.android.hoststubgen.filters.FilterPolicy
+import com.android.hoststubgen.filters.FilterPolicyWithReason
+import com.android.hoststubgen.filters.OutputFilter
+import com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+import com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+import com.android.hoststubgen.log
+import org.objectweb.asm.ClassVisitor
+import org.objectweb.asm.FieldVisitor
+import org.objectweb.asm.MethodVisitor
+import org.objectweb.asm.Opcodes
+import org.objectweb.asm.util.TraceClassVisitor
+import java.io.PrintWriter
+
+val OPCODE_VERSION = Opcodes.ASM9
+
+abstract class BaseAdapter (
+        protected val classes: ClassNodes,
+        nextVisitor: ClassVisitor,
+        protected val filter: OutputFilter,
+        protected val options: Options,
+) : ClassVisitor(OPCODE_VERSION, nextVisitor) {
+
+    /**
+     * Options to control the behavior.
+     */
+    data class Options (
+            val errors: HostStubGenErrors,
+            val enablePreTrace: Boolean,
+            val enablePostTrace: Boolean,
+            val enableMethodLogging: Boolean,
+            val enableNonStubMethodCallDetection: Boolean,
+    )
+
+    protected lateinit var currentPackageName: String
+    protected lateinit var currentClassName: String
+    protected var nativeSubstitutionClass: String? = null
+    protected lateinit var classPolicy: FilterPolicyWithReason
+
+    /**
+     * Return whether an item with a given policy should be included in the output.
+     */
+    protected abstract fun shouldEmit(policy: FilterPolicy): Boolean
+
+    override fun visit(
+            version: Int,
+            access: Int,
+            name: String,
+            signature: String?,
+            superName: String?,
+            interfaces: Array<String>,
+    ) {
+        super.visit(version, access, name, signature, superName, interfaces)
+        currentClassName = name
+        currentPackageName = getPackageNameFromClassName(name)
+        classPolicy = filter.getPolicyForClass(currentClassName)
+
+        log.d("[%s] visit: %s (package: %s)", this.javaClass.simpleName, name, currentPackageName)
+        log.indent()
+        log.v("Emitting class: %s", name)
+        log.indent()
+
+        filter.getNativeSubstitutionClass(currentClassName)?.let { className ->
+            val fullClassName = resolveClassName(className, currentPackageName).toJvmClassName()
+            log.d("  NativeSubstitutionClass: $fullClassName")
+            if (classes.findClass(fullClassName) == null) {
+                log.w("Native substitution class $fullClassName not found. Class must be " +
+                        "available at runtime.")
+            } else {
+                // If the class exists, it must have a KeepClass policy.
+                if (filter.getPolicyForClass(fullClassName).policy != FilterPolicy.KeepClass) {
+                    // TODO: Use real annotation name.
+                    options.errors.onErrorFound(
+                            "Native substitution class $fullClassName should have @Keep.")
+                }
+            }
+
+            nativeSubstitutionClass = fullClassName
+        }
+        // Inject annotations to generated classes.
+        if (classPolicy.policy.needsInStub) {
+            visitAnnotation(HostStubGenProcessedStubClass.CLASS_DESCRIPTOR, true)
+        }
+        if (classPolicy.policy.needsInImpl) {
+            visitAnnotation(HostStubGenProcessedKeepClass.CLASS_DESCRIPTOR, true)
+        }
+    }
+
+    override fun visitEnd() {
+        log.unindent()
+        log.unindent()
+        super.visitEnd()
+    }
+
+    var skipMemberModificationNestCount = 0
+
+    /**
+     * This method allows writing class members without any modifications.
+     */
+    protected inline fun writeRawMembers(callback: () -> Unit) {
+        skipMemberModificationNestCount++
+        try {
+            callback()
+        } finally {
+            skipMemberModificationNestCount--
+        }
+    }
+
+    override fun visitField(
+            access: Int,
+            name: String,
+            descriptor: String,
+            signature: String?,
+            value: Any?,
+    ): FieldVisitor? {
+        if (skipMemberModificationNestCount > 0) {
+            return super.visitField(access, name, descriptor, signature, value)
+        }
+        val policy = filter.getPolicyForField(currentClassName, name)
+        log.d("visitField: %s %s [%x] Policy: %s", name, descriptor, access, policy)
+
+        log.withIndent {
+            if (!shouldEmit(policy.policy)) {
+                log.d("Removing %s %s", name, policy)
+                return null
+            }
+
+            log.v("Emitting field: %s %s %s", name, descriptor, policy)
+            return super.visitField(access, name, descriptor, signature, value)
+        }
+    }
+
+    override fun visitMethod(
+            access: Int,
+            name: String,
+            descriptor: String,
+            signature: String?,
+            exceptions: Array<String>?,
+    ): MethodVisitor? {
+        if (skipMemberModificationNestCount > 0) {
+            return super.visitMethod(access, name, descriptor, signature, exceptions)
+        }
+        val p = filter.getPolicyForMethod(currentClassName, name, descriptor)
+        log.d("visitMethod: %s%s [%x] [%s] Policy: %s", name, descriptor, access, signature, p)
+
+        log.withIndent {
+            // If it's a substitute-to method, then skip.
+            val policy = filter.getPolicyForMethod(currentClassName, name, descriptor)
+            if (policy.policy.isSubstitute) {
+                log.d("Skipping %s%s %s", name, descriptor, policy)
+                return null
+            }
+            if (!shouldEmit(p.policy)) {
+                log.d("Removing %s%s %s", name, descriptor, policy)
+                return null
+            }
+
+            // Maybe rename the method.
+            val newName: String
+            val substituteTo = filter.getRenameTo(currentClassName, name, descriptor)
+            if (substituteTo != null) {
+                newName = substituteTo
+                log.v("Emitting %s.%s%s as %s %s", currentClassName, name, descriptor,
+                        newName, policy)
+            } else {
+                log.v("Emitting method: %s%s %s", name, descriptor, policy)
+                newName = name
+            }
+
+            // Let subclass update the flag.
+            // But note, we only use it when calling the super's method,
+            // but not for visitMethodInner(), beucase when subclass wants to change access,
+            // it can do so inside visitMethodInner().
+            val newAccess = updateAccessFlags(access, name, descriptor)
+
+            return visitMethodInner(access, newName, descriptor, signature, exceptions, policy,
+                    super.visitMethod(newAccess, newName, descriptor, signature, exceptions))
+        }
+    }
+
+    open fun updateAccessFlags(
+            access: Int,
+            name: String,
+            descriptor: String,
+    ): Int {
+        return access
+    }
+
+    abstract fun visitMethodInner(
+        access: Int,
+        name: String,
+        descriptor: String,
+        signature: String?,
+        exceptions: Array<String>?,
+        policy: FilterPolicyWithReason,
+        superVisitor: MethodVisitor?,
+        ): MethodVisitor?
+
+    companion object {
+        fun getVisitor(
+                classes: ClassNodes,
+                nextVisitor: ClassVisitor,
+                filter: OutputFilter,
+                forImpl: Boolean,
+                options: Options,
+        ): ClassVisitor {
+            var next = nextVisitor
+
+            val verbosePrinter = PrintWriter(log.getVerbosePrintStream())
+
+            // TODO: This doesn't work yet.
+
+            // Inject TraceClassVisitor for debugging.
+            if (options.enablePostTrace) {
+                next = TraceClassVisitor(next, verbosePrinter)
+            }
+            var ret: ClassVisitor
+            if (forImpl) {
+                ret = ImplGeneratingAdapter(classes, next, filter, options)
+            } else {
+                ret = StubGeneratingAdapter(classes, next, filter, options)
+            }
+
+            // Inject TraceClassVisitor for debugging.
+            if (options.enablePreTrace) {
+                ret = TraceClassVisitor(ret, verbosePrinter)
+            }
+            return ret
+        }
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BodyReplacingMethodVisitor.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BodyReplacingMethodVisitor.kt
new file mode 100644
index 0000000..8250412
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BodyReplacingMethodVisitor.kt
@@ -0,0 +1,354 @@
+/*
+ * 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.visitors
+
+import org.objectweb.asm.AnnotationVisitor
+import org.objectweb.asm.Attribute
+import org.objectweb.asm.Handle
+import org.objectweb.asm.Label
+import org.objectweb.asm.MethodVisitor
+import org.objectweb.asm.Opcodes
+import org.objectweb.asm.TypePath
+
+/**
+ * A method visitor that removes everything from method body.
+ *
+ * To inject a method body, override [visitCode] and create the opcodes there.
+ */
+abstract class BodyReplacingMethodVisitor(
+    access: Int,
+    name: String,
+    descriptor: String,
+    signature: String?,
+    exceptions: Array<String>?,
+    next: MethodVisitor?,
+) : MethodVisitor(OPCODE_VERSION, next) {
+    val isVoid: Boolean
+    val isStatic: Boolean
+
+    init {
+        isVoid = descriptor.endsWith(")V")
+        isStatic = access and Opcodes.ACC_STATIC != 0
+    }
+
+    // Following methods are for things that we need to keep.
+    // Since they're all calling the super method, we can just remove them, but we keep them
+    // just to clarify what we're keeping.
+
+    final override fun visitParameter(
+            name: String?,
+            access: Int
+    ) {
+        super.visitParameter(name, access)
+    }
+
+    final override fun visitAnnotationDefault(): AnnotationVisitor? {
+        return super.visitAnnotationDefault()
+    }
+
+    final override fun visitAnnotation(
+            descriptor: String?,
+            visible: Boolean
+    ): AnnotationVisitor? {
+        return super.visitAnnotation(descriptor, visible)
+    }
+
+    final override fun visitTypeAnnotation(
+        typeRef: Int,
+        typePath: TypePath?,
+        descriptor: String?,
+        visible: Boolean
+    ): AnnotationVisitor? {
+        return super.visitTypeAnnotation(typeRef, typePath, descriptor, visible)
+    }
+
+    final override fun visitAnnotableParameterCount(
+            parameterCount: Int,
+            visible: Boolean
+    ) {
+        super.visitAnnotableParameterCount(parameterCount, visible)
+    }
+
+    final override fun visitParameterAnnotation(
+            parameter: Int,
+            descriptor: String?,
+            visible: Boolean
+    ): AnnotationVisitor? {
+        return super.visitParameterAnnotation(parameter, descriptor, visible)
+    }
+
+    final override fun visitAttribute(attribute: Attribute?) {
+        super.visitAttribute(attribute)
+    }
+
+    override fun visitEnd() {
+        super.visitEnd()
+    }
+
+    /**
+     * Control when to emit the code. We use this to ignore all visitXxx method calls caused by
+     * the original method, so we'll remove all the original code.
+     *
+     * Only when visitXxx methods are called from [emitNewCode], we pass-through to the base class,
+     * so the body will be generated.
+     *
+     * (See also https://asm.ow2.io/asm4-guide.pdf section 3.2.1 about the MethovVisitor
+     * call order.)
+     */
+    var emitCode = false
+
+    final override fun visitCode() {
+        super.visitCode()
+
+        try {
+            emitCode = true
+
+            emitNewCode()
+        } finally {
+            emitCode = false
+        }
+    }
+
+    /**
+     * Subclass must implement it and emit code, and call [visitMaxs] at the end.
+     */
+    abstract fun emitNewCode()
+
+    final override fun visitMaxs(
+            maxStack: Int,
+            maxLocals: Int
+    ) {
+        if (emitCode) {
+            super.visitMaxs(maxStack, maxLocals)
+        }
+    }
+
+    // Following methods are called inside a method body, and we don't want to
+    // emit any of them, so they are all no-op.
+
+    final override fun visitFrame(
+            type: Int,
+            numLocal: Int,
+            local: Array<out Any>?,
+            numStack: Int,
+            stack: Array<out Any>?
+    ) {
+        if (emitCode) {
+            super.visitFrame(type, numLocal, local, numStack, stack)
+        }
+    }
+
+    final override fun visitInsn(opcode: Int) {
+        if (emitCode) {
+            super.visitInsn(opcode)
+        }
+    }
+
+    final override fun visitIntInsn(
+            opcode: Int,
+            operand: Int
+    ) {
+        if (emitCode) {
+            super.visitIntInsn(opcode, operand)
+        }
+    }
+
+    final override fun visitVarInsn(
+            opcode: Int,
+            varIndex: Int
+    ) {
+        if (emitCode) {
+            super.visitVarInsn(opcode, varIndex)
+        }
+    }
+
+    final override fun visitTypeInsn(
+            opcode: Int,
+            type: String?
+    ) {
+        if (emitCode) {
+            super.visitTypeInsn(opcode, type)
+        }
+    }
+
+    final override fun visitFieldInsn(
+            opcode: Int,
+            owner: String?,
+            name: String?,
+            descriptor: String?
+    ) {
+        if (emitCode) {
+            super.visitFieldInsn(opcode, owner, name, descriptor)
+        }
+    }
+
+    final override fun visitMethodInsn(
+            opcode: Int,
+            owner: String?,
+            name: String?,
+            descriptor: String?,
+            isInterface: Boolean
+    ) {
+        if (emitCode) {
+            super.visitMethodInsn(opcode, owner, name, descriptor, isInterface)
+        }
+    }
+
+    final override fun visitInvokeDynamicInsn(
+            name: String?,
+            descriptor: String?,
+            bootstrapMethodHandle: Handle?,
+            vararg bootstrapMethodArguments: Any?
+    ) {
+        if (emitCode) {
+            super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle,
+                    *bootstrapMethodArguments)
+        }
+    }
+
+    final override fun visitJumpInsn(
+            opcode: Int,
+            label: Label?
+    ) {
+        if (emitCode) {
+            super.visitJumpInsn(opcode, label)
+        }
+    }
+
+    final override fun visitLabel(label: Label?) {
+        if (emitCode) {
+            super.visitLabel(label)
+        }
+    }
+
+    final override fun visitLdcInsn(value: Any?) {
+        if (emitCode) {
+            super.visitLdcInsn(value)
+        }
+    }
+
+    final override fun visitIincInsn(
+            varIndex: Int,
+            increment: Int
+    ) {
+        if (emitCode) {
+            super.visitIincInsn(varIndex, increment)
+        }
+    }
+
+    final override fun visitTableSwitchInsn(
+            min: Int,
+            max: Int,
+            dflt: Label?,
+            vararg labels: Label?
+    ) {
+        if (emitCode) {
+            super.visitTableSwitchInsn(min, max, dflt, *labels)
+        }
+    }
+
+    final override fun visitLookupSwitchInsn(
+            dflt: Label?,
+            keys: IntArray?,
+            labels: Array<out Label>?
+    ) {
+        if (emitCode) {
+            super.visitLookupSwitchInsn(dflt, keys, labels)
+        }
+    }
+
+    final override fun visitMultiANewArrayInsn(
+            descriptor: String?,
+            numDimensions: Int
+    ) {
+        if (emitCode) {
+            super.visitMultiANewArrayInsn(descriptor, numDimensions)
+        }
+    }
+
+    final override fun visitInsnAnnotation(
+            typeRef: Int,
+            typePath: TypePath?,
+            descriptor: String?,
+            visible: Boolean
+    ): AnnotationVisitor? {
+        if (emitCode) {
+            return super.visitInsnAnnotation(typeRef, typePath, descriptor, visible)
+        }
+        return null
+    }
+
+    final override fun visitTryCatchBlock(
+            start: Label?,
+            end: Label?,
+            handler: Label?,
+            type: String?
+    ) {
+        if (emitCode) {
+            super.visitTryCatchBlock(start, end, handler, type)
+        }
+    }
+
+    final override fun visitTryCatchAnnotation(
+            typeRef: Int,
+            typePath: TypePath?,
+            descriptor: String?,
+            visible: Boolean
+    ): AnnotationVisitor? {
+        if (emitCode) {
+            return super.visitTryCatchAnnotation(typeRef, typePath, descriptor, visible)
+        }
+        return null
+    }
+
+    final override fun visitLocalVariable(
+            name: String?,
+            descriptor: String?,
+            signature: String?,
+            start: Label?,
+            end: Label?,
+            index: Int
+    ) {
+        if (emitCode) {
+            super.visitLocalVariable(name, descriptor, signature, start, end, index)
+        }
+    }
+
+    final override fun visitLocalVariableAnnotation(
+            typeRef: Int,
+            typePath: TypePath?,
+            start: Array<out Label>?,
+            end: Array<out Label>?,
+            index: IntArray?,
+            descriptor: String?,
+            visible: Boolean
+    ): AnnotationVisitor? {
+        if (emitCode) {
+            return super.visitLocalVariableAnnotation(
+                    typeRef, typePath, start, end, index, descriptor, visible)
+        }
+        return null
+    }
+
+    final override fun visitLineNumber(
+            line: Int,
+            start: Label?
+    ) {
+        if (emitCode) {
+            super.visitLineNumber(line, start)
+        }
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt
new file mode 100644
index 0000000..ac06886
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt
@@ -0,0 +1,370 @@
+/*
+ * 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.visitors
+
+import com.android.hoststubgen.asm.CLASS_INITIALIZER_DESC
+import com.android.hoststubgen.asm.CLASS_INITIALIZER_NAME
+import com.android.hoststubgen.asm.ClassNodes
+import com.android.hoststubgen.asm.isVisibilityPrivateOrPackagePrivate
+import com.android.hoststubgen.asm.writeByteCodeToPushArguments
+import com.android.hoststubgen.asm.writeByteCodeToReturn
+import com.android.hoststubgen.filters.FilterPolicy
+import com.android.hoststubgen.filters.FilterPolicyWithReason
+import com.android.hoststubgen.filters.OutputFilter
+import com.android.hoststubgen.hosthelper.HostTestUtils
+import com.android.hoststubgen.log
+import org.objectweb.asm.ClassVisitor
+import org.objectweb.asm.MethodVisitor
+import org.objectweb.asm.Opcodes
+import org.objectweb.asm.Type
+
+/**
+ * An adapter that generates the "impl" class file from an input class file.
+ */
+class ImplGeneratingAdapter(
+        classes: ClassNodes,
+        nextVisitor: ClassVisitor,
+        filter: OutputFilter,
+        options: Options,
+) : BaseAdapter(classes, nextVisitor, filter, options) {
+
+    override fun shouldEmit(policy: FilterPolicy): Boolean {
+        return policy.needsInImpl
+    }
+
+    private var classLoadHookMethod: String? = null
+
+    override fun visit(
+        version: Int,
+        access: Int,
+        name: String,
+        signature: String?,
+        superName: String?,
+        interfaces: Array<String>
+    ) {
+        super.visit(version, access, name, signature, superName, interfaces)
+
+        classLoadHookMethod = filter.getClassLoadHook(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 (!classes.hasClassInitializer(currentClassName)) {
+                injectClassLoadHook(callback)
+            }
+        }
+    }
+
+    private fun injectClassLoadHook(callback: String) {
+        writeRawMembers {
+            // Create a class initializer to call onClassLoaded().
+            // Each class can only have at most one class initializer, but the base class
+            // StaticInitMerger will merge it with the existing one, if any.
+            visitMethod(
+                Opcodes.ACC_PRIVATE or Opcodes.ACC_STATIC,
+                "<clinit>",
+                "()V",
+                null,
+                null
+            )!!.let { mv ->
+                // Method prologue
+                mv.visitCode()
+
+                writeClassLoadHookCall(mv)
+                mv.visitInsn(Opcodes.RETURN)
+
+                // Method epilogue
+                mv.visitMaxs(0, 0)
+                mv.visitEnd()
+            }
+        }
+    }
+
+    private fun writeClassLoadHookCall(mv: MethodVisitor) {
+        // First argument: the class type.
+        mv.visitLdcInsn(Type.getType("L" + currentClassName + ";"))
+
+        // Second argument: method name
+        mv.visitLdcInsn(classLoadHookMethod)
+
+        // Call HostTestUtils.onClassLoaded().
+        mv.visitMethodInsn(
+            Opcodes.INVOKESTATIC,
+            HostTestUtils.CLASS_INTERNAL_NAME,
+            "onClassLoaded",
+            "(Ljava/lang/Class;Ljava/lang/String;)V",
+            false
+        )
+    }
+
+    override fun updateAccessFlags(
+            access: Int,
+            name: String,
+            descriptor: String,
+    ): Int {
+        if ((access and Opcodes.ACC_NATIVE) != 0 && nativeSubstitutionClass != null) {
+            return access and Opcodes.ACC_NATIVE.inv()
+        }
+        return access
+    }
+
+    override fun visitMethodInner(
+            access: Int,
+            name: String,
+            descriptor: String,
+            signature: String?,
+            exceptions: Array<String>?,
+            policy: FilterPolicyWithReason,
+            superVisitor: MethodVisitor?,
+    ): MethodVisitor? {
+        // Inject method log, if needed.
+        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,
+                    )
+        }
+
+        // If this class already has a class initializer and a class load hook is needed, then
+        // we inject code.
+        if (classLoadHookMethod != null &&
+            name == CLASS_INITIALIZER_NAME &&
+            descriptor == CLASS_INITIALIZER_DESC) {
+            innerVisitor = ClassLoadHookInjectingMethodAdapter(
+                access,
+                name,
+                descriptor,
+                signature,
+                exceptions,
+                innerVisitor,
+            )
+        }
+
+        // If non-stub method call detection is enabled, then inject a call to the checker.
+        if (options.enableNonStubMethodCallDetection && doesMethodNeedNonStubCallCheck(
+                access, name, descriptor, policy) ) {
+            innerVisitor = NonStubMethodCallDetectingAdapter(
+                    access,
+                    name,
+                    descriptor,
+                    signature,
+                    exceptions,
+                    innerVisitor,
+            )
+        }
+
+        log.withIndent {
+            if ((access and Opcodes.ACC_NATIVE) != 0 && nativeSubstitutionClass != null) {
+                log.v("Rewriting native method...")
+                return NativeSubstitutingMethodAdapter(
+                        access, name, descriptor, signature, exceptions, innerVisitor)
+            }
+            if (policy.policy == FilterPolicy.Throw) {
+                log.v("Making method throw...")
+                return ThrowingMethodAdapter(
+                        access, name, descriptor, signature, exceptions, innerVisitor)
+            }
+        }
+
+        return innerVisitor
+    }
+
+    fun doesMethodNeedNonStubCallCheck(
+            access: Int,
+            name: String,
+            descriptor: String,
+            policy: FilterPolicyWithReason,
+    ): Boolean {
+        // If a method is in the stub, then no need to check.
+        if (policy.policy.needsInStub) {
+            return false
+        }
+        // If a method is private or package-private, no need to check.
+        // Technically test code can use framework package name, so it's a bit too lenient.
+        if (isVisibilityPrivateOrPackagePrivate(access)) {
+            return false
+        }
+        // TODO: If the method overrides a method that's accessible by tests, then we shouldn't
+        // do the check. (e.g. overrides a stub method or java standard method.)
+
+        return true
+    }
+
+    /**
+     * A method adapter that replaces the method body with a HostTestUtils.onThrowMethodCalled()
+     * call.
+     */
+    private inner class ThrowingMethodAdapter(
+            access: Int,
+            val name: String,
+            descriptor: String,
+            signature: String?,
+            exceptions: Array<String>?,
+            next: MethodVisitor?
+    ) : BodyReplacingMethodVisitor(access, name, descriptor, signature, exceptions, next) {
+        override fun emitNewCode() {
+            visitMethodInsn(Opcodes.INVOKESTATIC,
+                    HostTestUtils.CLASS_INTERNAL_NAME,
+                    "onThrowMethodCalled",
+                    "()V",
+                    false)
+
+            // We still need a RETURN opcode for the return type.
+            // For now, let's just inject a `throw`.
+            visitTypeInsn(Opcodes.NEW, "java/lang/RuntimeException")
+            visitInsn(Opcodes.DUP)
+            visitLdcInsn("Unreachable")
+            visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/RuntimeException",
+                    "<init>", "(Ljava/lang/String;)V", false)
+            visitInsn(Opcodes.ATHROW)
+
+            // visitMaxs(3, if (isStatic) 0 else 1)
+            visitMaxs(0, 0) // We let ASM figure them out.
+        }
+    }
+
+    /**
+     * A method adapter that replaces a native method call with a call to the "native substitution"
+     * class.
+     */
+    private inner class NativeSubstitutingMethodAdapter(
+            access: Int,
+            private val name: String,
+            private val descriptor: String,
+            signature: String?,
+            exceptions: Array<String>?,
+            next: MethodVisitor?
+    ) : MethodVisitor(OPCODE_VERSION, next) {
+        override fun visitCode() {
+            super.visitCode()
+
+            throw RuntimeException("NativeSubstitutingMethodVisitor should be called on " +
+                    " native method, where visitCode() shouldn't be called.")
+        }
+
+        override fun visitEnd() {
+            writeByteCodeToPushArguments(descriptor, this)
+
+            visitMethodInsn(Opcodes.INVOKESTATIC,
+                    nativeSubstitutionClass,
+                    name,
+                    descriptor,
+                    false)
+
+            writeByteCodeToReturn(descriptor, this)
+
+            visitMaxs(99, 0) // We let ASM figure them out.
+            super.visitEnd()
+        }
+    }
+
+    /**
+     * A method adapter that injects a call to HostTestUtils.logMethodCall() to every method.
+     *
+     * 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(
+            access: Int,
+            val name: String,
+            val descriptor: String,
+            signature: String?,
+            exceptions: Array<String>?,
+            next: MethodVisitor?
+    ) : MethodVisitor(OPCODE_VERSION, next) {
+        override fun visitCode() {
+            super.visitCode()
+            visitLdcInsn(currentClassName)
+            visitLdcInsn(name)
+            visitLdcInsn(descriptor)
+            visitMethodInsn(Opcodes.INVOKESTATIC,
+                    HostTestUtils.CLASS_INTERNAL_NAME,
+                    "logMethodCall",
+                    "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
+                    false)
+        }
+    }
+
+    /**
+     * Inject a class load hook call.
+     */
+    private inner class ClassLoadHookInjectingMethodAdapter(
+        access: Int,
+        val name: String,
+        val descriptor: String,
+        signature: String?,
+        exceptions: Array<String>?,
+        next: MethodVisitor?
+    ) : MethodVisitor(OPCODE_VERSION, next) {
+        override fun visitCode() {
+            super.visitCode()
+
+            writeClassLoadHookCall(this)
+        }
+    }
+
+    /**
+     * A method adapter that detects calls to non-stub methods.
+     */
+    private inner class NonStubMethodCallDetectingAdapter(
+            access: Int,
+            val name: String,
+            val descriptor: String,
+            signature: String?,
+            exceptions: Array<String>?,
+            next: MethodVisitor?
+    ) : MethodVisitor(OPCODE_VERSION, next) {
+        override fun visitCode() {
+            super.visitCode()
+
+            // First three arguments to HostTestUtils.onNonStubMethodCalled().
+            visitLdcInsn(currentClassName)
+            visitLdcInsn(name)
+            visitLdcInsn(descriptor)
+
+            // Call: HostTestUtils.getStackWalker().getCallerClass().
+            // This push the caller Class in the stack.
+            visitMethodInsn(Opcodes.INVOKESTATIC,
+                    HostTestUtils.CLASS_INTERNAL_NAME,
+                    "getStackWalker",
+                    "()Ljava/lang/StackWalker;",
+                    false)
+            visitMethodInsn(Opcodes.INVOKEVIRTUAL,
+                    "java/lang/StackWalker",
+                    "getCallerClass",
+                    "()Ljava/lang/Class;",
+                    false)
+
+            // Then call onNonStubMethodCalled().
+            visitMethodInsn(Opcodes.INVOKESTATIC,
+                    HostTestUtils.CLASS_INTERNAL_NAME,
+                    "onNonStubMethodCalled",
+                    "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V",
+                    false)
+        }
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/StubGeneratingAdapter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/StubGeneratingAdapter.kt
new file mode 100644
index 0000000..37e2a88
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/StubGeneratingAdapter.kt
@@ -0,0 +1,85 @@
+/*
+ * 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.visitors
+
+import com.android.hoststubgen.asm.ClassNodes
+import com.android.hoststubgen.filters.FilterPolicy
+import com.android.hoststubgen.filters.FilterPolicyWithReason
+import com.android.hoststubgen.filters.OutputFilter
+import com.android.hoststubgen.log
+import org.objectweb.asm.ClassVisitor
+import org.objectweb.asm.MethodVisitor
+import org.objectweb.asm.Opcodes
+
+/**
+ * An adapter that generates the "impl" class file from an input class file.
+ */
+class StubGeneratingAdapter(
+        classes: ClassNodes,
+        nextVisitor: ClassVisitor,
+        filter: OutputFilter,
+        options: Options,
+) : BaseAdapter(classes, nextVisitor, filter, options) {
+
+    override fun shouldEmit(policy: FilterPolicy): Boolean {
+        return policy.needsInStub
+    }
+
+    override fun visitMethodInner(
+            access: Int,
+            name: String,
+            descriptor: String,
+            signature: String?,
+            exceptions: Array<String>?,
+            policy: FilterPolicyWithReason,
+            superVisitor: MethodVisitor?,
+    ): MethodVisitor? {
+        return StubMethodVisitor(access, name, descriptor, signature, exceptions, superVisitor)
+    }
+
+    private inner class StubMethodVisitor(
+            access: Int,
+            val name: String,
+            descriptor: String,
+            signature: String?,
+            exceptions: Array<String>?,
+            next: MethodVisitor?
+    ) : BodyReplacingMethodVisitor(access, name, descriptor, signature, exceptions, next) {
+        override fun emitNewCode() {
+            log.d("  Generating stub method for $currentClassName.$name")
+
+            // Inject the following code:
+            //   throw new RuntimeException("Stub!");
+
+            /*
+                NEW java/lang/RuntimeException
+                DUP
+                LDC "not supported on host side"
+                INVOKESPECIAL java/lang/RuntimeException.<init> (Ljava/lang/String;)V
+                ATHROW
+                MAXSTACK = 3
+                MAXLOCALS = 2 <- 1 for this, 1 for return value.
+             */
+            visitTypeInsn(Opcodes.NEW, "java/lang/RuntimeException")
+            visitInsn(Opcodes.DUP)
+            visitLdcInsn("Stub!")
+            visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/RuntimeException",
+                    "<init>", "(Ljava/lang/String;)V", false)
+            visitInsn(Opcodes.ATHROW)
+            visitMaxs(0, 0) // We let ASM figure them out.
+        }
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-framework/Android.bp b/tools/hoststubgen/hoststubgen/test-framework/Android.bp
new file mode 100644
index 0000000..2b91cc1
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-framework/Android.bp
@@ -0,0 +1,19 @@
+// 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+build = ["AndroidHostTest.bp"]
diff --git a/tools/hoststubgen/hoststubgen/test-framework/AndroidHostTest.bp b/tools/hoststubgen/hoststubgen/test-framework/AndroidHostTest.bp
new file mode 100644
index 0000000..e7fb2de
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-framework/AndroidHostTest.bp
@@ -0,0 +1,44 @@
+// 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.
+
+// Add `build = ["AndroidHostTest.bp"]` to Android.bp to include this file.
+
+// Compile the test jar, using 2 rules.
+// 1. Build the test against the stub.
+java_library_host {
+    name: "HostStubGenTest-framework-test-host-test-lib",
+    defaults: ["hosttest-with-framework-all-hidden-api-test-lib-defaults"],
+    srcs: [
+        "src/**/*.java",
+    ],
+    static_libs: [
+        "junit",
+        "truth-prebuilt",
+        "mockito",
+
+        // http://cs/h/googleplex-android/platform/superproject/main/+/main:platform_testing/libraries/annotations/src/android/platform/test/annotations/
+        "platform-test-annotations",
+        "hoststubgen-annotations",
+    ],
+}
+
+// 2. Link the above module with necessary runtime dependencies, so it can be executed stand-alone.
+java_test_host {
+    name: "HostStubGenTest-framework-all-test-host-test",
+    defaults: ["hosttest-with-framework-all-hidden-api-test-defaults"],
+    static_libs: [
+        "HostStubGenTest-framework-test-host-test-lib",
+    ],
+    test_suites: ["general-tests"],
+}
diff --git a/tools/hoststubgen/hoststubgen/test-framework/AndroidTest-host.xml b/tools/hoststubgen/hoststubgen/test-framework/AndroidTest-host.xml
new file mode 100644
index 0000000..f35dcf6
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-framework/AndroidTest-host.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- [Ravenwood] Copied from $ANDROID_BUILD_TOP/cts/hostsidetests/devicepolicy/AndroidTest.xml  -->
+<configuration description="CtsContentTestCases host-side test">
+    <option name="test-suite-tag" value="ravenwood" />
+    <option name="config-descriptor:metadata" key="component" value="framework" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_secondary_user" />
+    <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
+
+    <test class="com.android.tradefed.testtype.IsolatedHostTest" >
+        <option name="jar" value="HostStubGenTest-framework-all-test-host-test.jar" />
+    </test>
+</configuration>
diff --git a/tools/hoststubgen/hoststubgen/test-framework/README.md b/tools/hoststubgen/hoststubgen/test-framework/README.md
new file mode 100644
index 0000000..20e2f87
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-framework/README.md
@@ -0,0 +1,27 @@
+# HostStubGen: real framework test
+
+This directory contains tests against the actual framework.jar code. The tests were
+copied from somewhere else in the android tree. We use this directory to quickly run existing
+tests.
+
+## How to run
+
+- With `atest`. This is the proper way to run it, but it may fail due to atest's known problems.
+
+  See the top level README.md on why `--no-bazel-mode` is needed (for now).
+
+```
+$ atest --no-bazel-mode HostStubGenTest-framework-test-host-test
+```
+
+- With `run-ravenwood-test`
+
+```
+$ run-ravenwood-test HostStubGenTest-framework-test-host-test
+```
+
+- Advanced option: `run-test-without-atest.sh` runs the test without using `atest` or `run-ravenwood-test`
+
+```
+$ ./run-test-without-atest.sh
+```
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/test-framework/run-test-without-atest.sh b/tools/hoststubgen/hoststubgen/test-framework/run-test-without-atest.sh
new file mode 100755
index 0000000..cfc06a1
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-framework/run-test-without-atest.sh
@@ -0,0 +1,85 @@
+#!/bin/bash
+# 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.
+
+# Run HostStubGenTest-framework-test-host-test directly with JUnit.
+# (without using atest.)
+
+source "${0%/*}"/../../common.sh
+
+
+# Options:
+# -v enable verbose log
+# -d enable debugger
+
+verbose=0
+debug=0
+while getopts "vd" opt; do
+  case "$opt" in
+    v) verbose=1 ;;
+    d) debug=1 ;;
+  esac
+done
+shift $(($OPTIND - 1))
+
+
+if (( $verbose )) ; then
+  JAVA_OPTS="$JAVA_OPTS -verbose:class"
+fi
+
+if (( $debug )) ; then
+  JAVA_OPTS="$JAVA_OPTS -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8700"
+fi
+
+#=======================================
+module=HostStubGenTest-framework-all-test-host-test
+module_jar=$ANDROID_BUILD_TOP/out/host/linux-x86/testcases/$module/$module.jar
+run m $module
+
+out=out
+
+rm -fr $out
+mkdir -p $out
+
+
+# Copy and extract the relevant jar files so we can look into them.
+run cp \
+    $module_jar \
+    $SOONG_INT/frameworks/base/tools/hoststubgen/hoststubgen/framework-all-hidden-api-host/linux_glibc_common/gen/*.jar \
+    $out
+
+run extract $out/*.jar
+
+# Result is the number of failed tests.
+result=0
+
+
+# This suite runs all tests in the JAR.
+tests=(com.android.hoststubgen.hosthelper.HostTestSuite)
+
+# Uncomment this to run a specific test.
+# tests=(com.android.hoststubgen.frameworktest.LogTest)
+
+
+for class in ${tests[@]} ; do
+  echo "Running $class ..."
+
+  run cd "${module_jar%/*}"
+  run $JAVA $JAVA_OPTS \
+      -cp $module_jar \
+      org.junit.runner.JUnitCore \
+      $class || result=$(( $result + 1 ))
+done
+
+exit $result
diff --git a/tools/hoststubgen/hoststubgen/test-framework/src/com/android/hoststubgen/frameworktest/ArrayMapTest.java b/tools/hoststubgen/hoststubgen/test-framework/src/com/android/hoststubgen/frameworktest/ArrayMapTest.java
new file mode 100644
index 0000000..62bbf48
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-framework/src/com/android/hoststubgen/frameworktest/ArrayMapTest.java
@@ -0,0 +1,737 @@
+/*
+ * 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.frameworktest;
+
+// [ravewnwood] Copied from cts/, and commented out unsupported stuff.
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.AbstractMap;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.function.BiFunction;
+
+/**
+ * Some basic tests for {@link android.util.ArrayMap}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class ArrayMapTest {
+    static final boolean DEBUG = false;
+
+    static final int OP_ADD = 1;
+    static final int OP_REM = 2;
+
+    static int[] OPS = new int[]{
+            OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
+            OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
+            OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
+            OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
+
+            OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
+            OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
+
+            OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
+            OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
+
+            OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
+            OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
+
+            OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
+            OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
+            OP_ADD, OP_ADD, OP_ADD,
+            OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
+            OP_REM, OP_REM, OP_REM,
+            OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
+    };
+
+    static int[] KEYS = new int[]{
+            // General adding and removing.
+            -1, 1900, 600, 200, 1200, 1500, 1800, 100, 1900,
+            2100, 300, 800, 600, 1100, 1300, 2000, 1000, 1400,
+            600, -1, 1900, 600, 300, 2100, 200, 800, 800,
+            1800, 1500, 1300, 1100, 2000, 1400, 1000, 1200, 1900,
+
+            // Shrink when removing item from end.
+            100, 200, 300, 400, 500, 600, 700, 800, 900,
+            900, 800, 700, 600, 500, 400, 300, 200, 100,
+
+            // Shrink when removing item from middle.
+            100, 200, 300, 400, 500, 600, 700, 800, 900,
+            900, 800, 700, 600, 500, 400, 200, 300, 100,
+
+            // Shrink when removing item from front.
+            100, 200, 300, 400, 500, 600, 700, 800, 900,
+            900, 800, 700, 600, 500, 400, 100, 200, 300,
+
+            // Test hash collisions.
+            105, 106, 108, 104, 102, 102, 107, 5, 205,
+            4, 202, 203, 3, 5, 101, 109, 200, 201,
+            0, -1, 100,
+            106, 108, 104, 102, 103, 105, 107, 101, 109,
+            -1, 100, 0,
+            4, 5, 3, 5, 200, 203, 202, 201, 205,
+    };
+
+    public static class ControlledHash implements Parcelable {
+        final int mValue;
+
+        ControlledHash(int value) {
+            mValue = value;
+        }
+
+        @Override
+        public final boolean equals(Object o) {
+            if (o == null) {
+                return false;
+            }
+            return mValue == ((ControlledHash)o).mValue;
+        }
+
+        @Override
+        public final int hashCode() {
+            return mValue/100;
+        }
+
+        @Override
+        public final String toString() {
+            return Integer.toString(mValue);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(mValue);
+        }
+
+        public static final Parcelable.Creator<ControlledHash> CREATOR
+                = new Parcelable.Creator<ControlledHash>() {
+            public ControlledHash createFromParcel(Parcel in) {
+                return new ControlledHash(in.readInt());
+            }
+
+            public ControlledHash[] newArray(int size) {
+                return new ControlledHash[size];
+            }
+        };
+    }
+
+    private static boolean compare(Object v1, Object v2) {
+        if (v1 == null) {
+            return v2 == null;
+        }
+        if (v2 == null) {
+            return false;
+        }
+        return v1.equals(v2);
+    }
+
+    private static void compareMaps(HashMap map, ArrayMap array) {
+        if (map.size() != array.size()) {
+            fail("Bad size: expected " + map.size() + ", got " + array.size());
+        }
+
+        Set<Entry> mapSet = map.entrySet();
+        for (Map.Entry entry : mapSet) {
+            Object expValue = entry.getValue();
+            Object gotValue = array.get(entry.getKey());
+            if (!compare(expValue, gotValue)) {
+                fail("Bad value: expected " + expValue + ", got " + gotValue
+                        + " at key " + entry.getKey());
+            }
+        }
+
+        for (int i = 0; i < array.size(); i++) {
+            Object gotValue = array.valueAt(i);
+            Object key = array.keyAt(i);
+            Object expValue = map.get(key);
+            if (!compare(expValue, gotValue)) {
+                fail("Bad value: expected " + expValue + ", got " + gotValue
+                        + " at key " + key);
+            }
+        }
+
+        if (map.entrySet().hashCode() != array.entrySet().hashCode()) {
+            fail("Entry set hash codes differ: map=0x"
+                    + Integer.toHexString(map.entrySet().hashCode()) + " array=0x"
+                    + Integer.toHexString(array.entrySet().hashCode()));
+        }
+
+        if (!map.entrySet().equals(array.entrySet())) {
+            fail("Failed calling equals on map entry set against array set");
+        }
+
+        if (!array.entrySet().equals(map.entrySet())) {
+            fail("Failed calling equals on array entry set against map set");
+        }
+
+        if (map.keySet().hashCode() != array.keySet().hashCode()) {
+            fail("Key set hash codes differ: map=0x"
+                    + Integer.toHexString(map.keySet().hashCode()) + " array=0x"
+                    + Integer.toHexString(array.keySet().hashCode()));
+        }
+
+        if (!map.keySet().equals(array.keySet())) {
+            fail("Failed calling equals on map key set against array set");
+        }
+
+        if (!array.keySet().equals(map.keySet())) {
+            fail("Failed calling equals on array key set against map set");
+        }
+
+        if (!map.keySet().containsAll(array.keySet())) {
+            fail("Failed map key set contains all of array key set");
+        }
+
+        if (!array.keySet().containsAll(map.keySet())) {
+            fail("Failed array key set contains all of map key set");
+        }
+
+        if (!array.containsAll(map.keySet())) {
+            fail("Failed array contains all of map key set");
+        }
+
+        if (!map.entrySet().containsAll(array.entrySet())) {
+            fail("Failed map entry set contains all of array entry set");
+        }
+
+        if (!array.entrySet().containsAll(map.entrySet())) {
+            fail("Failed array entry set contains all of map entry set");
+        }
+    }
+
+    private static void validateArrayMap(ArrayMap array) {
+        Set<Map.Entry> entrySet = array.entrySet();
+        int index = 0;
+        Iterator<Entry> entryIt = entrySet.iterator();
+        while (entryIt.hasNext()) {
+            Map.Entry entry = entryIt.next();
+            Object value = entry.getKey();
+            Object realValue = array.keyAt(index);
+            if (!compare(realValue, value)) {
+                fail("Bad array map entry set: expected key " + realValue
+                        + ", got " + value + " at index " + index);
+            }
+            value = entry.getValue();
+            realValue = array.valueAt(index);
+            if (!compare(realValue, value)) {
+                fail("Bad array map entry set: expected value " + realValue
+                        + ", got " + value + " at index " + index);
+            }
+            index++;
+        }
+
+        index = 0;
+        Set keySet = array.keySet();
+        Iterator keyIt = keySet.iterator();
+        while (keyIt.hasNext()) {
+            Object value = keyIt.next();
+            Object realValue = array.keyAt(index);
+            if (!compare(realValue, value)) {
+                fail("Bad array map key set: expected key " + realValue
+                        + ", got " + value + " at index " + index);
+            }
+            index++;
+        }
+
+        index = 0;
+        Collection valueCol = array.values();
+        Iterator valueIt = valueCol.iterator();
+        while (valueIt.hasNext()) {
+            Object value = valueIt.next();
+            Object realValue = array.valueAt(index);
+            if (!compare(realValue, value)) {
+                fail("Bad array map value col: expected value " + realValue
+                        + ", got " + value + " at index " + index);
+            }
+            index++;
+        }
+    }
+
+    private static void compareBundles(Bundle bundle1, Bundle bundle2) {
+        Set<String> keySet1 = bundle1.keySet();
+        Iterator<String> iterator1 = keySet1.iterator();
+        while (iterator1.hasNext()) {
+            String key = iterator1.next();
+            int value1 = bundle1.getInt(key);
+            if (bundle2.get(key) == null) {
+                fail("Bad Bundle: bundle2 didn't have expected key " + key);
+            }
+            int value2 = bundle2.getInt(key);
+            if (value1 != value2) {
+                fail("Bad Bundle: at key key " + key + " expected " + value1 + ", got " + value2);
+            }
+        }
+        Set<String> keySet2 = bundle2.keySet();
+        Iterator<String> iterator2 = keySet2.iterator();
+        while (iterator2.hasNext()) {
+            String key = iterator2.next();
+            if (bundle1.get(key) == null) {
+                fail("Bad Bundle: bundle1 didn't have expected key " + key);
+            }
+            int value1 = bundle1.getInt(key);
+            int value2 = bundle2.getInt(key);
+            if (value1 != value2) {
+                fail("Bad Bundle: at key key " + key + " expected " + value1 + ", got " + value2);
+            }
+        }
+    }
+
+    private static void dump(Map map, ArrayMap array) {
+        Log.e("test", "HashMap of " + map.size() + " entries:");
+        Set<Map.Entry> mapSet = map.entrySet();
+        for (Map.Entry entry : mapSet) {
+            Log.e("test", "    " + entry.getKey() + " -> " + entry.getValue());
+        }
+        Log.e("test", "ArrayMap of " + array.size() + " entries:");
+        for (int i = 0; i < array.size(); i++) {
+            Log.e("test", "    " + array.keyAt(i) + " -> " + array.valueAt(i));
+        }
+    }
+
+    private static void dump(ArrayMap map1, ArrayMap map2) {
+        Log.e("test", "ArrayMap of " + map1.size() + " entries:");
+        for (int i = 0; i < map1.size(); i++) {
+            Log.e("test", "    " + map1.keyAt(i) + " -> " + map1.valueAt(i));
+        }
+        Log.e("test", "ArrayMap of " + map2.size() + " entries:");
+        for (int i = 0; i < map2.size(); i++) {
+            Log.e("test", "    " + map2.keyAt(i) + " -> " + map2.valueAt(i));
+        }
+    }
+
+    private static void dump(Bundle bundle1, Bundle bundle2) {
+        Log.e("test", "First Bundle of " + bundle1.size() + " entries:");
+        Set<String> keys1 = bundle1.keySet();
+        for (String key : keys1) {
+            Log.e("test", "    " + key + " -> " + bundle1.get(key));
+        }
+        Log.e("test", "Second Bundle of " + bundle2.size() + " entries:");
+        Set<String> keys2 = bundle2.keySet();
+        for (String key : keys2) {
+            Log.e("test", "    " + key + " -> " + bundle2.get(key));
+        }
+    }
+
+    @Test
+    public void testBasicArrayMap() {
+        HashMap<ControlledHash, Integer> hashMap = new HashMap<>();
+        ArrayMap<ControlledHash, Integer> arrayMap = new ArrayMap<>();
+        Bundle bundle = new Bundle();
+
+        for (int i = 0; i < OPS.length; i++) {
+            Integer oldHash;
+            Integer oldArray;
+            ControlledHash key = KEYS[i] < 0 ? null : new ControlledHash(KEYS[i]);
+            String strKey = KEYS[i] < 0 ? null : Integer.toString(KEYS[i]);
+            switch (OPS[i]) {
+                case OP_ADD:
+                    if (DEBUG) Log.i("test", "Adding key: " + key);
+                    oldHash = hashMap.put(key, i);
+                    oldArray = arrayMap.put(key, i);
+                    bundle.putInt(strKey, i);
+                    break;
+                case OP_REM:
+                    if (DEBUG) Log.i("test", "Removing key: " + key);
+                    oldHash = hashMap.remove(key);
+                    oldArray = arrayMap.remove(key);
+                    bundle.remove(strKey);
+                    break;
+                default:
+                    fail("Bad operation " + OPS[i] + " @ " + i);
+                    return;
+            }
+            if (!compare(oldHash, oldArray)) {
+                String msg = "Bad result: expected " + oldHash + ", got " + oldArray;
+                Log.e("test", msg);
+                dump(hashMap, arrayMap);
+                fail(msg);
+            }
+            try {
+                validateArrayMap(arrayMap);
+            } catch (Throwable e) {
+                Log.e("test", e.getMessage());
+                dump(hashMap, arrayMap);
+                throw e;
+            }
+            try {
+                compareMaps(hashMap, arrayMap);
+            } catch (Throwable e) {
+                Log.e("test", e.getMessage());
+                dump(hashMap, arrayMap);
+                throw e;
+            }
+            Parcel parcel = Parcel.obtain();
+            bundle.writeToParcel(parcel, 0);
+            parcel.setDataPosition(0);
+            Bundle bundle2 = parcel.readBundle();
+            try {
+                compareBundles(bundle, bundle2);
+            } catch (Throwable e) {
+                Log.e("test", e.getMessage());
+                dump(bundle, bundle2);
+                throw e;
+            }
+        }
+
+        arrayMap.put(new ControlledHash(50000), 100);
+        ControlledHash lookup = new ControlledHash(50000);
+        Iterator<ControlledHash> it = arrayMap.keySet().iterator();
+        while (it.hasNext()) {
+            if (it.next().equals(lookup)) {
+                it.remove();
+            }
+        }
+        if (arrayMap.containsKey(lookup)) {
+            String msg = "Bad map iterator: didn't remove test key";
+            Log.e("test", msg);
+            dump(hashMap, arrayMap);
+            fail(msg);
+        }
+    }
+
+    @Test
+    public void testCopyArrayMap() {
+        // map copy constructor test
+        ArrayMap newMap = new ArrayMap<Integer, String>();
+        for (int i = 0; i < 10; ++i) {
+            newMap.put(i, String.valueOf(i));
+        }
+        ArrayMap mapCopy = new ArrayMap(newMap);
+        if (!compare(mapCopy, newMap)) {
+            String msg = "ArrayMap copy constructor failure: expected " +
+                    newMap + ", got " + mapCopy;
+            Log.e("test", msg);
+            dump(newMap, mapCopy);
+            fail(msg);
+            return;
+        }
+    }
+
+    @Test
+    public void testEqualsArrayMap() {
+        ArrayMap<Integer, String> map1 = new ArrayMap<>();
+        ArrayMap<Integer, String> map2 = new ArrayMap<>();
+        HashMap<Integer, String> map3 = new HashMap<>();
+        if (!compare(map1, map2) || !compare(map1, map3) || !compare(map3, map2)) {
+            fail("ArrayMap equals failure for empty maps " + map1 + ", " +
+                    map2 + ", " + map3);
+        }
+
+        for (int i = 0; i < 10; ++i) {
+            String value = String.valueOf(i);
+            map1.put(i, value);
+            map2.put(i, value);
+            map3.put(i, value);
+        }
+        if (!compare(map1, map2) || !compare(map1, map3) || !compare(map3, map2)) {
+            fail("ArrayMap equals failure for populated maps " + map1 + ", " +
+                    map2 + ", " + map3);
+        }
+
+        map1.remove(0);
+        if (compare(map1, map2) || compare(map1, map3) || compare(map3, map1)) {
+            fail("ArrayMap equals failure for map size " + map1 + ", " +
+                    map2 + ", " + map3);
+        }
+
+        map1.put(0, "-1");
+        if (compare(map1, map2) || compare(map1, map3) || compare(map3, map1)) {
+            fail("ArrayMap equals failure for map contents " + map1 + ", " +
+                    map2 + ", " + map3);
+        }
+    }
+
+//    /**
+//     * Test creating a malformed array map with duplicated keys and that we will catch this when
+//     * unparcelling.
+//     */
+//    @Test
+//    public void testDuplicateKeys() throws NoSuchMethodException,
+//            InvocationTargetException, IllegalAccessException, NoSuchFieldException {
+//        ArrayMap<String, Object> map1 = new ArrayMap(2);
+//
+//        Method appendMethod = ArrayMap.class.getMethod("append", Object.class, Object.class);
+//        appendMethod.invoke(map1, Integer.toString(100000), "foo");
+//        appendMethod.invoke(map1, Integer.toString(100000), "bar");
+//
+//        // Now parcel/unparcel, and verify we get the expected error.
+//        Parcel parcel = Parcel.obtain();
+//        Method writeArrayMapMethod = Parcel.class.getMethod("writeArrayMap", ArrayMap.class);
+//        writeArrayMapMethod.invoke(parcel, map1);
+//        parcel.setDataPosition(0);
+//        ArrayMap<String, Object> map2 = new ArrayMap(2);
+//
+//        try {
+//            Parcel.class.getMethod("readArrayMap", ArrayMap.class, ClassLoader.class).invoke(
+//                    parcel, map2, null);
+//        } catch (InvocationTargetException e) {
+//            Throwable cause = e.getCause();
+//            if (cause instanceof IllegalArgumentException) {
+//                // Good!
+//                return;
+//            }
+//            throw e;
+//        }
+//
+//        String msg = "Didn't throw expected IllegalArgumentException";
+//        Log.e("test", msg);
+//        dump(map1, map2);
+//        fail(msg);
+//    }
+
+    private static void checkEntrySetToArray(ArrayMap<?, ?> testMap) {
+        try {
+            testMap.entrySet().toArray();
+            fail();
+        } catch (UnsupportedOperationException expected) {
+        }
+
+        try {
+            Map.Entry<?, ?>[] entries = new Map.Entry[20];
+            testMap.entrySet().toArray(entries);
+            fail();
+        } catch (UnsupportedOperationException expected) {
+        }
+    }
+
+    // http://b/32294038, Test ArrayMap.entrySet().toArray()
+    @Test
+    public void testEntrySetArray() {
+        // Create
+        ArrayMap<Integer, String> testMap = new ArrayMap<>();
+
+        // Test empty
+        checkEntrySetToArray(testMap);
+
+        // Test non-empty
+        for (int i = 0; i < 10; ++i) {
+            testMap.put(i, String.valueOf(i));
+        }
+        checkEntrySetToArray(testMap);
+    }
+
+    @Test
+    public void testCanNotIteratePastEnd_entrySetIterator() {
+        Map<String, String> map = new ArrayMap<>();
+        map.put("key 1", "value 1");
+        map.put("key 2", "value 2");
+        Set<Map.Entry<String, String>> expectedEntriesToIterate = new HashSet<>(Arrays.asList(
+                entryOf("key 1", "value 1"),
+                entryOf("key 2", "value 2")
+        ));
+        Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
+
+        // Assert iteration over the expected two entries in any order
+        assertTrue(iterator.hasNext());
+        Map.Entry<String, String> firstEntry = copyOf(iterator.next());
+        assertTrue(expectedEntriesToIterate.remove(firstEntry));
+
+        assertTrue(iterator.hasNext());
+        Map.Entry<String, String> secondEntry = copyOf(iterator.next());
+        assertTrue(expectedEntriesToIterate.remove(secondEntry));
+
+        assertFalse(iterator.hasNext());
+
+        try {
+            iterator.next();
+            fail();
+        } catch (NoSuchElementException expected) {
+        }
+    }
+
+    private static <K, V> Map.Entry<K, V> entryOf(K key, V value) {
+        return new AbstractMap.SimpleEntry<>(key, value);
+    }
+
+    private static <K, V> Map.Entry<K, V> copyOf(Map.Entry<K, V> entry) {
+        return entryOf(entry.getKey(), entry.getValue());
+    }
+
+    @Test
+    public void testCanNotIteratePastEnd_keySetIterator() {
+        Map<String, String> map = new ArrayMap<>();
+        map.put("key 1", "value 1");
+        map.put("key 2", "value 2");
+        Set<String> expectedKeysToIterate = new HashSet<>(Arrays.asList("key 1", "key 2"));
+        Iterator<String> iterator = map.keySet().iterator();
+
+        // Assert iteration over the expected two keys in any order
+        assertTrue(iterator.hasNext());
+        String firstKey = iterator.next();
+        assertTrue(expectedKeysToIterate.remove(firstKey));
+
+        assertTrue(iterator.hasNext());
+        String secondKey = iterator.next();
+        assertTrue(expectedKeysToIterate.remove(secondKey));
+
+        assertFalse(iterator.hasNext());
+
+        try {
+            iterator.next();
+            fail();
+        } catch (NoSuchElementException expected) {
+        }
+    }
+
+    @Test
+    public void testCanNotIteratePastEnd_valuesIterator() {
+        Map<String, String> map = new ArrayMap<>();
+        map.put("key 1", "value 1");
+        map.put("key 2", "value 2");
+        Set<String> expectedValuesToIterate = new HashSet<>(Arrays.asList("value 1", "value 2"));
+        Iterator<String> iterator = map.values().iterator();
+
+        // Assert iteration over the expected two values in any order
+        assertTrue(iterator.hasNext());
+        String firstValue = iterator.next();
+        assertTrue(expectedValuesToIterate.remove(firstValue));
+
+        assertTrue(iterator.hasNext());
+        String secondValue = iterator.next();
+        assertTrue(expectedValuesToIterate.remove(secondValue));
+
+        assertFalse(iterator.hasNext());
+
+        try {
+            iterator.next();
+            fail();
+        } catch (NoSuchElementException expected) {
+        }
+    }
+
+    @Test
+    public void testForEach() {
+        ArrayMap<String, Integer> map = new ArrayMap<>();
+
+        for (int i = 0; i < 50; ++i) {
+            map.put(Integer.toString(i), i * 10);
+        }
+
+        // Make sure forEach goes through all of the elements.
+        HashMap<String, Integer> seen = new HashMap<>();
+        map.forEach(seen::put);
+        compareMaps(seen, map);
+    }
+
+    /**
+     * The entrySet Iterator returns itself from each call to {@code next()}. This is unusual
+     * behavior for {@link Iterator#next()}; this test ensures that any future change to this
+     * behavior is deliberate.
+     */
+    @Test
+    public void testUnusualBehavior_eachEntryIsSameAsIterator_entrySetIterator() {
+        Map<String, String> map = new ArrayMap<>();
+        map.put("key 1", "value 1");
+        map.put("key 2", "value 2");
+        Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
+
+        assertSame(iterator, iterator.next());
+        assertSame(iterator, iterator.next());
+    }
+
+    @SuppressWarnings("SelfEquals")
+    @Test
+    public void testUnusualBehavior_equalsThrowsAfterRemove_entrySetIterator() {
+        Map<String, String> map = new ArrayMap<>();
+        map.put("key 1", "value 1");
+        map.put("key 2", "value 2");
+        Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
+        iterator.next();
+        iterator.remove();
+        try {
+            iterator.equals(iterator);
+            fail();
+        } catch (IllegalStateException expected) {
+        }
+    }
+
+    private static <T> void assertEqualsBothWays(T a, T b) {
+        assertEquals(a, b);
+        assertEquals(b, a);
+        assertEquals(a.hashCode(), b.hashCode());
+    }
+
+    @Test
+    public void testRemoveAll() {
+        final ArrayMap<Integer, String> map = new ArrayMap<>();
+        for (Integer i : Arrays.asList(0, 1, 2, 3, 4, 5)) {
+            map.put(i, i.toString());
+        }
+
+        final ArrayMap<Integer, String> expectedMap = new ArrayMap<>();
+        for (Integer i : Arrays.asList(2, 4)) {
+            expectedMap.put(i, String.valueOf(i));
+        }
+        map.removeAll(Arrays.asList(0, 1, 3, 5, 6));
+        if (!compare(map, expectedMap)) {
+            fail("ArrayMap removeAll failure, expect " + expectedMap + ", but " + map);
+        }
+
+        map.removeAll(Collections.emptyList());
+        if (!compare(map, expectedMap)) {
+            fail("ArrayMap removeAll failure for empty maps, expect " + expectedMap + ", but " +
+                    map);
+        }
+
+        map.removeAll(Arrays.asList(2, 4));
+        if (!map.isEmpty()) {
+            fail("ArrayMap removeAll failure, expect empty, but " + map);
+        }
+    }
+
+    @Test
+    public void testReplaceAll() {
+        final ArrayMap<Integer, Integer> map = new ArrayMap<>();
+        final ArrayMap<Integer, Integer> expectedMap = new ArrayMap<>();
+        final BiFunction<Integer, Integer, Integer> function = (k, v) -> 2 * v;
+        for (Integer i : Arrays.asList(0, 1, 2, 3, 4, 5)) {
+            map.put(i, i);
+            expectedMap.put(i, 2 * i);
+        }
+
+        map.replaceAll(function);
+        if (!compare(map, expectedMap)) {
+            fail("ArrayMap replaceAll failure, expect " + expectedMap + ", but " + map);
+        }
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/test-framework/src/com/android/hoststubgen/frameworktest/LogTest.java b/tools/hoststubgen/hoststubgen/test-framework/src/com/android/hoststubgen/frameworktest/LogTest.java
new file mode 100644
index 0000000..56544b4
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-framework/src/com/android/hoststubgen/frameworktest/LogTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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.frameworktest;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.util.Log;
+import android.util.Slog;
+
+import org.junit.Test;
+
+/**
+ * Some basic tests for {@link android.util.Log}.
+ */
+public class LogTest {
+    @Test
+    public void testBasicLogging() {
+        Log.v("TAG", "Test v log");
+        Log.d("TAG", "Test d log");
+        Log.i("TAG", "Test i log");
+        Log.w("TAG", "Test w log");
+        Log.e("TAG", "Test e log");
+
+        Slog.v("TAG", "Test v slog");
+        Slog.d("TAG", "Test d slog");
+        Slog.i("TAG", "Test i slog");
+        Slog.w("TAG", "Test w slog");
+        Slog.e("TAG", "Test e slog");
+    }
+
+    @Test
+    public void testNativeMethods() {
+        assertThat(Log.isLoggable("mytag", Log.INFO)).isTrue();
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp b/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp
new file mode 100644
index 0000000..8c76a61
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp
@@ -0,0 +1,141 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+// A library that simulates framework-all.jar
+java_library {
+    name: "hoststubgen-test-tiny-framework",
+    installable: true,
+    host_supported: true,
+    srcs: ["tiny-framework/src/**/*.java"],
+    static_libs: [
+        "hoststubgen-annotations",
+    ],
+}
+
+// Create stub/impl jars from "hoststubgen-test-tiny-framework", using the following 3 rules.
+java_genrule_host {
+    name: "hoststubgen-test-tiny-framework-host",
+    defaults: ["hoststubgen-command-defaults"],
+    cmd: hoststubgen_common_options +
+        "--in-jar $(location :hoststubgen-test-tiny-framework) " +
+        "--policy-override-file $(location policy-override-tiny-framework.txt) ",
+    srcs: [
+        ":hoststubgen-test-tiny-framework",
+        "policy-override-tiny-framework.txt",
+    ],
+}
+
+java_genrule_host {
+    name: "hoststubgen-test-tiny-framework-host-stub",
+    cmd: "cp $(in) $(out)",
+    srcs: [
+        ":hoststubgen-test-tiny-framework-host{host_stub.jar}",
+    ],
+    out: [
+        "host_stub.jar",
+    ],
+}
+
+java_genrule_host {
+    name: "hoststubgen-test-tiny-framework-host-impl",
+    cmd: "cp $(in) $(out)",
+    srcs: [
+        ":hoststubgen-test-tiny-framework-host{host_impl.jar}",
+    ],
+    out: [
+        "host_impl.jar",
+    ],
+}
+
+// Compile the test jar, using 2 rules.
+// 1. Build the test against the stub.
+java_library_host {
+    name: "hoststubgen-test-tiny-test-lib",
+    srcs: ["tiny-test/src/**/*.java"],
+
+    libs: [
+        "hoststubgen-test-tiny-framework-host-stub",
+    ],
+    static_libs: [
+        "junit",
+        "truth-prebuilt",
+
+        // http://cs/h/googleplex-android/platform/superproject/main/+/main:platform_testing/libraries/annotations/src/android/platform/test/annotations/
+        "platform-test-annotations",
+    ],
+    visibility: ["//visibility:private"],
+}
+
+// 2. Link "hoststubgen-test-tiny-test-lib" with necessary runtime dependencies, so it can be
+// executed stand-alone.
+java_test_host {
+    name: "hoststubgen-test-tiny-test",
+    test_config: "AndroidTest-host.xml",
+    static_libs: [
+        "hoststubgen-test-tiny-test-lib",
+        "hoststubgen-helper-runtime",
+        "hoststubgen-test-tiny-framework-host-impl",
+    ],
+    test_suites: ["general-tests"],
+}
+
+// Dump the original, stub and impl jars as text files.
+// We use them in test-and-update-golden.sh.
+java_genrule_host {
+    name: "hoststubgen-test-tiny-framework-orig-dump",
+    defaults: ["hoststubgen-jar-dump-defaults"],
+    srcs: [
+        ":hoststubgen-test-tiny-framework",
+    ],
+    out: [
+        "01-hoststubgen-test-tiny-framework-orig-dump.txt",
+    ],
+    visibility: ["//visibility:private"],
+}
+
+java_genrule_host {
+    name: "hoststubgen-test-tiny-framework-host-stub-dump",
+    defaults: ["hoststubgen-jar-dump-defaults"],
+    srcs: [
+        ":hoststubgen-test-tiny-framework-host-stub",
+    ],
+    out: [
+        "02-hoststubgen-test-tiny-framework-host-stub-dump.txt",
+    ],
+    visibility: ["//visibility:private"],
+}
+
+java_genrule_host {
+    name: "hoststubgen-test-tiny-framework-host-impl-dump",
+    defaults: ["hoststubgen-jar-dump-defaults"],
+    srcs: [
+        ":hoststubgen-test-tiny-framework-host-impl",
+    ],
+    out: [
+        "03-hoststubgen-test-tiny-framework-host-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",
+    srcs: [
+        "tiny-framework-dump-test.py",
+    ],
+    data: [
+        "golden-output/*.txt",
+    ],
+    java_data: [
+        "hoststubgen-test-tiny-framework-host-stub-dump",
+        "hoststubgen-test-tiny-framework-host-impl-dump",
+        "hoststubgen-test-tiny-framework-orig-dump",
+    ],
+    test_suites: ["general-tests"],
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/AndroidTest-host.xml b/tools/hoststubgen/hoststubgen/test-tiny-framework/AndroidTest-host.xml
new file mode 100644
index 0000000..84aad69
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/AndroidTest-host.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- [Ravenwood] Copied from $ANDROID_BUILD_TOP/cts/hostsidetests/devicepolicy/AndroidTest.xml  -->
+<configuration description="HostStubGen sample test">
+    <option name="test-suite-tag" value="ravenwood" />
+    <option name="config-descriptor:metadata" key="component" value="framework" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_secondary_user" />
+    <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
+
+    <test class="com.android.tradefed.testtype.IsolatedHostTest" >
+        <option name="jar" value="hoststubgen-test-tiny-test.jar" />
+    </test>
+</configuration>
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/README.md b/tools/hoststubgen/hoststubgen/test-tiny-framework/README.md
new file mode 100644
index 0000000..f3c0450
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/README.md
@@ -0,0 +1,27 @@
+# HostStubGen: tiny-framework test
+
+This directory contains a small classes that "simulates" framework.jar, and tests against it.
+
+This test doesn't use the actual android framework code.
+
+## How to run
+
+- With `atest`. This is the proper way to run it, but `atest` has known problems that may
+  affect the result. If you see weird problems, try the next `run-ravenwood-test` command.
+
+```
+$ atest hoststubgen-test-tiny-test
+```
+
+- With `run-ravenwood-test` should work too. This is the proper way to run it.
+
+```
+$ run-ravenwood-test hoststubgen-test-tiny-test
+```
+
+- `run-test-manually.sh` also run the test, but it builds the stub/impl jars and the test without
+  using the build system. This is useful for debugging the tool.
+
+```
+$ ./run-test-manually.sh
+```
\ No newline at end of file
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
new file mode 100755
index 0000000..4d58869
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/diff-and-update-golden.sh
@@ -0,0 +1,134 @@
+#!/bin/bash
+# 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.
+
+help() {
+  cat <<'EOF'
+
+  diff-and-update-golden.sh [OPTIONS]
+
+    Compare the generated jar files from tiny-framework to the "golden" files.
+
+  OPTIONS:
+    -u: Update the golden files.
+
+    -3: Run `meld` to compare original, stub and impl jar files in 3-way diff.
+        This is useful to visualize the exact differences between 3 jar files.
+
+    -2: Run `meld` to compare original <-> impl, and impl <-> stub as two different diffs.
+EOF
+}
+
+source "${0%/*}"/../../common.sh
+
+SCRIPT_NAME="${0##*/}"
+
+GOLDEN_DIR=golden-output
+mkdir -p $GOLDEN_DIR
+
+DIFF_CMD=${DIFF:-diff -u --ignore-blank-lines --ignore-space-change}
+
+update=0
+three_way=0
+two_way=0
+while getopts "u32" opt; do
+case "$opt" in
+    u)
+        update=1
+        ;;
+    3)
+        three_way=1
+        ;;
+    2)
+        two_way=1
+        ;;
+    '?')
+        help
+        exit 1
+        ;;
+esac
+done
+shift $(($OPTIND - 1))
+
+
+# Build the dump files, which are the input of this test.
+run m tiny-framework-dump-test
+
+
+# Get the path to the generate text files. (not the golden files.)
+# We get them from $OUT/module-info.json
+
+files=(
+$(python3 -c '
+import sys
+import os
+import json
+
+with open(sys.argv[1], "r") as f:
+    data = json.load(f)
+
+    # Equivalent to: jq -r '.["tiny-framework-dump-test"]["installed"][]'
+    for path in data["tiny-framework-dump-test"]["installed"]:
+
+      if "golden-output" in path:
+        continue
+      if path.endswith(".txt"):
+        print(os.getenv("ANDROID_BUILD_TOP") + "/" + path)
+' $OUT/module-info.json)
+)
+
+# Next, compare each file and update them in $GOLDEN_DIR
+
+any_file_changed=0
+
+for file in ${files[*]} ; do
+  name=$(basename $file)
+  echo "# Checking $name ..."
+
+  file_changed=0
+  if run $DIFF_CMD $GOLDEN_DIR/$name $file; then
+    : # No diff
+  else
+    file_changed=1
+    any_file_changed=1
+  fi
+
+  if (( $update && $file_changed )) ; then
+    echo "# Updating $name ..."
+    run cp $file $GOLDEN_DIR/$name
+  fi
+done
+
+if (( $three_way )) ; then
+  echo "# Running 3-way diff with meld..."
+  run meld ${files[*]} &
+fi
+
+if (( $two_way )) ; then
+  echo "# Running meld..."
+  run meld --diff ${files[0]} ${files[1]} --diff ${files[1]} ${files[2]}
+fi
+
+if (( $any_file_changed == 0 )) ; then
+  echo "$SCRIPT_NAME: Success: no changes detected."
+  exit 0
+else
+  if (( $update )) ; then
+    echo "$SCRIPT_NAME: Warning: golden files have been updated."
+    exit 2
+  else
+    echo "$SCRIPT_NAME: Failure: changes detected. See above diff for the details."
+    exit 3
+  fi
+fi
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
new file mode 100644
index 0000000..1aa4859
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
@@ -0,0 +1,1671 @@
+## 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: 1, attributes: 2
+  public abstract java.lang.String value();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+}
+SourceFile: "HostSideTestClassLoadHook.java"
+RuntimeVisibleAnnotations:
+  0: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE]
+    )
+  1: #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: 0, attributes: 2
+}
+SourceFile: "HostSideTestKeep.java"
+RuntimeVisibleAnnotations:
+  0: #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]
+    )
+  1: #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: 1, attributes: 2
+  public abstract java.lang.String value();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+}
+SourceFile: "HostSideTestNativeSubstitutionClass.java"
+RuntimeVisibleAnnotations:
+  0: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE]
+    )
+  1: #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: 0, attributes: 2
+}
+SourceFile: "HostSideTestRemove.java"
+RuntimeVisibleAnnotations:
+  0: #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]
+    )
+  1: #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: 0, attributes: 2
+}
+SourceFile: "HostSideTestStub.java"
+RuntimeVisibleAnnotations:
+  0: #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]
+    )
+  1: #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: 1, attributes: 2
+  public abstract java.lang.String suffix();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+}
+SourceFile: "HostSideTestSubstitute.java"
+RuntimeVisibleAnnotations:
+  0: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.METHOD]
+    )
+  1: #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: 0, attributes: 2
+}
+SourceFile: "HostSideTestThrow.java"
+RuntimeVisibleAnnotations:
+  0: #x(#x=[e#x.#x,e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+    )
+  1: #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: 0, attributes: 2
+}
+SourceFile: "HostSideTestWholeClassKeep.java"
+RuntimeVisibleAnnotations:
+  0: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE]
+    )
+  1: #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: 0, attributes: 2
+}
+SourceFile: "HostSideTestWholeClassStub.java"
+RuntimeVisibleAnnotations:
+  0: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE]
+    )
+  1: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/tests/HostSideTestSuppress.class
+  Compiled from "HostSideTestSuppress.java"
+public interface android.hosttest.annotation.tests.HostSideTestSuppress 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/tests/HostSideTestSuppress
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestSuppress.java"
+RuntimeVisibleAnnotations:
+  0: #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]
+    )
+## 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: 3, attributes: 3
+  private com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl();
+    descriptor: ()V
+    flags: (0x0002) ACC_PRIVATE
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl;
+
+  public static int getOneKeep();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         0: iconst_1
+         1: ireturn
+      LineNumberTable:
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static int getOneStub();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         0: iconst_1
+         1: ireturn
+      LineNumberTable:
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+}
+SourceFile: "TinyFrameworkCallerCheck.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
+InnerClasses:
+  private static #x= #x of #x;          // Impl=class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl of 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: 4
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck;
+
+  public static int getOne_withCheck();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         0: invokestatic  #x                  // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.getOneKeep:()I
+         3: ireturn
+      LineNumberTable:
+
+  public static int getOne_noCheck();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         0: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.getOneStub:()I
+         3: ireturn
+      LineNumberTable:
+}
+SourceFile: "TinyFrameworkCallerCheck.java"
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl
+InnerClasses:
+  private static #x= #x of #x;          // Impl=class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl of class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
+## 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: 3, methods: 10, attributes: 2
+  public int stub;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+
+  public int keep;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public int remove;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: aload_0
+         5: iconst_1
+         6: putfield      #x                  // Field stub:I
+         9: aload_0
+        10: iconst_2
+        11: putfield      #x                 // Field keep:I
+        14: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      15     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: aload_0
+         1: iload_1
+         2: invokevirtual #x                 // Method addOneInner:(I)I
+         5: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+            0       6     1 value   I
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+
+  public int addOneInner(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: iload_1
+         1: iconst_1
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+            0       4     1 value   I
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public void toBeRemoved(java.lang.String);
+    descriptor: (Ljava/lang/String;)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: invokespecial #x                 // Method java/lang/RuntimeException."<init>":()V
+         7: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       8     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+            0       8     1   foo   Ljava/lang/String;
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestRemove
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String not supported on host side
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+            0      10     1 value   I
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+      1: #x(#x=s#x)
+        android.hosttest.annotation.HostSideTestSubstitute(
+          suffix="_host"
+        )
+
+  public int addTwo_host(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: iload_1
+         1: iconst_2
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+            0       4     1 value   I
+
+  public static native int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+      1: #x(#x=s#x)
+        android.hosttest.annotation.HostSideTestSubstitute(
+          suffix="_host"
+        )
+
+  public static int nativeAddThree_host(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         0: iload_0
+         1: iconst_3
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0 value   I
+
+  public java.lang.String unsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: ldc           #x                 // String This value shouldn\'t be seen on the host side.
+         2: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       3     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestThrow
+
+  public java.lang.String visibleButUsesUnsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokevirtual #x                 // Method unsupportedMethod:()Ljava/lang/String;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+}
+SourceFile: "TinyFrameworkClassAnnotations.java"
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestStub
+  1: #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: 10, attributes: 2
+  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=2, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: aload_0
+         5: iconst_1
+         6: putfield      #x                  // Field stub:I
+         9: aload_0
+        10: iconst_2
+        11: putfield      #x                 // Field keep:I
+        14: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      15     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: aload_0
+         1: iload_1
+         2: invokevirtual #x                 // Method addOneInner:(I)I
+         5: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+            0       6     1 value   I
+
+  public int addOneInner(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: iload_1
+         1: iconst_1
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+            0       4     1 value   I
+
+  public void toBeRemoved(java.lang.String);
+    descriptor: (Ljava/lang/String;)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: invokespecial #x                 // Method java/lang/RuntimeException."<init>":()V
+         7: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       8     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+            0       8     1   foo   Ljava/lang/String;
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String not supported on host side
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+            0      10     1 value   I
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+      1: #x(#x=s#x)
+        android.hosttest.annotation.HostSideTestSubstitute(
+          suffix="_host"
+        )
+
+  public int addTwo_host(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: iload_1
+         1: iconst_2
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+            0       4     1 value   I
+
+  public static native int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+      1: #x(#x=s#x)
+        android.hosttest.annotation.HostSideTestSubstitute(
+          suffix="_host"
+        )
+
+  public static int nativeAddThree_host(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         0: iload_0
+         1: iconst_3
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0 value   I
+
+  public java.lang.String unsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: ldc           #x                 // String This value shouldn\'t be seen on the host side.
+         2: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       3     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+
+  public java.lang.String visibleButUsesUnsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokevirtual #x                 // Method unsupportedMethod:()Ljava/lang/String;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+}
+SourceFile: "TinyFrameworkClassClassWideAnnotations.java"
+RuntimeInvisibleAnnotations:
+  0: #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: 2
+  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=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       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=2, locals=1, args_size=1
+         0: getstatic     #x                  // Field sLoadedClasses:Ljava/util/Set;
+         3: aload_0
+         4: invokeinterface #x,  2           // InterfaceMethod java/util/Set.add:(Ljava/lang/Object;)Z
+         9: pop
+        10: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      11     0 clazz   Ljava/lang/Class;
+      LocalVariableTypeTable:
+        Start  Length  Slot  Name   Signature
+            0      11     0 clazz   Ljava/lang/Class<*>;
+    Signature: #x                          // (Ljava/lang/Class<*>;)V
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         0: new           #x                 // class java/util/HashSet
+         3: dup
+         4: invokespecial #x                 // Method java/util/HashSet."<init>":()V
+         7: putstatic     #x                  // Field sLoadedClasses:Ljava/util/Set;
+        10: return
+      LineNumberTable:
+}
+SourceFile: "TinyFrameworkClassLoadHook.java"
+RuntimeInvisibleAnnotations:
+  0: #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: 2
+  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=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer;
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         0: iconst_1
+         1: putstatic     #x                  // Field sInitialized:Z
+         4: return
+      LineNumberTable:
+}
+SourceFile: "TinyFrameworkClassWithInitializer.java"
+RuntimeInvisibleAnnotations:
+  0: #x(#x=s#x)
+    android.hosttest.annotation.HostSideTestClassLoadHook(
+      value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+    )
+  1: #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: 2
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       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
+         0: new           #x                  // class java/lang/IllegalStateException
+         3: dup
+         4: ldc           #x                  // String Inner exception
+         6: invokespecial #x                 // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V
+         9: athrow
+        10: astore_0
+        11: new           #x                 // class java/lang/RuntimeException
+        14: dup
+        15: ldc           #x                 // String Outer exception
+        17: aload_0
+        18: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;Ljava/lang/Throwable;)V
+        21: athrow
+      Exception table:
+         from    to  target type
+             0    10    10   Class java/lang/Exception
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      11     0     e   Ljava/lang/Exception;
+      StackMapTable: number_of_entries = 1
+        frame_type = 74 /* same_locals_1_stack_item */
+          stack = [ class java/lang/Exception ]
+}
+SourceFile: "TinyFrameworkExceptionTester.java"
+RuntimeInvisibleAnnotations:
+  0: #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: 3, methods: 10, attributes: 1
+  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.TinyFrameworkForTextPolicy();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: aload_0
+         5: iconst_1
+         6: putfield      #x                  // Field stub:I
+         9: aload_0
+        10: iconst_2
+        11: putfield      #x                 // Field keep:I
+        14: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      15     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: aload_0
+         1: iload_1
+         2: invokevirtual #x                 // Method addOneInner:(I)I
+         5: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+            0       6     1 value   I
+
+  public int addOneInner(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: iload_1
+         1: iconst_1
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+            0       4     1 value   I
+
+  public void toBeRemoved(java.lang.String);
+    descriptor: (Ljava/lang/String;)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: invokespecial #x                 // Method java/lang/RuntimeException."<init>":()V
+         7: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       8     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+            0       8     1   foo   Ljava/lang/String;
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String not supported on host side
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+            0      10     1 value   I
+
+  public int addTwo_host(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: iload_1
+         1: iconst_2
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+            0       4     1 value   I
+
+  public static native int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+
+  public static int addThree_host(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         0: iload_0
+         1: iconst_3
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0 value   I
+
+  public java.lang.String unsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: ldc           #x                 // String This value shouldn\'t be seen on the host side.
+         2: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       3     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+  public java.lang.String visibleButUsesUnsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokevirtual #x                 // Method unsupportedMethod:()Ljava/lang/String;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+}
+SourceFile: "TinyFrameworkForTextPolicy.java"
+## 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: 2
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+
+  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=1, locals=1, args_size=1
+         0: iload_0
+         1: invokestatic  #x                  // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeAddTwo:(I)I
+         4: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0   arg   I
+
+  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=4, locals=4, args_size=2
+         0: lload_0
+         1: lload_2
+         2: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeLongPlus:(JJ)J
+         5: lreturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  arg1   J
+            0       6     2  arg2   J
+}
+SourceFile: "TinyFrameworkNative.java"
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+  1: #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: 3, attributes: 2
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       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=2, locals=1, args_size=1
+         0: iload_0
+         1: iconst_2
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       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
+         0: lload_0
+         1: lload_2
+         2: ladd
+         3: lreturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  arg1   J
+            0       4     2  arg2   J
+}
+SourceFile: "TinyFrameworkNative_host.java"
+RuntimeInvisibleAnnotations:
+  0: #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: 3, attributes: 5
+  final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC
+
+  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=2, locals=2, args_size=2
+         0: aload_0
+         1: aload_1
+         2: putfield      #x                  // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+         5: aload_0
+         6: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         9: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+            0      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=1, locals=1, args_size=1
+         0: iconst_1
+         1: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       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=1, locals=1, args_size=1
+         0: aload_0
+         1: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+}
+Signature: #x                          // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+EnclosingMethod: #x.#x                 // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+  #x;                                     // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+## 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: 3, attributes: 5
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2();
+    descriptor: ()V
+    flags: (0x0000)
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       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=1, locals=1, args_size=1
+         0: iconst_2
+         1: invokestatic  #x                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       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=1, locals=1, args_size=1
+         0: aload_0
+         1: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2;
+}
+Signature: #x                          // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+EnclosingMethod: #x.#x                 // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+## 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: 3, attributes: 5
+  final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC
+
+  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=2, locals=2, args_size=2
+         0: aload_0
+         1: aload_1
+         2: putfield      #x                  // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+         5: aload_0
+         6: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         9: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+            0      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=1, locals=1, args_size=1
+         0: iconst_3
+         1: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       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=1, locals=1, args_size=1
+         0: aload_0
+         1: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+}
+Signature: #x                          // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+EnclosingMethod: #x.#x                // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.getSupplier
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+  #x;                                     // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+## 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: 3, attributes: 5
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4();
+    descriptor: ()V
+    flags: (0x0000)
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       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=1, locals=1, args_size=1
+         0: iconst_4
+         1: invokestatic  #x                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       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=1, locals=1, args_size=1
+         0: aload_0
+         1: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4;
+}
+Signature: #x                          // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+EnclosingMethod: #x.#x                // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.getSupplier_static
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+## 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: 3
+  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=2, locals=2, args_size=2
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: aload_0
+         5: iload_1
+         6: putfield      #x                  // Field value:I
+         9: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass;
+            0      10     1     x   I
+}
+SourceFile: "TinyFrameworkNestedClasses.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+  public static #x= #x of #x;           // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of 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: 4
+  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=2, locals=2, args_size=2
+         0: aload_0
+         1: aload_1
+         2: putfield      #x                  // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+         5: aload_0
+         6: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         9: aload_0
+        10: iconst_5
+        11: putfield      #x                 // Field value:I
+        14: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      15     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass;
+            0      15     1 this$0   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+}
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+NestHost: class com/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
+## 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: 3, attributes: 5
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$1();
+    descriptor: ()V
+    flags: (0x0000)
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       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=1, locals=1, args_size=1
+         0: bipush        7
+         2: invokestatic  #x                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         5: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       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=1, locals=1, args_size=1
+         0: aload_0
+         1: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1;
+}
+Signature: #x                          // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+EnclosingMethod: #x.#x                // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass.getSupplier_static
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+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
+## 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: 4
+  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=2, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: aload_0
+         5: bipush        6
+         7: putfield      #x                  // Field value:I
+        10: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      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=2, locals=0, args_size=0
+         0: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+         3: dup
+         4: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1."<init>":()V
+         7: areturn
+      LineNumberTable:
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+}
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+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
+## 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: 3
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass(int);
+    descriptor: (I)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: aload_0
+         1: iload_1
+         2: invokespecial #x                  // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass."<init>":(I)V
+         5: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass;
+            0       6     1     x   I
+}
+SourceFile: "TinyFrameworkNestedClasses.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+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
+## 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: 4
+  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
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: aload_0
+         5: new           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+         8: dup
+         9: aload_0
+        10: invokespecial #x                  // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+        13: putfield      #x                 // Field mSupplier:Ljava/util/function/Supplier;
+        16: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      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=3, locals=1, args_size=1
+         0: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+         3: dup
+         4: aload_0
+         5: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+         8: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       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=2, locals=0, args_size=0
+         0: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+         3: dup
+         4: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4."<init>":()V
+         7: areturn
+      LineNumberTable:
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         0: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+         3: dup
+         4: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2."<init>":()V
+         7: putstatic     #x                 // Field sSupplier:Ljava/util/function/Supplier;
+        10: return
+      LineNumberTable:
+}
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeInvisibleAnnotations:
+  0: #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
+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
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
new file mode 100644
index 0000000..6e1528a
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-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
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public static int getOneStub();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=0, args_size=0
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+    RuntimeInvisibleAnnotations:
+      0: #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:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #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
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public static int getOne_withCheck();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=0, args_size=0
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public static int getOne_noCheck();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=0, args_size=0
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: 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:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #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:
+      0: #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
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public static int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public java.lang.String visibleButUsesUnsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+}
+SourceFile: "TinyFrameworkClassAnnotations.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestStub
+  1: #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
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public int addOneInner(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public void toBeRemoved(java.lang.String);
+    descriptor: (Ljava/lang/String;)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public static int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public java.lang.String unsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public java.lang.String visibleButUsesUnsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+}
+SourceFile: "TinyFrameworkClassClassWideAnnotations.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #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
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: 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
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+    Signature: #x                          // (Ljava/lang/Class<*>;)V
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=3, locals=0, args_size=0
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+}
+SourceFile: "TinyFrameworkClassLoadHook.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #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
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=3, locals=0, args_size=0
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+}
+SourceFile: "TinyFrameworkClassWithInitializer.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #x(#x=s#x)
+    android.hosttest.annotation.HostSideTestClassLoadHook(
+      value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+    )
+  1: #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
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public static int testException();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=0, args_size=0
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+}
+SourceFile: "TinyFrameworkExceptionTester.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #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
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public static int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public java.lang.String visibleButUsesUnsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+}
+SourceFile: "TinyFrameworkForTextPolicy.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #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
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: 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
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: 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
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+}
+SourceFile: "TinyFrameworkNative.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+  1: #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
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: 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:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #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
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: 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:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #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
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: 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
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: 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:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #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
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: 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:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #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
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: 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
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: 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
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: 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
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: 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:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #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/03-hoststubgen-test-tiny-framework-host-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
new file mode 100644
index 0000000..5672e9c
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
@@ -0,0 +1,1774 @@
+## 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: 1, attributes: 2
+  public abstract java.lang.String value();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+}
+SourceFile: "HostSideTestClassLoadHook.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+  1: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE]
+    )
+  2: #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: 0, attributes: 2
+}
+SourceFile: "HostSideTestKeep.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+  1: #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]
+    )
+  2: #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: 1, attributes: 2
+  public abstract java.lang.String value();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+}
+SourceFile: "HostSideTestNativeSubstitutionClass.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+  1: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE]
+    )
+  2: #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: 0, attributes: 2
+}
+SourceFile: "HostSideTestRemove.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+  1: #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]
+    )
+  2: #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: 0, attributes: 2
+}
+SourceFile: "HostSideTestStub.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+  1: #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]
+    )
+  2: #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: 1, attributes: 2
+  public abstract java.lang.String suffix();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+}
+SourceFile: "HostSideTestSubstitute.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+  1: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.METHOD]
+    )
+  2: #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: 0, attributes: 2
+}
+SourceFile: "HostSideTestThrow.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+  1: #x(#x=[e#x.#x,e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+    )
+  2: #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: 0, attributes: 2
+}
+SourceFile: "HostSideTestWholeClassKeep.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+  1: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE]
+    )
+  2: #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: 0, attributes: 2
+}
+SourceFile: "HostSideTestWholeClassStub.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+  1: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE]
+    )
+  2: #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: 3, attributes: 4
+  private com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl();
+    descriptor: ()V
+    flags: (0x0002) ACC_PRIVATE
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       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
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl
+         2: ldc           #x                 // String getOneKeep
+         4: ldc           #x                 // String ()I
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: iconst_1
+        16: ireturn
+      LineNumberTable:
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static int getOneStub();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         0: iconst_1
+         1: ireturn
+      LineNumberTable:
+    RuntimeInvisibleAnnotations:
+      0: #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:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #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=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck;
+
+  public static int getOne_withCheck();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         0: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.getOneKeep:()I
+         3: ireturn
+      LineNumberTable:
+
+  public static int getOne_noCheck();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         0: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.getOneStub:()I
+         3: 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:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #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:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+
+  public int keep;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         0: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
+         2: ldc           #x                 // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
+         4: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         7: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: aload_0
+         5: iconst_1
+         6: putfield      #x                 // Field stub:I
+         9: aload_0
+        10: iconst_2
+        11: putfield      #x                 // Field keep:I
+        14: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      15     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: aload_0
+         1: iload_1
+         2: invokevirtual #x                 // Method addOneInner:(I)I
+         5: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+            0       6     1 value   I
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+
+  public int addOneInner(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
+         2: ldc           #x                 // String addOneInner
+         4: ldc           #x                 // String (I)I
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: iload_1
+        16: iconst_1
+        17: iadd
+        18: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+           15       4     1 value   I
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: iload_1
+         1: iconst_2
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+            0       4     1 value   I
+
+  public static int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         0: iload_0
+         1: iconst_3
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       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
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
+         2: ldc           #x                 // String unsupportedMethod
+         4: ldc           #x                 // String ()Ljava/lang/String;
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
+        18: new           #x                 // class java/lang/RuntimeException
+        21: dup
+        22: ldc           #x                 // String Unreachable
+        24: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+        27: athrow
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestThrow
+
+  public java.lang.String visibleButUsesUnsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokevirtual #x                 // Method unsupportedMethod:()Ljava/lang/String;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+}
+SourceFile: "TinyFrameworkClassAnnotations.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestStub
+  1: #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=2, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: aload_0
+         5: iconst_1
+         6: putfield      #x                 // Field stub:I
+         9: aload_0
+        10: iconst_2
+        11: putfield      #x                 // Field keep:I
+        14: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      15     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: aload_0
+         1: iload_1
+         2: invokevirtual #x                 // Method addOneInner:(I)I
+         5: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+            0       6     1 value   I
+
+  public int addOneInner(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: iload_1
+         1: iconst_1
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+            0       4     1 value   I
+
+  public void toBeRemoved(java.lang.String);
+    descriptor: (Ljava/lang/String;)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: invokespecial #x                 // Method java/lang/RuntimeException."<init>":()V
+         7: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       8     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+            0       8     1   foo   Ljava/lang/String;
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: iload_1
+         1: iconst_2
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+            0       4     1 value   I
+
+  public static int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         0: iload_0
+         1: iconst_3
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0 value   I
+
+  public java.lang.String unsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: ldc           #x                 // String This value shouldn\'t be seen on the host side.
+         2: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       3     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+
+  public java.lang.String visibleButUsesUnsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokevirtual #x                 // Method unsupportedMethod:()Ljava/lang/String;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+}
+SourceFile: "TinyFrameworkClassClassWideAnnotations.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #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=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       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=2, locals=1, args_size=1
+         0: getstatic     #x                 // Field sLoadedClasses:Ljava/util/Set;
+         3: aload_0
+         4: invokeinterface #x,  2           // InterfaceMethod java/util/Set.add:(Ljava/lang/Object;)Z
+         9: pop
+        10: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      11     0 clazz   Ljava/lang/Class;
+      LocalVariableTypeTable:
+        Start  Length  Slot  Name   Signature
+            0      11     0 clazz   Ljava/lang/Class<*>;
+    Signature: #x                          // (Ljava/lang/Class<*>;)V
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         0: new           #x                 // class java/util/HashSet
+         3: dup
+         4: invokespecial #x                 // Method java/util/HashSet."<init>":()V
+         7: putstatic     #x                 // Field sLoadedClasses:Ljava/util/Set;
+        10: return
+      LineNumberTable:
+}
+SourceFile: "TinyFrameworkClassLoadHook.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #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=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer;
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         0: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer
+         2: ldc           #x                 // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
+         4: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         7: iconst_1
+         8: putstatic     #x                 // Field sInitialized:Z
+        11: return
+      LineNumberTable:
+}
+SourceFile: "TinyFrameworkClassWithInitializer.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #x(#x=s#x)
+    android.hosttest.annotation.HostSideTestClassLoadHook(
+      value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+    )
+  1: #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=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       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
+         0: new           #x                 // class java/lang/IllegalStateException
+         3: dup
+         4: ldc           #x                 // String Inner exception
+         6: invokespecial #x                 // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V
+         9: athrow
+        10: astore_0
+        11: new           #x                 // class java/lang/RuntimeException
+        14: dup
+        15: ldc           #x                 // String Outer exception
+        17: aload_0
+        18: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;Ljava/lang/Throwable;)V
+        21: athrow
+      Exception table:
+         from    to  target type
+             0    10    10   Class java/lang/Exception
+      StackMapTable: number_of_entries = 1
+        frame_type = 74 /* same_locals_1_stack_item */
+          stack = [ class java/lang/Exception ]
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      11     0     e   Ljava/lang/Exception;
+}
+SourceFile: "TinyFrameworkExceptionTester.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #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
+         0: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         2: ldc           #x                 // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
+         4: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         7: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPolicy();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: aload_0
+         5: iconst_1
+         6: putfield      #x                 // Field stub:I
+         9: aload_0
+        10: iconst_2
+        11: putfield      #x                 // Field keep:I
+        14: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      15     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: aload_0
+         1: iload_1
+         2: invokevirtual #x                 // Method addOneInner:(I)I
+         5: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+            0       6     1 value   I
+
+  public int addOneInner(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         2: ldc           #x                 // String addOneInner
+         4: ldc           #x                 // String (I)I
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: iload_1
+        16: iconst_1
+        17: iadd
+        18: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+           15       4     1 value   I
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: iload_1
+         1: iconst_2
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+            0       4     1 value   I
+
+  public static int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         0: iload_0
+         1: iconst_3
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       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
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         2: ldc           #x                 // String unsupportedMethod
+         4: ldc           #x                 // String ()Ljava/lang/String;
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
+        18: new           #x                 // class java/lang/RuntimeException
+        21: dup
+        22: ldc           #x                 // String Unreachable
+        24: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+        27: athrow
+
+  public java.lang.String visibleButUsesUnsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokevirtual #x                 // Method unsupportedMethod:()Ljava/lang/String;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+}
+SourceFile: "TinyFrameworkForTextPolicy.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #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=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       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
+         0: iload_0
+         1: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeAddTwo:(I)I
+         4: ireturn
+
+  public static int nativeAddTwo_should_be_like_this(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: iload_0
+         1: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeAddTwo:(I)I
+         4: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       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
+         0: lload_0
+         1: lload_2
+         2: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeLongPlus:(JJ)J
+         5: 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
+         0: lload_0
+         1: lload_2
+         2: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeLongPlus:(JJ)J
+         5: lreturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  arg1   J
+            0       6     2  arg2   J
+}
+SourceFile: "TinyFrameworkNative.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+  1: #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: 3, attributes: 3
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+         2: ldc           #x                 // String <init>
+         4: ldc           #x                 // String ()V
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: aload_0
+        16: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        19: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       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
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+         2: ldc           #x                 // String nativeAddTwo
+         4: ldc           #x                 // String (I)I
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: iload_0
+        16: iconst_2
+        17: iadd
+        18: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       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
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+         2: ldc           #x                 // String nativeLongPlus
+         4: ldc           #x                 // String (JJ)J
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: lload_0
+        16: lload_2
+        17: ladd
+        18: lreturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       4     0  arg1   J
+           15       4     2  arg2   J
+}
+SourceFile: "TinyFrameworkNative_host.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #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: 3, attributes: 6
+  final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC
+
+  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=2, locals=2, args_size=2
+         0: aload_0
+         1: aload_1
+         2: putfield      #x                 // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+         5: aload_0
+         6: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         9: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+            0      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
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+         2: ldc           #x                 // String get
+         4: ldc           #x                 // String ()Ljava/lang/Integer;
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: iconst_1
+        16: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+        19: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       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
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+         2: ldc           #x                 // String get
+         4: ldc           #x                 // String ()Ljava/lang/Object;
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: aload_0
+        16: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+        19: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       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:
+  0: #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: 3, attributes: 6
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2();
+    descriptor: ()V
+    flags: (0x0000)
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       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
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+         2: ldc           #x                 // String get
+         4: ldc           #x                 // String ()Ljava/lang/Integer;
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: iconst_2
+        16: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+        19: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       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
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+         2: ldc           #x                 // String get
+         4: ldc           #x                 // String ()Ljava/lang/Object;
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: aload_0
+        16: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+        19: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       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:
+  0: #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: 3, attributes: 6
+  final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC
+
+  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=2, locals=2, args_size=2
+         0: aload_0
+         1: aload_1
+         2: putfield      #x                 // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+         5: aload_0
+         6: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         9: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+            0      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
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+         2: ldc           #x                 // String get
+         4: ldc           #x                 // String ()Ljava/lang/Integer;
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: iconst_3
+        16: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+        19: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       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
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+         2: ldc           #x                 // String get
+         4: ldc           #x                 // String ()Ljava/lang/Object;
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: aload_0
+        16: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+        19: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       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:
+  0: #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: 3, attributes: 6
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4();
+    descriptor: ()V
+    flags: (0x0000)
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       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
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+         2: ldc           #x                 // String get
+         4: ldc           #x                 // String ()Ljava/lang/Integer;
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: iconst_4
+        16: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+        19: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       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
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+         2: ldc           #x                 // String get
+         4: ldc           #x                 // String ()Ljava/lang/Object;
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: aload_0
+        16: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+        19: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       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:
+  0: #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: 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=2, locals=2, args_size=2
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: aload_0
+         5: iload_1
+         6: putfield      #x                 // Field value:I
+         9: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass;
+            0      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:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #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=2, locals=2, args_size=2
+         0: aload_0
+         1: aload_1
+         2: putfield      #x                 // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+         5: aload_0
+         6: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         9: aload_0
+        10: iconst_5
+        11: putfield      #x                 // Field value:I
+        14: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      15     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass;
+            0      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:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #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: 3, attributes: 6
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$1();
+    descriptor: ()V
+    flags: (0x0000)
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       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
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+         2: ldc           #x                 // String get
+         4: ldc           #x                 // String ()Ljava/lang/Integer;
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: bipush        7
+        17: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+        20: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       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
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+         2: ldc           #x                 // String get
+         4: ldc           #x                 // String ()Ljava/lang/Object;
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: aload_0
+        16: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+        19: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       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:
+  0: #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: 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=2, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: aload_0
+         5: bipush        6
+         7: putfield      #x                 // Field value:I
+        10: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      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=2, locals=0, args_size=0
+         0: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+         3: dup
+         4: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1."<init>":()V
+         7: 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:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #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=2, locals=2, args_size=2
+         0: aload_0
+         1: iload_1
+         2: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass."<init>":(I)V
+         5: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass;
+            0       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:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #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
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: aload_0
+         5: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+         8: dup
+         9: aload_0
+        10: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+        13: putfield      #x                 // Field mSupplier:Ljava/util/function/Supplier;
+        16: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      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=3, locals=1, args_size=1
+         0: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+         3: dup
+         4: aload_0
+         5: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+         8: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       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=2, locals=0, args_size=0
+         0: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+         3: dup
+         4: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4."<init>":()V
+         7: areturn
+      LineNumberTable:
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         0: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+         3: dup
+         4: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2."<init>":()V
+         7: putstatic     #x                 // Field sSupplier:Ljava/util/function/Supplier;
+        10: 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:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #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/policy-override-tiny-framework.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt
new file mode 100644
index 0000000..079d2a8
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt
@@ -0,0 +1,17 @@
+class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy	stub
+  field stub	stub
+  field keep	keep
+  # field remove	remove # Implicitly remove
+  method <init>	()V	            stub
+  method addOne	(I)I	        stub
+  method addOneInner	(I)I	keep
+  method toBeRemoved	(Ljava/lang/String;)V	remove
+  method addTwo	(I)I	        @addTwo_host
+  # method addTwo_host	(I)I	# used as a substitute
+  method nativeAddThree	(I)I	@addThree_host
+  # method addThree_host	(I)I	# used as a substitute
+  method unsupportedMethod	()Ljava/lang/String;	throw
+  method visibleButUsesUnsupportedMethod	()Ljava/lang/String;	stub
+
+# Class load hook
+class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy	~com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/run-test-manually.sh b/tools/hoststubgen/hoststubgen/test-tiny-framework/run-test-manually.sh
new file mode 100755
index 0000000..fd48646
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/run-test-manually.sh
@@ -0,0 +1,132 @@
+#!/bin/bash
+# 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.
+
+
+source "${0%/*}"/../../common.sh
+
+# This scripts run the "tiny-framework" test, but does most stuff from the command line, using
+# the native java and javac commands.
+# This is useful to
+
+
+debug=0
+while getopts "d" opt; do
+case "$opt" in
+    d) debug=1 ;;
+esac
+done
+shift $(($OPTIND - 1))
+
+
+out=out
+
+rm -fr $out
+mkdir -p $out
+
+HOSTSTUBGEN=hoststubgen
+
+# Rebuild the tool and the dependencies. These are the only things we build with the build system.
+run m $HOSTSTUBGEN hoststubgen-annotations hoststubgen-helper-runtime truth-prebuilt junit
+
+
+# Build tiny-framework
+
+tiny_framework_classes=$out/tiny-framework/classes/
+tiny_framework_jar=$out/tiny-framework.jar
+tiny_framework_host_stub_jar=$out/tiny-framework_host_stub.jar
+tiny_framework_host_impl_jar=$out/tiny-framework_host_impl.jar
+
+tiny_test_classes=$out/tiny-test/classes/
+tiny_test_jar=$out/tiny-test.jar
+
+framework_compile_classpaths=(
+  $SOONG_INT/frameworks/base/tools/hoststubgen/hoststubgen/hoststubgen-annotations/android_common/javac/hoststubgen-annotations.jar
+)
+
+test_compile_classpaths=(
+  $SOONG_INT/external/junit/junit/android_common/combined/junit.jar
+  $SOONG_INT/prebuilts/tools/common/m2/truth-prebuilt/android_common/combined/truth-prebuilt.jar
+)
+
+test_runtime_classpaths=(
+  $SOONG_INT/frameworks/base/tools/hoststubgen/hoststubgen/hoststubgen-helper-runtime/linux_glibc_common/javac/hoststubgen-helper-runtime.jar
+)
+
+# This suite runs all tests in the JAR.
+test_classes=(com.android.hoststubgen.hosthelper.HostTestSuite)
+
+# Uncomment this to run a specific test.
+# tests=(com.android.hoststubgen.test.tinyframework.TinyFrameworkBenchmark)
+
+
+# Build tiny-framework.jar
+echo "# Building tiny-framework..."
+run $JAVAC \
+    -cp $( \
+        join : \
+        ${framework_compile_classpaths[@]} \
+        ) \
+    -d $tiny_framework_classes \
+    tiny-framework/src/**/*.java
+
+run $JAR cvf $tiny_framework_jar \
+    -C $tiny_framework_classes .
+
+# Build stub/impl jars
+echo "# Generating the stub and impl jars..."
+run $HOSTSTUBGEN \
+    @../hoststubgen-standard-options.txt \
+    --in-jar $tiny_framework_jar \
+    --out-stub-jar $tiny_framework_host_stub_jar \
+    --out-impl-jar $tiny_framework_host_impl_jar \
+    --policy-override-file policy-override-tiny-framework.txt \
+    --gen-keep-all-file out/tiny-framework_keep_all.txt \
+    --gen-input-dump-file out/tiny-framework_dump.txt \
+    $HOSTSTUBGEN_OPTS
+
+# Extract the jar files, so we can look into them.
+extract $tiny_framework_host_stub_jar $tiny_framework_host_impl_jar
+
+# Build the test
+echo "# Building tiny-test..."
+run $JAVAC \
+    -cp $( \
+        join : \
+        $tiny_framework_host_stub_jar \
+        "${test_compile_classpaths[@]}" \
+        ) \
+    -d $tiny_test_classes \
+    tiny-test/src/**/*.java
+
+run $JAR cvf $tiny_test_jar \
+    -C $tiny_test_classes .
+
+if (( $debug )) ; then
+  JAVA_OPTS="$JAVA_OPTS -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8700"
+fi
+
+# Run the test
+echo "# Running tiny-test..."
+run $JAVA \
+    $JAVA_OPTS \
+    -cp $( \
+        join : \
+        $tiny_test_jar \
+        $tiny_framework_host_impl_jar \
+        "${test_compile_classpaths[@]}" \
+        "${test_runtime_classpaths[@]}" \
+        ) \
+    org.junit.runner.JUnitCore \
+    ${test_classes[@]}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py
new file mode 100755
index 0000000..cee29dc
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py
@@ -0,0 +1,64 @@
+#!/usr/bin/python3
+# 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.
+
+# Compare the tiny-framework JAR dumps to the golden files.
+
+import sys
+import os
+import unittest
+import subprocess
+
+GOLDEN_DIR = 'golden-output'
+
+# Run diff.
+def run_diff(file1, file2):
+    command = ['diff', '-u', '--ignore-blank-lines', '--ignore-space-change', file1, file2]
+    print(' '.join(command))
+    result = subprocess.run(command, stderr = sys.stdout)
+
+    success = result.returncode == 0
+
+    if success:
+        print(f'No diff found.')
+    else:
+        print(f'Fail: {file1} and {file2} are different.')
+
+    return success
+
+
+# Check one golden file.
+def check_one_file(filename):
+    print(f'= Checking file: {filename}')
+    return run_diff(os.path.join(GOLDEN_DIR, filename), filename)
+
+class TestWithGoldenOutput(unittest.TestCase):
+
+    # Test to check the generated jar files to the golden output.
+    def test_compare_to_golden(self):
+        files = os.listdir(GOLDEN_DIR)
+        files.sort()
+
+        print(f"Golden files: {files}")
+        success = True
+
+        for file in files:
+            if not check_one_file(file):
+                success = False
+
+        if not success:
+            self.fail('Some files are different. See stdout log for more details.')
+
+if __name__ == "__main__":
+    unittest.main(verbosity=2)
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck.java
new file mode 100644
index 0000000..f530207
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck.java
@@ -0,0 +1,57 @@
+/*
+ * 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.test.tinyframework;
+
+import android.hosttest.annotation.HostSideTestKeep;
+import android.hosttest.annotation.HostSideTestStub;
+import android.hosttest.annotation.HostSideTestWholeClassStub;
+
+/**
+ * Used by the benchmark.
+ */
+@HostSideTestWholeClassStub
+public class TinyFrameworkCallerCheck {
+
+    /**
+     * This method uses an inner method (which has the caller check).
+     *
+     * Benchmark result: 768ns
+     */
+    public static int getOne_withCheck() {
+        return Impl.getOneKeep();
+    }
+
+    /**
+     * This method doesn't have any caller check.
+     *
+     * Benchmark result: 2ns
+     */
+    public static int getOne_noCheck() {
+        return Impl.getOneStub();
+    }
+
+    private static class Impl {
+        @HostSideTestKeep
+        public static int getOneKeep() {
+            return 1;
+        }
+
+        @HostSideTestStub
+        public static int getOneStub() {
+            return 1;
+        }
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations.java
new file mode 100644
index 0000000..ab387e0
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations.java
@@ -0,0 +1,89 @@
+/*
+ * 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.test.tinyframework;
+
+import android.hosttest.annotation.HostSideTestClassLoadHook;
+import android.hosttest.annotation.HostSideTestKeep;
+import android.hosttest.annotation.HostSideTestRemove;
+import android.hosttest.annotation.HostSideTestStub;
+import android.hosttest.annotation.HostSideTestSubstitute;
+import android.hosttest.annotation.HostSideTestThrow;
+
+/**
+ * Test without class-wide annotations.
+ */
+@HostSideTestStub
+@HostSideTestClassLoadHook(
+        "com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded")
+public class TinyFrameworkClassAnnotations {
+    @HostSideTestStub
+    public TinyFrameworkClassAnnotations() {
+    }
+
+    @HostSideTestStub
+    public int stub = 1;
+
+    @HostSideTestKeep
+    public int keep = 2;
+
+    // Members will be deleted by default.
+    // Deleted fields cannot have an initial value, because otherwise .ctor will fail to set it at
+    // runtime.
+    public int remove;
+
+    @HostSideTestStub
+    public int addOne(int value) {
+        return addOneInner(value);
+    }
+
+    @HostSideTestKeep
+    public int addOneInner(int value) {
+        return value + 1;
+    }
+
+    @HostSideTestRemove // Explicitly remove
+    public void toBeRemoved(String foo) {
+        throw new RuntimeException();
+    }
+
+    @HostSideTestStub
+    @HostSideTestSubstitute(suffix = "_host")
+    public int addTwo(int value) {
+        throw new RuntimeException("not supported on host side");
+    }
+
+    public int addTwo_host(int value) {
+        return value + 2;
+    }
+
+    @HostSideTestStub
+    @HostSideTestSubstitute(suffix = "_host")
+    public static native int nativeAddThree(int value);
+
+    public static int nativeAddThree_host(int value) {
+        return value + 3;
+    }
+
+    @HostSideTestThrow
+    public String unsupportedMethod() {
+        return "This value shouldn't be seen on the host side.";
+    }
+
+    @HostSideTestStub
+    public String visibleButUsesUnsupportedMethod() {
+        return unsupportedMethod();
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations.java
new file mode 100644
index 0000000..145b65a
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations.java
@@ -0,0 +1,74 @@
+/*
+ * 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.test.tinyframework;
+
+import android.hosttest.annotation.HostSideTestStub;
+import android.hosttest.annotation.HostSideTestSubstitute;
+import android.hosttest.annotation.HostSideTestWholeClassStub;
+
+@HostSideTestWholeClassStub
+public class TinyFrameworkClassClassWideAnnotations {
+    public TinyFrameworkClassClassWideAnnotations() {
+    }
+
+    public int stub = 1;
+
+    public int keep = 2;
+
+    // Cannot have an initial value, because otherwise .ctor will fail to set it at runtime.
+    public int remove;
+
+    // @Stub
+    public int addOne(int value) {
+        return addOneInner(value);
+    }
+
+    // @Keep
+    public int addOneInner(int value) {
+        return value + 1;
+    }
+
+    // @Remove
+    public void toBeRemoved(String foo) {
+        throw new RuntimeException();
+    }
+
+    @HostSideTestStub
+    @HostSideTestSubstitute(suffix = "_host")
+    public int addTwo(int value) {
+        throw new RuntimeException("not supported on host side");
+    }
+
+    public int addTwo_host(int value) {
+        return value + 2;
+    }
+
+    @HostSideTestStub
+    @HostSideTestSubstitute(suffix = "_host")
+    public static native int nativeAddThree(int value);
+
+    public static int nativeAddThree_host(int value) {
+        return value + 3;
+    }
+
+    public String unsupportedMethod() {
+        return "This value shouldn't be seen on the host side.";
+    }
+
+    public String visibleButUsesUnsupportedMethod() {
+        return unsupportedMethod();
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.java
new file mode 100644
index 0000000..98fc634
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.java
@@ -0,0 +1,33 @@
+/*
+ * 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.test.tinyframework;
+
+import android.hosttest.annotation.HostSideTestWholeClassStub;
+
+import java.util.HashSet;
+import java.util.Set;
+
+@HostSideTestWholeClassStub
+public class TinyFrameworkClassLoadHook {
+    private TinyFrameworkClassLoadHook() {
+    }
+
+    public static final Set<Class<?>> sLoadedClasses = new HashSet<>();
+
+    public static void onClassLoaded(Class<?> clazz) {
+        sLoadedClasses.add(clazz);
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.java
new file mode 100644
index 0000000..53cfdf6
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.java
@@ -0,0 +1,30 @@
+/*
+ * 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.test.tinyframework;
+
+import android.hosttest.annotation.HostSideTestClassLoadHook;
+import android.hosttest.annotation.HostSideTestWholeClassStub;
+
+@HostSideTestClassLoadHook(
+        "com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded")
+@HostSideTestWholeClassStub
+public class TinyFrameworkClassWithInitializer {
+    static {
+        sInitialized = true;
+    }
+
+    public static boolean sInitialized;
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.java
new file mode 100644
index 0000000..909d3b4
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.java
@@ -0,0 +1,29 @@
+/*
+ * 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.test.tinyframework;
+
+import android.hosttest.annotation.HostSideTestWholeClassStub;
+
+@HostSideTestWholeClassStub
+public class TinyFrameworkExceptionTester {
+    public static int testException() {
+        try {
+            throw new IllegalStateException("Inner exception");
+        } catch (Exception e) {
+            throw new RuntimeException("Outer exception", e);
+        }
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.java
new file mode 100644
index 0000000..bde7c35
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.java
@@ -0,0 +1,66 @@
+/*
+ * 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.test.tinyframework;
+
+/**
+ * Class for testing the "text policy" file.
+ */
+public class TinyFrameworkForTextPolicy {
+    public TinyFrameworkForTextPolicy() {
+    }
+
+    public int stub = 1;
+
+    public int keep = 2;
+
+    // Removed fields cannot have an initial value, because otherwise .ctor will fail to set it at
+    // runtime.
+    public int remove;
+
+    public int addOne(int value) {
+        return addOneInner(value);
+    }
+
+    public int addOneInner(int value) {
+        return value + 1;
+    }
+
+    public void toBeRemoved(String foo) {
+        throw new RuntimeException();
+    }
+
+    public int addTwo(int value) {
+        throw new RuntimeException("not supported on host side");
+    }
+
+    public int addTwo_host(int value) {
+        return value + 2;
+    }
+
+    public static native int nativeAddThree(int value);
+
+    public static int addThree_host(int value) {
+        return value + 3;
+    }
+
+    public String unsupportedMethod() {
+        return "This value shouldn't be seen on the host side.";
+    }
+
+    public String visibleButUsesUnsupportedMethod() {
+        return unsupportedMethod();
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.java
new file mode 100644
index 0000000..c151dcc
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.java
@@ -0,0 +1,35 @@
+/*
+ * 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.test.tinyframework;
+
+import android.hosttest.annotation.HostSideTestNativeSubstitutionClass;
+import android.hosttest.annotation.HostSideTestWholeClassStub;
+
+@HostSideTestWholeClassStub
+@HostSideTestNativeSubstitutionClass("TinyFrameworkNative_host")
+public class TinyFrameworkNative {
+    public static native int nativeAddTwo(int arg);
+
+    public static int nativeAddTwo_should_be_like_this(int arg) {
+        return TinyFrameworkNative_host.nativeAddTwo(arg);
+    }
+
+    public static native long nativeLongPlus(long arg1, long arg2);
+
+    public static long nativeLongPlus_should_be_like_this(long arg1, long arg2) {
+        return TinyFrameworkNative_host.nativeLongPlus(arg1, arg2);
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.java
new file mode 100644
index 0000000..48f7dea
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.java
@@ -0,0 +1,31 @@
+/*
+ * 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.test.tinyframework;
+
+import android.hosttest.annotation.HostSideTestWholeClassKeep;
+
+// TODO: This annotation shouldn't be needed.
+// We should infer it from HostSideTestNativeSubstitutionClass.
+@HostSideTestWholeClassKeep
+public class TinyFrameworkNative_host {
+    public static int nativeAddTwo(int arg) {
+        return arg + 2;
+    }
+
+    public static long nativeLongPlus(long arg1, long arg2) {
+        return arg1 + arg2;
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.java
new file mode 100644
index 0000000..e1c48bb
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.java
@@ -0,0 +1,87 @@
+/*
+ * 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.test.tinyframework;
+
+import android.hosttest.annotation.HostSideTestWholeClassStub;
+
+import java.util.function.Supplier;
+
+@HostSideTestWholeClassStub
+public class TinyFrameworkNestedClasses {
+    public final Supplier<Integer> mSupplier = new Supplier<Integer>() {
+        @Override
+        public Integer get() {
+            return 1;
+        }
+    };
+
+    public static final Supplier<Integer> sSupplier =  new Supplier<Integer>() {
+        @Override
+        public Integer get() {
+            return 2;
+        }
+    };
+    public Supplier<Integer> getSupplier() {
+        return new Supplier<Integer>() {
+            @Override
+            public Integer get() {
+                return 3;
+            }
+        };
+    }
+
+    public static Supplier<Integer> getSupplier_static() {
+        return new Supplier<Integer>() {
+            @Override
+            public Integer get() {
+                return 4;
+            }
+        };
+    }
+
+    @HostSideTestWholeClassStub
+    public class InnerClass {
+        public int value = 5;
+    }
+
+    @HostSideTestWholeClassStub
+    public static class StaticNestedClass {
+        public int value = 6;
+
+        // Double-nest
+        public static Supplier<Integer> getSupplier_static() {
+            return new Supplier<Integer>() {
+                @Override
+                public Integer get() {
+                    return 7;
+                }
+            };
+        }
+    }
+
+    public static class BaseClass {
+        public int value;
+        public BaseClass(int x) {
+            value = x;
+        }
+    }
+
+    public static class SubClass extends BaseClass {
+        public SubClass(int x) {
+            super(x);
+        }
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkBenchmark.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkBenchmark.java
new file mode 100644
index 0000000..6b5110e
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkBenchmark.java
@@ -0,0 +1,70 @@
+/*
+ * 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.test.tinyframework;
+
+import org.junit.Test;
+
+import java.text.DecimalFormat;
+
+/**
+ * Contains simple micro-benchmarks.
+ */
+public class TinyFrameworkBenchmark {
+    private static final int MINIMAL_ITERATION = 1000;
+    private static final int MEASURE_SECONDS = 3;
+
+    private static final DecimalFormat sFormatter = new DecimalFormat("#,###");
+
+    private void doBenchmark(String name, Runnable r) {
+        // Worm up
+        for (int i = 0; i < MINIMAL_ITERATION; i++) {
+            r.run();
+        }
+
+        // Start measuring.
+        final long start = System.nanoTime();
+        final long end = start + MEASURE_SECONDS * 1_000_000_000L;
+
+        double iteration = 0;
+        while (System.nanoTime() <= end) {
+            for (int i = 0; i < MINIMAL_ITERATION; i++) {
+                r.run();
+            }
+            iteration += MINIMAL_ITERATION;
+        }
+
+        final long realEnd = System.nanoTime();
+
+        System.out.println(String.format("%s\t%s", name,
+                sFormatter.format((((double) realEnd - start)) / iteration)));
+    }
+
+    /**
+     * Micro-benchmark for a method without a non-stub caller check.
+     */
+    @Test
+    public void benchNoCallerCheck() {
+        doBenchmark("No caller check", TinyFrameworkCallerCheck::getOne_noCheck);
+    }
+
+    /**
+     * Micro-benchmark for a method with a non-stub caller check.
+     */
+    @Test
+    public void benchWithCallerCheck() {
+        doBenchmark("With caller check", TinyFrameworkCallerCheck::getOne_withCheck);
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
new file mode 100644
index 0000000..246d065
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
@@ -0,0 +1,143 @@
+/*
+ * 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.test.tinyframework;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.SubClass;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class TinyFrameworkClassTest {
+    @Rule
+    public ExpectedException thrown = ExpectedException.none();
+
+    @Test
+    public void testSimple() {
+        TinyFrameworkForTextPolicy tfc = new TinyFrameworkForTextPolicy();
+        assertThat(tfc.addOne(1)).isEqualTo(2);
+        assertThat(tfc.stub).isEqualTo(1);
+    }
+
+//    @Test
+//    public void testDoesntCompile() {
+//        TinyFrameworkClass tfc = new TinyFrameworkClass();
+//
+//        tfc.addOneInner(1); // Shouldn't compile.
+//        tfc.toBeRemoved("abc"); // Shouldn't compile.
+//        tfc.unsupportedMethod(); // Shouldn't compile.
+//        int a = tfc.keep; // Shouldn't compile
+//        int b = tfc.remove; // Shouldn't compile
+//    }
+
+    @Test
+    public void testSubstitute() {
+        TinyFrameworkForTextPolicy tfc = new TinyFrameworkForTextPolicy();
+        assertThat(tfc.addTwo(1)).isEqualTo(3);
+    }
+
+    @Test
+    public void testSubstituteNative() {
+        TinyFrameworkForTextPolicy tfc = new TinyFrameworkForTextPolicy();
+        assertThat(tfc.nativeAddThree(1)).isEqualTo(4);
+    }
+
+    @Test
+    public void testVisibleButUsesUnsupportedMethod() {
+        TinyFrameworkForTextPolicy tfc = new TinyFrameworkForTextPolicy();
+
+        thrown.expect(RuntimeException.class);
+        thrown.expectMessage("This method is not supported on the host side");
+        tfc.visibleButUsesUnsupportedMethod();
+    }
+
+    @Test
+    public void testNestedClass1() {
+        assertThat(new TinyFrameworkNestedClasses().mSupplier.get()).isEqualTo(1);
+    }
+
+    @Test
+    public void testNestedClass2() {
+        assertThat(TinyFrameworkNestedClasses.sSupplier.get()).isEqualTo(2);
+    }
+
+    @Test
+    public void testNestedClass3() {
+        assertThat(new TinyFrameworkNestedClasses().getSupplier().get()).isEqualTo(3);
+    }
+
+    @Test
+    public void testNestedClass4() {
+        assertThat(TinyFrameworkNestedClasses.getSupplier_static().get()).isEqualTo(4);
+    }
+
+    @Test
+    public void testNestedClass5() {
+        assertThat((new TinyFrameworkNestedClasses()).new InnerClass().value).isEqualTo(5);
+    }
+
+    @Test
+    public void testNestedClass6() {
+        assertThat(new TinyFrameworkNestedClasses.StaticNestedClass().value).isEqualTo(6);
+    }
+
+    @Test
+    public void testNestedClass7() {
+        assertThat(TinyFrameworkNestedClasses.StaticNestedClass.getSupplier_static().get())
+                .isEqualTo(7);
+    }
+
+    @Test
+    public void testNativeSubstitutionClass() {
+        assertThat(TinyFrameworkNative.nativeAddTwo(3)).isEqualTo(5);
+    }
+
+    @Test
+    public void testExitLog() {
+        thrown.expect(RuntimeException.class);
+        thrown.expectMessage("Outer exception");
+
+        TinyFrameworkExceptionTester.testException();
+
+    }
+
+    @Test
+    public void testMethodCallBeforeSuperCall() {
+        assertThat(new SubClass(3).value).isEqualTo(3);
+    }
+
+    @Test
+    public void testClassLoadHook() {
+        assertThat(TinyFrameworkClassWithInitializer.sInitialized).isTrue();
+
+        // Having this line before assertThat() will ensure these class are already loaded.
+        var classes = new Class[] {
+                TinyFrameworkClassWithInitializer.class,
+                TinyFrameworkClassAnnotations.class,
+                TinyFrameworkForTextPolicy.class,
+        };
+
+        // The following classes have a class load hook, so they should be registered.
+        assertThat(TinyFrameworkClassLoadHook.sLoadedClasses)
+                .containsAnyIn(classes);
+
+        // This class doesn't have a class load hook, so shouldn't be included.
+        assertThat(TinyFrameworkClassLoadHook.sLoadedClasses)
+                .doesNotContain(TinyFrameworkNestedClasses.class);
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithAnnotTest.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithAnnotTest.java
new file mode 100644
index 0000000..20cc2ec
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithAnnotTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.test.tinyframework;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class TinyFrameworkClassWithAnnotTest {
+    @Rule
+    public ExpectedException thrown = ExpectedException.none();
+
+    @Test
+    public void testSimple() {
+        TinyFrameworkClassAnnotations tfc = new TinyFrameworkClassAnnotations();
+        assertThat(tfc.addOne(1)).isEqualTo(2);
+        assertThat(tfc.stub).isEqualTo(1);
+    }
+
+//    @Test
+//    public void testDoesntCompile() {
+//        TinyFrameworkClassWithAnnot tfc = new TinyFrameworkClassWithAnnot();
+//
+//        tfc.addOneInner(1); // Shouldn't compile.
+//        tfc.toBeRemoved("abc"); // Shouldn't compile.
+//        tfc.unsupportedMethod(); // Shouldn't compile.
+//        int a = tfc.keep; // Shouldn't compile
+//        int b = tfc.remove; // Shouldn't compile
+//    }
+
+    @Test
+    public void testSubstitute() {
+        TinyFrameworkClassAnnotations tfc = new TinyFrameworkClassAnnotations();
+        assertThat(tfc.addTwo(1)).isEqualTo(3);
+    }
+
+    @Test
+    public void testSubstituteNative() {
+        TinyFrameworkClassAnnotations tfc = new TinyFrameworkClassAnnotations();
+        assertThat(tfc.nativeAddThree(1)).isEqualTo(4);
+    }
+
+    @Test
+    public void testVisibleButUsesUnsupportedMethod() {
+        TinyFrameworkClassAnnotations tfc = new TinyFrameworkClassAnnotations();
+
+        thrown.expect(RuntimeException.class);
+        thrown.expectMessage("This method is not supported on the host side");
+        tfc.visibleButUsesUnsupportedMethod();
+    }
+}
diff --git a/tools/hoststubgen/scripts/Android.bp b/tools/hoststubgen/scripts/Android.bp
new file mode 100644
index 0000000..5da805e
--- /dev/null
+++ b/tools/hoststubgen/scripts/Android.bp
@@ -0,0 +1,26 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+sh_binary_host {
+    name: "dump-jar",
+    src: "dump-jar",
+    visibility: ["//visibility:public"],
+}
+
+genrule_defaults {
+    name: "hoststubgen-jar-dump-defaults",
+    tools: ["dump-jar"],
+    cmd: "$(location dump-jar) -s -o $(out) $(in)",
+}
+
+sh_binary_host {
+    name: "run-ravenwood-test",
+    src: "run-ravenwood-test",
+    visibility: ["//visibility:public"],
+}
diff --git a/tools/hoststubgen/scripts/build-framework-hostside-jars-and-extract.sh b/tools/hoststubgen/scripts/build-framework-hostside-jars-and-extract.sh
new file mode 100755
index 0000000..7268123
--- /dev/null
+++ b/tools/hoststubgen/scripts/build-framework-hostside-jars-and-extract.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+# 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.
+
+
+# Script to build `framework-host-stub` and `framework-host-impl`, and copy the
+# generated jars to $out, and unzip them. Useful for looking into the generated files.
+
+source "${0%/*}"/../common.sh
+
+out=framework-all-stub-out
+
+rm -fr $out
+mkdir -p $out
+
+# Build the jars with `m`.
+run m framework-all-hidden-api-host
+
+# Copy the jar to out/ and extract them.
+run cp \
+    $SOONG_INT/frameworks/base/tools/hoststubgen/hoststubgen/framework-all-hidden-api-host/linux_glibc_common/gen/* \
+    $out
+
+extract $out/*.jar
diff --git a/tools/hoststubgen/scripts/build-framework-hostside-jars-without-genrules.sh b/tools/hoststubgen/scripts/build-framework-hostside-jars-without-genrules.sh
new file mode 100755
index 0000000..c3605a9
--- /dev/null
+++ b/tools/hoststubgen/scripts/build-framework-hostside-jars-without-genrules.sh
@@ -0,0 +1,76 @@
+#!/bin/bash
+# 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.
+
+
+# Script to build hoststubgen and run it directly (without using the build rules)
+# on framework-all.jar.
+
+
+echo "THIS SCRIPT IS BROKEN DUE TO CHANGES TO FILE PATHS TO DEPENDENT FILES. FIX IT WHEN YOU NEED TO USE IT." 1>&2
+
+exit 99
+
+
+source "${0%/*}"/../common.sh
+
+out=out
+
+mkdir -p $out
+
+# Build the tool and target jar.
+run m hoststubgen framework-all
+
+base_args=(
+  @../hoststubgen/hoststubgen-standard-options.txt
+
+  --in-jar $ANDROID_BUILD_TOP/out/soong/.intermediates/frameworks/base/framework-all/android_common/combined/framework-all.jar
+  --policy-override-file ../hoststubgen/framework-policy-override.txt "${@}"
+
+  # This file will contain all classes as an annotation file, with "keep all" policy.
+  --gen-keep-all-file $out/framework-all-keep-all-policy.txt
+
+  # This file will contains dump of all classes in the input jar.
+  --gen-input-dump-file $out/framework-all-dump.txt
+)
+
+do_it() {
+  local out_file_stem="$1"
+  shift
+  local extra_args=("${@}")
+
+  run hoststubgen \
+      "${base_args[@]}" \
+      "${extra_args[@]}" \
+      --out-stub-jar ${out_file_stem}_stub.jar \
+      --out-impl-jar ${out_file_stem}_impl.jar \
+      $HOSTSTUBGEN_OPTS
+
+  # Extract the jar files, so we can look into them.
+  run extract ${out_file_stem}_*.jar
+}
+
+#-----------------------------------------------------------------------------
+# framework-all, with all hidden APIs.
+#-----------------------------------------------------------------------------
+
+# No extra args.
+do_it $out/framework-all_host
+
+#-----------------------------------------------------------------------------
+# framework-test-api, only public/system/test-APIs in the stub.
+#-----------------------------------------------------------------------------
+
+do_it $out/framework-test-api_host \
+    --intersect-stub-jar $SOONG_INT/frameworks/base/api/android_test_stubs_current/android_common/combined/*.jar
diff --git a/tools/hoststubgen/scripts/dump-jar b/tools/hoststubgen/scripts/dump-jar
new file mode 100755
index 0000000..93729fb
--- /dev/null
+++ b/tools/hoststubgen/scripts/dump-jar
@@ -0,0 +1,163 @@
+#!/bin/bash
+# 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.
+
+set -e
+
+
+help() {
+    cat <<'EOF'
+
+  dump-jar: Dump java classes in jar files
+
+    Usage:
+      dump-jar [-v] CLASS-FILE [...]
+
+        Dump a *.class file
+
+      dump-jar [-v] [-s] [-o OUTPUT-FILENAME] JAR-FILE[: filename regex] [...]
+
+        Dump a jar file.
+
+        If a filename contains a ':', then the following part
+        will be used to filter files in the jar file.
+
+        For example, "file.jar:/MyClass$" will only dump "MyClass" in file.jar.
+
+    Options:
+      -v: Enable verbose output.
+
+      -s: Simple output mode, used to check HostStubGen output jars.
+
+      -o: Write the output to a specified file.
+EOF
+}
+
+# Parse the options.
+
+verbose=0
+simple=0
+output=""
+while getopts "hvso:" opt; do
+case "$opt" in
+    h)
+        help
+        exit 0
+        ;;
+    v)
+        verbose=1
+        ;;
+    s)
+        simple=1
+        ;;
+    o)
+        output="$OPTARG"
+        ;;
+    '?')
+        help
+        exit 1
+        ;;
+esac
+done
+shift $(($OPTIND - 1))
+
+JAVAP_OPTS="${JAVAP_OPTS:--v -p -s -sysinfo -constants}"
+
+if (( $simple )) ; then
+  JAVAP_OPTS="-p -c -v"
+fi
+
+
+# Normalize a java class name.
+# Convert '.' to '/'
+# Remove the *.class suffix.
+normalize() {
+  local name="$1"
+  name="${name%.class}" # Remove the .class suffix.
+  echo "$name" | tr '.' '/'
+}
+
+# Convert the output for `-s` as needed.
+filter_output() {
+  if (( $simple )) ; then
+    # For "simple output" mode,
+    # - Normalize the constant numbers (replace with "#x")
+    # - Remove the constant pool
+    # - Remove the line number table
+    # - Some other transient lines
+    #
+    # `/PATTERN-1/,/PATTERN-1/{//!d}` is a trick to delete lines between two patterns, without
+    # the start and the end lines.
+    sed -e 's/#[0-9][0-9]*/#x/g' \
+        -e '/^Constant pool:/,/^[^ ]/{//!d}' \
+        -e '/^ *line *[0-9][0-9]*: *[0-9][0-9]*$/d' \
+        -e '/SHA-256 checksum/d' \
+        -e '/Last modified/d' \
+        -e '/^Classfile jar/d'
+  else
+    cat # Print as-is.
+  fi
+}
+
+# Write to the output file (specified with -o) as needed.
+write_to_out() {
+  if [[ -n "$output" ]] ; then
+    cat >"$output"
+    echo "Wrote output to $output" 1>&2
+  else
+    cat # print to stdout
+  fi
+}
+
+for file in "${@}"; do
+
+    # *.class?
+    if echo "$file" | grep -qE '\.class$' ; then
+        echo "# Class: $file" 1>&2
+        javap $dump_code_opt $JAVAP_OPTS $file
+
+    # *.jar?
+    elif echo "$file" | grep -qE '\.jar(:.*)?$' ; then
+        # Take the regex. Remove everything up to : in $file
+        regex=""
+        if [[ "$file" =~ : ]] ; then
+            regex="$(normalize "${file##*:}")"
+        fi
+
+        # Remove everything after ':', inclusively, in $file.
+        file="${file%:*}"
+
+        # Print the filename and the regex.
+        if ! (( $simple )) ; then
+          echo -n "# Jar: $file"
+          if [[ "$regex" != "" ]] ;then
+              echo -n "  (regex: $regex)"
+          fi
+          echo
+        fi
+
+        jar tf "$file" | grep '\.class$' | sort | while read -r class ; do
+            if normalize "$class" | grep -q -- "$regex" ; then
+                echo "## Class: $class"
+                javap $dump_code_opt $JAVAP_OPTS -cp $file ${class%.class}
+            else
+                (( $verbose )) && echo "## Skipping class: $class"
+            fi
+        done
+
+    else
+        echo "Unknown file type: $file" 1>&2
+        exit 1
+    fi
+done | filter_output | write_to_out
diff --git a/tools/hoststubgen/scripts/run-all-tests.sh b/tools/hoststubgen/scripts/run-all-tests.sh
new file mode 100755
index 0000000..6bc0ddb
--- /dev/null
+++ b/tools/hoststubgen/scripts/run-all-tests.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+# 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.
+
+source "${0%/*}"/../common.sh
+
+# Move to the top directory of hoststubgen
+cd ..
+
+# These tests are known to pass.
+READY_TEST_MODULES=(
+  HostStubGenTest-framework-all-test-host-test
+  hoststubgen-test-tiny-test
+)
+
+# First, build all the test modules. This shouldn't fail.
+run m run-ravenwood-test ${READY_TEST_MODULES[*]} ${NOT_READY_TEST_MODULES[*]}
+
+# Next, run the golden check. This should always pass too.
+# The following scripts _should_ pass too, but they depend on the internal paths to soong generated
+# files, and they may fail when something changes in the build system.
+run ./hoststubgen/test-tiny-framework/diff-and-update-golden.sh
+
+run ./hoststubgen/test-framework/run-test-without-atest.sh
+run ./hoststubgen/test-tiny-framework/run-test-manually.sh
+run ./scripts/build-framework-hostside-jars-and-extract.sh
+
+# This script is already broken on goog/master
+# run ./scripts/build-framework-hostside-jars-without-genrules.sh
+
+# These tests should all pass.
+run-ravenwood-test ${READY_TEST_MODULES[*]}
+
+echo ""${0##*/}" finished, with no unexpected failures. Ready to submit!"
\ No newline at end of file
diff --git a/tools/hoststubgen/scripts/run-ravenwood-test b/tools/hoststubgen/scripts/run-ravenwood-test
new file mode 100755
index 0000000..9bbb859
--- /dev/null
+++ b/tools/hoststubgen/scripts/run-ravenwood-test
@@ -0,0 +1,129 @@
+#!/bin/bash
+# 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.
+
+set -e
+
+# Script to run a "Ravenwood" host side test.
+#
+# A proper way to run these tests is to use `atest`, but `atest` has a known issue of loading
+# unrelated jar files as the class path, so for now we use this script to run host side tests.
+
+# Copy (with some changes) some functions from ../common.sh, so this script can be used without it.
+
+m() {
+  if (( $SKIP_BUILD )) ; then
+    echo "Skipping build: $*" 1>&2
+    return 0
+  fi
+  run ${ANDROID_BUILD_TOP}/build/soong/soong_ui.bash --make-mode "$@"
+}
+
+run() {
+  echo "Running: $*" 1>&2
+  "$@"
+}
+
+run_junit_test_jar() {
+  local jar="$1"
+  echo "Starting test: $jar ..."
+  run cd "${jar%/*}"
+
+  run ${JAVA:-java} $JAVA_OPTS \
+      -cp $jar \
+      org.junit.runner.JUnitCore \
+      com.android.hoststubgen.hosthelper.HostTestSuite || return 1
+  return 0
+}
+
+help() {
+  cat <<'EOF'
+
+  run-ravenwood-test -- Run Ravenwood host tests
+
+  Usage:
+    run-ravenwood-test [options] MODULE-NAME ...
+
+  Options:
+    -h: Help
+    -t: Run test only, without building
+    -b: Build only, without running
+
+  Example:
+    run-ravenwood-test HostStubGenTest-framework-test-host-test
+
+EOF
+}
+
+#-------------------------------------------------------------------------
+# Parse options
+#-------------------------------------------------------------------------
+build=0
+test=0
+
+while getopts "htb" opt; do
+  case "$opt" in
+    h) help; exit 0 ;;
+    t)
+      test=1
+      ;;
+    b)
+      build=1
+      ;;
+  esac
+done
+shift $(($OPTIND - 1))
+
+# If neither -t nor -b is provided, then build and run./
+if (( ( $build + $test ) == 0 )) ; then
+  build=1
+  test=1
+fi
+
+
+modules=("${@}")
+
+if (( "${#modules[@]}" == 0 )); then
+  help
+  exit 1
+fi
+
+#-------------------------------------------------------------------------
+# Build
+#-------------------------------------------------------------------------
+if (( $build )) ; then
+  run m "${modules[@]}"
+fi
+
+#-------------------------------------------------------------------------
+# Run
+#-------------------------------------------------------------------------
+
+failures=0
+if (( test )) ; then
+  for module in "${modules[@]}"; do
+    if run_junit_test_jar "$ANDROID_BUILD_TOP/out/host/linux-x86/testcases/${module}/${module}.jar"; then
+      : # passed.
+    else
+      failures=$(( failures + 1 ))
+    fi
+  done
+
+  if (( $failures > 0 )) ; then
+    echo "$failures test jar(s) failed." 1>&2
+    exit 2
+  fi
+fi
+
+exit 0
\ No newline at end of file
diff --git a/tools/split-select/Main.cpp b/tools/split-select/Main.cpp
index 1e75117..73bfa19 100644
--- a/tools/split-select/Main.cpp
+++ b/tools/split-select/Main.cpp
@@ -257,7 +257,7 @@
                 usage();
                 return 1;
             }
-            targetConfigStr.setTo(*argv);
+            targetConfigStr = *argv;
         } else if (arg == "--split") {
             argc--;
             argv++;
@@ -281,7 +281,7 @@
                 usage();
                 return 1;
             }
-            baseApkPath.setTo(*argv);
+            baseApkPath = *argv;
         } else if (arg == "--generate") {
             generateFlag = true;
         } else if (arg == "--help") {
diff --git a/tools/split-select/SplitDescription.cpp b/tools/split-select/SplitDescription.cpp
index 7150008..c02e2d7 100644
--- a/tools/split-select/SplitDescription.cpp
+++ b/tools/split-select/SplitDescription.cpp
@@ -134,10 +134,10 @@
     String8 configStr;
     String8 extensionStr;
     if (index >= 0) {
-        configStr.setTo(str.c_str(), index);
-        extensionStr.setTo(str.c_str() + index + 1);
+        configStr = String8(str.c_str(), index);
+        extensionStr = (str.c_str() + index + 1);
     } else {
-        configStr.setTo(str);
+        configStr = str;
     }
 
     SplitDescription split;