diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 0ec68d7f94e8e19545e784316de77c3612ae50e5..c35424d80dae1af081328889dd63f5daad74e327 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -15,6 +15,7 @@
 aconfig_srcjars = [
     ":android.app.usage.flags-aconfig-java{.generated_srcjars}",
     ":android.content.pm.flags-aconfig-java{.generated_srcjars}",
+    ":android.nfc.flags-aconfig-java{.generated_srcjars}",
     ":android.os.flags-aconfig-java{.generated_srcjars}",
     ":android.os.vibrator.flags-aconfig-java{.generated_srcjars}",
     ":android.security.flags-aconfig-java{.generated_srcjars}",
@@ -122,6 +123,19 @@ cc_aconfig_library {
     aconfig_declarations: "com.android.text.flags-aconfig",
 }
 
+// NFC
+aconfig_declarations {
+    name: "android.nfc.flags-aconfig",
+    package: "android.nfc",
+    srcs: ["core/java/android/nfc/*.aconfig"],
+}
+
+java_aconfig_library {
+    name: "android.nfc.flags-aconfig-java",
+    aconfig_declarations: "android.nfc.flags-aconfig",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
 // Security
 aconfig_declarations {
     name: "android.security.flags-aconfig",
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index e7ea7c2dbcbed34677183e903063e77af7b05700..a143d6fd42507ae91118a3fbbccb765c4e63af3e 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -1762,8 +1762,16 @@ public class JobSchedulerService extends com.android.server.SystemService
                 sEnqueuedJwiHighWaterMarkLogger.logSampleWithUid(uId, jobStatus.getWorkCount());
             }
 
-            FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED,
-                    uId, null, jobStatus.getBatteryName(),
+            final int sourceUid = uId;
+            FrameworkStatsLog.write(FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED,
+                    jobStatus.isProxyJob()
+                            ? new int[]{sourceUid, jobStatus.getUid()} : new int[]{sourceUid},
+                    // Given that the source tag is set by the calling app, it should be connected
+                    // to the calling app in the attribution for a proxied job.
+                    jobStatus.isProxyJob()
+                            ? new String[]{null, jobStatus.getSourceTag()}
+                            : new String[]{jobStatus.getSourceTag()},
+                    jobStatus.getBatteryName(),
                     FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__SCHEDULED,
                     JobProtoEnums.INTERNAL_STOP_REASON_UNKNOWN, jobStatus.getStandbyBucket(),
                     jobStatus.getLoggingJobId(),
@@ -2191,8 +2199,16 @@ public class JobSchedulerService extends com.android.server.SystemService
                 cancelled, reason, internalReasonCode, debugReason);
         // If the job was running, the JobServiceContext should log with state FINISHED.
         if (!wasRunning) {
-            FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED,
-                    cancelled.getSourceUid(), null, cancelled.getBatteryName(),
+            final int sourceUid = cancelled.getSourceUid();
+            FrameworkStatsLog.write(FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED,
+                    cancelled.isProxyJob()
+                            ? new int[]{sourceUid, cancelled.getUid()} : new int[]{sourceUid},
+                    // Given that the source tag is set by the calling app, it should be connected
+                    // to the calling app in the attribution for a proxied job.
+                    cancelled.isProxyJob()
+                            ? new String[]{null, cancelled.getSourceTag()}
+                            : new String[]{cancelled.getSourceTag()},
+                    cancelled.getBatteryName(),
                     FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__CANCELLED,
                     internalReasonCode, cancelled.getStandbyBucket(),
                     cancelled.getLoggingJobId(),
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index b737041f838e3d602cbc6ffc06227aa84db7bbf1..43d2ae9e077b74b5c3bb989ccd19ce61b6a85bea 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -470,8 +470,15 @@ public final class JobServiceContext implements ServiceConnection {
                 return false;
             }
             mJobPackageTracker.noteActive(job);
-            FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED,
-                    job.getSourceUid(), null, job.getBatteryName(),
+            final int sourceUid = job.getSourceUid();
+            FrameworkStatsLog.write(FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED,
+                    job.isProxyJob() ? new int[]{sourceUid, job.getUid()} : new int[]{sourceUid},
+                    // Given that the source tag is set by the calling app, it should be connected
+                    // to the calling app in the attribution for a proxied job.
+                    job.isProxyJob()
+                            ? new String[]{null, job.getSourceTag()}
+                            : new String[]{job.getSourceTag()},
+                    job.getBatteryName(),
                     FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__STARTED,
                     JobProtoEnums.INTERNAL_STOP_REASON_UNKNOWN,
                     job.getStandbyBucket(),
@@ -1531,8 +1538,16 @@ public final class JobServiceContext implements ServiceConnection {
         }
         mJobPackageTracker.noteInactive(completedJob,
                 loggingInternalStopReason, loggingDebugReason);
-        FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED,
-                completedJob.getSourceUid(), null, completedJob.getBatteryName(),
+        final int sourceUid = completedJob.getSourceUid();
+        FrameworkStatsLog.write(FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED,
+                completedJob.isProxyJob()
+                        ? new int[]{sourceUid, completedJob.getUid()} : new int[]{sourceUid},
+                // Given that the source tag is set by the calling app, it should be connected
+                // to the calling app in the attribution for a proxied job.
+                completedJob.isProxyJob()
+                        ? new String[]{null, completedJob.getSourceTag()}
+                        : new String[]{completedJob.getSourceTag()},
+                completedJob.getBatteryName(),
                 FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__FINISHED,
                 loggingInternalStopReason, completedJob.getStandbyBucket(),
                 completedJob.getLoggingJobId(),
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index e0c766f9c7679e2bdc65421601cddd8b86260941..458ff35c30ee975222e47ff1a2c0728e470c3116 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -255,6 +255,9 @@ public final class JobStatus {
 
     final String tag;
 
+    /** Whether this job was scheduled by one app on behalf of another. */
+    final boolean mIsProxyJob;
+
     private GrantedUriPermissions uriPerms;
     private boolean prepared;
 
@@ -626,6 +629,9 @@ public final class JobStatus {
                 : bnNamespace + job.getService().flattenToShortString();
         this.tag = "*job*/" + this.batteryName + "#" + job.getId();
 
+        final String componentPackage = job.getService().getPackageName();
+        mIsProxyJob = !this.sourcePackageName.equals(componentPackage);
+
         this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis;
         this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
         this.mOriginalLatestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
@@ -1048,6 +1054,11 @@ public final class JobStatus {
         return mLoggingJobId;
     }
 
+    /** Returns whether this job was scheduled by one app on behalf of another. */
+    public boolean isProxyJob() {
+        return mIsProxyJob;
+    }
+
     public void printUniqueId(PrintWriter pw) {
         if (mNamespace != null) {
             pw.print(mNamespace);
@@ -1292,6 +1303,12 @@ public final class JobStatus {
         return mNamespaceHash;
     }
 
+    /**
+     * Returns the tag passed by the calling app to describe the source app work. This is primarily
+     * only valid if {@link #isProxyJob()} returns true, but may be non-null if an app uses
+     * {@link JobScheduler#scheduleAsPackage(JobInfo, String, int, String)} for itself.
+     */
+    @Nullable
     public String getSourceTag() {
         return sourceTag;
     }
@@ -1871,9 +1888,13 @@ public final class JobStatus {
         mReadyDynamicSatisfied = mDynamicConstraints != 0
                 && mDynamicConstraints == (satisfiedConstraints & mDynamicConstraints);
         if (STATS_LOG_ENABLED && (STATSD_CONSTRAINTS_TO_LOG & constraint) != 0) {
-            FrameworkStatsLog.write_non_chained(
+            FrameworkStatsLog.write(
                     FrameworkStatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED,
-                    sourceUid, null, getBatteryName(), getProtoConstraint(constraint),
+                    isProxyJob() ? new int[]{sourceUid, getUid()} : new int[]{sourceUid},
+                    // Given that the source tag is set by the calling app, it should be connected
+                    // to the calling app in the attribution for a proxied job.
+                    isProxyJob() ? new String[]{null, sourceTag} : new String[]{sourceTag},
+                    getBatteryName(), getProtoConstraint(constraint),
                     state ? FrameworkStatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED__STATE__SATISFIED
                             : FrameworkStatsLog
                                     .SCHEDULED_JOB_CONSTRAINT_CHANGED__STATE__UNSATISFIED);
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 3de774868bb78d3bf8f0f26d879e89e9ad62bf08..9b8d2b496a302f6acf904c4de3757ee0c5a91986 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -554,6 +554,30 @@ package android.provider {
 
 }
 
+package android.se.omapi {
+
+  @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public class SeFrameworkInitializer {
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @Nullable public static android.se.omapi.SeServiceManager getSeServiceManager();
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public static void setSeServiceManager(@NonNull android.se.omapi.SeServiceManager);
+  }
+
+  @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public class SeServiceManager {
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @NonNull public android.se.omapi.SeServiceManager.ServiceRegisterer getSeManagerServiceRegisterer();
+  }
+
+  @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public static class SeServiceManager.ServiceNotFoundException extends java.lang.Exception {
+    ctor @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public SeServiceManager.ServiceNotFoundException(@NonNull String);
+  }
+
+  @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public static final class SeServiceManager.ServiceRegisterer {
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @Nullable public android.os.IBinder get();
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @NonNull public android.os.IBinder getOrThrow() throws android.se.omapi.SeServiceManager.ServiceNotFoundException;
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public void register(@NonNull android.os.IBinder);
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @Nullable public android.os.IBinder tryGet();
+  }
+
+}
+
 package android.telecom {
 
   public abstract class ConnectionService extends android.app.Service {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 69ed5aeda7de648912e90965548b62cc15fc316f..660859d6e66e469444b1faa228b703599e5c2ebf 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -9627,6 +9627,73 @@ package android.nfc {
 
 }
 
+package android.nfc.cardemulation {
+
+  @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public final class AidGroup implements android.os.Parcelable {
+    ctor @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public AidGroup(@NonNull java.util.List<java.lang.String>, @Nullable String);
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @Nullable public static android.nfc.cardemulation.AidGroup createFromXml(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public int describeContents();
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public void dump(@NonNull android.util.proto.ProtoOutputStream);
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @NonNull public java.util.List<java.lang.String> getAids();
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @NonNull public String getCategory();
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public void writeAsXml(@NonNull org.xmlpull.v1.XmlSerializer) throws java.io.IOException;
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @NonNull public static final android.os.Parcelable.Creator<android.nfc.cardemulation.AidGroup> CREATOR;
+  }
+
+  @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public final class ApduServiceInfo implements android.os.Parcelable {
+    ctor @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public ApduServiceInfo(@NonNull android.content.pm.PackageManager, @NonNull android.content.pm.ResolveInfo, boolean) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public int describeContents();
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public void dump(@NonNull android.os.ParcelFileDescriptor, @NonNull java.io.PrintWriter, @NonNull String[]);
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public void dumpDebug(@NonNull android.util.proto.ProtoOutputStream);
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @NonNull public java.util.List<android.nfc.cardemulation.AidGroup> getAidGroups();
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @NonNull public java.util.List<java.lang.String> getAids();
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @NonNull public String getCategoryForAid(@NonNull String);
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @NonNull public android.content.ComponentName getComponent();
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @NonNull public String getDescription();
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @NonNull public android.nfc.cardemulation.AidGroup getDynamicAidGroupForCategory(@NonNull String);
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @Nullable public String getOffHostSecureElement();
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @NonNull public java.util.List<java.lang.String> getPrefixAids();
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @NonNull public String getSettingsActivityName();
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @NonNull public java.util.List<java.lang.String> getSubsetAids();
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public int getUid();
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public boolean hasCategory(@NonNull String);
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public boolean isOnHost();
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @NonNull public CharSequence loadAppLabel(@NonNull android.content.pm.PackageManager);
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @NonNull public android.graphics.drawable.Drawable loadBanner(@NonNull android.content.pm.PackageManager);
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @NonNull public android.graphics.drawable.Drawable loadIcon(@NonNull android.content.pm.PackageManager);
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @NonNull public CharSequence loadLabel(@NonNull android.content.pm.PackageManager);
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @NonNull public boolean removeDynamicAidGroupForCategory(@NonNull String);
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public boolean requiresScreenOn();
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public boolean requiresUnlock();
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public void resetOffHostSecureElement();
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public void setDynamicAidGroup(@NonNull android.nfc.cardemulation.AidGroup);
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public void setOffHostSecureElement(@NonNull String);
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @NonNull public static final android.os.Parcelable.Creator<android.nfc.cardemulation.ApduServiceInfo> CREATOR;
+  }
+
+  @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public final class NfcFServiceInfo implements android.os.Parcelable {
+    ctor @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public NfcFServiceInfo(@NonNull android.content.pm.PackageManager, @NonNull android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public int describeContents();
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public void dump(@NonNull android.os.ParcelFileDescriptor, @NonNull java.io.PrintWriter, @NonNull String[]);
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public void dumpDebug(@NonNull android.util.proto.ProtoOutputStream);
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @NonNull public android.content.ComponentName getComponent();
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @NonNull public String getDescription();
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @NonNull public String getNfcid2();
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @NonNull public String getSystemCode();
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @NonNull public String getT3tPmm();
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public int getUid();
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @NonNull public android.graphics.drawable.Drawable loadIcon(@NonNull android.content.pm.PackageManager);
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @NonNull public CharSequence loadLabel(@NonNull android.content.pm.PackageManager);
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public void setDynamicNfcid2(@NonNull String);
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public void setDynamicSystemCode(@NonNull String);
+    method @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE) @NonNull public static final android.os.Parcelable.Creator<android.nfc.cardemulation.NfcFServiceInfo> CREATOR;
+  }
+
+}
+
 package android.os {
 
   public class BatteryManager {
diff --git a/core/api/system-lint-baseline.txt b/core/api/system-lint-baseline.txt
index ee031db50b620071b47d618dc65af3e188901585..b11a686d8f3260711c52a1da94bcc6096a852066 100644
--- a/core/api/system-lint-baseline.txt
+++ b/core/api/system-lint-baseline.txt
@@ -251,6 +251,18 @@ UnflaggedApi: android.net.wifi.sharedconnectivity.app.NetworkProviderInfo#isBatt
     New API must be flagged with @FlaggedApi: method android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.isBatteryCharging()
 UnflaggedApi: android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder#setBatteryCharging(boolean):
     New API must be flagged with @FlaggedApi: method android.net.wifi.sharedconnectivity.app.NetworkProviderInfo.Builder.setBatteryCharging(boolean)
+UnflaggedApi: android.nfc.cardemulation.AidGroup#CONTENTS_FILE_DESCRIPTOR:
+    New API must be flagged with @FlaggedApi: field android.nfc.cardemulation.AidGroup.CONTENTS_FILE_DESCRIPTOR
+UnflaggedApi: android.nfc.cardemulation.AidGroup#PARCELABLE_WRITE_RETURN_VALUE:
+    New API must be flagged with @FlaggedApi: field android.nfc.cardemulation.AidGroup.PARCELABLE_WRITE_RETURN_VALUE
+UnflaggedApi: android.nfc.cardemulation.ApduServiceInfo#CONTENTS_FILE_DESCRIPTOR:
+    New API must be flagged with @FlaggedApi: field android.nfc.cardemulation.ApduServiceInfo.CONTENTS_FILE_DESCRIPTOR
+UnflaggedApi: android.nfc.cardemulation.ApduServiceInfo#PARCELABLE_WRITE_RETURN_VALUE:
+    New API must be flagged with @FlaggedApi: field android.nfc.cardemulation.ApduServiceInfo.PARCELABLE_WRITE_RETURN_VALUE
+UnflaggedApi: android.nfc.cardemulation.NfcFServiceInfo#CONTENTS_FILE_DESCRIPTOR:
+    New API must be flagged with @FlaggedApi: field android.nfc.cardemulation.NfcFServiceInfo.CONTENTS_FILE_DESCRIPTOR
+UnflaggedApi: android.nfc.cardemulation.NfcFServiceInfo#PARCELABLE_WRITE_RETURN_VALUE:
+    New API must be flagged with @FlaggedApi: field android.nfc.cardemulation.NfcFServiceInfo.PARCELABLE_WRITE_RETURN_VALUE
 UnflaggedApi: android.os.BugreportParams#BUGREPORT_MODE_ONBOARDING:
     New API must be flagged with @FlaggedApi: field android.os.BugreportParams.BUGREPORT_MODE_ONBOARDING
 UnflaggedApi: android.provider.Settings#ACTION_APP_PERMISSIONS_SETTINGS:
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index b4f6d6fe770d0aa0226f50b9239fe8f38a063ebb..4f4569134c1959acc83c2a0d6ba277c65e9c2a4d 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -5192,11 +5192,21 @@ public class ActivityManager {
      * @hide
      */
     public static void broadcastStickyIntent(Intent intent, int appOp, Bundle options, int userId) {
+        broadcastStickyIntent(intent, null, appOp, options, userId);
+    }
+
+    /**
+     * Convenience for sending a sticky broadcast.  For internal use only.
+     *
+     * @hide
+     */
+    public static void broadcastStickyIntent(Intent intent, String[] excludedPackages,
+            int appOp, Bundle options, int userId) {
         try {
             getService().broadcastIntentWithFeature(
                     null, null, intent, null, null, Activity.RESULT_OK, null, null,
                     null /*requiredPermissions*/, null /*excludedPermissions*/,
-                    null /*excludedPackages*/, appOp, options, false, true, userId);
+                    excludedPackages, appOp, options, false, true, userId);
         } catch (RemoteException ex) {
         }
     }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 9f03030b35186d04f91d8b9473145917b95ddc6d..25c48e630380cb00dbe58633c04c6439ee7aa77d 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -167,6 +167,8 @@ import android.provider.Downloads;
 import android.provider.FontsContract;
 import android.provider.Settings;
 import android.renderscript.RenderScriptCacheDir;
+import android.se.omapi.SeFrameworkInitializer;
+import android.se.omapi.SeServiceManager;
 import android.security.NetworkSecurityPolicy;
 import android.security.net.config.NetworkSecurityConfigProvider;
 import android.system.ErrnoException;
@@ -8402,8 +8404,8 @@ public final class ActivityThread extends ClientTransactionHandler
             BinderCallsStats.startForBluetooth(context);
         });
         NfcFrameworkInitializer.setNfcServiceManager(new NfcServiceManager());
-
         DeviceConfigInitializer.setDeviceConfigServiceManager(new DeviceConfigServiceManager());
+        SeFrameworkInitializer.setSeServiceManager(new SeServiceManager());
     }
 
     private void purgePendingResources() {
diff --git a/core/java/android/nfc/cardemulation/AidGroup.java b/core/java/android/nfc/cardemulation/AidGroup.java
index 2436e57b74bc168dd18ab02de50f57a172e91b12..958669ee58528ff49db732c9eb823671e88cc1b1 100644
--- a/core/java/android/nfc/cardemulation/AidGroup.java
+++ b/core/java/android/nfc/cardemulation/AidGroup.java
@@ -16,7 +16,11 @@
 
 package android.nfc.cardemulation;
 
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.nfc.Flags;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Log;
@@ -29,6 +33,11 @@ import org.xmlpull.v1.XmlSerializer;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Locale;
+
+/**********************************************************************
+ * This file is not a part of the NFC mainline module                 *
+ * *******************************************************************/
 
 /**
  * The AidGroup class represents a group of Application Identifiers (AIDs).
@@ -39,28 +48,30 @@ import java.util.List;
  *
  * @hide
  */
+@SystemApi
+@FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
 public final class AidGroup implements Parcelable {
     /**
      * The maximum number of AIDs that can be present in any one group.
      */
-    public static final int MAX_NUM_AIDS = 256;
+    private static final int MAX_NUM_AIDS = 256;
+
+    private static final String TAG = "AidGroup";
 
-    static final String TAG = "AidGroup";
 
-    @UnsupportedAppUsage
-    final List<String> aids;
-    @UnsupportedAppUsage
-    final String category;
-    @UnsupportedAppUsage
-    final String description;
+    private final List<String> mAids;
+    private final String mCategory;
+    @SuppressWarnings("unused") // Unused as of now, but part of the XML input.
+    private final String mDescription;
 
     /**
      * Creates a new AidGroup object.
      *
-     * @param aids The list of AIDs present in the group
-     * @param category The category of this group, e.g. {@link CardEmulation#CATEGORY_PAYMENT}
+     * @param aids list of AIDs present in the group
+     * @param category category of this group, e.g. {@link CardEmulation#CATEGORY_PAYMENT}
      */
-    public AidGroup(List<String> aids, String category) {
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    public AidGroup(@NonNull List<String> aids, @Nullable String category) {
         if (aids == null || aids.size() == 0) {
             throw new IllegalArgumentException("No AIDS in AID group.");
         }
@@ -73,45 +84,55 @@ public final class AidGroup implements Parcelable {
             }
         }
         if (isValidCategory(category)) {
-            this.category = category;
+            this.mCategory = category;
         } else {
-            this.category = CardEmulation.CATEGORY_OTHER;
+            this.mCategory = CardEmulation.CATEGORY_OTHER;
         }
-        this.aids = new ArrayList<String>(aids.size());
+        this.mAids = new ArrayList<String>(aids.size());
         for (String aid : aids) {
-            this.aids.add(aid.toUpperCase());
+            this.mAids.add(aid.toUpperCase(Locale.US));
         }
-        this.description = null;
+        this.mDescription = null;
     }
 
-    @UnsupportedAppUsage
-    AidGroup(String category, String description) {
-        this.aids = new ArrayList<String>();
-        this.category = category;
-        this.description = description;
+    /**
+     * Creates a new AidGroup object.
+     *
+     * @param category category of this group, e.g. {@link CardEmulation#CATEGORY_PAYMENT}
+     * @param description description of this group
+     */
+    AidGroup(@NonNull String category, @NonNull String description) {
+        this.mAids = new ArrayList<String>();
+        this.mCategory = category;
+        this.mDescription = description;
     }
 
     /**
+     * Returns the category of this group.
      * @return the category of this AID group
      */
-    @UnsupportedAppUsage
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    @NonNull
     public String getCategory() {
-        return category;
+        return mCategory;
     }
 
     /**
+     * Returns the list of AIDs in this group.
+     *
      * @return the list of AIDs in this group
      */
-    @UnsupportedAppUsage
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    @NonNull
     public List<String> getAids() {
-        return aids;
+        return mAids;
     }
 
     @Override
     public String toString() {
-        StringBuilder out = new StringBuilder("Category: " + category +
-                  ", AIDs:");
-        for (String aid : aids) {
+        StringBuilder out = new StringBuilder("Category: " + mCategory
+                + ", AIDs:");
+        for (String aid : mAids) {
             out.append(aid);
             out.append(", ");
         }
@@ -119,41 +140,44 @@ public final class AidGroup implements Parcelable {
     }
 
     /**
-     * Dump debugging info as AidGroupProto
+     * Dump debugging info as AidGroupProto.
      *
      * If the output belongs to a sub message, the caller is responsible for wrapping this function
      * between {@link ProtoOutputStream#start(long)} and {@link ProtoOutputStream#end(long)}.
      *
      * @param proto the ProtoOutputStream to write to
      */
-    public void dump(ProtoOutputStream proto) {
-        proto.write(AidGroupProto.CATEGORY, category);
-        for (String aid : aids) {
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    public void dump(@NonNull ProtoOutputStream proto) {
+        proto.write(AidGroupProto.CATEGORY, mCategory);
+        for (String aid : mAids) {
             proto.write(AidGroupProto.AIDS, aid);
         }
     }
 
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
     @Override
     public int describeContents() {
         return 0;
     }
 
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
     @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(category);
-        dest.writeInt(aids.size());
-        if (aids.size() > 0) {
-            dest.writeStringList(aids);
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeString8(mCategory);
+        dest.writeInt(mAids.size());
+        if (mAids.size() > 0) {
+            dest.writeStringList(mAids);
         }
     }
 
-    @UnsupportedAppUsage
-    public static final @android.annotation.NonNull Parcelable.Creator<AidGroup> CREATOR =
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    public static final @NonNull Parcelable.Creator<AidGroup> CREATOR =
             new Parcelable.Creator<AidGroup>() {
 
         @Override
         public AidGroup createFromParcel(Parcel source) {
-            String category = source.readString();
+            String category = source.readString8();
             int listSize = source.readInt();
             ArrayList<String> aidList = new ArrayList<String>();
             if (listSize > 0) {
@@ -168,8 +192,17 @@ public final class AidGroup implements Parcelable {
         }
     };
 
-    @UnsupportedAppUsage
-    static public AidGroup createFromXml(XmlPullParser parser) throws XmlPullParserException, IOException {
+    /**
+     * Create an instance of AID group from XML file.
+     *
+     * @param parser input xml parser stream
+     * @throws XmlPullParserException If an error occurs parsing the element.
+     * @throws IOException If an error occurs reading the element.
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    @Nullable
+    public static AidGroup createFromXml(@NonNull XmlPullParser parser)
+            throws XmlPullParserException, IOException {
         String category = null;
         ArrayList<String> aids = new ArrayList<String>();
         AidGroup group = null;
@@ -210,11 +243,16 @@ public final class AidGroup implements Parcelable {
         return group;
     }
 
-    @UnsupportedAppUsage
-    public void writeAsXml(XmlSerializer out) throws IOException {
+    /**
+     * Serialize instance of AID group to XML file.
+     * @param out XML serializer stream
+     * @throws IOException If an error occurs reading the element.
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    public void writeAsXml(@NonNull XmlSerializer out) throws IOException {
         out.startTag(null, "aid-group");
-        out.attribute(null, "category", category);
-        for (String aid : aids) {
+        out.attribute(null, "category", mCategory);
+        for (String aid : mAids) {
             out.startTag(null, "aid");
             out.attribute(null, "value", aid);
             out.endTag(null, "aid");
@@ -222,7 +260,7 @@ public final class AidGroup implements Parcelable {
         out.endTag(null, "aid-group");
     }
 
-    static boolean isValidCategory(String category) {
+    private static boolean isValidCategory(String category) {
         return CardEmulation.CATEGORY_PAYMENT.equals(category) ||
                 CardEmulation.CATEGORY_OTHER.equals(category);
     }
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index 793a70e93f56c3cb3343ce4127623f10371a2a47..18ec914860fb77a982fdc7f9e6dd0deba72dce37 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -14,10 +14,16 @@
  * limitations under the License.
  */
 
+/**********************************************************************
+ * This file is not a part of the NFC mainline module                 *
+ * *******************************************************************/
+
 package android.nfc.cardemulation;
 
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.SystemApi;
 import android.content.ComponentName;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -28,7 +34,9 @@ import android.content.res.Resources.NotFoundException;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Drawable;
+import android.nfc.Flags;
 import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -38,7 +46,6 @@ import android.util.proto.ProtoOutputStream;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -47,82 +54,82 @@ import java.util.List;
 import java.util.Map;
 
 /**
+ * Class holding APDU service info.
+ *
  * @hide
  */
+@SystemApi
+@FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
 public final class ApduServiceInfo implements Parcelable {
-    static final String TAG = "ApduServiceInfo";
+    private static final String TAG = "ApduServiceInfo";
 
     /**
      * The service that implements this
      */
-    @UnsupportedAppUsage
-    final ResolveInfo mService;
+    private final ResolveInfo mService;
 
     /**
      * Description of the service
      */
-    final String mDescription;
+    private final String mDescription;
 
     /**
      * Whether this service represents AIDs running on the host CPU
      */
-    final boolean mOnHost;
+    private final boolean mOnHost;
 
     /**
      * Offhost reader name.
      * eg: SIM, eSE etc
      */
-    String mOffHostName;
+    private String mOffHostName;
 
     /**
      * Offhost reader name from manifest file.
-     * Used for unsetOffHostSecureElement()
+     * Used for resetOffHostSecureElement()
      */
-    final String mStaticOffHostName;
+    private final String mStaticOffHostName;
 
     /**
      * Mapping from category to static AID group
      */
-    @UnsupportedAppUsage
-    final HashMap<String, AidGroup> mStaticAidGroups;
+    private final HashMap<String, AidGroup> mStaticAidGroups;
 
     /**
      * Mapping from category to dynamic AID group
      */
-    @UnsupportedAppUsage
-    final HashMap<String, AidGroup> mDynamicAidGroups;
+    private final HashMap<String, AidGroup> mDynamicAidGroups;
 
     /**
      * Whether this service should only be started when the device is unlocked.
      */
-    final boolean mRequiresDeviceUnlock;
+    private final boolean mRequiresDeviceUnlock;
 
     /**
      * Whether this service should only be started when the device is screen on.
      */
-    final boolean mRequiresDeviceScreenOn;
+    private final boolean mRequiresDeviceScreenOn;
 
     /**
      * The id of the service banner specified in XML.
      */
-    final int mBannerResourceId;
+    private final int mBannerResourceId;
 
     /**
      * The uid of the package the service belongs to
      */
-    final int mUid;
+    private final int mUid;
 
     /**
      * Settings Activity for this service
      */
-    final String mSettingsActivityName;
+    private final String mSettingsActivityName;
 
     /**
      * @hide
      */
-    @UnsupportedAppUsage
     public ApduServiceInfo(ResolveInfo info, boolean onHost, String description,
-            ArrayList<AidGroup> staticAidGroups, ArrayList<AidGroup> dynamicAidGroups,
+            List<AidGroup> staticAidGroups, List<AidGroup> dynamicAidGroups,
             boolean requiresUnlock, int bannerResource, int uid,
             String settingsActivityName, String offHost, String staticOffHost) {
         this(info, onHost, description, staticAidGroups, dynamicAidGroups,
@@ -134,7 +141,7 @@ public final class ApduServiceInfo implements Parcelable {
      * @hide
      */
     public ApduServiceInfo(ResolveInfo info, boolean onHost, String description,
-            ArrayList<AidGroup> staticAidGroups, ArrayList<AidGroup> dynamicAidGroups,
+            List<AidGroup> staticAidGroups, List<AidGroup> dynamicAidGroups,
             boolean requiresUnlock, boolean requiresScreenOn, int bannerResource, int uid,
             String settingsActivityName, String offHost, String staticOffHost) {
         this.mService = info;
@@ -147,19 +154,28 @@ public final class ApduServiceInfo implements Parcelable {
         this.mRequiresDeviceUnlock = requiresUnlock;
         this.mRequiresDeviceScreenOn = requiresScreenOn;
         for (AidGroup aidGroup : staticAidGroups) {
-            this.mStaticAidGroups.put(aidGroup.category, aidGroup);
+            this.mStaticAidGroups.put(aidGroup.getCategory(), aidGroup);
         }
         for (AidGroup aidGroup : dynamicAidGroups) {
-            this.mDynamicAidGroups.put(aidGroup.category, aidGroup);
+            this.mDynamicAidGroups.put(aidGroup.getCategory(), aidGroup);
         }
         this.mBannerResourceId = bannerResource;
         this.mUid = uid;
         this.mSettingsActivityName = settingsActivityName;
     }
 
-    @UnsupportedAppUsage
-    public ApduServiceInfo(PackageManager pm, ResolveInfo info, boolean onHost) throws
-            XmlPullParserException, IOException {
+    /**
+     * Creates a new ApduServiceInfo object.
+     *
+     * @param pm packageManager instance
+     * @param info app component info
+     * @param onHost whether service is on host or not (secure element)
+     * @throws XmlPullParserException If an error occurs parsing the element.
+     * @throws IOException If an error occurs reading the element.
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    public ApduServiceInfo(@NonNull PackageManager pm, @NonNull ResolveInfo info, boolean onHost)
+            throws XmlPullParserException, IOException {
         ServiceInfo si = info.serviceInfo;
         XmlResourceParser parser = null;
         try {
@@ -277,9 +293,9 @@ public final class ApduServiceInfo implements Parcelable {
                     groupAttrs.recycle();
                 } else if (eventType == XmlPullParser.END_TAG && "aid-group".equals(tagName) &&
                         currentGroup != null) {
-                    if (currentGroup.aids.size() > 0) {
-                        if (!mStaticAidGroups.containsKey(currentGroup.category)) {
-                            mStaticAidGroups.put(currentGroup.category, currentGroup);
+                    if (currentGroup.getAids().size() > 0) {
+                        if (!mStaticAidGroups.containsKey(currentGroup.getCategory())) {
+                            mStaticAidGroups.put(currentGroup.getCategory(), currentGroup);
                         }
                     } else {
                         Log.e(TAG, "Not adding <aid-group> with empty or invalid AIDs");
@@ -291,8 +307,8 @@ public final class ApduServiceInfo implements Parcelable {
                             com.android.internal.R.styleable.AidFilter);
                     String aid = a.getString(com.android.internal.R.styleable.AidFilter_name).
                             toUpperCase();
-                    if (CardEmulation.isValidAid(aid) && !currentGroup.aids.contains(aid)) {
-                        currentGroup.aids.add(aid);
+                    if (CardEmulation.isValidAid(aid) && !currentGroup.getAids().contains(aid)) {
+                        currentGroup.getAids().add(aid);
                     } else {
                         Log.e(TAG, "Ignoring invalid or duplicate aid: " + aid);
                     }
@@ -305,8 +321,8 @@ public final class ApduServiceInfo implements Parcelable {
                             toUpperCase();
                     // Add wildcard char to indicate prefix
                     aid = aid.concat("*");
-                    if (CardEmulation.isValidAid(aid) && !currentGroup.aids.contains(aid)) {
-                        currentGroup.aids.add(aid);
+                    if (CardEmulation.isValidAid(aid) && !currentGroup.getAids().contains(aid)) {
+                        currentGroup.getAids().add(aid);
                     } else {
                         Log.e(TAG, "Ignoring invalid or duplicate aid: " + aid);
                     }
@@ -319,8 +335,8 @@ public final class ApduServiceInfo implements Parcelable {
                             toUpperCase();
                     // Add wildcard char to indicate suffix
                     aid = aid.concat("#");
-                    if (CardEmulation.isValidAid(aid) && !currentGroup.aids.contains(aid)) {
-                        currentGroup.aids.add(aid);
+                    if (CardEmulation.isValidAid(aid) && !currentGroup.getAids().contains(aid)) {
+                        currentGroup.getAids().add(aid);
                     } else {
                         Log.e(TAG, "Ignoring invalid or duplicate aid: " + aid);
                     }
@@ -336,11 +352,25 @@ public final class ApduServiceInfo implements Parcelable {
         mUid = si.applicationInfo.uid;
     }
 
+    /**
+     * Returns the app component corresponding to this APDU service.
+     *
+     * @return app component for this service
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    @NonNull
     public ComponentName getComponent() {
         return new ComponentName(mService.serviceInfo.packageName,
                 mService.serviceInfo.name);
     }
 
+    /**
+     * Returns the offhost secure element name (if the service is offhost).
+     *
+     * @return offhost secure element name for offhost services
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    @Nullable
     public String getOffHostSecureElement() {
         return mOffHostName;
     }
@@ -353,18 +383,30 @@ public final class ApduServiceInfo implements Parcelable {
      * for that category.
      * @return List of AIDs registered by the service
      */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    @NonNull
     public List<String> getAids() {
         final ArrayList<String> aids = new ArrayList<String>();
         for (AidGroup group : getAidGroups()) {
-            aids.addAll(group.aids);
+            aids.addAll(group.getAids());
         }
         return aids;
     }
 
+    /**
+     * Returns a consolidated list of AIDs with prefixes from the AID groups
+     * registered by this service. Note that if a service has both
+     * a static (manifest-based) AID group for a category and a dynamic
+     * AID group, only the dynamically registered AIDs will be returned
+     * for that category.
+     * @return List of prefix AIDs registered by the service
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    @NonNull
     public List<String> getPrefixAids() {
         final ArrayList<String> prefixAids = new ArrayList<String>();
         for (AidGroup group : getAidGroups()) {
-            for (String aid : group.aids) {
+            for (String aid : group.getAids()) {
                 if (aid.endsWith("*")) {
                     prefixAids.add(aid);
                 }
@@ -373,10 +415,20 @@ public final class ApduServiceInfo implements Parcelable {
         return prefixAids;
     }
 
+    /**
+     * Returns a consolidated list of AIDs with subsets from the AID groups
+     * registered by this service. Note that if a service has both
+     * a static (manifest-based) AID group for a category and a dynamic
+     * AID group, only the dynamically registered AIDs will be returned
+     * for that category.
+     * @return List of prefix AIDs registered by the service
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    @NonNull
     public List<String> getSubsetAids() {
         final ArrayList<String> subsetAids = new ArrayList<String>();
         for (AidGroup group : getAidGroups()) {
-            for (String aid : group.aids) {
+            for (String aid : group.getAids()) {
                 if (aid.endsWith("#")) {
                     subsetAids.add(aid);
                 }
@@ -384,14 +436,28 @@ public final class ApduServiceInfo implements Parcelable {
         }
         return subsetAids;
     }
+
     /**
      * Returns the registered AID group for this category.
+     *
+     * @param category category name
+     * @return {@link AidGroup} instance for the provided category
      */
-    public AidGroup getDynamicAidGroupForCategory(String category) {
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    @NonNull
+    public AidGroup getDynamicAidGroupForCategory(@NonNull String category) {
         return mDynamicAidGroups.get(category);
     }
 
-    public boolean removeDynamicAidGroupForCategory(String category) {
+    /**
+     * Removes the registered AID group for this category.
+     *
+     * @param category category name
+     * @return {@code true} if an AID group existed
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    @NonNull
+    public boolean removeDynamicAidGroupForCategory(@NonNull String category) {
         return (mDynamicAidGroups.remove(category) != null);
     }
 
@@ -403,7 +469,9 @@ public final class ApduServiceInfo implements Parcelable {
      * for that category.
      * @return List of AIDs registered by the service
      */
-    public ArrayList<AidGroup> getAidGroups() {
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    @NonNull
+    public List<AidGroup> getAidGroups() {
         final ArrayList<AidGroup> groups = new ArrayList<AidGroup>();
         for (Map.Entry<String, AidGroup> entry : mDynamicAidGroups.entrySet()) {
             groups.add(entry.getValue());
@@ -421,49 +489,83 @@ public final class ApduServiceInfo implements Parcelable {
     /**
      * Returns the category to which this service has attributed the AID that is passed in,
      * or null if we don't know this AID.
+     * @param aid AID to lookup for
+     * @return category name corresponding to this AID
      */
-    public String getCategoryForAid(String aid) {
-        ArrayList<AidGroup> groups = getAidGroups();
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    @NonNull
+    public String getCategoryForAid(@NonNull String aid) {
+        List<AidGroup> groups = getAidGroups();
         for (AidGroup group : groups) {
-            if (group.aids.contains(aid.toUpperCase())) {
-                return group.category;
+            if (group.getAids().contains(aid.toUpperCase())) {
+                return group.getCategory();
             }
         }
         return null;
     }
 
-    public boolean hasCategory(String category) {
+    /**
+     * Returns whether there is any AID group for this category.
+     * @param category category name
+     * @return {@code true} if an AID group exists
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    public boolean hasCategory(@NonNull String category) {
         return (mStaticAidGroups.containsKey(category) || mDynamicAidGroups.containsKey(category));
     }
 
-    @UnsupportedAppUsage
+    /**
+     * Returns whether the service is on host or not.
+     * @return true if the service is on host (not secure element)
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
     public boolean isOnHost() {
         return mOnHost;
     }
 
-    @UnsupportedAppUsage
+    /**
+     * Returns whether the service requires device unlock.
+     * @return whether the service requires device unlock
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
     public boolean requiresUnlock() {
         return mRequiresDeviceUnlock;
     }
 
     /**
      * Returns whether this service should only be started when the device is screen on.
+     * @return whether the service requires screen on
      */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
     public boolean requiresScreenOn() {
         return mRequiresDeviceScreenOn;
     }
 
-    @UnsupportedAppUsage
+    /**
+     * Returns description of service.
+     * @return user readable description of service
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    @NonNull
     public String getDescription() {
         return mDescription;
     }
 
-    @UnsupportedAppUsage
+    /**
+     * Returns uid of service.
+     * @return uid of the service
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
     public int getUid() {
         return mUid;
     }
 
-    public void setOrReplaceDynamicAidGroup(AidGroup aidGroup) {
+    /**
+     * Add or replace an AID group to this service.
+     * @param aidGroup instance of aid group to set or replace
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    public void setDynamicAidGroup(@NonNull AidGroup aidGroup) {
         mDynamicAidGroups.put(aidGroup.getCategory(), aidGroup);
     }
 
@@ -476,7 +578,8 @@ public final class ApduServiceInfo implements Parcelable {
      *                  TS26_NFC_REQ_070: For embedded SE, Secure Element Name SHALL be eSE[number]
      *                                    (e.g. eSE/eSE1, eSE2, etc.).
      */
-    public void setOffHostSecureElement(String offHost) {
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    public void setOffHostSecureElement(@NonNull String offHost) {
         mOffHostName = offHost;
     }
 
@@ -484,15 +587,30 @@ public final class ApduServiceInfo implements Parcelable {
      * Resets the off host Secure Element to statically defined
      * by the service in the manifest file.
      */
-    public void unsetOffHostSecureElement() {
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    public void resetOffHostSecureElement() {
         mOffHostName = mStaticOffHostName;
     }
 
-    public CharSequence loadLabel(PackageManager pm) {
+    /**
+     * Load label for this service.
+     * @param pm packagemanager instance
+     * @return label name corresponding to service
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    @NonNull
+    public CharSequence loadLabel(@NonNull PackageManager pm) {
         return mService.loadLabel(pm);
     }
 
-    public CharSequence loadAppLabel(PackageManager pm) {
+    /**
+     * Load application label for this service.
+     * @param pm packagemanager instance
+     * @return app label name corresponding to service
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    @NonNull
+    public CharSequence loadAppLabel(@NonNull PackageManager pm) {
         try {
             return pm.getApplicationLabel(pm.getApplicationInfo(
                     mService.resolvePackageName, PackageManager.GET_META_DATA));
@@ -501,12 +619,25 @@ public final class ApduServiceInfo implements Parcelable {
         }
     }
 
-    public Drawable loadIcon(PackageManager pm) {
+    /**
+     * Load application icon for this service.
+     * @param pm packagemanager instance
+     * @return app icon corresponding to service
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    @NonNull
+    public Drawable loadIcon(@NonNull PackageManager pm) {
         return mService.loadIcon(pm);
     }
 
-    @UnsupportedAppUsage
-    public Drawable loadBanner(PackageManager pm) {
+    /**
+     * Load application banner for this service.
+     * @param pm packagemanager instance
+     * @return app banner corresponding to service
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    @NonNull
+    public Drawable loadBanner(@NonNull PackageManager pm) {
         Resources res;
         try {
             res = pm.getResourcesForApplication(mService.serviceInfo.packageName);
@@ -521,7 +652,12 @@ public final class ApduServiceInfo implements Parcelable {
         }
     }
 
-    @UnsupportedAppUsage
+    /**
+     * Load activity name for this service.
+     * @return activity name for this service
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    @NonNull
     public String getSettingsActivityName() { return mSettingsActivityName; }
 
     @Override
@@ -556,14 +692,15 @@ public final class ApduServiceInfo implements Parcelable {
         return getComponent().hashCode();
     }
 
-
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
     @Override
     public int describeContents() {
         return 0;
     }
 
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
     @Override
-    public void writeToParcel(Parcel dest, int flags) {
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         mService.writeToParcel(dest, flags);
         dest.writeString(mDescription);
         dest.writeInt(mOnHost ? 1 : 0);
@@ -584,8 +721,8 @@ public final class ApduServiceInfo implements Parcelable {
         dest.writeString(mSettingsActivityName);
     };
 
-    @UnsupportedAppUsage
-    public static final @android.annotation.NonNull Parcelable.Creator<ApduServiceInfo> CREATOR =
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    public static final @NonNull Parcelable.Creator<ApduServiceInfo> CREATOR =
             new Parcelable.Creator<ApduServiceInfo>() {
         @Override
         public ApduServiceInfo createFromParcel(Parcel source) {
@@ -620,7 +757,15 @@ public final class ApduServiceInfo implements Parcelable {
         }
     };
 
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+    /**
+     * Dump contents for debugging.
+     * @param fd parcelfiledescriptor instance
+     * @param pw printwriter instance
+     * @param args args for dumping
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    public void dump(@NonNull ParcelFileDescriptor fd, @NonNull PrintWriter pw,
+                     @NonNull String[] args) {
         pw.println("    " + getComponent()
                 + " (Description: " + getDescription() + ")"
                 + " (UID: " + getUid() + ")");
@@ -633,15 +778,15 @@ public final class ApduServiceInfo implements Parcelable {
         }
         pw.println("    Static AID groups:");
         for (AidGroup group : mStaticAidGroups.values()) {
-            pw.println("        Category: " + group.category);
-            for (String aid : group.aids) {
+            pw.println("        Category: " + group.getCategory());
+            for (String aid : group.getAids()) {
                 pw.println("            AID: " + aid);
             }
         }
         pw.println("    Dynamic AID groups:");
         for (AidGroup group : mDynamicAidGroups.values()) {
-            pw.println("        Category: " + group.category);
-            for (String aid : group.aids) {
+            pw.println("        Category: " + group.getCategory());
+            for (String aid : group.getAids()) {
                 pw.println("            AID: " + aid);
             }
         }
@@ -651,7 +796,7 @@ public final class ApduServiceInfo implements Parcelable {
     }
 
     /**
-     * Dump debugging info as ApduServiceInfoProto
+     * Dump debugging info as ApduServiceInfoProto.
      *
      * If the output belongs to a sub message, the caller is responsible for wrapping this function
      * between {@link ProtoOutputStream#start(long)} and {@link ProtoOutputStream#end(long)}.
@@ -659,7 +804,8 @@ public final class ApduServiceInfo implements Parcelable {
      *
      * @param proto the ProtoOutputStream to write to
      */
-    public void dumpDebug(ProtoOutputStream proto) {
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    public void dumpDebug(@NonNull ProtoOutputStream proto) {
         Utils.dumpDebugComponentName(getComponent(), proto, ApduServiceInfoProto.COMPONENT_NAME);
         proto.write(ApduServiceInfoProto.DESCRIPTION, getDescription());
         proto.write(ApduServiceInfoProto.ON_HOST, mOnHost);
diff --git a/core/java/android/nfc/cardemulation/NfcFServiceInfo.java b/core/java/android/nfc/cardemulation/NfcFServiceInfo.java
index 7a36b269240cd38578fee8751c671acf20f669b6..ec919e4d66bc334f80d42a5d5703f9744e62f8af 100644
--- a/core/java/android/nfc/cardemulation/NfcFServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/NfcFServiceInfo.java
@@ -14,9 +14,16 @@
  * limitations under the License.
  */
 
+/**********************************************************************
+ * This file is not a part of the NFC mainline module                 *
+ * *******************************************************************/
+
 package android.nfc.cardemulation;
 
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.content.ComponentName;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -26,7 +33,9 @@ import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Drawable;
+import android.nfc.Flags;
 import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -36,13 +45,16 @@ import android.util.proto.ProtoOutputStream;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
 
 /**
+ * Class to hold NfcF service info.
+ *
  * @hide
  */
+@SystemApi
+@FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
 public final class NfcFServiceInfo implements Parcelable {
     static final String TAG = "NfcFServiceInfo";
 
@@ -51,42 +63,42 @@ public final class NfcFServiceInfo implements Parcelable {
     /**
      * The service that implements this
      */
-    final ResolveInfo mService;
+    private final ResolveInfo mService;
 
     /**
      * Description of the service
      */
-    final String mDescription;
+    private final String mDescription;
 
     /**
      * System Code of the service
      */
-    final String mSystemCode;
+    private final String mSystemCode;
 
     /**
      * System Code of the service registered by API
      */
-    String mDynamicSystemCode;
+    private String mDynamicSystemCode;
 
     /**
      * NFCID2 of the service
      */
-    final String mNfcid2;
+    private final String mNfcid2;
 
     /**
      * NFCID2 of the service registered by API
      */
-    String mDynamicNfcid2;
+    private String mDynamicNfcid2;
 
     /**
      * The uid of the package the service belongs to
      */
-    final int mUid;
+    private final int mUid;
 
     /**
      * LF_T3T_PMM of the service
      */
-    final String mT3tPmm;
+    private final String mT3tPmm;
 
     /**
      * @hide
@@ -104,7 +116,16 @@ public final class NfcFServiceInfo implements Parcelable {
         this.mT3tPmm = t3tPmm;
     }
 
-    public NfcFServiceInfo(PackageManager pm, ResolveInfo info)
+    /**
+     * Creates a new NfcFServiceInfo object.
+     *
+     * @param pm packageManager instance
+     * @param info app component info
+     * @throws XmlPullParserException If an error occurs parsing the element.
+     * @throws IOException If an error occurs reading the element.
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    public NfcFServiceInfo(@NonNull PackageManager pm, @NonNull ResolveInfo info)
             throws XmlPullParserException, IOException {
         ServiceInfo si = info.serviceInfo;
         XmlResourceParser parser = null;
@@ -192,44 +213,107 @@ public final class NfcFServiceInfo implements Parcelable {
         mUid = si.applicationInfo.uid;
     }
 
+    /**
+     * Returns the app component corresponding to this NFCF service.
+     *
+     * @return app component for this service
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    @NonNull
     public ComponentName getComponent() {
         return new ComponentName(mService.serviceInfo.packageName,
                 mService.serviceInfo.name);
     }
 
+    /**
+     * Returns the system code corresponding to this service.
+     *
+     * @return system code for this service
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    @NonNull
     public String getSystemCode() {
         return (mDynamicSystemCode == null ? mSystemCode : mDynamicSystemCode);
     }
 
-    public void setOrReplaceDynamicSystemCode(String systemCode) {
+    /**
+     * Add or replace a system code to this service.
+     * @param systemCode system code to set or replace
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    public void setDynamicSystemCode(@NonNull String systemCode) {
         mDynamicSystemCode = systemCode;
     }
 
+    /**
+     * Returns NFC ID2.
+     *
+     * @return nfc id2 to return
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    @NonNull
     public String getNfcid2() {
         return (mDynamicNfcid2 == null ? mNfcid2 : mDynamicNfcid2);
     }
 
-    public void setOrReplaceDynamicNfcid2(String nfcid2) {
+    /**
+     * Set or replace NFC ID2
+     *
+     * @param nfcid2 NFC ID2 string
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    public void setDynamicNfcid2(@NonNull String nfcid2) {
         mDynamicNfcid2 = nfcid2;
     }
 
+    /**
+     * Returns description of service.
+     * @return user readable description of service
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    @NonNull
     public String getDescription() {
         return mDescription;
     }
 
+    /**
+     * Returns uid of service.
+     * @return uid of the service
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
     public int getUid() {
         return mUid;
     }
 
+    /**
+     * Returns LF_T3T_PMM of the service
+     * @return returns LF_T3T_PMM of the service
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    @NonNull
     public String getT3tPmm() {
         return mT3tPmm;
     }
 
-    public CharSequence loadLabel(PackageManager pm) {
+    /**
+     * Load application label for this service.
+     * @param pm packagemanager instance
+     * @return label name corresponding to service
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    @NonNull
+    public CharSequence loadLabel(@NonNull PackageManager pm) {
         return mService.loadLabel(pm);
     }
 
-    public Drawable loadIcon(PackageManager pm) {
+    /**
+     * Load application icon for this service.
+     * @param pm packagemanager instance
+     * @return app icon corresponding to service
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    @NonNull
+    public Drawable loadIcon(@NonNull PackageManager pm) {
         return mService.loadIcon(pm);
     }
 
@@ -270,13 +354,15 @@ public final class NfcFServiceInfo implements Parcelable {
         return getComponent().hashCode();
     }
 
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
     @Override
     public int describeContents() {
         return 0;
     }
 
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
     @Override
-    public void writeToParcel(Parcel dest, int flags) {
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         mService.writeToParcel(dest, flags);
         dest.writeString(mDescription);
         dest.writeString(mSystemCode);
@@ -293,7 +379,8 @@ public final class NfcFServiceInfo implements Parcelable {
         dest.writeString(mT3tPmm);
     };
 
-    public static final @android.annotation.NonNull Parcelable.Creator<NfcFServiceInfo> CREATOR =
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    public static final @NonNull Parcelable.Creator<NfcFServiceInfo> CREATOR =
             new Parcelable.Creator<NfcFServiceInfo>() {
         @Override
         public NfcFServiceInfo createFromParcel(Parcel source) {
@@ -322,7 +409,15 @@ public final class NfcFServiceInfo implements Parcelable {
         }
     };
 
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+    /**
+     * Dump contents of the service for debugging.
+     * @param fd parcelfiledescriptor instance
+     * @param pw printwriter instance
+     * @param args args for dumping
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    public void dump(@NonNull ParcelFileDescriptor fd, @NonNull PrintWriter pw,
+                     @NonNull String[] args) {
         pw.println("    " + getComponent()
                 + " (Description: " + getDescription() + ")"
                 + " (UID: " + getUid() + ")");
@@ -332,14 +427,15 @@ public final class NfcFServiceInfo implements Parcelable {
     }
 
     /**
-     * Dump debugging info as NfcFServiceInfoProto
+     * Dump debugging info as NfcFServiceInfoProto.
      *
      * If the output belongs to a sub message, the caller is responsible for wrapping this function
      * between {@link ProtoOutputStream#start(long)} and {@link ProtoOutputStream#end(long)}.
      *
      * @param proto the ProtoOutputStream to write to
      */
-    public void dumpDebug(ProtoOutputStream proto) {
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    public void dumpDebug(@NonNull ProtoOutputStream proto) {
         Utils.dumpDebugComponentName(getComponent(), proto, NfcFServiceInfoProto.COMPONENT_NAME);
         proto.write(NfcFServiceInfoProto.DESCRIPTION, getDescription());
         proto.write(NfcFServiceInfoProto.SYSTEM_CODE, getSystemCode());
@@ -347,4 +443,3 @@ public final class NfcFServiceInfo implements Parcelable {
         proto.write(NfcFServiceInfoProto.T3T_PMM, getT3tPmm());
     }
 }
-
diff --git a/core/java/android/nfc/flags.aconfig b/core/java/android/nfc/flags.aconfig
new file mode 100644
index 0000000000000000000000000000000000000000..e3faf3978856cfc172c3d873880ea7580fb35f46
--- /dev/null
+++ b/core/java/android/nfc/flags.aconfig
@@ -0,0 +1,8 @@
+package: "android.nfc"
+
+flag {
+    name: "enable_nfc_mainline"
+    namespace: "nfc"
+    description: "Flag for NFC mainline changes"
+    bug: "292140387"
+}
diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java
index ecf17707a5c84efb446fb04a5006678f0b1027ea..dc024701fbef1ad499457e27c76cae506086433f 100644
--- a/core/java/android/printservice/PrintService.java
+++ b/core/java/android/printservice/PrintService.java
@@ -178,7 +178,7 @@ public abstract class PrintService extends Service {
      * <pre> &lt;print-service
      *     android:vendor="SomeVendor"
      *     android:settingsActivity="foo.bar.MySettingsActivity"
-     *     andorid:addPrintersActivity="foo.bar.MyAddPrintersActivity."
+     *     android:addPrintersActivity="foo.bar.MyAddPrintersActivity."
      *     . . .
      * /&gt;</pre>
      * <p>
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 052c28325545a2503a1059b96e9c1170e1710338..be6fb313b2304cf8f34522c1952caa7bef54e728 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -263,6 +263,8 @@ public final class SurfaceControl implements Parcelable {
             long nativeObject, int compatibility);
     private static native void nativeSetFrameRateCategory(
             long transactionObj, long nativeObject, int category);
+    private static native void nativeSetFrameRateSelectionStrategy(
+            long transactionObj, long nativeObject, int strategy);
     private static native long nativeGetHandle(long nativeObject);
 
     private static native void nativeSetFixedTransformHint(long transactionObj, long nativeObject,
@@ -850,6 +852,35 @@ public final class SurfaceControl implements Parcelable {
      */
     public static final int METADATA_GAME_MODE = 8;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"FRAME_RATE_SELECTION_STRATEGY_"},
+            value = {FRAME_RATE_SELECTION_STRATEGY_SELF,
+                    FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN})
+    public @interface FrameRateSelectionStrategy {}
+
+    // From window.h. Keep these in sync.
+    /**
+     * Default value. The layer uses its own frame rate specifications, assuming it has any
+     * specifications, instead of its parent's.
+     * However, {@link #FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN} on an ancestor layer
+     * supersedes this behavior, meaning that this layer will inherit the frame rate specifications
+     * of that ancestor layer.
+     * @hide
+     */
+    public static final int FRAME_RATE_SELECTION_STRATEGY_SELF = 0;
+
+    /**
+     * The layer's frame rate specifications will propagate to and override those of its descendant
+     * layers.
+     * The layer with this strategy has the {@link #FRAME_RATE_SELECTION_STRATEGY_SELF} behavior
+     * for itself. This does mean that any parent or ancestor layer that also has the strategy
+     * {@link FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN} will override this layer's
+     * frame rate specifications.
+     * @hide
+     */
+    public static final int FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN = 1;
+
     /**
      * Builder class for {@link SurfaceControl} objects.
      *
@@ -3668,6 +3699,31 @@ public final class SurfaceControl implements Parcelable {
             return this;
         }
 
+        /**
+         * Sets the frame rate selection strategy for the {@link SurfaceControl}.
+         *
+         * This instructs the system on how to choose a display refresh rate, following the
+         * strategy for the layer's frame rate specifications relative to other layers'.
+         *
+         * @param sc The SurfaceControl to specify the frame rate category of.
+         * @param strategy The frame rate selection strategy.
+         *
+         * @return This transaction object.
+         *
+         * @see #setFrameRate(SurfaceControl, float, int, int)
+         * @see #setFrameRateCategory(SurfaceControl, int)
+         * @see #setDefaultFrameRateCompatibility(SurfaceControl, int)
+         *
+         * @hide
+         */
+        @NonNull
+        public Transaction setFrameRateSelectionStrategy(
+                @NonNull SurfaceControl sc, @FrameRateSelectionStrategy int strategy) {
+            checkPreconditions(sc);
+            nativeSetFrameRateSelectionStrategy(mNativeObject, sc.mNativeObject, strategy);
+            return this;
+        }
+
         /**
          * Sets focus on the window identified by the input {@code token} if the window is focusable
          * otherwise the request is dropped.
diff --git a/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java b/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java
index 61470f2bc71a9da9bfa4b90e3c6078b05d4df8c2..3557f16a6dc888e641f24864068720866cdd0644 100644
--- a/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java
+++ b/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java
@@ -417,7 +417,9 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub {
         if (mBeamer == null) {
             return;
         }
-        mBeamer.forget(token);
+        dispatch(() -> {
+            mBeamer.forget(token);
+        });
     }
 
     @Override
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index b8d251fc5cc5e8f46d56351cf2a799a404113ba4..ec5d4ff16ee5d63599865a2d45173046fa27ada0 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -15,3 +15,10 @@ flag {
     description: "Whether the overlay presentation feature is enabled"
     bug: "243518738"
 }
+
+flag {
+    namespace: "windowing_sdk"
+    name: "task_fragment_system_organizer_flag"
+    description: "Whether the TaskFragment system organizer feature is enabled"
+    bug: "284050041"
+}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 74f64b758ff78433f51836ccf9db868e3ccff5f0..9384f41e26f5049e29c7e5b172367957de2be0f6 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -967,6 +967,13 @@ static void nativeSetFrameRateCategory(JNIEnv* env, jclass clazz, jlong transact
     transaction->setFrameRateCategory(ctrl, static_cast<int8_t>(category));
 }
 
+static void nativeSetFrameRateSelectionStrategy(JNIEnv* env, jclass clazz, jlong transactionObj,
+                                                jlong nativeObject, jint strategy) {
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+    const auto ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
+    transaction->setFrameRateSelectionStrategy(ctrl, static_cast<int8_t>(strategy));
+}
+
 static void nativeSetFixedTransformHint(JNIEnv* env, jclass clazz, jlong transactionObj,
                                         jlong nativeObject, jint transformHint) {
     auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
@@ -2173,6 +2180,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
             (void*)nativeSetDefaultFrameRateCompatibility},
     {"nativeSetFrameRateCategory", "(JJI)V",
             (void*)nativeSetFrameRateCategory},
+    {"nativeSetFrameRateSelectionStrategy", "(JJI)V",
+            (void*)nativeSetFrameRateSelectionStrategy},
     {"nativeSetDisplaySurface", "(JLandroid/os/IBinder;J)V",
             (void*)nativeSetDisplaySurface },
     {"nativeSetDisplayLayerStack", "(JLandroid/os/IBinder;I)V",
diff --git a/core/tests/fuzzers/ParcelFuzzer/ReadUtils.java b/core/tests/fuzzers/ParcelFuzzer/ReadUtils.java
index b5e5b258b7d6a43878f8d02ed64319108b44904d..cb988555d5f78f6ef96f9bf53d8a92c59e0087b0 100644
--- a/core/tests/fuzzers/ParcelFuzzer/ReadUtils.java
+++ b/core/tests/fuzzers/ParcelFuzzer/ReadUtils.java
@@ -364,6 +364,12 @@ public class ReadUtils {
                         TestClassLoader loader = new TestClassLoader();
                         parcel.readParcelableArray(loader);
                     },
+                    (parcel, provider) -> {
+                        parcel.readParcelable(null);
+                    },
+                    (parcel, provider) -> {
+                        parcel.readParcelableArray(null);
+                    },
 
                     // read lists
                     (parcel, provider) -> {
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index fe611a28dda970deb554498af5edc16a14c68970..b00fc699e515d2e212c941e3e8afe53760e8ce7e 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -918,10 +918,10 @@ const SkM44& CanvasContext::getPixelSnapMatrix() const {
 }
 
 void CanvasContext::prepareAndDraw(RenderNode* node) {
-    ATRACE_CALL();
+    int64_t vsyncId = mRenderThread.timeLord().lastVsyncId();
+    ATRACE_FORMAT("%s %" PRId64, __func__, vsyncId);
 
     nsecs_t vsync = mRenderThread.timeLord().computeFrameTimeNanos();
-    int64_t vsyncId = mRenderThread.timeLord().lastVsyncId();
     int64_t frameDeadline = mRenderThread.timeLord().lastFrameDeadline();
     int64_t frameInterval = mRenderThread.timeLord().frameIntervalNanos();
     int64_t frameInfo[UI_THREAD_FRAME_INFO_SIZE];
diff --git a/omapi/java/android/se/omapi/SeFrameworkInitializer.java b/omapi/java/android/se/omapi/SeFrameworkInitializer.java
new file mode 100644
index 0000000000000000000000000000000000000000..d09a35d85009ff37aeb4ff939437a1b0a574f3aa
--- /dev/null
+++ b/omapi/java/android/se/omapi/SeFrameworkInitializer.java
@@ -0,0 +1,70 @@
+/*
+ * 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 android.se.omapi;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.nfc.Flags;
+
+/**
+ * Class for performing registration for SE service.
+ *
+ * @hide
+ */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+@FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+public class SeFrameworkInitializer {
+    private SeFrameworkInitializer() {}
+
+    private static volatile SeServiceManager sSeServiceManager;
+
+    /**
+     * Sets an instance of {@link SeServiceManager} that allows
+     * the se mainline module to register/obtain se binder services. This is called
+     * by the platform during the system initialization.
+     *
+     * @param seServiceManager instance of {@link SeServiceManager} that allows
+     * the se/nfc mainline module to register/obtain se binder services.
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    public static void setSeServiceManager(
+            @NonNull SeServiceManager seServiceManager) {
+        if (sSeServiceManager != null) {
+            throw new IllegalStateException("setSeServiceManager called twice!");
+        }
+
+        if (seServiceManager == null) {
+            throw new IllegalArgumentException("seServiceManager must not be null");
+        }
+
+        sSeServiceManager = seServiceManager;
+    }
+
+    /**
+     * Gets an instance of {@link SeServiceManager} that allows
+     * the se mainline module to register/obtain se binder services.
+     *
+     * @return instance of {@link SeServiceManager} that allows
+     * the se/nfc mainline module to register/obtain se binder services.
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    @Nullable
+    public static SeServiceManager getSeServiceManager() {
+        return sSeServiceManager;
+    }
+}
diff --git a/omapi/java/android/se/omapi/SeServiceManager.java b/omapi/java/android/se/omapi/SeServiceManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..7910737067529ffef77123614748b04215ae9d67
--- /dev/null
+++ b/omapi/java/android/se/omapi/SeServiceManager.java
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+
+
+/**********************************************************************
+ * This file is not a part of the SE mainline module                 *
+ * *******************************************************************/
+
+package android.se.omapi;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.SystemApi.Client;
+import android.content.Context;
+import android.nfc.Flags;
+import android.os.IBinder;
+import android.os.ServiceManager;
+
+/**
+ * Provides a way to register and obtain the system service binder objects managed by the
+ * SecureElement service.
+ *
+ * @hide
+ */
+@SystemApi(client = Client.MODULE_LIBRARIES)
+@FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+public class SeServiceManager {
+
+    /**
+     * @hide
+     */
+    public SeServiceManager() {
+    }
+
+    /**
+     * A class that exposes the methods to register and obtain each system service.
+     * @hide
+     */
+    @SystemApi(client = Client.MODULE_LIBRARIES)
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    public static final class ServiceRegisterer {
+        private final String mServiceName;
+
+        /**
+         * @hide
+         */
+        public ServiceRegisterer(String serviceName) {
+            mServiceName = serviceName;
+        }
+
+        /**
+         * Register a system server binding object for a service.
+         */
+        @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+        public void register(@NonNull IBinder service) {
+            ServiceManager.addService(mServiceName, service);
+        }
+
+        /**
+         * Get the system server binding object for a service.
+         *
+         * <p>This blocks until the service instance is ready,
+         * or a timeout happens, in which case it returns null.
+         */
+        @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+        @Nullable
+        public IBinder get() {
+            return ServiceManager.getService(mServiceName);
+        }
+
+        /**
+         * Get the system server binding object for a service.
+         *
+         * <p>This blocks until the service instance is ready,
+         * or a timeout happens, in which case it throws {@link ServiceNotFoundException}.
+         */
+        @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+        @NonNull
+        public IBinder getOrThrow() throws ServiceNotFoundException {
+            try {
+                return ServiceManager.getServiceOrThrow(mServiceName);
+            } catch (ServiceManager.ServiceNotFoundException e) {
+                throw new ServiceNotFoundException(mServiceName);
+            }
+        }
+
+        /**
+         * Get the system server binding object for a service. If the specified service is
+         * not available, it returns null.
+         */
+        @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+        @Nullable
+        public IBinder tryGet() {
+            return ServiceManager.checkService(mServiceName);
+        }
+    }
+
+    /**
+     * See {@link ServiceRegisterer#getOrThrow}.
+     * @hide
+     */
+    @SystemApi(client = Client.MODULE_LIBRARIES)
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    public static class ServiceNotFoundException extends ServiceManager.ServiceNotFoundException {
+        /**
+         * Constructor.
+         *
+         * @param name the name of the binder service that cannot be found.
+         *
+         */
+        @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+        public ServiceNotFoundException(@NonNull String name) {
+            super(name);
+        }
+    }
+
+    /**
+     * Returns {@link ServiceRegisterer} for the "secure_element" service.
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+    @NonNull
+    public ServiceRegisterer getSeManagerServiceRegisterer() {
+        return new ServiceRegisterer(Context.SECURE_ELEMENT_SERVICE);
+    }
+}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 0a98032e26d832ab1260bc38e0c05bd3be35936a..e9533e598336ae745d0257bdf9ea40204cd4dc3e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -137,6 +137,13 @@ final class SettingsState {
     private static final String ATTR_VALUE_BASE64 = "valueBase64";
     private static final String ATTR_DEFAULT_VALUE_BASE64 = "defaultValueBase64";
 
+    /**
+     * In the config table, there are special flags of the form {@code staged/namespace*flagName}.
+     * On boot, when the XML file is initially parsed, these transform into
+     * {@code namespace/flagName}, and the special staged flags are deleted.
+     */
+    private static final String CONFIG_STAGED_PREFIX = "staged/";
+
     // This was used in version 120 and before.
     private static final String NULL_VALUE_OLD_STYLE = "null";
 
@@ -1191,6 +1198,42 @@ final class SettingsState {
         }
     }
 
+    /**
+     * Transforms a staged flag name to its real flag name.
+     *
+     * Staged flags take the form {@code staged/namespace*flagName}. If
+     * {@code stagedFlagName} takes the proper form, returns
+     * {@code namespace/flagName}. Otherwise, returns {@code stagedFlagName}
+     * unmodified, and logs an error message.
+     *
+     */
+    @VisibleForTesting
+    public static String createRealFlagName(String stagedFlagName) {
+        int slashIndex = stagedFlagName.indexOf("/");
+        if (slashIndex == -1 || slashIndex == stagedFlagName.length() - 1
+                || slashIndex == 0) {
+            Slog.w(LOG_TAG, "invalid staged flag, not applying: " + stagedFlagName);
+            return stagedFlagName;
+        }
+
+        String namespaceAndFlag =
+                stagedFlagName.substring(slashIndex + 1);
+
+        int starIndex = namespaceAndFlag.indexOf("*");
+        if (starIndex == -1 || starIndex == namespaceAndFlag.length() - 1
+                || starIndex == 0) {
+            Slog.w(LOG_TAG, "invalid staged flag, not applying: " + stagedFlagName);
+            return stagedFlagName;
+        }
+
+        String namespace =
+                namespaceAndFlag.substring(0, starIndex);
+        String flagName =
+                namespaceAndFlag.substring(starIndex + 1);
+
+        return namespace + "/" + flagName;
+    }
+
     @GuardedBy("mLock")
     private void parseSettingsLocked(TypedXmlPullParser parser)
             throws IOException, XmlPullParserException {
@@ -1199,6 +1242,7 @@ final class SettingsState {
 
         final int outerDepth = parser.getDepth();
         int type;
+        HashSet<String> flagsWithStagedValueApplied = new HashSet<String>();
         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
@@ -1221,6 +1265,18 @@ final class SettingsState {
                     fromSystem = parser.getAttributeBoolean(null, ATTR_DEFAULT_SYS_SET, false);
                     tag = getValueAttribute(parser, ATTR_TAG, ATTR_TAG_BASE64);
                 }
+
+                if (isConfigSettingsKey(mKey)) {
+                    if (flagsWithStagedValueApplied.contains(name)) {
+                        continue;
+                    }
+
+                    if (name.startsWith(CONFIG_STAGED_PREFIX)) {
+                        name = createRealFlagName(name);
+                        flagsWithStagedValueApplied.add(name);
+                    }
+                }
+
                 mSettings.put(name, new Setting(name, value, defaultValue, packageName, tag,
                         fromSystem, id, isPreservedInRestore));
 
@@ -1229,6 +1285,16 @@ final class SettingsState {
                 }
             }
         }
+
+        if (isConfigSettingsKey(mKey) && !flagsWithStagedValueApplied.isEmpty()) {
+            // On boot, the config table XML file includes special staged flags. On the initial
+            // boot XML -> HashMap parse, these staged flags get transformed into real flags.
+            // After this, the HashMap contains no special staged flags (only the transformed
+            // real flags), but the XML still does. We then have no need for the special staged
+            // flags in the XML, so we overwrite the XML with the latest contents of the
+            // HashMap.
+            writeStateAsyncLocked();
+        }
     }
 
     @GuardedBy("mLock")
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
index 26cac37f8b354aeed08af66cf1fe5c52498a9847..df4d2a1ed89f1b7b963e7644e5ab6b63013ba948 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
@@ -51,6 +51,21 @@ public class SettingsStateTest extends AndroidTestCase {
     private static final String SYSTEM_PACKAGE = "android";
     private static final String SETTING_NAME = "test_setting";
 
+    private static final String FLAG_NAME_1 = "namespace123/flag456";
+    private static final String FLAG_NAME_1_STAGED = "staged/namespace123*flag456";
+    private static final String FLAG_NAME_2 = "not_staged/flag101";
+
+    private static final String INVALID_STAGED_FLAG_1 = "stagednamespace*flagName";
+    private static final String INVALID_STAGED_FLAG_2 = "staged/";
+    private static final String INVALID_STAGED_FLAG_3 = "staged/namespace*";
+    private static final String INVALID_STAGED_FLAG_4 = "staged/*flagName";
+
+    private static final String VALID_STAGED_FLAG_1 = "staged/namespace*flagName";
+    private static final String VALID_STAGED_FLAG_1_TRANSFORMED = "namespace/flagName";
+
+    private static final String VALUE1 = "5";
+    private static final String VALUE2 = "6";
+
     private final Object mLock = new Object();
 
     private File mSettingsFile;
@@ -454,4 +469,68 @@ public class SettingsStateTest extends AndroidTestCase {
             }
         }
     }
+
+    public void testApplyStagedConfigValues() {
+        int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0);
+        Object lock = new Object();
+        SettingsState settingsState = new SettingsState(
+                getContext(), lock, mSettingsFile, configKey,
+                SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
+
+        synchronized (lock) {
+            settingsState.insertSettingLocked(
+                    FLAG_NAME_1_STAGED, VALUE1, null, false, TEST_PACKAGE);
+            settingsState.insertSettingLocked(FLAG_NAME_2, VALUE2, null, false, TEST_PACKAGE);
+            settingsState.persistSyncLocked();
+
+            assertEquals(VALUE1, settingsState.getSettingLocked(FLAG_NAME_1_STAGED).getValue());
+            assertEquals(VALUE2, settingsState.getSettingLocked(FLAG_NAME_2).getValue());
+        }
+
+        settingsState = new SettingsState(getContext(), lock, mSettingsFile, configKey,
+                SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
+
+        synchronized (lock) {
+            assertEquals(VALUE1, settingsState.getSettingLocked(FLAG_NAME_1).getValue());
+            assertEquals(VALUE2, settingsState.getSettingLocked(FLAG_NAME_2).getValue());
+
+            assertEquals(null, settingsState.getSettingLocked(FLAG_NAME_1_STAGED).getValue());
+        }
+    }
+
+    public void testStagingTransformation() {
+        assertEquals(INVALID_STAGED_FLAG_1,
+                SettingsState.createRealFlagName(INVALID_STAGED_FLAG_1));
+        assertEquals(INVALID_STAGED_FLAG_2,
+                SettingsState.createRealFlagName(INVALID_STAGED_FLAG_2));
+        assertEquals(INVALID_STAGED_FLAG_3,
+                SettingsState.createRealFlagName(INVALID_STAGED_FLAG_3));
+        assertEquals(INVALID_STAGED_FLAG_4,
+                SettingsState.createRealFlagName(INVALID_STAGED_FLAG_4));
+
+        assertEquals(VALID_STAGED_FLAG_1_TRANSFORMED,
+                SettingsState.createRealFlagName(VALID_STAGED_FLAG_1));
+    }
+
+    public void testInvalidStagedFlagsUnaffectedByReboot() {
+        int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0);
+        Object lock = new Object();
+        SettingsState settingsState = new SettingsState(
+                getContext(), lock, mSettingsFile, configKey,
+                SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
+
+        synchronized (lock) {
+            settingsState.insertSettingLocked(INVALID_STAGED_FLAG_1,
+                    VALUE2, null, false, TEST_PACKAGE);
+            settingsState.persistSyncLocked();
+            assertEquals(VALUE2, settingsState.getSettingLocked(INVALID_STAGED_FLAG_1).getValue());
+        }
+
+        settingsState = new SettingsState(getContext(), lock, mSettingsFile, configKey,
+                SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
+
+        synchronized (lock) {
+            assertEquals(VALUE2, settingsState.getSettingLocked(INVALID_STAGED_FLAG_1).getValue());
+        }
+    }
 }
diff --git a/packages/SystemUI/aconfig/OWNERS b/packages/SystemUI/aconfig/OWNERS
new file mode 100644
index 0000000000000000000000000000000000000000..e1a7a0f84ad002471732dd27fa7a40b56f0bfa26
--- /dev/null
+++ b/packages/SystemUI/aconfig/OWNERS
@@ -0,0 +1 @@
+per-file accessibility.aconfig = file:/core/java/android/view/accessibility/OWNERS
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt
index 8a8557aa1f436fc4e94368ffe5c1e23587bfaff1..df22a7023ebfafe19caf9dfe758da1a883279015 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt
@@ -17,8 +17,11 @@
 package com.android.systemui.bouncer.ui.composable
 
 import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.ExperimentalLayoutApi
 import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.WindowInsets
 import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.imeAnimationTarget
 import androidx.compose.foundation.text.KeyboardActions
 import androidx.compose.foundation.text.KeyboardOptions
 import androidx.compose.material3.LocalTextStyle
@@ -29,6 +32,7 @@ import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberUpdatedState
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.drawBehind
@@ -44,6 +48,7 @@ import androidx.compose.ui.unit.dp
 import com.android.systemui.bouncer.ui.viewmodel.PasswordBouncerViewModel
 
 /** UI for the input part of a password-requiring version of the bouncer. */
+@OptIn(ExperimentalLayoutApi::class)
 @Composable
 internal fun PasswordBouncer(
     viewModel: PasswordBouncerViewModel,
@@ -54,6 +59,10 @@ internal fun PasswordBouncer(
     val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsState()
     val animateFailure: Boolean by viewModel.animateFailure.collectAsState()
 
+    val density = LocalDensity.current
+    val isImeVisible by rememberUpdatedState(WindowInsets.imeAnimationTarget.getBottom(density) > 0)
+    LaunchedEffect(isImeVisible) { viewModel.onImeVisibilityChanged(isImeVisible) }
+
     LaunchedEffect(Unit) {
         // When the UI comes up, request focus on the TextField to bring up the software keyboard.
         focusRequester.requestFocus()
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 199036f09e9a10170599e50a748d758db3923d45..9b2f2baba94bde8fcec02e1c3229654331894a76 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
@@ -225,6 +225,20 @@ constructor(
         repository.setMessage(errorMessage(authenticationInteractor.getAuthenticationMethod()))
     }
 
+    /** If the bouncer is showing, hides the bouncer and return to the lockscreen scene. */
+    fun hide(
+        loggingReason: String,
+    ) {
+        if (sceneInteractor.desiredScene.value.key != SceneKey.Bouncer) {
+            return
+        }
+
+        sceneInteractor.changeScene(
+            scene = SceneModel(SceneKey.Lockscreen),
+            loggingReason = loggingReason,
+        )
+    }
+
     private fun promptMessage(authMethod: AuthenticationMethodModel): String {
         return when (authMethod) {
             is AuthenticationMethodModel.Pin ->
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModel.kt
index d95b70c85fe0f5f3f2781a4a5bf9374ccf8c7956..4546bea3b89b09271e9c2217b4a27ca810bf537a 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModel.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.bouncer.ui.viewmodel
 
+import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
@@ -28,6 +29,7 @@ sealed class AuthMethodBouncerViewModel(
      * being able to attempt to unlock the device.
      */
     val isInputEnabled: StateFlow<Boolean>,
+    private val interactor: BouncerInteractor,
 ) {
 
     private val _animateFailure = MutableStateFlow(false)
@@ -37,6 +39,9 @@ sealed class AuthMethodBouncerViewModel(
      */
     val animateFailure: StateFlow<Boolean> = _animateFailure.asStateFlow()
 
+    /** Whether the input method editor (for example, the software keyboard) is visible. */
+    private var isImeVisible: Boolean = false
+
     /**
      * Notifies that the failure animation has been shown. This should be called to consume a `true`
      * value in [animateFailure].
@@ -45,6 +50,21 @@ sealed class AuthMethodBouncerViewModel(
         _animateFailure.value = false
     }
 
+    /**
+     * Notifies that the input method editor (for example, the software keyboard) has been shown or
+     * hidden.
+     */
+    fun onImeVisibilityChanged(isVisible: Boolean) {
+        if (isImeVisible && !isVisible) {
+            // The IME has gone from visible to invisible, dismiss the bouncer.
+            interactor.hide(
+                loggingReason = "IME hidden",
+            )
+        }
+
+        isImeVisible = isVisible
+    }
+
     /** Ask the UI to show the failure animation. */
     protected fun showFailureAnimation() {
         _animateFailure.value = true
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
index d21479746744d91e8d2ae05f2c303ddbea2ee327..9e10f29a00f94c54c87bcbe38c8db160452ae938 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
@@ -31,6 +31,7 @@ class PasswordBouncerViewModel(
 ) :
     AuthMethodBouncerViewModel(
         isInputEnabled = isInputEnabled,
+        interactor = interactor,
     ) {
 
     private val _password = MutableStateFlow("")
@@ -60,6 +61,10 @@ class PasswordBouncerViewModel(
     /** Notifies that the user has pressed the key for attempting to authenticate the password. */
     fun onAuthenticateKeyPressed() {
         val password = _password.value.toCharArray().toList()
+        if (password.isEmpty()) {
+            return
+        }
+
         _password.value = ""
 
         applicationScope.launch {
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
index 1985c37e1d5da20ce64ece6803da134088c58a79..497276b479960d738e1b155e2e9f65dbd9164fa2 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
@@ -42,6 +42,7 @@ class PatternBouncerViewModel(
 ) :
     AuthMethodBouncerViewModel(
         isInputEnabled = isInputEnabled,
+        interactor = interactor,
     ) {
 
     /** The number of columns in the dot grid. */
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
index dc5c5288df9f245642537b82dc319c66df4d113d..8e6421ed3f0ab1bc348d7b2917dc2aa26aa5ce60 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
@@ -37,6 +37,7 @@ class PinBouncerViewModel(
 ) :
     AuthMethodBouncerViewModel(
         isInputEnabled = isInputEnabled,
+        interactor = interactor,
     ) {
 
     val pinShapes = PinShapeAdapter(applicationContext)
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index f97f6bd7613b35966f6bdfd52b26e9aede294460..e170849e487fea64bc915210fa6d0b8d0c43ddac 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -386,7 +386,8 @@ object Flags {
     // 600- status bar
 
     // TODO(b/291315866): Tracking Bug
-    @JvmField val SIGNAL_CALLBACK_DEPRECATION = unreleasedFlag("signal_callback_deprecation")
+    @JvmField val SIGNAL_CALLBACK_DEPRECATION =
+        unreleasedFlag("signal_callback_deprecation", teamfood = true)
 
     // TODO(b/265892345): Tracking Bug
     val PLUG_IN_STATUS_BAR_CHIP = releasedFlag("plug_in_status_bar_chip")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
index 6205c277bbd900c68973ab8b989178da8de096bf..77d8102fff2e4a4d40ef87a73f7594f6a8d1d42f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
@@ -353,6 +353,34 @@ class BouncerInteractorTest : SysuiTestCase() {
             assertThat(throttling).isEqualTo(AuthenticationThrottlingModel())
         }
 
+    @Test
+    fun hide_whenOnBouncerScene_hidesBouncerAndGoesToLockscreenScene() =
+        testScope.runTest {
+            sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "")
+            sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "")
+            val currentScene by collectLastValue(sceneInteractor.desiredScene)
+            val bouncerSceneKey = currentScene?.key
+            assertThat(bouncerSceneKey).isEqualTo(SceneKey.Bouncer)
+
+            underTest.hide("")
+
+            assertThat(currentScene?.key).isEqualTo(SceneKey.Lockscreen)
+        }
+
+    @Test
+    fun hide_whenNotOnBouncerScene_doesNothing() =
+        testScope.runTest {
+            sceneInteractor.changeScene(SceneModel(SceneKey.Shade), "")
+            sceneInteractor.onSceneChanged(SceneModel(SceneKey.Shade), "")
+            val currentScene by collectLastValue(sceneInteractor.desiredScene)
+            val notBouncerSceneKey = currentScene?.key
+            assertThat(notBouncerSceneKey).isNotEqualTo(SceneKey.Bouncer)
+
+            underTest.hide("")
+
+            assertThat(currentScene?.key).isEqualTo(notBouncerSceneKey)
+        }
+
     private fun assertTryAgainMessage(
         message: String?,
         time: Int,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
index 7af8a042540203fe131eaf08ff62060bf4eee868..9011c2f296c3753694e57a164cb5640880c03cc7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
@@ -22,6 +22,8 @@ import com.android.systemui.authentication.data.model.AuthenticationMethodModel
 import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.scene.SceneTestUtils
+import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.SceneModel
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.test.runTest
@@ -39,6 +41,7 @@ class AuthMethodBouncerViewModelTest : SysuiTestCase() {
         utils.authenticationInteractor(
             utils.authenticationRepository(),
         )
+    private val sceneInteractor = utils.sceneInteractor()
     private val underTest =
         PinBouncerViewModel(
             applicationContext = context,
@@ -46,7 +49,7 @@ class AuthMethodBouncerViewModelTest : SysuiTestCase() {
             interactor =
                 utils.bouncerInteractor(
                     authenticationInteractor = authenticationInteractor,
-                    sceneInteractor = utils.sceneInteractor(),
+                    sceneInteractor = sceneInteractor,
                 ),
             isInputEnabled = MutableStateFlow(true),
         )
@@ -75,4 +78,22 @@ class AuthMethodBouncerViewModelTest : SysuiTestCase() {
             underTest.onAuthenticateButtonClicked()
             assertThat(animateFailure).isFalse()
         }
+
+    @Test
+    fun onImeVisibilityChanged() =
+        testScope.runTest {
+            val desiredScene by collectLastValue(sceneInteractor.desiredScene)
+            sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "")
+            sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "")
+            assertThat(desiredScene?.key).isEqualTo(SceneKey.Bouncer)
+
+            underTest.onImeVisibilityChanged(false)
+            assertThat(desiredScene?.key).isEqualTo(SceneKey.Bouncer)
+
+            underTest.onImeVisibilityChanged(true)
+            assertThat(desiredScene?.key).isEqualTo(SceneKey.Bouncer)
+
+            underTest.onImeVisibilityChanged(false)
+            assertThat(desiredScene?.key).isEqualTo(SceneKey.Lockscreen)
+        }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
index 8df29e4d4e585a2237a54cad5da00b9d4b8ba8c6..3375184c1cf6003f8401e2065840f63adb2ed210 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
@@ -156,6 +156,29 @@ class PasswordBouncerViewModelTest : SysuiTestCase() {
             assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
         }
 
+    @Test
+    fun onAuthenticateKeyPressed_whenEmpty() =
+        testScope.runTest {
+            val currentScene by collectLastValue(sceneInteractor.desiredScene)
+            val message by collectLastValue(bouncerViewModel.message)
+            val password by collectLastValue(underTest.password)
+            utils.authenticationRepository.setAuthenticationMethod(
+                AuthenticationMethodModel.Password
+            )
+            utils.authenticationRepository.setUnlocked(false)
+            sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
+            sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
+            assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
+            underTest.onShown()
+            // Enter nothing.
+
+            underTest.onAuthenticateKeyPressed()
+
+            assertThat(password).isEqualTo("")
+            assertThat(message?.text).isEqualTo(ENTER_YOUR_PASSWORD)
+            assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
+        }
+
     @Test
     fun onAuthenticateKeyPressed_correctAfterWrong() =
         testScope.runTest {
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 9c8d14de1c74d69cce4c7310e31ab9aced584741..6b918c6ba15b5c5ea40f5b83e7b101ab57f46046 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
@@ -22,7 +22,6 @@ import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
 import com.android.systemui.authentication.domain.model.AuthenticationMethodModel as DomainLayerAuthenticationMethodModel
-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.keyguard.shared.model.WakefulnessState
@@ -48,7 +47,9 @@ import com.android.systemui.util.mockito.mock
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.Job
 import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.launch
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
@@ -159,6 +160,8 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() {
             repository = keyguardRepository,
         )
 
+    private var bouncerSceneJob: Job? = null
+
     @Before
     fun setUp() {
         shadeHeaderViewModel =
@@ -288,7 +291,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() {
     @Test
     fun withAuthMethodNone_deviceWakeUp_skipsLockscreen() =
         testScope.runTest {
-            setAuthMethod(AuthenticationMethodModel.None)
+            setAuthMethod(DomainLayerAuthenticationMethodModel.None)
             putDeviceToSleep(instantlyLockDevice = false)
             assertCurrentScene(SceneKey.Lockscreen)
 
@@ -299,7 +302,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() {
     @Test
     fun withAuthMethodSwipe_deviceWakeUp_doesNotSkipLockscreen() =
         testScope.runTest {
-            setAuthMethod(AuthenticationMethodModel.Swipe)
+            setAuthMethod(DomainLayerAuthenticationMethodModel.Swipe)
             putDeviceToSleep(instantlyLockDevice = false)
             assertCurrentScene(SceneKey.Lockscreen)
 
@@ -364,6 +367,23 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() {
             assertCurrentScene(SceneKey.Lockscreen)
         }
 
+    @Test
+    fun dismissingIme_whileOnPasswordBouncer_navigatesToLockscreen() =
+        testScope.runTest {
+            setAuthMethod(DomainLayerAuthenticationMethodModel.Password)
+            val upDestinationSceneKey by
+                collectLastValue(lockscreenSceneViewModel.upDestinationSceneKey)
+            assertThat(upDestinationSceneKey).isEqualTo(SceneKey.Bouncer)
+            emulateUserDrivenTransition(
+                to = upDestinationSceneKey,
+            )
+
+            dismissIme()
+
+            assertCurrentScene(SceneKey.Lockscreen)
+            emulateUiSceneTransition()
+        }
+
     /**
      * Asserts that the current scene in the view-model matches what's expected.
      *
@@ -396,7 +416,9 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() {
         // Set the lockscreen enabled bit _before_ set the auth method as the code picks up on the
         // lockscreen enabled bit _after_ the auth method is changed and the lockscreen enabled bit
         // is not an observable that can trigger a new evaluation.
-        authenticationRepository.setLockscreenEnabled(authMethod !is AuthenticationMethodModel.None)
+        authenticationRepository.setLockscreenEnabled(
+            authMethod !is DomainLayerAuthenticationMethodModel.None
+        )
         authenticationRepository.setAuthenticationMethod(authMethod.toDataLayer())
         if (!authMethod.isSecure) {
             // When the auth method is not secure, the device is never considered locked.
@@ -455,6 +477,19 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() {
         assertWithMessage("Visibility mismatch after scene transition from $from to ${to.key}!")
             .that(sceneContainerViewModel.isVisible.value)
             .isEqualTo(expectedVisible)
+
+        bouncerSceneJob =
+            if (to.key == SceneKey.Bouncer) {
+                testScope.backgroundScope.launch {
+                    bouncerViewModel.authMethod.collect {
+                        // Do nothing. Need this to turn this otherwise cold flow, hot.
+                    }
+                }
+            } else {
+                bouncerSceneJob?.cancel()
+                null
+            }
+        runCurrent()
     }
 
     /**
@@ -573,4 +608,16 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() {
             lockDevice()
         }
     }
+
+    /** Emulates the dismissal of the IME (soft keyboard). */
+    private fun TestScope.dismissIme(
+        showImeBeforeDismissing: Boolean = true,
+    ) {
+        if (showImeBeforeDismissing) {
+            bouncerViewModel.authMethod.value?.onImeVisibilityChanged(true)
+        }
+
+        bouncerViewModel.authMethod.value?.onImeVisibilityChanged(false)
+        runCurrent()
+    }
 }
diff --git a/services/autofill/java/com/android/server/autofill/FieldClassificationEventLogger.java b/services/autofill/java/com/android/server/autofill/FieldClassificationEventLogger.java
index ffb4632164a385ae0c3803bb0749ab9fa566e46b..db2e18a0fd578775884618889b63e472ae6dc0b7 100644
--- a/services/autofill/java/com/android/server/autofill/FieldClassificationEventLogger.java
+++ b/services/autofill/java/com/android/server/autofill/FieldClassificationEventLogger.java
@@ -17,12 +17,19 @@
 package com.android.server.autofill;
 
 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FIELD_CLASSIFICATION_EVENT_REPORTED;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FIELD_CLASSIFICATION_EVENT_REPORTED__STATUS__STATUS_CANCELLED;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FIELD_CLASSIFICATION_EVENT_REPORTED__STATUS__STATUS_FAIL;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FIELD_CLASSIFICATION_EVENT_REPORTED__STATUS__STATUS_SUCCESS;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FIELD_CLASSIFICATION_EVENT_REPORTED__STATUS__STATUS_UNKNOWN;
 import static com.android.server.autofill.Helper.sVerbose;
 
+import android.annotation.IntDef;
 import android.util.Slog;
 
 import com.android.internal.util.FrameworkStatsLog;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Optional;
 
 /**
@@ -36,6 +43,29 @@ public final class FieldClassificationEventLogger {
         mEventInternal = Optional.empty();
     }
 
+    public static final int STATUS_SUCCESS =
+            AUTOFILL_FIELD_CLASSIFICATION_EVENT_REPORTED__STATUS__STATUS_SUCCESS;
+    public static final int STATUS_UNKNOWN =
+            AUTOFILL_FIELD_CLASSIFICATION_EVENT_REPORTED__STATUS__STATUS_UNKNOWN;
+    public static final int STATUS_FAIL =
+            AUTOFILL_FIELD_CLASSIFICATION_EVENT_REPORTED__STATUS__STATUS_FAIL;
+    public static final int STATUS_CANCELLED =
+            AUTOFILL_FIELD_CLASSIFICATION_EVENT_REPORTED__STATUS__STATUS_CANCELLED;
+
+    /**
+     * Status of the FieldClassification IPC request. These are wrappers around
+     * {@link com.android.os.AtomsProto.AutofillFieldClassificationEventReported.FieldClassificationRequestStatus}.
+     */
+    @IntDef(prefix = {"STATUS"}, value = {
+            STATUS_UNKNOWN,
+            STATUS_SUCCESS,
+            STATUS_FAIL,
+            STATUS_CANCELLED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface FieldClassificationStatus {
+    }
+
     /**
      * A factory constructor to create FieldClassificationEventLogger.
      */
@@ -56,7 +86,7 @@ public final class FieldClassificationEventLogger {
     }
 
     /**
-     * Set latency as long as mEventInternal presents.
+     * Set latency_millis as long as mEventInternal presents.
      */
     public void maybeSetLatencyMillis(long timestamp) {
         mEventInternal.ifPresent(event -> {
@@ -64,6 +94,69 @@ public final class FieldClassificationEventLogger {
         });
     }
 
+    /**
+     * Set count_classifications as long as mEventInternal presents.
+     */
+    public void maybeSetCountClassifications(int countClassifications) {
+        mEventInternal.ifPresent(event -> {
+            event.mCountClassifications = countClassifications;
+        });
+    }
+
+    /**
+     * Set session_id as long as mEventInternal presents.
+     */
+    public void maybeSetSessionId(int sessionId) {
+        mEventInternal.ifPresent(event -> {
+            event.mSessionId = sessionId;
+        });
+    }
+
+    /**
+     * Set request_id as long as mEventInternal presents.
+     */
+    public void maybeSetRequestId(int requestId) {
+        mEventInternal.ifPresent(event -> {
+            event.mRequestId = requestId;
+        });
+    }
+
+    /**
+     * Set next_fill_request_id as long as mEventInternal presents.
+     */
+    public void maybeSetNextFillRequestId(int nextFillRequestId) {
+        mEventInternal.ifPresent(event -> {
+            event.mNextFillRequestId = nextFillRequestId;
+        });
+    }
+
+    /**
+     * Set app_package_uid as long as mEventInternal presents.
+     */
+    public void maybeSetAppPackageUid(int uid) {
+        mEventInternal.ifPresent(event -> {
+            event.mAppPackageUid = uid;
+        });
+    }
+
+    /**
+     * Set status as long as mEventInternal presents.
+     */
+    public void maybeSetRequestStatus(@FieldClassificationStatus int status) {
+        mEventInternal.ifPresent(event -> {
+            event.mStatus = status;
+        });
+    }
+
+    /**
+     * Set is_session_gc as long as mEventInternal presents.
+     */
+    public void maybeSetSessionGc(boolean isSessionGc) {
+        mEventInternal.ifPresent(event -> {
+            event.mIsSessionGc = isSessionGc;
+        });
+    }
+
     /**
      * Log an AUTOFILL_FIELD_CLASSIFICATION_EVENT_REPORTED event.
      */
@@ -77,16 +170,37 @@ public final class FieldClassificationEventLogger {
         if (sVerbose) {
             Slog.v(TAG, "Log AutofillFieldClassificationEventReported:"
                     + " mLatencyClassificationRequestMillis="
-                    + event.mLatencyClassificationRequestMillis);
+                    + event.mLatencyClassificationRequestMillis
+                    + " mCountClassifications=" + event.mCountClassifications
+                    + " mSessionId=" + event.mSessionId
+                    + " mRequestId=" + event.mRequestId
+                    + " mNextFillRequestId=" + event.mNextFillRequestId
+                    + " mAppPackageUid=" + event.mAppPackageUid
+                    + " mStatus=" + event.mStatus
+                    + " mIsSessionGc=" + event.mIsSessionGc);
         }
         FrameworkStatsLog.write(
                 AUTOFILL_FIELD_CLASSIFICATION_EVENT_REPORTED,
-                event.mLatencyClassificationRequestMillis);
+                event.mLatencyClassificationRequestMillis,
+                event.mCountClassifications,
+                event.mSessionId,
+                event.mRequestId,
+                event.mNextFillRequestId,
+                event.mAppPackageUid,
+                event.mStatus,
+                event.mIsSessionGc);
         mEventInternal = Optional.empty();
     }
 
     private static final class FieldClassificationEventInternal {
         long mLatencyClassificationRequestMillis = -1;
+        int mCountClassifications = -1;
+        int mSessionId = -1;
+        int mRequestId = -1;
+        int mNextFillRequestId = -1;
+        int mAppPackageUid = -1;
+        int mStatus;
+        boolean mIsSessionGc;
 
         FieldClassificationEventInternal() {
         }
diff --git a/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
index 11b45db29d5d0f5d2b008465a0349bdd6914257d..6b0fdb5f7fe0542cc3f1ef1812a991412f01f294 100644
--- a/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
+++ b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
@@ -211,15 +211,25 @@ public final class PresentationStatsEventLogger {
     public static final int DETECTION_PREFER_PCC =
             AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_PCC;
     private final int mSessionId;
+
+    /**
+     * For app_package_uid.
+     */
+    private final int mCallingAppUid;
     private Optional<PresentationStatsEventInternal> mEventInternal;
 
-    private PresentationStatsEventLogger(int sessionId) {
+    private PresentationStatsEventLogger(int sessionId, int callingAppUid) {
         mSessionId = sessionId;
+        mCallingAppUid = callingAppUid;
         mEventInternal = Optional.empty();
     }
 
-    public static PresentationStatsEventLogger forSessionId(int sessionId) {
-        return new PresentationStatsEventLogger(sessionId);
+    /**
+     * Create PresentationStatsEventLogger, populated with sessionId and the callingAppUid
+     */
+    public static PresentationStatsEventLogger createPresentationLog(
+            int sessionId, int callingAppUid) {
+        return new PresentationStatsEventLogger(sessionId, callingAppUid);
     }
 
     public void startNewEvent() {
@@ -508,6 +518,14 @@ public final class PresentationStatsEventLogger {
         return PICK_REASON_UNKNOWN;
     }
 
+    /**
+     * Set field_classification_request_id as long as mEventInternal presents.
+     */
+    public void maybeSetFieldClassificationRequestId(int requestId) {
+        mEventInternal.ifPresent(event -> {
+            event.mFieldClassificationRequestId = requestId;
+        });
+    }
 
     public void logAndEndEvent() {
         if (!mEventInternal.isPresent()) {
@@ -547,7 +565,9 @@ public final class PresentationStatsEventLogger {
                     + " mAvailablePccCount=" + event.mAvailablePccCount
                     + " mAvailablePccOnlyCount=" + event.mAvailablePccOnlyCount
                     + " mSelectedDatasetPickedReason=" + event.mSelectedDatasetPickedReason
-                    + " mDetectionPreference=" + event.mDetectionPreference);
+                    + " mDetectionPreference=" + event.mDetectionPreference
+                    + " mFieldClassificationRequestId=" + event.mFieldClassificationRequestId
+                    + " mAppPackageUid=" + mCallingAppUid);
         }
 
         // TODO(b/234185326): Distinguish empty responses from other no presentation reasons.
@@ -584,7 +604,9 @@ public final class PresentationStatsEventLogger {
                 event.mAvailablePccCount,
                 event.mAvailablePccOnlyCount,
                 event.mSelectedDatasetPickedReason,
-                event.mDetectionPreference);
+                event.mDetectionPreference,
+                event.mFieldClassificationRequestId,
+                mCallingAppUid);
         mEventInternal = Optional.empty();
     }
 
@@ -617,6 +639,7 @@ public final class PresentationStatsEventLogger {
         int mAvailablePccOnlyCount = -1;
         @DatasetPickedReason int mSelectedDatasetPickedReason = PICK_REASON_UNKNOWN;
         @DetectionPreference int mDetectionPreference = DETECTION_PREFER_UNKNOWN;
+        int mFieldClassificationRequestId = -1;
 
         PresentationStatsEventInternal() {}
     }
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFieldClassificationService.java b/services/autofill/java/com/android/server/autofill/RemoteFieldClassificationService.java
index bcca0069eb349a9e4aafb7daab8c7075caa6f84c..50fabfdaef83a88d8a8051fa2f8e6e200724addd 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFieldClassificationService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFieldClassificationService.java
@@ -69,6 +69,9 @@ final class RemoteFieldClassificationService
         void onClassificationRequestFailure(int requestId, @Nullable CharSequence message);
         void onClassificationRequestTimeout(int requestId);
         void onServiceDied(@NonNull RemoteFieldClassificationService service);
+        void logFieldClassificationEvent(
+                long startTime, @NonNull FieldClassificationResponse response,
+                @FieldClassificationEventLogger.FieldClassificationStatus int status);
     }
 
     RemoteFieldClassificationService(Context context, ComponentName serviceName,
@@ -149,15 +152,24 @@ final class RemoteFieldClassificationService
                                 new IFieldClassificationCallback.Stub() {
                                     @Override
                                     public void onCancellable(ICancellationSignal cancellation) {
-                                        logLatency(startTime);
                                         if (sDebug) {
                                             Log.d(TAG, "onCancellable");
                                         }
+                                        FieldClassificationServiceCallbacks
+                                                fieldClassificationServiceCallbacks =
+                                                Helper.weakDeref(
+                                                        fieldClassificationServiceCallbacksWeakRef,
+                                                        TAG, "onCancellable "
+                                                );
+                                        logFieldClassificationEvent(
+                                                startTime,
+                                                fieldClassificationServiceCallbacks,
+                                                FieldClassificationEventLogger.STATUS_CANCELLED,
+                                                null);
                                     }
 
                                     @Override
                                     public void onSuccess(FieldClassificationResponse response) {
-                                        logLatency(startTime);
                                         if (sDebug) {
                                             if (Build.IS_DEBUGGABLE) {
                                                 Slog.d(TAG, "onSuccess Response: " + response);
@@ -179,6 +191,11 @@ final class RemoteFieldClassificationService
                                                                 fieldClassificationServiceCallbacksWeakRef,
                                                                 TAG, "onSuccess "
                                                         );
+                                        logFieldClassificationEvent(
+                                                startTime,
+                                                fieldClassificationServiceCallbacks,
+                                                FieldClassificationEventLogger.STATUS_SUCCESS,
+                                                response);
                                         if (fieldClassificationServiceCallbacks == null) {
                                             return;
                                         }
@@ -188,7 +205,6 @@ final class RemoteFieldClassificationService
 
                                     @Override
                                     public void onFailure() {
-                                        logLatency(startTime);
                                         if (sDebug) {
                                             Slog.d(TAG, "onFailure");
                                         }
@@ -198,6 +214,11 @@ final class RemoteFieldClassificationService
                                                                 fieldClassificationServiceCallbacksWeakRef,
                                                                 TAG, "onFailure "
                                                         );
+                                        logFieldClassificationEvent(
+                                                startTime,
+                                                fieldClassificationServiceCallbacks,
+                                                FieldClassificationEventLogger.STATUS_FAIL,
+                                                null);
                                         if (fieldClassificationServiceCallbacks == null) {
                                             return;
                                         }
@@ -215,11 +236,24 @@ final class RemoteFieldClassificationService
                                 }));
     }
 
-    private void logLatency(long startTime) {
-        final FieldClassificationEventLogger logger = FieldClassificationEventLogger.createLogger();
-        logger.startNewLogForRequest();
-        logger.maybeSetLatencyMillis(
-                SystemClock.elapsedRealtime() - startTime);
-        logger.logAndEndEvent();
+    private void logFieldClassificationEvent(
+            long startTime,
+            @Nullable FieldClassificationServiceCallbacks fieldClassificationServiceCallbacks,
+            @FieldClassificationEventLogger.FieldClassificationStatus int status,
+            FieldClassificationResponse response) {
+        if (fieldClassificationServiceCallbacks == null) {
+            final FieldClassificationEventLogger logger =
+                    FieldClassificationEventLogger.createLogger();
+            logger.startNewLogForRequest();
+            logger.maybeSetLatencyMillis(
+                    SystemClock.elapsedRealtime() - startTime);
+            logger.maybeSetSessionGc(true);
+            logger.maybeSetRequestStatus(status);
+            logger.logAndEndEvent();
+        } else {
+            fieldClassificationServiceCallbacks.logFieldClassificationEvent(
+                    startTime, response, status);
+        }
+
     }
 }
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 1ae912544cc8a28723f2b70cdd4fa3d8c70d0719..4e5b0589446a1710357d68b8a7a8510f664b6005 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -229,6 +229,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
 
     private static final String PCC_HINTS_DELIMITER = ",";
     public static final String EXTRA_KEY_DETECTIONS = "detections";
+    private static final int DEFAULT__FILL_REQUEST_ID_SNAPSHOT = -2;
+    private static final int DEFAULT__FIELD_CLASSIFICATION_REQUEST_ID_SNAPSHOT = -2;
 
     final Object mLock;
 
@@ -412,6 +414,20 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
     @GuardedBy("mLock")
     private long mUiShownTime;
 
+    /**
+     * Tracks the value of the fill request id at the time of issuing request for field
+     * classification.
+     */
+    @GuardedBy("mLock")
+    private int mFillRequestIdSnapshot = DEFAULT__FILL_REQUEST_ID_SNAPSHOT;
+
+    /**
+     * Tracks the value of the field classification id at the time of issuing request for fill
+     * request.
+     */
+    @GuardedBy("mLock")
+    private int mFieldClassificationIdSnapshot = DEFAULT__FIELD_CLASSIFICATION_REQUEST_ID_SNAPSHOT;
+
     @GuardedBy("mLock")
     private final LocalLog mUiLatencyHistory;
 
@@ -673,6 +689,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
             if (mPendingFillRequest == null) {
                 return;
             }
+            mFieldClassificationIdSnapshot = sIdCounterForPcc.get();
 
             if (mWaitForInlineRequest) {
                 if (mPendingInlineSuggestionsRequest == null) {
@@ -1239,6 +1256,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                     + ", flags=" + flags);
         }
         mPresentationStatsEventLogger.maybeSetRequestId(requestId);
+        mPresentationStatsEventLogger.maybeSetFieldClassificationRequestId(
+                mFieldClassificationIdSnapshot);
         mFillRequestEventLogger.maybeSetRequestId(requestId);
         mFillRequestEventLogger.maybeSetAutofillServiceUid(getAutofillServiceUid());
         if (mSessionFlags.mInlineSupportedByService) {
@@ -1327,6 +1346,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
     @GuardedBy("mLock")
     private void requestAssistStructureForPccLocked(int flags) {
         if (!mClassificationState.shouldTriggerRequest()) return;
+        mFillRequestIdSnapshot = sIdCounter.get();
         mClassificationState.updatePendingRequest();
         // Get request id
         int requestId;
@@ -1411,7 +1431,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
         mStartTime = SystemClock.elapsedRealtime();
         mLatencyBaseTime = mStartTime;
         mRequestCount = 0;
-        mPresentationStatsEventLogger = PresentationStatsEventLogger.forSessionId(sessionId);
+        mPresentationStatsEventLogger = PresentationStatsEventLogger.createPresentationLog(
+                sessionId, uid);
         mFillRequestEventLogger = FillRequestEventLogger.forSessionId(sessionId);
         mFillResponseEventLogger = FillResponseEventLogger.forSessionId(sessionId);
         mSessionCommittedEventLogger = SessionCommittedEventLogger.forSessionId(sessionId);
@@ -4301,6 +4322,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                 if (viewState.getResponse() != null) {
                     FillResponse response = viewState.getResponse();
                     mPresentationStatsEventLogger.maybeSetRequestId(response.getRequestId());
+                    mPresentationStatsEventLogger.maybeSetFieldClassificationRequestId(
+                            mFieldClassificationIdSnapshot);
                     mPresentationStatsEventLogger.maybeSetAvailableCount(
                             response.getDatasets(), mCurrentViewId);
                 }
@@ -4478,6 +4501,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
     public void onFillReady(@NonNull FillResponse response, @NonNull AutofillId filledId,
             @Nullable AutofillValue value, int flags) {
         synchronized (mLock) {
+            mPresentationStatsEventLogger.maybeSetFieldClassificationRequestId(
+                    mFieldClassificationIdSnapshot);
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#onFillReady() rejected - session: "
                         + id + " destroyed");
@@ -5389,6 +5414,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
 
         List<Dataset> datasetList = newResponse.getDatasets();
 
+        mPresentationStatsEventLogger.maybeSetFieldClassificationRequestId(sIdCounterForPcc.get());
         mPresentationStatsEventLogger.maybeSetAvailableCount(datasetList, mCurrentViewId);
         mFillResponseEventLogger.maybeSetDatasetsCountAfterPotentialPccFiltering(datasetList);
 
@@ -6451,7 +6477,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
         return serviceInfo == null ? Process.INVALID_UID : serviceInfo.applicationInfo.uid;
     }
 
-    // FieldClassificationServiceCallbacks
+    // FieldClassificationServiceCallbacks start
     public void onClassificationRequestSuccess(@Nullable FieldClassificationResponse response) {
         mClassificationState.updateResponseReceived(response);
     }
@@ -6472,6 +6498,28 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
             // forceRemoveFromServiceLocked();
         }
     }
-    // DetectionServiceCallbacks end
+
+    @Override
+    public void logFieldClassificationEvent(
+            long startTime, FieldClassificationResponse response,
+            @FieldClassificationEventLogger.FieldClassificationStatus int status) {
+        final FieldClassificationEventLogger logger = FieldClassificationEventLogger.createLogger();
+        logger.startNewLogForRequest();
+        logger.maybeSetLatencyMillis(
+                SystemClock.elapsedRealtime() - startTime);
+        logger.maybeSetAppPackageUid(uid);
+        logger.maybeSetNextFillRequestId(mFillRequestIdSnapshot + 1);
+        logger.maybeSetRequestId(sIdCounterForPcc.get());
+        logger.maybeSetSessionId(id);
+        int count = -1;
+        if (response != null) {
+            count = response.getClassifications().size();
+        }
+        logger.maybeSetRequestStatus(status);
+        logger.maybeSetCountClassifications(count);
+        logger.logAndEndEvent();
+        mFillRequestIdSnapshot = DEFAULT__FILL_REQUEST_ID_SNAPSHOT;
+    }
+    // FieldClassificationServiceCallbacks end
 
 }
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index d94f4f22f2c94f4b6735517448320a916b00cf54..556eba6ced768e96780ca8b6e7d539092ce85c5b 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -167,6 +167,8 @@ public final class BatteryService extends SystemService {
     private int mBatteryNearlyFullLevel;
     private int mShutdownBatteryTemperature;
 
+    private static String sSystemUiPackage;
+
     private int mPlugType;
     private int mLastPlugType = -1; // Extra state so we can detect first run
 
@@ -228,6 +230,8 @@ public final class BatteryService extends SystemService {
                 com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
         mShutdownBatteryTemperature = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_shutdownBatteryTemperature);
+        sSystemUiPackage = mContext.getResources().getString(
+                com.android.internal.R.string.config_systemUi);
 
         mBatteryLevelsEventQueue = new ArrayDeque<>();
         mMetricsLogger = new MetricsLogger();
@@ -750,8 +754,21 @@ public final class BatteryService extends SystemService {
                     + ", info:" + mHealthInfo.toString());
         }
 
-        mHandler.post(() -> ActivityManager.broadcastStickyIntent(intent, AppOpsManager.OP_NONE,
-                mBatteryChangedOptions, UserHandle.USER_ALL));
+        mHandler.post(() -> broadcastBatteryChangedIntent(intent, mBatteryChangedOptions));
+    }
+
+    private static void broadcastBatteryChangedIntent(Intent intent, Bundle options) {
+        // TODO (293959093): It is important that SystemUI receives this broadcast as soon as
+        // possible. Ideally, it should be using binder callbacks but until then, dispatch this
+        // as a foreground broadcast to SystemUI.
+        final Intent fgIntent = new Intent(intent);
+        fgIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+        fgIntent.setPackage(sSystemUiPackage);
+        ActivityManager.broadcastStickyIntent(fgIntent, AppOpsManager.OP_NONE,
+                options, UserHandle.USER_ALL);
+
+        ActivityManager.broadcastStickyIntent(intent, new String[] {sSystemUiPackage},
+                AppOpsManager.OP_NONE, options, UserHandle.USER_ALL);
     }
 
     private void sendBatteryLevelChangedIntentLocked() {
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
index 1012bc1828c007738a4569de0f1e5d381e11af95..fac727f1728363df842556119f333d7208bda583 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
@@ -37,7 +37,8 @@ import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
-import android.app.TaskStackListener;
+import android.app.ActivityManagerInternal;
+import android.app.IProcessObserver;
 import android.content.Context;
 import android.hardware.devicestate.DeviceStateInfo;
 import android.hardware.devicestate.DeviceStateManager;
@@ -184,7 +185,30 @@ public final class DeviceStateManagerService extends SystemService {
     private final SystemPropertySetter mSystemPropertySetter;
 
     @VisibleForTesting
-    TaskStackListener mOverrideRequestTaskStackListener = new OverrideRequestTaskStackListener();
+    final IProcessObserver mProcessObserver = new IProcessObserver.Stub() {
+        @Override
+        public void onForegroundActivitiesChanged(int pid, int uid, boolean fg) {
+            synchronized (mLock) {
+                if (!shouldCancelOverrideRequestWhenRequesterNotOnTop()) {
+                    return;
+                }
+
+                OverrideRequest request = mActiveOverride.get();
+                if (pid != request.getPid() || uid != request.getUid()) {
+                    return;
+                }
+                if (!fg) {
+                    mOverrideRequestController.cancelRequest(request);
+                }
+            }
+        }
+
+        @Override
+        public void onProcessDied(int pid, int uid) {}
+
+        @Override
+        public void onForegroundServicesChanged(int pid, int uid, int serviceTypes) {}
+    };
     @VisibleForTesting
     ActivityTaskManagerInternal.ScreenObserver mOverrideRequestScreenObserver =
             new OverrideRequestScreenObserver();
@@ -239,8 +263,9 @@ public final class DeviceStateManagerService extends SystemService {
             mFoldedDeviceStates = readFoldedStates();
         }
 
-        mActivityTaskManagerInternal.registerTaskStackListener(mOverrideRequestTaskStackListener);
         mActivityTaskManagerInternal.registerScreenObserver(mOverrideRequestScreenObserver);
+        LocalServices.getService(ActivityManagerInternal.class).registerProcessObserver(
+                mProcessObserver);
     }
 
     @VisibleForTesting
@@ -1288,23 +1313,6 @@ public final class DeviceStateManagerService extends SystemService {
         return deviceState.hasFlag(DeviceState.FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP);
     }
 
-    private class OverrideRequestTaskStackListener extends TaskStackListener {
-        @Override
-        public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo)
-                throws RemoteException {
-            synchronized (mLock) {
-                if (!shouldCancelOverrideRequestWhenRequesterNotOnTop()) {
-                    return;
-                }
-
-                OverrideRequest request = mActiveOverride.get();
-                if (!isTopApp(request.getPid())) {
-                    mOverrideRequestController.cancelRequest(request);
-                }
-            }
-        }
-    }
-
     private class OverrideRequestScreenObserver implements
             ActivityTaskManagerInternal.ScreenObserver {
 
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateNotificationController.java b/services/core/java/com/android/server/devicestate/DeviceStateNotificationController.java
index f4c84e7fe464cf88655bd6228387a77e7327716c..f9aefd0535d0e4e767450c6de6990afe9c3fa962 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateNotificationController.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateNotificationController.java
@@ -109,6 +109,7 @@ class DeviceStateNotificationController extends BroadcastReceiver {
                     .setPackage(mContext.getPackageName());
             final PendingIntent pendingIntent = PendingIntent.getBroadcast(
                     mContext, 0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE);
+
             showNotification(
                     info.name, info.activeNotificationTitle,
                     String.format(info.activeNotificationContent, requesterApplicationLabel),
@@ -175,7 +176,7 @@ class DeviceStateNotificationController extends BroadcastReceiver {
         if (getNotificationInfos().get(state) == null) {
             return;
         }
-        mNotificationManager.cancel(NOTIFICATION_TAG, NOTIFICATION_ID);
+        mHandler.post(() -> mNotificationManager.cancel(NOTIFICATION_TAG, NOTIFICATION_ID));
     }
 
     @Override
@@ -219,8 +220,10 @@ class DeviceStateNotificationController extends BroadcastReceiver {
             builder.addAction(action);
         }
 
-        mNotificationManager.createNotificationChannel(channel);
-        mNotificationManager.notify(NOTIFICATION_TAG, NOTIFICATION_ID, builder.build());
+        mHandler.post(() -> {
+            mNotificationManager.createNotificationChannel(channel);
+            mNotificationManager.notify(NOTIFICATION_TAG, NOTIFICATION_ID, builder.build());
+        });
     }
 
     private SparseArray<NotificationInfo> getNotificationInfos() {
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 032778c797687d16510e19ff1d45810f16ea8300..d3ad6c437f788f1e3b5626abffe939757345bafa 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -3303,6 +3303,10 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
         }
 
         // Changing to a different IME.
+        IInputMethodInvoker curMethod = getCurMethodLocked();
+        if (curMethod != null) {
+            curMethod.removeStylusHandwritingWindow();
+        }
         final long ident = Binder.clearCallingIdentity();
         try {
             // Set a subtype to this input method.
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index b001c6aa95efb61df417469630568b301fc0a90d..097656cac7f7b135cbb2f0312754764dcd5e8257 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3972,15 +3972,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
      */
     private int handleTransitionForKeyguardLw(boolean startKeyguardExitAnimation,
             boolean notifyOccluded) {
+        int redoLayout = 0;
         if (notifyOccluded) {
-            final int redoLayout = applyKeyguardOcclusionChange();
-            if (redoLayout != 0) return redoLayout;
+            redoLayout = applyKeyguardOcclusionChange();
         }
         if (startKeyguardExitAnimation) {
             if (DEBUG_KEYGUARD) Slog.d(TAG, "Starting keyguard exit animation");
             startKeyguardExitAnimation(SystemClock.uptimeMillis());
         }
-        return 0;
+        return redoLayout;
     }
 
     // There are several different flavors of "assistant" that can be launched from
diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
index 8f88ba6ff9a78bc030b58fcd4464b360e8c12541..7d735632b675bd632812694fc19ff4126ffd0580 100644
--- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
@@ -30,7 +30,6 @@ import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertThrows;
 
-import android.app.ActivityManager;
 import android.hardware.devicestate.DeviceStateInfo;
 import android.hardware.devicestate.DeviceStateRequest;
 import android.hardware.devicestate.IDeviceStateManagerCallback;
@@ -582,10 +581,10 @@ public final class DeviceStateManagerServiceTest {
                 // When the app is foreground, the state should not change
                 () -> {
                     int pid = Binder.getCallingPid();
-                    when(mWindowProcessController.getPid()).thenReturn(pid);
+                    int uid = Binder.getCallingUid();
                     try {
-                        mService.mOverrideRequestTaskStackListener.onTaskMovedToFront(
-                                new ActivityManager.RunningTaskInfo());
+                        mService.mProcessObserver.onForegroundActivitiesChanged(pid, uid,
+                                true /* foregroundActivities */);
                     } catch (RemoteException e) {
                         throw new RuntimeException(e);
                     }
@@ -594,8 +593,11 @@ public final class DeviceStateManagerServiceTest {
                 () -> {
                     when(mWindowProcessController.getPid()).thenReturn(FAKE_PROCESS_ID);
                     try {
-                        mService.mOverrideRequestTaskStackListener.onTaskMovedToFront(
-                                new ActivityManager.RunningTaskInfo());
+                        int pid = Binder.getCallingPid();
+                        int uid = Binder.getCallingUid();
+                        mService.mProcessObserver.onForegroundActivitiesChanged(pid, uid,
+                                false /* foregroundActivities */);
+
                     } catch (RemoteException e) {
                         throw new RuntimeException(e);
                     }
diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateNotificationControllerTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateNotificationControllerTest.java
index 728606f9f62855c18c3c660814b48682b920b65d..bb0de032d98756ad65519f8f266ef0ac362273ef 100644
--- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateNotificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateNotificationControllerTest.java
@@ -33,6 +33,8 @@ import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
 import android.platform.test.annotations.Presubmit;
 import android.util.SparseArray;
 
@@ -89,11 +91,12 @@ public class DeviceStateNotificationControllerTest {
     @Before
     public void setup() throws Exception {
         Context context = InstrumentationRegistry.getInstrumentation().getContext();
-        Handler handler = mock(Handler.class);
         PackageManager packageManager = mock(PackageManager.class);
         Runnable cancelStateRunnable = mock(Runnable.class);
         ApplicationInfo applicationInfo = mock(ApplicationInfo.class);
 
+        Handler handler = new DeviceStateNotificationControllerTestHandler(Looper.getMainLooper());
+
         final SparseArray<DeviceStateNotificationController.NotificationInfo> notificationInfos =
                 new SparseArray<>();
         notificationInfos.put(STATE_WITH_ACTIVE_NOTIFICATION,
@@ -259,4 +262,16 @@ public class DeviceStateNotificationControllerTest {
         assertEquals(Locale.ITALY, mNotificationInfoProvider.getCachedLocale());
         clearInvocations(mNotificationInfoProvider);
     }
+
+    private static class DeviceStateNotificationControllerTestHandler extends Handler {
+        DeviceStateNotificationControllerTestHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
+            msg.getCallback().run();
+            return true;
+        }
+    }
 }
diff --git a/tests/CtsSurfaceControlTestsStaging/Android.bp b/tests/CtsSurfaceControlTestsStaging/Android.bp
index 3272cef2eb796741399b99951c346cb9765ecfec..680952157fdcc3f5f6c5792c8e8e619678a7bdb5 100644
--- a/tests/CtsSurfaceControlTestsStaging/Android.bp
+++ b/tests/CtsSurfaceControlTestsStaging/Android.bp
@@ -36,6 +36,7 @@ android_test {
         "androidx.test.rules",
         "compatibility-device-util-axt",
         "com.google.android.material_material",
+        "SurfaceFlingerProperties",
         "truth-prebuilt",
     ],
     resource_dirs: ["src/main/res"],
diff --git a/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java
index 4b12053af5c7aba9b30d182f99be5c716281d141..79348d104745f263c362531df7f088773516f30c 100644
--- a/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java
+++ b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java
@@ -30,6 +30,7 @@ import android.hardware.display.DisplayManager;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
+import android.sysprop.SurfaceFlingerProperties;
 import android.util.Log;
 import android.view.Display;
 import android.view.Surface;
@@ -45,6 +46,7 @@ import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Optional;
+import java.util.stream.Collectors;
 
 /**
  * An Activity to help with frame rate testing.
@@ -217,6 +219,27 @@ public class GraphicsActivity extends Activity {
             postBuffer();
         }
 
+        Surface getSurface() {
+            return mSurface;
+        }
+
+        SurfaceControl getSurfaceControl() {
+            return mSurfaceControl;
+        }
+
+        public int setFrameRate(float frameRate) {
+            Log.i(TAG,
+                    String.format("Setting frame rate for %s: frameRate=%.2f", mName, frameRate));
+
+            int rc = 0;
+            try (SurfaceControl.Transaction transaction = new SurfaceControl.Transaction()) {
+                transaction.setFrameRate(
+                        mSurfaceControl, frameRate, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT);
+                transaction.apply();
+            }
+            return rc;
+        }
+
         public int setFrameRateCategory(int category) {
             Log.i(TAG,
                     String.format(
@@ -230,6 +253,19 @@ public class GraphicsActivity extends Activity {
             return rc;
         }
 
+        public int setFrameRateSelectionStrategy(int strategy) {
+            Log.i(TAG,
+                    String.format("Setting frame rate selection strategy for %s: strategy=%d",
+                            mName, strategy));
+
+            int rc = 0;
+            try (SurfaceControl.Transaction transaction = new SurfaceControl.Transaction()) {
+                transaction.setFrameRateSelectionStrategy(mSurfaceControl, strategy);
+                transaction.apply();
+            }
+            return rc;
+        }
+
         public void setVisibility(boolean visible) {
             Log.i(TAG,
                     String.format("Setting visibility for %s: %s", mName,
@@ -342,6 +378,11 @@ public class GraphicsActivity extends Activity {
                 uniqueFrameRates.add(frameRate);
             }
         }
+        Log.i(TAG,
+                "**** Available display refresh rates: "
+                        + uniqueFrameRates.stream()
+                                  .map(Object::toString)
+                                  .collect(Collectors.joining(", ")));
         return uniqueFrameRates;
     }
 
@@ -358,6 +399,10 @@ public class GraphicsActivity extends Activity {
                 <= FRAME_RATE_TOLERANCE;
     }
 
+    private boolean frameRateEquals(float frameRate1, float frameRate2) {
+        return Math.abs(frameRate1 - frameRate2) <= FRAME_RATE_TOLERANCE;
+    }
+
     // Waits until our SurfaceHolder has a surface and the activity is resumed.
     private void waitForPreconditions() throws InterruptedException {
         assertNotSame(
@@ -447,9 +492,22 @@ public class GraphicsActivity extends Activity {
         verifyCompatibleAndStableFrameRate(0, surfaces);
     }
 
-    // Set expectedFrameRate to 0.0 to verify only stable frame rate.
+    private void verifyExactAndStableFrameRate(
+            float expectedFrameRate,
+            TestSurface... surfaces) throws InterruptedException {
+        verifyFrameRate(expectedFrameRate, false, surfaces);
+    }
+
     private void verifyCompatibleAndStableFrameRate(
-            float expectedFrameRate, TestSurface... surfaces) throws InterruptedException {
+            float expectedFrameRate,
+            TestSurface... surfaces) throws InterruptedException {
+        verifyFrameRate(expectedFrameRate, true, surfaces);
+    }
+
+    // Set expectedFrameRate to 0.0 to verify only stable frame rate.
+    private void verifyFrameRate(
+            float expectedFrameRate, boolean multiplesAllowed,
+            TestSurface... surfaces) throws InterruptedException {
         Log.i(TAG, "Verifying compatible and stable frame rate");
         long nowNanos = System.nanoTime();
         long gracePeriodEndTimeNanos =
@@ -457,9 +515,19 @@ public class GraphicsActivity extends Activity {
         while (true) {
             if (expectedFrameRate > FRAME_RATE_TOLERANCE) { // expectedFrameRate > 0
                 // Wait until we switch to a compatible frame rate.
-                while (!isFrameRateMultiple(mDeviceFrameRate, expectedFrameRate)
-                        && !waitForEvents(gracePeriodEndTimeNanos, surfaces)) {
-                    // Empty
+                Log.i(TAG,
+                        "Verifying expected frame rate: actual (device)=" + mDeviceFrameRate
+                                + " expected=" + expectedFrameRate);
+                if (multiplesAllowed) {
+                    while (!isFrameRateMultiple(mDeviceFrameRate, expectedFrameRate)
+                            && !waitForEvents(gracePeriodEndTimeNanos, surfaces)) {
+                        // Empty
+                    }
+                } else {
+                    while (!frameRateEquals(mDeviceFrameRate, expectedFrameRate)
+                            && !waitForEvents(gracePeriodEndTimeNanos, surfaces)) {
+                        // Empty
+                    }
                 }
                 nowNanos = System.nanoTime();
                 if (nowNanos >= gracePeriodEndTimeNanos) {
@@ -604,12 +672,65 @@ public class GraphicsActivity extends Activity {
                 "frame rate category=" + category);
     }
 
+    private void testSurfaceControlFrameRateSelectionStrategyInternal(int parentStrategy)
+            throws InterruptedException {
+        Log.i(TAG,
+                "**** Running testSurfaceControlFrameRateSelectionStrategy for strategy "
+                        + parentStrategy);
+        TestSurface parent = null;
+        TestSurface child = null;
+        try {
+            parent = new TestSurface(mSurfaceView.getSurfaceControl(), mSurface,
+                    "testSurfaceParent", mSurfaceView.getHolder().getSurfaceFrame(),
+                    /*visible=*/true, Color.RED);
+            child = new TestSurface(parent.getSurfaceControl(), parent.getSurface(),
+                    "testSurfaceChild", mSurfaceView.getHolder().getSurfaceFrame(),
+                    /*visible=*/true, Color.BLUE);
+
+            // Test
+            Display display = getDisplay();
+            List<Float> frameRates = getRefreshRates(display.getMode(), display);
+            assumeTrue("**** SKIPPED due to frame rate override disabled",
+                    SurfaceFlingerProperties.enable_frame_rate_override().orElse(true));
+            float childFrameRate = Collections.max(frameRates);
+            float parentFrameRate = childFrameRate / 2;
+            int initialNumEvents = mModeChangedEvents.size();
+            parent.setFrameRate(parentFrameRate);
+            parent.setFrameRateSelectionStrategy(parentStrategy);
+            child.setFrameRate(childFrameRate);
+
+            // Verify
+            float expectedFrameRate =
+                    parentStrategy == SurfaceControl.FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN
+                    ? parentFrameRate
+                    : childFrameRate;
+            verifyExactAndStableFrameRate(expectedFrameRate, parent, child);
+            verifyModeSwitchesDontChangeResolution(initialNumEvents, mModeChangedEvents.size());
+        } finally {
+            if (parent != null) {
+                parent.release();
+            }
+            if (child != null) {
+                child.release();
+            }
+        }
+    }
+
+    public void testSurfaceControlFrameRateSelectionStrategy(int parentStrategy)
+            throws InterruptedException {
+        runTestsWithPreconditions(
+                () -> testSurfaceControlFrameRateSelectionStrategyInternal(parentStrategy),
+                "frame rate strategy=" + parentStrategy);
+    }
+
     private float getExpectedFrameRate(int category) {
         Display display = getDisplay();
         List<Float> frameRates = getRefreshRates(display.getMode(), display);
 
-        if (category == Surface.FRAME_RATE_CATEGORY_DEFAULT
-                || category == Surface.FRAME_RATE_CATEGORY_NO_PREFERENCE) {
+        if (category == Surface.FRAME_RATE_CATEGORY_DEFAULT) {
+            // Max due to default vote and no other frame rate specifications.
+            return Collections.max(frameRates);
+        } else if (category == Surface.FRAME_RATE_CATEGORY_NO_PREFERENCE) {
             return Collections.min(frameRates);
         }
 
diff --git a/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/SurfaceControlTest.java b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/SurfaceControlTest.java
index ccbda7f2fdf0f62759a486592ff416e8a6d073e2..bed9cff75e1daedb8e2b7e043d72768e0232227d 100644
--- a/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/SurfaceControlTest.java
+++ b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/SurfaceControlTest.java
@@ -23,11 +23,14 @@ import android.hardware.display.DisplayManager;
 import android.os.SystemProperties;
 import android.support.test.uiautomator.UiDevice;
 import android.view.Surface;
+import android.view.SurfaceControl;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.rule.ActivityTestRule;
 
+import com.android.compatibility.common.util.DisplayUtil;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
@@ -59,19 +62,15 @@ public class SurfaceControlTest {
         uiDevice.executeShellCommand("wm dismiss-keyguard");
 
         InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
-                Manifest.permission.LOG_COMPAT_CHANGE,
-                Manifest.permission.READ_COMPAT_CHANGE_CONFIG,
                 Manifest.permission.MODIFY_REFRESH_RATE_SWITCHING_TYPE,
-                Manifest.permission.OVERRIDE_DISPLAY_MODE_REQUESTS,
-                Manifest.permission.MANAGE_GAME_MODE);
+                Manifest.permission.OVERRIDE_DISPLAY_MODE_REQUESTS);
 
         // Prevent DisplayManager from limiting the allowed refresh rate range based on
         // non-app policies (e.g. low battery, user settings, etc).
         mDisplayManager = activity.getSystemService(DisplayManager.class);
         mDisplayManager.setShouldAlwaysRespectAppRequestedMode(true);
 
-        mInitialRefreshRateSwitchingType =
-                toSwitchingType(mDisplayManager.getMatchContentFrameRateUserPreference());
+        mInitialRefreshRateSwitchingType = DisplayUtil.getRefreshRateSwitchingType(mDisplayManager);
         mDisplayManager.setRefreshRateSwitchingType(
                 DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS);
     }
@@ -118,16 +117,18 @@ public class SurfaceControlTest {
         activity.testSurfaceControlFrameRateCategory(Surface.FRAME_RATE_CATEGORY_DEFAULT);
     }
 
-    private int toSwitchingType(int matchContentFrameRateUserPreference) {
-        switch (matchContentFrameRateUserPreference) {
-            case DisplayManager.MATCH_CONTENT_FRAMERATE_NEVER:
-                return DisplayManager.SWITCHING_TYPE_NONE;
-            case DisplayManager.MATCH_CONTENT_FRAMERATE_SEAMLESSS_ONLY:
-                return DisplayManager.SWITCHING_TYPE_WITHIN_GROUPS;
-            case DisplayManager.MATCH_CONTENT_FRAMERATE_ALWAYS:
-                return DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS;
-            default:
-                return -1;
-        }
+    @Test
+    public void testSurfaceControlFrameRateSelectionStrategySelf() throws InterruptedException {
+        GraphicsActivity activity = mActivityRule.getActivity();
+        activity.testSurfaceControlFrameRateSelectionStrategy(
+                SurfaceControl.FRAME_RATE_SELECTION_STRATEGY_SELF);
+    }
+
+    @Test
+    public void testSurfaceControlFrameRateSelectionStrategyOverrideChildren()
+            throws InterruptedException {
+        GraphicsActivity activity = mActivityRule.getActivity();
+        activity.testSurfaceControlFrameRateSelectionStrategy(
+                SurfaceControl.FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN);
     }
 }