Merge changes from topic "nfc_aosp_main_merge" into main

* changes:
  Adding wallet payment service to log protos for nfc.
  [nfc] Add disallow nfc change user restriction.
  Change NFC antenna api comments to indicated top-left start point for all axis.
  Eliminate boilder plate code for recovering service in NfcAdapter
  Add Test method to inject HCE data
  [framework] Add a flag for nfc persist log.
  Add NFC observe mode + auto-transact dumpsys protos
  Add NFC observe mode + auto-transact dumpsys logging
  Fix PollingFrame timestamp documentation
  Set default discovery technology
  [framework] Add Nfc oem extension api surface.
  Pass package name to `NfcService.setObserveMode()`
  [framework] Expose enable()/disable() as public api.
  Add POLLING_LOOP_TYPE_UNKNOWN to PollingFrameType
  Offhost NFC services shouldn't be able to register non-autotransact polling loop filters
  Document that only the currently preferred service can enable and disable observe mode
  nfc(api): Move @hide constants to Constants.java
  Use PollingFrame class instead of Bundles to represent polling frames in NFC stack
  Make NFC library available to multidevice CTS NFC tests
  nfc(api): Link against framework-permission
  KEY_POLLING_LOOP_TIMESTAMP is a long not an int
  Un-deprecate some NFC methods
  Reword autoTransact javadoc
  nfc(api): Change min_sdk to current for framework-nfc
  Revert^3 "nfc(api): Change min_sdk to V for framework-nfc"
  [nfc] Pass in package name to nfcService when enabling nfc.
  Add javadoc for autoTransact parameter
  Revert^2 "nfc(api): Change min_sdk to V for framework-nfc"
  Use long for timestamp in PollingFrame
  Revert "nfc(api): Change min_sdk to V for framework-nfc"
  nfc(api): Change min_sdk to V for framework-nfc
  Add API for polling loop pattern filters based on developer feedback.
  Add Javadoc for PollingFrame constructor
  Provide information on whether a polling frame is auto-transact
  Treat gain as an unsigned int
  Rename getGain() to getVendorSpecificGain()
  Deprecate methods on CardEmulation in favor of Wallet Role.
diff --git a/core/api/current.txt b/core/api/current.txt
index d645938..77cb03e 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -34045,6 +34045,7 @@
     field public static final String DISALLOW_BLUETOOTH_SHARING = "no_bluetooth_sharing";
     field public static final String DISALLOW_CAMERA_TOGGLE = "disallow_camera_toggle";
     field public static final String DISALLOW_CELLULAR_2G = "no_cellular_2g";
+    field @FlaggedApi("android.nfc.enable_nfc_user_restriction") public static final String DISALLOW_CHANGE_NEAR_FIELD_COMMUNICATION_RADIO = "no_change_near_field_communication_radio";
     field public static final String DISALLOW_CHANGE_WIFI_STATE = "no_change_wifi_state";
     field public static final String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
     field public static final String DISALLOW_CONFIG_BRIGHTNESS = "no_config_brightness";
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 805cfb7..02c88e2 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -10405,6 +10405,7 @@
   @FlaggedApi("android.nfc.enable_nfc_mainline") public final class ApduServiceInfo implements android.os.Parcelable {
     ctor @FlaggedApi("android.nfc.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("android.nfc.nfc_read_polling_loop") public void addPollingLoopFilter(@NonNull String, boolean);
+    method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void addPollingLoopPatternFilter(@NonNull String, boolean);
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public int describeContents();
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public void dump(@NonNull android.os.ParcelFileDescriptor, @NonNull java.io.PrintWriter, @NonNull String[]);
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public void dumpDebug(@NonNull android.util.proto.ProtoOutputStream);
@@ -10416,6 +10417,7 @@
     method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public android.nfc.cardemulation.AidGroup getDynamicAidGroupForCategory(@NonNull String);
     method @FlaggedApi("android.nfc.enable_nfc_mainline") @Nullable public String getOffHostSecureElement();
     method @FlaggedApi("android.nfc.nfc_read_polling_loop") @NonNull public java.util.List<java.lang.String> getPollingLoopFilters();
+    method @FlaggedApi("android.nfc.nfc_read_polling_loop") @NonNull public java.util.List<java.util.regex.Pattern> getPollingLoopPatternFilters();
     method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public java.util.List<java.lang.String> getPrefixAids();
     method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public String getSettingsActivityName();
     method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean getShouldAutoTransact(@NonNull String);
@@ -10430,6 +10432,7 @@
     method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public CharSequence loadLabel(@NonNull android.content.pm.PackageManager);
     method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public boolean removeDynamicAidGroupForCategory(@NonNull String);
     method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void removePollingLoopFilter(@NonNull String);
+    method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void removePollingLoopPatternFilter(@NonNull String);
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public boolean requiresScreenOn();
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public boolean requiresUnlock();
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public void resetOffHostSecureElement();
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 9757a10..599c6a5 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1900,6 +1900,31 @@
             "no_near_field_communication_radio";
 
     /**
+     * This user restriction specifies if Near-field communication is disallowed to change
+     * on the device. If Near-field communication is disallowed it cannot be changed via Settings.
+     *
+     * <p>This restriction can only be set by a device owner or a profile owner of an
+     * organization-owned managed profile on the parent profile.
+     * In both cases, the restriction applies globally on the device and will not allow Near-field
+     * communication state being changed.
+     *
+     * <p>
+     * Near-field communication (NFC) is a radio technology that allows two devices (like your phone
+     * and a payments terminal) to communicate with each other when they're close together.
+     *
+     * <p>Default is <code>false</code>.
+     *
+     * <p>Key for user restrictions.
+     * <p>Type: Boolean
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+     * @see #getUserRestrictions()
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_USER_RESTRICTION)
+    public static final String DISALLOW_CHANGE_NEAR_FIELD_COMMUNICATION_RADIO =
+            "no_change_near_field_communication_radio";
+
+    /**
      * This user restriction specifies if Thread network is disallowed on the device. If Thread
      * network is disallowed it cannot be turned on via Settings.
      *
@@ -2056,6 +2081,7 @@
             DISALLOW_WIFI_DIRECT,
             DISALLOW_ADD_WIFI_CONFIG,
             DISALLOW_CELLULAR_2G,
+            DISALLOW_CHANGE_NEAR_FIELD_COMMUNICATION_RADIO,
             DISALLOW_ULTRA_WIDEBAND_RADIO,
             DISALLOW_GRANT_ADMIN,
             DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO,
diff --git a/core/proto/android/nfc/apdu_service_info.proto b/core/proto/android/nfc/apdu_service_info.proto
index fd110c4..9efdfcb 100644
--- a/core/proto/android/nfc/apdu_service_info.proto
+++ b/core/proto/android/nfc/apdu_service_info.proto
@@ -27,6 +27,20 @@
 message ApduServiceInfoProto {
     option (.android.msg_privacy).dest = DEST_EXPLICIT;
 
+    message AutoTransactMapping {
+        option (.android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional string aid = 1;
+        optional bool should_auto_transact = 2;
+    }
+
+    message AutoTransactPattern {
+        option (.android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional string regexp_pattern = 1;
+        optional bool should_auto_transact = 2;
+    }
+
     optional .android.content.ComponentNameProto component_name = 1;
     optional string description = 2;
     optional bool on_host = 3;
@@ -35,4 +49,7 @@
     repeated AidGroupProto static_aid_groups = 6;
     repeated AidGroupProto dynamic_aid_groups = 7;
     optional string settings_activity_name = 8;
+    optional bool should_default_to_observe_mode = 9;
+    repeated AutoTransactMapping auto_transact_mapping = 10;
+    repeated AutoTransactPattern auto_transact_patterns = 11;
 }
diff --git a/core/proto/android/nfc/card_emulation.proto b/core/proto/android/nfc/card_emulation.proto
index 9c3c6d7..81da30d 100644
--- a/core/proto/android/nfc/card_emulation.proto
+++ b/core/proto/android/nfc/card_emulation.proto
@@ -59,6 +59,7 @@
     optional .android.content.ComponentNameProto foreground_requested = 5;
     optional .android.content.ComponentNameProto settings_default = 6;
     optional bool prefer_foreground = 7;
+    optional .android.content.ComponentNameProto wallet_role_holder_payment_service = 8;
 }
 
 // Debugging information for com.android.nfc.cardemulation.EnabledNfcFServices
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 48cf09a..f3cca8b 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4472,8 +4472,8 @@
     </declare-styleable>
 
     <!-- Specify one or more <code>polling-loop-filter</code> elements inside a
-         <code>host-apdu-service</code> to indicate polling loop frames that
-         your service can handle. -->
+         <code>host-apdu-service</code> or <code>offhost-apdu-service</code> to indicate polling
+         loop frames that your service can handle. -->
     <!-- @FlaggedApi("android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP") -->
     <declare-styleable name="PollingLoopFilter">
         <!-- The polling loop frame. This attribute is mandatory. -->
@@ -4484,6 +4484,21 @@
         <attr name="autoTransact" format="boolean"/>
     </declare-styleable>
 
+    <!-- Specify one or more <code>polling-loop-pattern-filter</code> elements inside a
+         <code>host-apdu-service</code> or <code>offhost-apdu-service</code>  to indicate polling
+         loop frames that your service can handle. -->
+    <!-- @FlaggedApi("android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP") -->
+    <declare-styleable name="PollingLoopPatternFilter">
+        <!-- The patter to match polling loop frames to, must to be compatible with
+         {@link java.util.regex.Pattern#compile(String)} and only contain hexadecimal numbers and
+         `.`, `?` and `*` operators. This attribute is mandatory. -->
+        <attr name="name" />
+        <!-- Whether or not the system should automatically start a transaction when this polling
+         loop filter matches. If not set, default value is false. -->
+        <!-- @FlaggedApi("android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP") -->
+        <attr name="autoTransact" format="boolean"/>
+    </declare-styleable>
+
     <!-- Use <code>host-nfcf-service</code> as the root tag of the XML resource that
          describes an {@link android.nfc.cardemulation.HostNfcFService} service, which
          is referenced from its {@link android.nfc.cardemulation.HostNfcFService#SERVICE_META_DATA}
diff --git a/nfc/Android.bp b/nfc/Android.bp
index 2a01b3f..0282e6f 100644
--- a/nfc/Android.bp
+++ b/nfc/Android.bp
@@ -38,6 +38,8 @@
     name: "framework-nfc",
     libs: [
         "unsupportedappusage", // for android.compat.annotation.UnsupportedAppUsage
+        "framework-permission-s",
+        "framework-permission",
     ],
     static_libs: [
         "android.nfc.flags-aconfig-java",
@@ -49,7 +51,7 @@
     ],
     defaults: ["framework-module-defaults"],
     sdk_version: "module_current",
-    min_sdk_version: "34", // should be 35 (making it 34 for compiling for `-next`)
+    min_sdk_version: "current",
     installable: true,
     optimize: {
         enabled: false,
@@ -61,6 +63,7 @@
     ],
     impl_library_visibility: [
         "//frameworks/base:__subpackages__",
+        "//cts/hostsidetests/multidevices/nfc:__subpackages__",
         "//cts/tests/tests/nfc",
         "//packages/apps/Nfc:__subpackages__",
     ],
diff --git a/nfc/api/current.txt b/nfc/api/current.txt
index 9d0221a..cf7aea4 100644
--- a/nfc/api/current.txt
+++ b/nfc/api/current.txt
@@ -64,8 +64,10 @@
   }
 
   public final class NfcAdapter {
+    method @FlaggedApi("android.nfc.nfc_state_change") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable();
     method public void disableForegroundDispatch(android.app.Activity);
     method public void disableReaderMode(android.app.Activity);
+    method @FlaggedApi("android.nfc.nfc_state_change") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enable();
     method public void enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], String[][]);
     method public void enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle);
     method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context);
@@ -205,7 +207,10 @@
     method public boolean isDefaultServiceForCategory(android.content.ComponentName, String);
     method public boolean registerAidsForService(android.content.ComponentName, String, java.util.List<java.lang.String>);
     method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean registerPollingLoopFilterForService(@NonNull android.content.ComponentName, @NonNull String, boolean);
+    method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean registerPollingLoopPatternFilterForService(@NonNull android.content.ComponentName, @NonNull String, boolean);
     method public boolean removeAidsForService(android.content.ComponentName, String);
+    method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean removePollingLoopFilterForService(@NonNull android.content.ComponentName, @NonNull String);
+    method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean removePollingLoopPatternFilterForService(@NonNull android.content.ComponentName, @NonNull String);
     method @NonNull @RequiresPermission(android.Manifest.permission.NFC) public boolean setOffHostForService(@NonNull android.content.ComponentName, @NonNull String);
     method public boolean setPreferredService(android.app.Activity, android.content.ComponentName);
     method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean setShouldDefaultToObserveModeForService(@NonNull android.content.ComponentName, boolean);
@@ -265,12 +270,12 @@
   }
 
   @FlaggedApi("android.nfc.nfc_read_polling_loop") public final class PollingFrame implements android.os.Parcelable {
-    ctor public PollingFrame(int, @Nullable byte[], int, int);
     method public int describeContents();
     method @NonNull public byte[] getData();
-    method public int getGain();
-    method public int getTimestamp();
+    method public long getTimestamp();
+    method public boolean getTriggeredAutoTransact();
     method public int getType();
+    method public int getVendorSpecificGain();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.nfc.cardemulation.PollingFrame> CREATOR;
     field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final int POLLING_LOOP_TYPE_A = 65; // 0x41
diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt
index 310130e..3375e18c 100644
--- a/nfc/api/system-current.txt
+++ b/nfc/api/system-current.txt
@@ -3,9 +3,7 @@
 
   public final class NfcAdapter {
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean addNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler, String[]);
-    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable();
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable(boolean);
-    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enable();
     method @FlaggedApi("android.nfc.enable_nfc_reader_option") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableReaderOption(boolean);
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableSecureNfc(boolean);
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public int getAdapterState();
@@ -29,6 +27,7 @@
     field @FlaggedApi("android.nfc.enable_nfc_mainline") public static final String ACTION_REQUIRE_UNLOCK_FOR_NFC = "android.nfc.action.REQUIRE_UNLOCK_FOR_NFC";
     field @FlaggedApi("android.nfc.enable_nfc_mainline") @RequiresPermission(android.Manifest.permission.SHOW_CUSTOMIZED_RESOLVER) public static final String ACTION_SHOW_NFC_RESOLVER = "android.nfc.action.SHOW_NFC_RESOLVER";
     field @FlaggedApi("android.nfc.enable_nfc_mainline") public static final String EXTRA_RESOLVE_INFOS = "android.nfc.extra.RESOLVE_INFOS";
+    field @FlaggedApi("android.nfc.nfc_set_default_disc_tech") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static final int FLAG_SET_DEFAULT_TECH = 1073741824; // 0x40000000
     field @FlaggedApi("android.nfc.nfc_vendor_cmd") public static final int MESSAGE_TYPE_COMMAND = 1; // 0x1
     field @FlaggedApi("android.nfc.nfc_vendor_cmd") public static final int SEND_VENDOR_NCI_STATUS_FAILED = 3; // 0x3
     field @FlaggedApi("android.nfc.nfc_vendor_cmd") public static final int SEND_VENDOR_NCI_STATUS_MESSAGE_CORRUPTED = 2; // 0x2
@@ -58,7 +57,9 @@
 
   @FlaggedApi("android.nfc.nfc_oem_extension") public final class NfcOemExtension {
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void clearPreference();
+    method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void maybeTriggerFirmwareUpdate();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcOemExtension.Callback);
+    method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void synchronizeScreenState();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void unregisterCallback(@NonNull android.nfc.NfcOemExtension.Callback);
   }
 
diff --git a/nfc/java/android/nfc/AvailableNfcAntenna.java b/nfc/java/android/nfc/AvailableNfcAntenna.java
index 6e6512a..e76aeb0 100644
--- a/nfc/java/android/nfc/AvailableNfcAntenna.java
+++ b/nfc/java/android/nfc/AvailableNfcAntenna.java
@@ -28,13 +28,13 @@
 public final class AvailableNfcAntenna implements Parcelable {
     /**
      * Location of the antenna on the Y axis in millimeters.
-     * 0 is the bottom-left when the user is facing the screen
+     * 0 is the top-left when the user is facing the screen
      * and the device orientation is Portrait.
      */
     private final int mLocationX;
     /**
      * Location of the antenna on the Y axis in millimeters.
-     * 0 is the bottom-left when the user is facing the screen
+     * 0 is the top-left when the user is facing the screen
      * and the device orientation is Portrait.
      */
     private final int mLocationY;
@@ -46,7 +46,7 @@
 
     /**
      * Location of the antenna on the X axis in millimeters.
-     * 0 is the bottom-left when the user is facing the screen
+     * 0 is the top-left when the user is facing the screen
      * and the device orientation is Portrait.
      */
     public int getLocationX() {
@@ -55,7 +55,7 @@
 
     /**
      * Location of the antenna on the Y axis in millimeters.
-     * 0 is the bottom-left when the user is facing the screen
+     * 0 is the top-left when the user is facing the screen
      * and the device orientation is Portrait.
      */
     public int getLocationY() {
diff --git a/nfc/java/android/nfc/Constants.java b/nfc/java/android/nfc/Constants.java
index f768330..9b11e2d 100644
--- a/nfc/java/android/nfc/Constants.java
+++ b/nfc/java/android/nfc/Constants.java
@@ -16,6 +16,8 @@
 
 package android.nfc;
 
+import android.provider.Settings;
+
 /**
  * @hide
  * TODO(b/303286040): Holds @hide API constants. Formalize these APIs.
@@ -26,4 +28,15 @@
     public static final String SETTINGS_SECURE_NFC_PAYMENT_FOREGROUND = "nfc_payment_foreground";
     public static final String SETTINGS_SECURE_NFC_PAYMENT_DEFAULT_COMPONENT = "nfc_payment_default_component";
     public static final String FEATURE_NFC_ANY = "android.hardware.nfc.any";
+
+    /**
+     * @hide constant copied from {@link Settings.Global}
+     * TODO(b/274636414): Migrate to official API in Android V.
+     */
+    public static final String SETTINGS_SATELLITE_MODE_RADIOS = "satellite_mode_radios";
+    /**
+     * @hide constant copied from {@link Settings.Global}
+     * TODO(b/274636414): Migrate to official API in Android V.
+     */
+    public static final String SETTINGS_SATELLITE_MODE_ENABLED = "satellite_mode_enabled";
 }
diff --git a/nfc/java/android/nfc/INfcAdapter.aidl b/nfc/java/android/nfc/INfcAdapter.aidl
index e151a0e..90ca92f 100644
--- a/nfc/java/android/nfc/INfcAdapter.aidl
+++ b/nfc/java/android/nfc/INfcAdapter.aidl
@@ -35,6 +35,7 @@
 import android.nfc.INfcWlcStateListener;
 import android.nfc.NfcAntennaInfo;
 import android.nfc.WlcListenerDeviceInfo;
+import android.nfc.cardemulation.PollingFrame;
 import android.os.Bundle;
 
 /**
@@ -48,8 +49,8 @@
     INfcAdapterExtras getNfcAdapterExtrasInterface(in String pkg);
     INfcDta getNfcDtaInterface(in String pkg);
     int getState();
-    boolean disable(boolean saveState);
-    boolean enable();
+    boolean disable(boolean saveState, in String pkg);
+    boolean enable(in String pkg);
     void pausePolling(int timeoutInMs);
     void resumePolling();
 
@@ -90,7 +91,7 @@
     boolean enableReaderOption(boolean enable);
     boolean isObserveModeSupported();
     boolean isObserveModeEnabled();
-    boolean setObserveMode(boolean enabled);
+    boolean setObserveMode(boolean enabled, String pkg);
 
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)")
     boolean setWlcEnabled(boolean enable);
@@ -101,12 +102,15 @@
 
     void updateDiscoveryTechnology(IBinder b, int pollFlags, int listenFlags);
 
-    void notifyPollingLoop(in Bundle frame);
+    void notifyPollingLoop(in PollingFrame frame);
     void notifyHceDeactivated();
+    void notifyTestHceData(in int technology, in byte[] data);
     int sendVendorNciMessage(int mt, int gid, int oid, in byte[] payload);
     void registerVendorExtensionCallback(in INfcVendorNciCallback callbacks);
     void unregisterVendorExtensionCallback(in INfcVendorNciCallback callbacks);
     void registerOemExtensionCallback(INfcOemExtensionCallback callbacks);
     void unregisterOemExtensionCallback(INfcOemExtensionCallback callbacks);
     void clearPreference();
+    void setScreenState();
+    void checkFirmware();
 }
diff --git a/nfc/java/android/nfc/INfcCardEmulation.aidl b/nfc/java/android/nfc/INfcCardEmulation.aidl
index 85a07b7..cb97f23 100644
--- a/nfc/java/android/nfc/INfcCardEmulation.aidl
+++ b/nfc/java/android/nfc/INfcCardEmulation.aidl
@@ -33,10 +33,13 @@
     boolean setShouldDefaultToObserveModeForService(int userId, in android.content.ComponentName service, boolean enable);
     boolean registerAidGroupForService(int userHandle, in ComponentName service, in AidGroup aidGroup);
     boolean registerPollingLoopFilterForService(int userHandle, in ComponentName service, in String pollingLoopFilter, boolean autoTransact);
+    boolean registerPollingLoopPatternFilterForService(int userHandle, in ComponentName service, in String pollingLoopPatternFilter, boolean autoTransact);
     boolean setOffHostForService(int userHandle, in ComponentName service, in String offHostSecureElement);
     boolean unsetOffHostForService(int userHandle, in ComponentName service);
     AidGroup getAidGroupForService(int userHandle, in ComponentName service, String category);
     boolean removeAidGroupForService(int userHandle, in ComponentName service, String category);
+    boolean removePollingLoopFilterForService(int userHandle, in ComponentName service, in String pollingLoopFilter);
+    boolean removePollingLoopPatternFilterForService(int userHandle, in ComponentName service, in String pollingLoopPatternFilter);
     List<ApduServiceInfo> getServices(int userHandle, in String category);
     boolean setPreferredService(in ComponentName service);
     boolean unsetPreferredService();
diff --git a/nfc/java/android/nfc/NfcAdapter.java b/nfc/java/android/nfc/NfcAdapter.java
index fe78c9b..395f81d 100644
--- a/nfc/java/android/nfc/NfcAdapter.java
+++ b/nfc/java/android/nfc/NfcAdapter.java
@@ -340,7 +340,8 @@
     public static final int FLAG_READER_NFC_BARCODE = 0x10;
 
     /** @hide */
-    @IntDef(flag = true, prefix = {"FLAG_READER_"}, value = {
+    @IntDef(flag = true, value = {
+        FLAG_SET_DEFAULT_TECH,
         FLAG_READER_KEEP,
         FLAG_READER_DISABLE,
         FLAG_READER_NFC_A,
@@ -438,7 +439,8 @@
     public static final int FLAG_USE_ALL_TECH = 0xff;
 
     /** @hide */
-    @IntDef(flag = true, prefix = {"FLAG_LISTEN_"}, value = {
+    @IntDef(flag = true, value = {
+        FLAG_SET_DEFAULT_TECH,
         FLAG_LISTEN_KEEP,
         FLAG_LISTEN_DISABLE,
         FLAG_LISTEN_NFC_PASSIVE_A,
@@ -449,6 +451,18 @@
     public @interface ListenTechnology {}
 
     /**
+     * Flag used in {@link #setDiscoveryTechnology(Activity, int, int)}.
+     * <p>
+     * Setting this flag changes the default listen or poll tech.
+     * Only available to privileged apps.
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_NFC_SET_DEFAULT_DISC_TECH)
+    @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+    public static final int FLAG_SET_DEFAULT_TECH = 0x40000000;
+
+    /**
      * @hide
      * @removed
      */
@@ -949,22 +963,9 @@
             throw new UnsupportedOperationException("You need a context on NfcAdapter to use the "
                     + " NFC extras APIs");
         }
-        try {
-            return sService.getNfcDtaInterface(mContext.getPackageName());
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-            // Try one more time
-            if (sService == null) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-                return null;
-            }
-            try {
-                return sService.getNfcDtaInterface(mContext.getPackageName());
-            } catch (RemoteException ee) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-            }
-            return null;
-        }
+        return callServiceReturn(() ->  sService.getNfcDtaInterface(mContext.getPackageName()),
+                null);
+
     }
 
     /**
@@ -1081,22 +1082,8 @@
     @SystemApi
     @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
     public @AdapterState int getAdapterState() {
-        try {
-            return sService.getState();
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-            // Try one more time
-            if (sService == null) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-                return NfcAdapter.STATE_OFF;
-            }
-            try {
-                return sService.getState();
-            } catch (RemoteException ee) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-            }
-            return NfcAdapter.STATE_OFF;
-        }
+        return callServiceReturn(() ->  sService.getState(), NfcAdapter.STATE_OFF);
+
     }
 
     /**
@@ -1106,6 +1093,9 @@
      * {@link #ACTION_ADAPTER_STATE_CHANGED} broadcasts to find out when the
      * operation is complete.
      *
+     * <p>This API is only allowed to be called by system apps
+     * or apps which are Device Owner or Profile Owner.
+     *
      * <p>If this returns true, then either NFC is already on, or
      * a {@link #ACTION_ADAPTER_STATE_CHANGED} broadcast will be sent
      * to indicate a state transition. If this returns false, then
@@ -1113,27 +1103,12 @@
      * NFC on (for example we are in airplane mode and NFC is not
      * toggleable in airplane mode on this platform).
      *
-     * @hide
      */
-    @SystemApi
+    @FlaggedApi(Flags.FLAG_NFC_STATE_CHANGE)
     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
     public boolean enable() {
-        try {
-            return sService.enable();
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-            // Try one more time
-            if (sService == null) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-                return false;
-            }
-            try {
-                return sService.enable();
-            } catch (RemoteException ee) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-            }
-            return false;
-        }
+        return callServiceReturn(() ->  sService.enable(mContext.getPackageName()), false);
+
     }
 
     /**
@@ -1146,33 +1121,22 @@
      * {@link #ACTION_ADAPTER_STATE_CHANGED} broadcasts to find out when the
      * operation is complete.
      *
+     * <p>This API is only allowed to be called by system apps
+     * or apps which are Device Owner or Profile Owner.
+     *
      * <p>If this returns true, then either NFC is already off, or
      * a {@link #ACTION_ADAPTER_STATE_CHANGED} broadcast will be sent
      * to indicate a state transition. If this returns false, then
      * there is some problem that prevents an attempt to turn
      * NFC off.
      *
-     * @hide
      */
-    @SystemApi
+    @FlaggedApi(Flags.FLAG_NFC_STATE_CHANGE)
     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
     public boolean disable() {
-        try {
-            return sService.disable(true);
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-            // Try one more time
-            if (sService == null) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-                return false;
-            }
-            try {
-                return sService.disable(true);
-            } catch (RemoteException ee) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-            }
-            return false;
-        }
+        return callServiceReturn(() ->  sService.disable(true, mContext.getPackageName()),
+                false);
+
     }
 
     /**
@@ -1182,22 +1146,9 @@
     @SystemApi
     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
     public boolean disable(boolean persist) {
-        try {
-            return sService.disable(persist);
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-            // Try one more time
-            if (sService == null) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-                return false;
-            }
-            try {
-                return sService.disable(persist);
-            } catch (RemoteException ee) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-            }
-            return false;
-        }
+        return callServiceReturn(() ->  sService.disable(persist, mContext.getPackageName()),
+                false);
+
     }
 
     /**
@@ -1223,12 +1174,7 @@
      */
     @FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE)
     public boolean isObserveModeSupported() {
-        try {
-            return sService.isObserveModeSupported();
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-            return false;
-        }
+        return callServiceReturn(() ->  sService.isObserveModeSupported(), false);
     }
 
     /**
@@ -1239,18 +1185,17 @@
 
     @FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE)
     public boolean isObserveModeEnabled() {
-        try {
-            return sService.isObserveModeEnabled();
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-            return false;
-        }
+        return callServiceReturn(() ->  sService.isObserveModeEnabled(), false);
     }
 
     /**
      * Controls whether the NFC adapter will allow transactions to proceed or be in observe mode
      * and simply observe and notify the APDU service of polling loop frames. See
-     * {@link #isObserveModeSupported()} for a description of observe mode.
+     * {@link #isObserveModeSupported()} for a description of observe mode. Only the package of the
+     * currently preferred service (the service set as preferred by the current foreground
+     * application via {@link CardEmulation#setPreferredService(Activity, ComponentName)} or the
+     * current Default Wallet Role Holder {@link android.app.role.RoleManager#ROLE_WALLET}),
+     * otherwise a call to this method will fail and return false.
      *
      * @param enabled false disables observe mode to allow the transaction to proceed while true
      *                enables observe mode and does not allow transactions to proceed.
@@ -1260,12 +1205,12 @@
 
     @FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE)
     public boolean setObserveModeEnabled(boolean enabled) {
-        try {
-            return sService.setObserveMode(enabled);
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-            return false;
+        if (mContext == null) {
+            throw new UnsupportedOperationException("You need a context on NfcAdapter to use the "
+                    + " observe mode APIs");
         }
+        return callServiceReturn(() ->  sService.setObserveMode(enabled, mContext.getPackageName()),
+                false);
     }
 
     /**
@@ -1862,14 +1807,6 @@
     public void setDiscoveryTechnology(@NonNull Activity activity,
             @PollTechnology int pollTechnology, @ListenTechnology int listenTechnology) {
 
-        // A special treatment of the _KEEP flags
-        if ((listenTechnology & FLAG_LISTEN_KEEP) != 0) {
-            listenTechnology = -1;
-        }
-        if ((pollTechnology & FLAG_READER_KEEP) != 0) {
-            pollTechnology = -1;
-        }
-
         if (listenTechnology == FLAG_LISTEN_DISABLE) {
             synchronized (sLock) {
                 if (!sHasNfcFeature) {
@@ -1889,7 +1826,25 @@
                 }
             }
         }
-        mNfcActivityManager.setDiscoveryTech(activity, pollTechnology, listenTechnology);
+    /*
+     * Privileged FLAG to set technology mask for all data processed by NFC controller
+     * Note: Use with caution! The app is responsible for ensuring that the discovery
+     * technology mask is returned to default.
+     * Note: FLAG_USE_ALL_TECH used with _KEEP flags will reset the technolody to android default
+     */
+        if (Flags.nfcSetDefaultDiscTech()
+                && ((pollTechnology & FLAG_SET_DEFAULT_TECH) == FLAG_SET_DEFAULT_TECH
+                || (listenTechnology & FLAG_SET_DEFAULT_TECH) == FLAG_SET_DEFAULT_TECH)) {
+            Binder token = new Binder();
+            try {
+                NfcAdapter.sService.updateDiscoveryTechnology(token,
+                        pollTechnology, listenTechnology);
+            } catch (RemoteException e) {
+                attemptDeadServiceRecovery(e);
+            }
+        } else {
+            mNfcActivityManager.setDiscoveryTech(activity, pollTechnology, listenTechnology);
+        }
     }
 
     /**
@@ -2021,22 +1976,8 @@
         if (!sHasNfcFeature && !sHasCeFeature) {
             throw new UnsupportedOperationException();
         }
-        try {
-            return sService.setNfcSecure(enable);
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-            // Try one more time
-            if (sService == null) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-                return false;
-            }
-            try {
-                return sService.setNfcSecure(enable);
-            } catch (RemoteException ee) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-            }
-            return false;
-        }
+        return callServiceReturn(() ->  sService.setNfcSecure(enable), false);
+
     }
 
     /**
@@ -2052,22 +1993,8 @@
         if (!sHasNfcFeature && !sHasCeFeature) {
             throw new UnsupportedOperationException();
         }
-        try {
-            return sService.deviceSupportsNfcSecure();
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-            // Try one more time
-            if (sService == null) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-                return false;
-            }
-            try {
-                return sService.deviceSupportsNfcSecure();
-            } catch (RemoteException ee) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-            }
-            return false;
-        }
+        return callServiceReturn(() ->  sService.deviceSupportsNfcSecure(), false);
+
     }
 
     /**
@@ -2085,22 +2012,8 @@
         if (!sHasNfcFeature && !sHasCeFeature) {
             throw new UnsupportedOperationException();
         }
-        try {
-            return sService.getNfcAntennaInfo();
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-            // Try one more time
-            if (sService == null) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-                return null;
-            }
-            try {
-                return sService.getNfcAntennaInfo();
-            } catch (RemoteException ee) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-            }
-            return null;
-        }
+        return callServiceReturn(() ->  sService.getNfcAntennaInfo(), null);
+
     }
 
     /**
@@ -2118,22 +2031,8 @@
         if (!sHasNfcFeature && !sHasCeFeature) {
             throw new UnsupportedOperationException();
         }
-        try {
-            return sService.isNfcSecureEnabled();
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-            // Try one more time
-            if (sService == null) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-                return false;
-            }
-            try {
-                return sService.isNfcSecureEnabled();
-            } catch (RemoteException ee) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-            }
-            return false;
-        }
+        return callServiceReturn(() ->  sService.isNfcSecureEnabled(), false);
+
     }
 
     /**
@@ -2149,22 +2048,8 @@
         if (!sHasNfcFeature) {
             throw new UnsupportedOperationException();
         }
-        try {
-            return sService.enableReaderOption(enable);
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-            // Try one more time
-            if (sService == null) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-                return false;
-            }
-            try {
-                return sService.enableReaderOption(enable);
-            } catch (RemoteException ee) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-            }
-            return false;
-        }
+        return callServiceReturn(() ->  sService.enableReaderOption(enable), false);
+
     }
 
     /**
@@ -2178,22 +2063,8 @@
         if (!sHasNfcFeature) {
             throw new UnsupportedOperationException();
         }
-        try {
-            return sService.isReaderOptionSupported();
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-            // Try one more time
-            if (sService == null) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-                return false;
-            }
-            try {
-                return sService.isReaderOptionSupported();
-            } catch (RemoteException ee) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-            }
-            return false;
-        }
+        return callServiceReturn(() ->  sService.isReaderOptionSupported(), false);
+
     }
 
     /**
@@ -2209,22 +2080,8 @@
         if (!sHasNfcFeature) {
             throw new UnsupportedOperationException();
         }
-        try {
-            return sService.isReaderOptionEnabled();
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-            // Try one more time
-            if (sService == null) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-                return false;
-            }
-            try {
-                return sService.isReaderOptionEnabled();
-            } catch (RemoteException ee) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-            }
-            return false;
-        }
+        return callServiceReturn(() ->  sService.isReaderOptionEnabled(), false);
+
     }
 
     /**
@@ -2352,11 +2209,9 @@
         synchronized (mLock) {
             mTagRemovedListener = iListener;
         }
-        try {
-            return sService.ignore(tag.getServiceHandle(), debounceMs, iListener);
-        } catch (RemoteException e) {
-            return false;
-        }
+        final ITagRemovedCallback.Stub passedListener = iListener;
+        return callServiceReturn(() ->
+                sService.ignore(tag.getServiceHandle(), debounceMs, passedListener), false);
     }
 
     /**
@@ -2473,22 +2328,9 @@
             throw new UnsupportedOperationException("You need a context on NfcAdapter to use the "
                     + " NFC extras APIs");
         }
-        try {
-            return sService.getNfcAdapterExtrasInterface(mContext.getPackageName());
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-            // Try one more time
-            if (sService == null) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-                return null;
-            }
-            try {
-                return sService.getNfcAdapterExtrasInterface(mContext.getPackageName());
-            } catch (RemoteException ee) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-            }
-            return null;
-        }
+        return callServiceReturn(() ->
+                sService.getNfcAdapterExtrasInterface(mContext.getPackageName()), null);
+
     }
 
     void enforceResumed(Activity activity) {
@@ -2533,22 +2375,8 @@
         if (!sHasNfcFeature && !sHasCeFeature) {
             throw new UnsupportedOperationException();
         }
-        try {
-            return sService.setControllerAlwaysOn(value);
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-            // Try one more time
-            if (sService == null) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-                return false;
-            }
-            try {
-                return sService.setControllerAlwaysOn(value);
-            } catch (RemoteException ee) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-            }
-            return false;
-        }
+        return callServiceReturn(() ->  sService.setControllerAlwaysOn(value), false);
+
     }
 
     /**
@@ -2564,22 +2392,8 @@
     @SystemApi
     @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
     public boolean isControllerAlwaysOn() {
-        try {
-            return sService.isControllerAlwaysOn();
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-            // Try one more time
-            if (sService == null) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-                return false;
-            }
-            try {
-                return sService.isControllerAlwaysOn();
-            } catch (RemoteException ee) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-            }
-            return false;
-        }
+        return callServiceReturn(() ->  sService.isControllerAlwaysOn(), false);
+
     }
 
     /**
@@ -2598,22 +2412,8 @@
         if (!sHasNfcFeature && !sHasCeFeature) {
             throw new UnsupportedOperationException();
         }
-        try {
-            return sService.isControllerAlwaysOnSupported();
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-            // Try one more time
-            if (sService == null) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-                return false;
-            }
-            try {
-                return sService.isControllerAlwaysOnSupported();
-            } catch (RemoteException ee) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-            }
-            return false;
-        }
+        return callServiceReturn(() ->  sService.isControllerAlwaysOnSupported(), false);
+
     }
 
     /**
@@ -2683,21 +2483,9 @@
             Log.e(TAG, "TagIntentAppPreference is not supported");
             throw new UnsupportedOperationException();
         }
-        try {
-            return sService.setTagIntentAppPreferenceForUser(userId, pkg, allow);
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-            // Try one more time
-            if (sService == null) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-            }
-            try {
-                return sService.setTagIntentAppPreferenceForUser(userId, pkg, allow);
-            } catch (RemoteException ee) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-            }
-            return TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE;
-        }
+        return callServiceReturn(() ->
+                sService.setTagIntentAppPreferenceForUser(userId, pkg, allow),
+                        TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE);
     }
 
 
@@ -2772,22 +2560,8 @@
         if (!sHasNfcFeature) {
             throw new UnsupportedOperationException();
         }
-        try {
-            return sService.isTagIntentAppPreferenceSupported();
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-            // Try one more time
-            if (sService == null) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-                return false;
-            }
-            try {
-                return sService.isTagIntentAppPreferenceSupported();
-            } catch (RemoteException ee) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-            }
-            return false;
-        }
+        return callServiceReturn(() ->  sService.isTagIntentAppPreferenceSupported(), false);
+
     }
 
    /**
@@ -2800,12 +2574,30 @@
     @TestApi
     @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
     public void notifyPollingLoop(@NonNull PollingFrame pollingFrame) {
-        Bundle frame = pollingFrame.toBundle();
+        callService(() ->  sService.notifyPollingLoop(pollingFrame));
+    }
+
+
+   /**
+     * Notifies the system of new HCE data for tests.
+     *
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public void notifyTestHceData(int technology, byte[] data) {
+        callService(() ->  sService.notifyTestHceData(technology, data));
+    }
+
+    interface ServiceCall {
+        void call() throws RemoteException;
+    }
+
+    void callService(ServiceCall call) {
         try {
             if (sService == null) {
                 attemptDeadServiceRecovery(null);
             }
-            sService.notifyPollingLoop(frame);
+            call.call();
         } catch (RemoteException e) {
             attemptDeadServiceRecovery(e);
             // Try one more time
@@ -2814,12 +2606,36 @@
                 return;
             }
             try {
-                sService.notifyPollingLoop(frame);
+                call.call();
             } catch (RemoteException ee) {
                 Log.e(TAG, "Failed to recover NFC Service.");
             }
         }
     }
+    interface ServiceCallReturn<T> {
+        T call() throws RemoteException;
+    }
+    <T> T callServiceReturn(ServiceCallReturn<T> call, T defaultReturn) {
+        try {
+            if (sService == null) {
+                attemptDeadServiceRecovery(null);
+            }
+            return call.call();
+        } catch (RemoteException e) {
+            attemptDeadServiceRecovery(e);
+            // Try one more time
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover NFC Service.");
+                return defaultReturn;
+            }
+            try {
+                return call.call();
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to recover NFC Service.");
+            }
+        }
+        return defaultReturn;
+    }
 
    /**
      * Notifies the system of a an HCE session being deactivated.
@@ -2829,24 +2645,7 @@
     @TestApi
     @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
     public void notifyHceDeactivated() {
-        try {
-            if (sService == null) {
-                attemptDeadServiceRecovery(null);
-            }
-            sService.notifyHceDeactivated();
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-            // Try one more time
-            if (sService == null) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-                return;
-            }
-            try {
-                sService.notifyHceDeactivated();
-            } catch (RemoteException ee) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-            }
-        }
+        callService(() ->  sService.notifyHceDeactivated());
     }
 
     /**
@@ -2862,22 +2661,7 @@
         if (!sHasNfcWlcFeature) {
             throw new UnsupportedOperationException();
         }
-        try {
-            return sService.setWlcEnabled(enable);
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-            // Try one more time
-            if (sService == null) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-                return false;
-            }
-            try {
-                return sService.setWlcEnabled(enable);
-            } catch (RemoteException ee) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-            }
-            return false;
-        }
+        return callServiceReturn(() ->  sService.setWlcEnabled(enable), false);
     }
 
     /**
@@ -2892,22 +2676,8 @@
         if (!sHasNfcWlcFeature) {
             throw new UnsupportedOperationException();
         }
-        try {
-            return sService.isWlcEnabled();
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-            // Try one more time
-            if (sService == null) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-                return false;
-            }
-            try {
-                return sService.isWlcEnabled();
-            } catch (RemoteException ee) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-            }
-            return false;
-        }
+        return callServiceReturn(() ->  sService.isWlcEnabled(), false);
+
     }
 
     /**
@@ -2986,22 +2756,8 @@
         if (!sHasNfcWlcFeature) {
             throw new UnsupportedOperationException();
         }
-        try {
-            return sService.getWlcListenerDeviceInfo();
-        } catch (RemoteException e) {
-            attemptDeadServiceRecovery(e);
-            // Try one more time
-            if (sService == null) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-                return null;
-            }
-            try {
-                return sService.getWlcListenerDeviceInfo();
-            } catch (RemoteException ee) {
-                Log.e(TAG, "Failed to recover NFC Service.");
-            }
-            return null;
-        }
+        return callServiceReturn(() ->  sService.getWlcListenerDeviceInfo(), null);
+
     }
 
     /**
diff --git a/nfc/java/android/nfc/NfcAntennaInfo.java b/nfc/java/android/nfc/NfcAntennaInfo.java
index b002ca2..c57b2e0 100644
--- a/nfc/java/android/nfc/NfcAntennaInfo.java
+++ b/nfc/java/android/nfc/NfcAntennaInfo.java
@@ -64,9 +64,9 @@
 
     /**
      * Whether the device is foldable. When the device is foldable,
-     * the 0, 0 is considered to be bottom-left when the device is unfolded and
+     * the 0, 0 is considered to be top-left when the device is unfolded and
      * the screens are facing the user. For non-foldable devices 0, 0
-     * is bottom-left when the user is facing the screen.
+     * is top-left when the user is facing the screen.
      */
     public boolean isDeviceFoldable() {
         return mDeviceFoldable;
diff --git a/nfc/java/android/nfc/NfcOemExtension.java b/nfc/java/android/nfc/NfcOemExtension.java
index 1eff58c..f6138a6 100644
--- a/nfc/java/android/nfc/NfcOemExtension.java
+++ b/nfc/java/android/nfc/NfcOemExtension.java
@@ -141,6 +141,34 @@
         }
     }
 
+    /**
+     * Get the screen state from system and set it to current screen state.
+     */
+    @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    public void synchronizeScreenState() {
+        try {
+            NfcAdapter.sService.setScreenState();
+        } catch (RemoteException e) {
+            mAdapter.attemptDeadServiceRecovery(e);
+        }
+    }
+
+    /**
+     * Check if the firmware needs updating.
+     *
+     * <p>If an update is needed, a firmware will be triggered when NFC is disabled.
+     */
+    @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    public void maybeTriggerFirmwareUpdate() {
+        try {
+            NfcAdapter.sService.checkFirmware();
+        } catch (RemoteException e) {
+            mAdapter.attemptDeadServiceRecovery(e);
+        }
+    }
+
     private final class NfcOemExtensionCallback extends INfcOemExtensionCallback.Stub {
         @Override
         public void onTagConnected(boolean connected, Tag tag) throws RemoteException {
diff --git a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
index 2c7d61e..3cf0a4d 100644
--- a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -108,6 +108,8 @@
 
     private final Map<String, Boolean> mAutoTransact;
 
+    private final Map<Pattern, Boolean> mAutoTransactPatterns;
+
     /**
      * Whether this service should only be started when the device is unlocked.
      */
@@ -179,7 +181,7 @@
         this(info, onHost, description, staticAidGroups, dynamicAidGroups,
                 requiresUnlock, requiresScreenOn, bannerResource, uid,
                 settingsActivityName, offHost, staticOffHost, isEnabled,
-                new HashMap<String, Boolean>());
+                new HashMap<String, Boolean>(), new HashMap<Pattern, Boolean>());
     }
 
     /**
@@ -189,12 +191,13 @@
             List<AidGroup> staticAidGroups, List<AidGroup> dynamicAidGroups,
             boolean requiresUnlock, boolean requiresScreenOn, int bannerResource, int uid,
             String settingsActivityName, String offHost, String staticOffHost, boolean isEnabled,
-            HashMap<String, Boolean> autoTransact) {
+            Map<String, Boolean> autoTransact, Map<Pattern, Boolean> autoTransactPatterns) {
         this.mService = info;
         this.mDescription = description;
         this.mStaticAidGroups = new HashMap<String, AidGroup>();
         this.mDynamicAidGroups = new HashMap<String, AidGroup>();
         this.mAutoTransact = autoTransact;
+        this.mAutoTransactPatterns = autoTransactPatterns;
         this.mOffHostName = offHost;
         this.mStaticOffHostName = staticOffHost;
         this.mOnHost = onHost;
@@ -314,6 +317,7 @@
             mStaticAidGroups = new HashMap<String, AidGroup>();
             mDynamicAidGroups = new HashMap<String, AidGroup>();
             mAutoTransact = new HashMap<String, Boolean>();
+            mAutoTransactPatterns = new HashMap<Pattern, Boolean>();
             mOnHost = onHost;
 
             final int depth = parser.getDepth();
@@ -406,7 +410,29 @@
                     boolean autoTransact = a.getBoolean(
                             com.android.internal.R.styleable.PollingLoopFilter_autoTransact,
                             false);
-                    mAutoTransact.put(plf, autoTransact);
+                    if (!mOnHost && !autoTransact) {
+                        Log.e(TAG, "Ignoring polling-loop-filter " + plf
+                                + " for offhost service that isn't autoTransact");
+                    } else {
+                        mAutoTransact.put(plf, autoTransact);
+                    }
+                    a.recycle();
+                } else if (eventType == XmlPullParser.START_TAG
+                        && "polling-loop-pattern-filter".equals(tagName) && currentGroup == null) {
+                    final TypedArray a = res.obtainAttributes(attrs,
+                            com.android.internal.R.styleable.PollingLoopPatternFilter);
+                    String plf = a.getString(
+                            com.android.internal.R.styleable.PollingLoopPatternFilter_name)
+                                    .toUpperCase(Locale.ROOT);
+                    boolean autoTransact = a.getBoolean(
+                            com.android.internal.R.styleable.PollingLoopFilter_autoTransact,
+                            false);
+                    if (!mOnHost && !autoTransact) {
+                        Log.e(TAG, "Ignoring polling-loop-filter " + plf
+                                + " for offhost service that isn't autoTransact");
+                    } else {
+                        mAutoTransactPatterns.put(Pattern.compile(plf), autoTransact);
+                    }
                     a.recycle();
                 }
             }
@@ -481,7 +507,30 @@
      */
     @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
     public boolean getShouldAutoTransact(@NonNull String plf) {
-        return mAutoTransact.getOrDefault(plf.toUpperCase(Locale.ROOT), false);
+        if (mAutoTransact.getOrDefault(plf.toUpperCase(Locale.ROOT), false)) {
+            return true;
+        }
+        List<Pattern> patternMatches = mAutoTransactPatterns.keySet().stream()
+                .filter(p -> p.matcher(plf).matches()).toList();
+        if (patternMatches == null || patternMatches.size() == 0) {
+            return false;
+        }
+        for (Pattern patternMatch : patternMatches) {
+            if (mAutoTransactPatterns.get(patternMatch)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns the current polling loop pattern filters for this service.
+     * @return List of polling loop pattern filters.
+     */
+    @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
+    @NonNull
+    public List<Pattern> getPollingLoopPatternFilters() {
+        return new ArrayList<>(mAutoTransactPatterns.keySet());
     }
 
     /**
@@ -683,13 +732,17 @@
      * Add a Polling Loop Filter. Custom NFC polling frames that match this filter will be
      * delivered to {@link HostApduService#processPollingFrames(List)}. Adding a key with this
      * multiple times will cause the value to be overwritten each time.
-     * @param pollingLoopFilter the polling loop filter to add, must be a  valide hexadecimal string
+     * @param pollingLoopFilter the polling loop filter to add, must be a valid hexadecimal string
+     * @param autoTransact when true, disable observe mode when this filter matches, when false,
+     *                     matching does not change the observe mode state
      */
     @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
     public void addPollingLoopFilter(@NonNull String pollingLoopFilter,
             boolean autoTransact) {
+        if (!mOnHost && !autoTransact) {
+            return;
+        }
         mAutoTransact.put(pollingLoopFilter, autoTransact);
-
     }
 
     /**
@@ -703,6 +756,35 @@
     }
 
     /**
+     * Add a Polling Loop Pattern Filter. Custom NFC polling frames that match this filter will be
+     * delivered to {@link HostApduService#processPollingFrames(List)}. Adding a key with this
+     * multiple times will cause the value to be overwritten each time.
+     * @param pollingLoopPatternFilter the polling loop pattern filter to add, must be a valid
+     *                                regex to match a hexadecimal string
+     * @param autoTransact when true, disable observe mode when this filter matches, when false,
+     *                     matching does not change the observe mode state
+     */
+    @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public void addPollingLoopPatternFilter(@NonNull String pollingLoopPatternFilter,
+            boolean autoTransact) {
+        if (!mOnHost && !autoTransact) {
+            return;
+        }
+        mAutoTransactPatterns.put(Pattern.compile(pollingLoopPatternFilter), autoTransact);
+    }
+
+    /**
+     * Remove a Polling Loop Pattern Filter. Custom NFC polling frames that match this filter will
+     * no longer be delivered to {@link HostApduService#processPollingFrames(List)}.
+     * @param pollingLoopPatternFilter this polling loop filter to add.
+     */
+    @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public void removePollingLoopPatternFilter(@NonNull String pollingLoopPatternFilter) {
+        mAutoTransactPatterns.remove(
+                Pattern.compile(pollingLoopPatternFilter.toUpperCase(Locale.ROOT)));
+    }
+
+    /**
      * Sets the off host Secure Element.
      * @param  offHost  Secure Element to set. Only accept strings with prefix SIM or prefix eSE.
      *                  Ref: GSMA TS.26 - NFC Handset Requirements
@@ -856,6 +938,8 @@
         dest.writeInt(mCategoryOtherServiceEnabled ? 1 : 0);
         dest.writeInt(mAutoTransact.size());
         dest.writeMap(mAutoTransact);
+        dest.writeInt(mAutoTransactPatterns.size());
+        dest.writeMap(mAutoTransactPatterns);
     };
 
     @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
@@ -889,10 +973,15 @@
                             new HashMap<String, Boolean>(autoTransactSize);
                     source.readMap(autoTransact, getClass().getClassLoader(),
                             String.class, Boolean.class);
+                    int autoTransactPatternSize = source.readInt();
+                    HashMap<Pattern, Boolean> autoTransactPatterns =
+                            new HashMap<Pattern, Boolean>(autoTransactSize);
+                    source.readMap(autoTransactPatterns, getClass().getClassLoader(),
+                            Pattern.class, Boolean.class);
                     return new ApduServiceInfo(info, onHost, description, staticAidGroups,
                             dynamicAidGroups, requiresUnlock, requiresScreenOn, bannerResource, uid,
                             settingsActivityName, offHostName, staticOffHostName,
-                            isEnabled, autoTransact);
+                            isEnabled, autoTransact, autoTransactPatterns);
                 }
 
                 @Override
@@ -939,6 +1028,9 @@
         pw.println("    Settings Activity: " + mSettingsActivityName);
         pw.println("    Requires Device Unlock: " + mRequiresDeviceUnlock);
         pw.println("    Requires Device ScreenOn: " + mRequiresDeviceScreenOn);
+        pw.println("    Should Default to Observe Mode: " + mShouldDefaultToObserveMode);
+        pw.println("    Auto-Transact Mapping: " + mAutoTransact);
+        pw.println("    Auto-Transact Patterns: " + mAutoTransactPatterns);
     }
 
 
@@ -992,6 +1084,27 @@
             proto.end(token);
         }
         proto.write(ApduServiceInfoProto.SETTINGS_ACTIVITY_NAME, mSettingsActivityName);
+        proto.write(ApduServiceInfoProto.SHOULD_DEFAULT_TO_OBSERVE_MODE,
+                mShouldDefaultToObserveMode);
+        {
+            long token = proto.start(ApduServiceInfoProto.AUTO_TRANSACT_MAPPING);
+            for (Map.Entry<String, Boolean> entry : mAutoTransact.entrySet()) {
+                proto.write(ApduServiceInfoProto.AutoTransactMapping.AID, entry.getKey());
+                proto.write(ApduServiceInfoProto.AutoTransactMapping.SHOULD_AUTO_TRANSACT,
+                        entry.getValue());
+            }
+            proto.end(token);
+        }
+        {
+            long token = proto.start(ApduServiceInfoProto.AUTO_TRANSACT_PATTERNS);
+            for (Map.Entry<Pattern, Boolean> entry : mAutoTransactPatterns.entrySet()) {
+                proto.write(ApduServiceInfoProto.AutoTransactPattern.REGEXP_PATTERN,
+                        entry.getKey().pattern());
+                proto.write(ApduServiceInfoProto.AutoTransactPattern.SHOULD_AUTO_TRANSACT,
+                        entry.getValue());
+            }
+            proto.end(token);
+        }
     }
 
     private static final Pattern AID_PATTERN = Pattern.compile("[0-9A-Fa-f]{10,32}\\*?\\#?");
diff --git a/nfc/java/android/nfc/cardemulation/CardEmulation.java b/nfc/java/android/nfc/cardemulation/CardEmulation.java
index 61d651fa..2fe2ce3 100644
--- a/nfc/java/android/nfc/cardemulation/CardEmulation.java
+++ b/nfc/java/android/nfc/cardemulation/CardEmulation.java
@@ -27,6 +27,7 @@
 import android.annotation.UserHandleAware;
 import android.annotation.UserIdInt;
 import android.app.Activity;
+import android.app.role.RoleManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -35,6 +36,7 @@
 import android.nfc.Flags;
 import android.nfc.INfcCardEmulation;
 import android.nfc.NfcAdapter;
+import android.os.Build;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -44,6 +46,7 @@
 import java.util.HashMap;
 import java.util.HexFormat;
 import java.util.List;
+import java.util.Locale;
 import java.util.regex.Pattern;
 
 /**
@@ -60,6 +63,7 @@
  */
 public final class CardEmulation {
     private static final Pattern AID_PATTERN = Pattern.compile("[0-9A-Fa-f]{10,32}\\*?\\#?");
+    private static final Pattern PLPF_PATTERN = Pattern.compile("[0-9A-Fa-f,\\?,\\*\\.]*");
 
     static final String TAG = "CardEmulation";
 
@@ -268,12 +272,16 @@
     }
 
     /**
+     * <p>
      * Returns whether the user has allowed AIDs registered in the
      * specified category to be handled by a service that is preferred
      * by the foreground application, instead of by a pre-configured default.
      *
      * Foreground applications can set such preferences using the
      * {@link #setPreferredService(Activity, ComponentName)} method.
+     * <p class="note">
+     * Starting with {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}, this method will always
+     * return true.
      *
      * @param category The category, e.g. {@link #CATEGORY_PAYMENT}
      * @return whether AIDs in the category can be handled by a service
@@ -281,10 +289,16 @@
      */
     @SuppressWarnings("NonUserGetterCalled")
     public boolean categoryAllowsForegroundPreference(String category) {
+        Context contextAsUser = mContext.createContextAsUser(
+                UserHandle.of(UserHandle.myUserId()), 0);
+
+        RoleManager roleManager = contextAsUser.getSystemService(RoleManager.class);
+        if (roleManager.isRoleAvailable(RoleManager.ROLE_WALLET)) {
+            return true;
+        }
+
         if (CATEGORY_PAYMENT.equals(category)) {
             boolean preferForeground = false;
-            Context contextAsUser = mContext.createContextAsUser(
-                    UserHandle.of(UserHandle.myUserId()), 0);
             try {
                 preferForeground = Settings.Secure.getInt(
                         contextAsUser.getContentResolver(),
@@ -307,6 +321,11 @@
      *    every time what service they would like to use in this category.
      * <p>{@link #SELECTION_MODE_ASK_IF_CONFLICT} the user will only be asked
      *    to pick a service if there is a conflict.
+     *
+     * <p class="note">
+     * Starting with {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}, the default service defined
+     * by the holder of {@link android.app.role.RoleManager#ROLE_WALLET} and is category agnostic.
+     *
      * @param category The category, for example {@link #CATEGORY_PAYMENT}
      * @return the selection mode for the passed in category
      */
@@ -364,9 +383,9 @@
      * auto-transact or not.  The PLF can be sequence of an
      * even number of at least 2 hexadecimal numbers (0-9, A-F or a-f), representing a series of
      * bytes. When non-standard polling loop frame matches this sequence exactly, it may be
-     * delivered to {@link HostApduService#processPollingFrames(List)}. If auto-transact is set to
-     * true, then observe mode will also be disabled.  if this service is currently preferred or
-     * there are no other services registered for this filter.
+     * delivered to {@link HostApduService#processPollingFrames(List)}.  If auto-transact
+     * is set to true and this service is currently preferred or there are no other services
+     * registered for this filter then observe mode will also be disabled.
      * @param service The HostApduService to register the filter for
      * @param pollingLoopFilter The filter to register
      * @param autoTransact true to have the NFC stack automatically disable observe mode and allow
@@ -401,6 +420,128 @@
     }
 
     /**
+     * Unregister a polling loop filter (PLF) for a HostApduService. If the PLF had previously been
+     * registered via {@link #registerPollingLoopFilterForService(ComponentName, String, boolean)}
+     * for this service it will be removed.
+     * @param service The HostApduService to unregister the filter for
+     * @param pollingLoopFilter The filter to unregister
+     * @return true if the filter was removed, false otherwise
+     * @throws IllegalArgumentException if the passed in string doesn't parse to at least one byte
+     */
+    @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public boolean removePollingLoopFilterForService(@NonNull ComponentName service,
+            @NonNull String pollingLoopFilter) {
+        pollingLoopFilter = validatePollingLoopFilter(pollingLoopFilter);
+
+        try {
+            return sService.removePollingLoopFilterForService(mContext.getUser().getIdentifier(),
+                    service, pollingLoopFilter);
+        } catch (RemoteException e) {
+            // Try one more time
+            recoverService();
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return false;
+            }
+            try {
+                return sService.removePollingLoopFilterForService(
+                        mContext.getUser().getIdentifier(), service,
+                        pollingLoopFilter);
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to reach CardEmulationService.");
+                return false;
+            }
+        }
+    }
+
+
+    /**
+     * Register a polling loop pattern filter (PLPF) for a HostApduService and indicate whether it
+     * should auto-transact or not. The pattern may include the characters 0-9 and A-F as well as
+     * the regular expression operators `.`, `?` and `*`. When the beginning of anon-standard
+     * polling loop frame matches this sequence exactly, it may be delivered to
+     * {@link HostApduService#processPollingFrames(List)}. If auto-transact is set to true and this
+     * service is currently preferred or there are no other services registered for this filter
+     * then observe mode will also be disabled.
+     * @param service The HostApduService to register the filter for
+     * @param pollingLoopPatternFilter The pattern filter to register, must to be compatible with
+     *         {@link java.util.regex.Pattern#compile(String)} and only contain hexadecimal numbers
+     *         and `.`, `?` and `*` operators
+     * @param autoTransact true to have the NFC stack automatically disable observe mode and allow
+     *         transactions to proceed when this filter matches, false otherwise
+     * @return true if the filter was registered, false otherwise
+     * @throws IllegalArgumentException if the filter containst elements other than hexadecimal
+     *         numbers and `.`, `?` and `*` operators
+     * @throws java.util.regex.PatternSyntaxException if the regex syntax is invalid
+     */
+    @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public boolean registerPollingLoopPatternFilterForService(@NonNull ComponentName service,
+            @NonNull String pollingLoopPatternFilter, boolean autoTransact) {
+        pollingLoopPatternFilter = validatePollingLoopPatternFilter(pollingLoopPatternFilter);
+
+        try {
+            return sService.registerPollingLoopPatternFilterForService(
+                    mContext.getUser().getIdentifier(),
+                    service, pollingLoopPatternFilter, autoTransact);
+        } catch (RemoteException e) {
+            // Try one more time
+            recoverService();
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return false;
+            }
+            try {
+                return sService.registerPollingLoopPatternFilterForService(
+                        mContext.getUser().getIdentifier(), service,
+                        pollingLoopPatternFilter, autoTransact);
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to reach CardEmulationService.");
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Unregister a polling loop pattern filter (PLPF) for a HostApduService. If the PLF had
+     * previously been registered via
+     * {@link #registerPollingLoopFilterForService(ComponentName, String, boolean)} for this
+     * service it will be removed.
+     * @param service The HostApduService to unregister the filter for
+     * @param pollingLoopPatternFilter The filter to unregister, must to be compatible with
+     *         {@link java.util.regex.Pattern#compile(String)} and only contain hexadecimal numbers
+     *         and`.`, `?` and `*` operators
+     * @return true if the filter was removed, false otherwise
+     * @throws IllegalArgumentException if the filter containst elements other than hexadecimal
+     *         numbers and `.`, `?` and `*` operators
+     * @throws java.util.regex.PatternSyntaxException if the regex syntax is invalid
+     */
+    @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public boolean removePollingLoopPatternFilterForService(@NonNull ComponentName service,
+            @NonNull String pollingLoopPatternFilter) {
+        pollingLoopPatternFilter = validatePollingLoopPatternFilter(pollingLoopPatternFilter);
+
+        try {
+            return sService.removePollingLoopPatternFilterForService(
+                    mContext.getUser().getIdentifier(), service, pollingLoopPatternFilter);
+        } catch (RemoteException e) {
+            // Try one more time
+            recoverService();
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return false;
+            }
+            try {
+                return sService.removePollingLoopPatternFilterForService(
+                        mContext.getUser().getIdentifier(), service,
+                        pollingLoopPatternFilter);
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to reach CardEmulationService.");
+                return false;
+            }
+        }
+    }
+
+    /**
      * Registers a list of AIDs for a specific category for the
      * specified service.
      *
@@ -780,6 +921,13 @@
     /**
      * Retrieves the route destination for the preferred payment service.
      *
+     * <p class="note">
+     * Starting with {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}, the preferred payment service
+     * no longer exists and is replaced by {@link android.app.role.RoleManager#ROLE_WALLET}. This
+     * will return the route for one of the services registered by the role holder (if any). If
+     * there are multiple services registered, it is unspecified which of those will be used to
+     * determine the route.
+     *
      * @return The route destination secure element name of the preferred payment service.
      *         HCE payment: "Host"
      *         OffHost payment: 1. String with prefix SIM or prefix eSE string.
@@ -835,6 +983,13 @@
     /**
      * Returns a user-visible description of the preferred payment service.
      *
+     * <p class="note">
+     * Starting with {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}, the preferred payment service
+     * no longer exists and is replaced by {@link android.app.role.RoleManager#ROLE_WALLET}. This
+     * will return the description for one of the services registered by the role holder (if any).
+     * If there are multiple services registered, it is unspecified which of those will be used
+     * to obtain the service description here.
+     *
      * @return the preferred payment service description
      */
     @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO)
@@ -998,6 +1153,23 @@
     }
 
     /**
+     * Tests the validity of the polling loop pattern filter.
+     * @param pollingLoopPatternFilter The polling loop filter to test.
+     *
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static @NonNull String validatePollingLoopPatternFilter(
+        @NonNull String pollingLoopPatternFilter) {
+        // Verify hex characters
+        if (!PLPF_PATTERN.matcher(pollingLoopPatternFilter).matches()) {
+            throw new IllegalArgumentException(
+                "Polling loop pattern filters may only contain hexadecimal numbers, ?s and *s");
+        }
+        return Pattern.compile(pollingLoopPatternFilter.toUpperCase(Locale.ROOT)).toString();
+    }
+
+    /**
      * A valid AID according to ISO/IEC 7816-4:
      * <ul>
      * <li>Has >= 5 bytes and <=16 bytes (>=10 hex chars and <= 32 hex chars)
diff --git a/nfc/java/android/nfc/cardemulation/HostApduService.java b/nfc/java/android/nfc/cardemulation/HostApduService.java
index f3ba2d0..c3c74a6 100644
--- a/nfc/java/android/nfc/cardemulation/HostApduService.java
+++ b/nfc/java/android/nfc/cardemulation/HostApduService.java
@@ -326,15 +326,12 @@
                 }
                 break;
                 case MSG_POLLING_LOOP:
-                    ArrayList<Bundle> frames =
-                            msg.getData().getParcelableArrayList(KEY_POLLING_LOOP_FRAMES_BUNDLE,
-                            Bundle.class);
-                    ArrayList<PollingFrame> pollingFrames =
-                            new ArrayList<PollingFrame>(frames.size());
-                    for (Bundle frame : frames) {
-                        pollingFrames.add(new PollingFrame(frame));
+                    if (android.nfc.Flags.nfcReadPollingLoop()) {
+                        ArrayList<PollingFrame> pollingFrames =
+                                msg.getData().getParcelableArrayList(
+                                    KEY_POLLING_LOOP_FRAMES_BUNDLE, PollingFrame.class);
+                        processPollingFrames(pollingFrames);
                     }
-                    processPollingFrames(pollingFrames);
                     break;
             default:
                 super.handleMessage(msg);
diff --git a/nfc/java/android/nfc/cardemulation/PollingFrame.aidl b/nfc/java/android/nfc/cardemulation/PollingFrame.aidl
new file mode 100644
index 0000000..8e09f8b
--- /dev/null
+++ b/nfc/java/android/nfc/cardemulation/PollingFrame.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2024 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.nfc.cardemulation;
+
+parcelable PollingFrame;
\ No newline at end of file
diff --git a/nfc/java/android/nfc/cardemulation/PollingFrame.java b/nfc/java/android/nfc/cardemulation/PollingFrame.java
index 994f4ae..5dcc84c 100644
--- a/nfc/java/android/nfc/cardemulation/PollingFrame.java
+++ b/nfc/java/android/nfc/cardemulation/PollingFrame.java
@@ -32,19 +32,26 @@
 
 /**
  * Polling Frames represent data about individual frames of an NFC polling loop. These frames will
- * be deliverd to subclasses of {@link HostApduService} that have registered filters with
- * {@link CardEmulation#registerPollingLoopFilterForService(ComponentName, String)} that match a
- * given frame in a loop and will be delivered through calls to
+ * be delivered to subclasses of {@link HostApduService} that have registered filters with
+ * {@link CardEmulation#registerPollingLoopFilterForService(ComponentName, String, boolean)} that
+ * match a given frame in a loop and will be delivered through calls to
  * {@link HostApduService#processPollingFrames(List)}.
  */
 @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
-public final class PollingFrame implements Parcelable{
+public final class PollingFrame implements Parcelable {
 
     /**
      * @hide
      */
-    @IntDef(prefix = { "POLLING_LOOP_TYPE_"}, value = { POLLING_LOOP_TYPE_A, POLLING_LOOP_TYPE_B,
-            POLLING_LOOP_TYPE_F, POLLING_LOOP_TYPE_OFF, POLLING_LOOP_TYPE_ON })
+    @IntDef(prefix = { "POLLING_LOOP_TYPE_"},
+        value = {
+            POLLING_LOOP_TYPE_A,
+            POLLING_LOOP_TYPE_B,
+            POLLING_LOOP_TYPE_F,
+            POLLING_LOOP_TYPE_OFF,
+            POLLING_LOOP_TYPE_ON,
+            POLLING_LOOP_TYPE_UNKNOWN
+        })
     @Retention(RetentionPolicy.SOURCE)
     @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
     public @interface PollingFrameType {}
@@ -100,45 +107,46 @@
     /**
      * KEY_POLLING_LOOP_TYPE is the Bundle key for the type of
      * polling loop frame in the Bundle included in MSG_POLLING_LOOP.
-     *
-     * @hide
      */
     @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
-    public static final String KEY_POLLING_LOOP_TYPE = "android.nfc.cardemulation.TYPE";
+    private static final String KEY_POLLING_LOOP_TYPE = "android.nfc.cardemulation.TYPE";
 
     /**
      * KEY_POLLING_LOOP_DATA is the Bundle key for the raw data of captured from
      * the polling loop frame in the Bundle included in MSG_POLLING_LOOP.
-     *
-     * @hide
      */
     @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
-    public static final String KEY_POLLING_LOOP_DATA = "android.nfc.cardemulation.DATA";
+    private static final String KEY_POLLING_LOOP_DATA = "android.nfc.cardemulation.DATA";
 
     /**
      * KEY_POLLING_LOOP_GAIN is the Bundle key for the field strength of
      * the polling loop frame in the Bundle included in MSG_POLLING_LOOP.
-     *
-     * @hide
-     */
+    */
     @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
-    public static final String KEY_POLLING_LOOP_GAIN = "android.nfc.cardemulation.GAIN";
+    private static final String KEY_POLLING_LOOP_GAIN = "android.nfc.cardemulation.GAIN";
 
     /**
      * KEY_POLLING_LOOP_TIMESTAMP is the Bundle key for the timestamp of
      * the polling loop frame in the Bundle included in MSG_POLLING_LOOP.
-     *
-     * @hide
-     */
+    */
     @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
-    public static final String KEY_POLLING_LOOP_TIMESTAMP = "android.nfc.cardemulation.TIMESTAMP";
+    private static final String KEY_POLLING_LOOP_TIMESTAMP = "android.nfc.cardemulation.TIMESTAMP";
+
+    /**
+     * KEY_POLLING_LOOP_TIMESTAMP is the Bundle key for whether this polling frame triggered
+     * autoTransact in the Bundle included in MSG_POLLING_LOOP.
+    */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    private static final String KEY_POLLING_LOOP_TRIGGERED_AUTOTRANSACT =
+            "android.nfc.cardemulation.TRIGGERED_AUTOTRANSACT";
 
 
     @PollingFrameType
     private final int mType;
     private final byte[] mData;
     private final int mGain;
-    private final int mTimestamp;
+    private final long mTimestamp;
+    private boolean mTriggeredAutoTransact;
 
     public static final @NonNull Parcelable.Creator<PollingFrame> CREATOR =
             new Parcelable.Creator<>() {
@@ -153,31 +161,46 @@
                 }
             };
 
-    PollingFrame(Bundle frame) {
+    private PollingFrame(Bundle frame) {
         mType = frame.getInt(KEY_POLLING_LOOP_TYPE);
         byte[] data = frame.getByteArray(KEY_POLLING_LOOP_DATA);
         mData = (data == null) ? new byte[0] : data;
-        mGain = frame.getByte(KEY_POLLING_LOOP_GAIN);
-        mTimestamp = frame.getInt(KEY_POLLING_LOOP_TIMESTAMP);
+        mGain = frame.getInt(KEY_POLLING_LOOP_GAIN, -1);
+        mTimestamp = frame.getLong(KEY_POLLING_LOOP_TIMESTAMP);
+        mTriggeredAutoTransact = frame.containsKey(KEY_POLLING_LOOP_TRIGGERED_AUTOTRANSACT)
+                && frame.getBoolean(KEY_POLLING_LOOP_TRIGGERED_AUTOTRANSACT);
     }
 
+    /**
+     * Constructor for Polling Frames.
+     *
+     * @param type the type of the frame
+     * @param data a byte array of the data contained in the frame
+     * @param gain the vendor-specific gain of the field
+     * @param timestampMicros the timestamp in microseconds
+     * @param triggeredAutoTransact whether or not this frame triggered the device to start a
+     * transaction automatically
+     *
+     * @hide
+     */
     public PollingFrame(@PollingFrameType int type, @Nullable byte[] data,
-            int gain, int timestamp) {
+            int gain, long timestampMicros, boolean triggeredAutoTransact) {
         mType = type;
         mData = data == null ? new byte[0] : data;
         mGain = gain;
-        mTimestamp = timestamp;
+        mTimestamp = timestampMicros;
+        mTriggeredAutoTransact = triggeredAutoTransact;
     }
 
     /**
      * Returns the type of frame for this polling loop frame.
      * The possible return values are:
      * <ul>
-     *   <li>{@link POLLING_LOOP_TYPE_ON}</li>
-     *   <li>{@link POLLING_LOOP_TYPE_OFF}</li>
-     *   <li>{@link POLLING_LOOP_TYPE_A}</li>
-     *   <li>{@link POLLING_LOOP_TYPE_B}</li>
-     *   <li>{@link POLLING_LOOP_TYPE_F}</li>
+     *   <li>{@link #POLLING_LOOP_TYPE_ON}</li>
+     *   <li>{@link #POLLING_LOOP_TYPE_OFF}</li>
+     *   <li>{@link #POLLING_LOOP_TYPE_A}</li>
+     *   <li>{@link #POLLING_LOOP_TYPE_B}</li>
+     *   <li>{@link #POLLING_LOOP_TYPE_F}</li>
      * </ul>
      */
     public @PollingFrameType int getType() {
@@ -194,21 +217,37 @@
     /**
      * Returns the gain representing the field strength of the NFC field when this polling loop
      * frame was observed.
+     * @return the gain or -1 if there is no gain measurement associated with this frame.
      */
-    public int getGain() {
+    public int getVendorSpecificGain() {
         return mGain;
     }
 
     /**
-     * Returns the timestamp of when the polling loop frame was observed in milliseconds. These
-     * timestamps are relative and not absolute and should only be used for comparing the timing of
-     * frames relative to each other.
-     * @return the timestamp in milliseconds
+     * Returns the timestamp of when the polling loop frame was observed, in microseconds. These
+     * timestamps are relative and should only be used for comparing the timing of frames relative
+     * to each other.
+     * @return the timestamp in microseconds
      */
-    public int getTimestamp() {
+    public long getTimestamp() {
         return mTimestamp;
     }
 
+    /**
+     * @hide
+     */
+    public void setTriggeredAutoTransact(boolean triggeredAutoTransact) {
+        mTriggeredAutoTransact = triggeredAutoTransact;
+    }
+
+    /**
+     * Returns whether this frame triggered the device to automatically disable observe mode and
+     * allow one transaction.
+     */
+    public boolean getTriggeredAutoTransact() {
+        return mTriggeredAutoTransact;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -220,24 +259,25 @@
     }
 
     /**
-     *
-     * @hide
      * @return a Bundle representing this frame
      */
-    public Bundle toBundle() {
+    private Bundle toBundle() {
         Bundle frame = new Bundle();
         frame.putInt(KEY_POLLING_LOOP_TYPE, getType());
-        frame.putByte(KEY_POLLING_LOOP_GAIN, (byte) getGain());
+        if (getVendorSpecificGain() != -1) {
+            frame.putInt(KEY_POLLING_LOOP_GAIN, (byte) getVendorSpecificGain());
+        }
         frame.putByteArray(KEY_POLLING_LOOP_DATA, getData());
-        frame.putInt(KEY_POLLING_LOOP_TIMESTAMP, getTimestamp());
+        frame.putLong(KEY_POLLING_LOOP_TIMESTAMP, getTimestamp());
+        frame.putBoolean(KEY_POLLING_LOOP_TRIGGERED_AUTOTRANSACT, getTriggeredAutoTransact());
         return frame;
     }
 
     @Override
     public String toString() {
         return "PollingFrame { Type: " + (char) getType()
-                + ", gain: " + getGain()
-                + ", timestamp: " + Integer.toUnsignedString(getTimestamp())
+                + ", gain: " + getVendorSpecificGain()
+                + ", timestamp: " + Long.toUnsignedString(getTimestamp())
                 + ", data: [" + HexFormat.ofDelimiter(" ").formatHex(getData()) + "] }";
     }
 }
diff --git a/nfc/java/android/nfc/flags.aconfig b/nfc/java/android/nfc/flags.aconfig
index 6841d2b..45036a5 100644
--- a/nfc/java/android/nfc/flags.aconfig
+++ b/nfc/java/android/nfc/flags.aconfig
@@ -92,3 +92,28 @@
     description: "Enable NFC OEM extension support"
     bug: "331206243"
 }
+
+flag {
+    name: "nfc_state_change"
+    is_exported: true
+    namespace: "nfc"
+    description: "Enable nfc state change API"
+    bug: "319934052"
+}
+
+flag {
+    name: "nfc_set_default_disc_tech"
+    is_exported: true
+    namespace: "nfc"
+    description: "Flag for NFC set default disc tech API"
+    bug: "321311407"
+}
+
+flag {
+    name: "nfc_persist_log"
+    is_exported: true
+    namespace: "nfc"
+    description: "Enable NFC persistent log support"
+    bug: "321310044"
+}
+
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index ee755dd..8c1eab9 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -156,7 +156,8 @@
             UserManager.DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO,
             UserManager.DISALLOW_SIM_GLOBALLY,
             UserManager.DISALLOW_ASSIST_CONTENT,
-            UserManager.DISALLOW_THREAD_NETWORK
+            UserManager.DISALLOW_THREAD_NETWORK,
+            UserManager.DISALLOW_CHANGE_NEAR_FIELD_COMMUNICATION_RADIO
     });
 
     public static final Set<String> DEPRECATED_USER_RESTRICTIONS = Sets.newArraySet(
@@ -208,7 +209,8 @@
             UserManager.DISALLOW_CELLULAR_2G,
             UserManager.DISALLOW_ULTRA_WIDEBAND_RADIO,
             UserManager.DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO,
-            UserManager.DISALLOW_THREAD_NETWORK
+            UserManager.DISALLOW_THREAD_NETWORK,
+            UserManager.DISALLOW_CHANGE_NEAR_FIELD_COMMUNICATION_RADIO
     );
 
     /**
@@ -255,8 +257,9 @@
                     UserManager.DISALLOW_CELLULAR_2G,
                     UserManager.DISALLOW_ULTRA_WIDEBAND_RADIO,
                     UserManager.DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO,
-                    UserManager.DISALLOW_THREAD_NETWORK
-    );
+                    UserManager.DISALLOW_THREAD_NETWORK,
+                    UserManager.DISALLOW_CHANGE_NEAR_FIELD_COMMUNICATION_RADIO
+            );
 
     /**
      * Special user restrictions that profile owner of an organization-owned managed profile can