Merge "[nfc] Standardized interface declaration definition in packages/modules/Nfc/apex/hiddenapi/hiddenapi-max-target-o.txt for NfcAdapter.java" into main
diff --git a/NfcNci/nci/jni/NativeNfcManager.cpp b/NfcNci/nci/jni/NativeNfcManager.cpp
index 704e827..f6c769f 100644
--- a/NfcNci/nci/jni/NativeNfcManager.cpp
+++ b/NfcNci/nci/jni/NativeNfcManager.cpp
@@ -114,6 +114,8 @@
 jmethodID gCachedNfcManagerNotifyEeTechSelected;
 jmethodID gCachedNfcManagerNotifyEeListenActivated;
 jmethodID gCachedNfcManagerOnRestartRfDiscovery;
+jmethodID gCachedNfcManagerOnObserveModeDisabledInFirmware;
+jmethodID gCachedNfcManagerOnObserveModeEnabledInFirmware;
 jmethodID gCachedNfcManagerNotifyEndpointRemoved;
 
 const char* gNativeNfcTagClassName = "com/android/nfc/dhimpl/NativeNfcTag";
@@ -149,7 +151,7 @@
 static bool sIsNfaEnabled = false;
 static bool sDiscoveryEnabled = false;  // is polling or listening
 static bool sPollingEnabled = false;    // is polling for tag?
-static bool sIsDisabling = false;
+bool sIsDisabling = false;
 static bool sRfEnabled = false;   // whether RF discovery is enabled
 static bool sSeRfActive = false;  // whether RF with SE is likely active
 static bool sReaderModeEnabled = false;  // whether we're only reading tags, not allowing card emu
@@ -269,6 +271,16 @@
 
   LOG(DEBUG) << StringPrintf("%s: ", __func__);
 
+  if (gIsSelectingRfInterface && !natTag.getMultiProtocolTagSupport()) {
+    if (discoveredDevice->more == NCI_DISCOVER_NTF_MORE) return;
+    LOG(WARNING) << StringPrintf(
+        "%s: reselecting, mismatch in nb of detected interfaces, "
+        "restarting discovery",
+        __func__);
+    nativeNfcTag_doConnectStatus(false);
+    natTag.setReselect(false);
+    NFA_Deactivate(FALSE);
+  }
   if (discoveredDevice->protocol != NFA_PROTOCOL_NFC_DEP) {
     natTag.setNumDiscNtf(natTag.getNumDiscNtf() + 1);
   }
@@ -410,6 +422,9 @@
         LOG(ERROR) << StringPrintf(
             "%s: NFA_SELECT_RESULT_EVT error: status = %d", __func__,
             eventData->status);
+        if (NfcTag::getInstance().retrySelect() == NFA_STATUS_OK) {
+          break;
+        }
         NFA_Deactivate(FALSE);
       }
       break;
@@ -421,6 +436,7 @@
 
     case NFA_ACTIVATED_EVT:  // NFC link/protocol activated
     {
+      bool notListen = !isListenMode(eventData->activated);
       LOG(DEBUG) << StringPrintf(
           "%s: NFA_ACTIVATED_EVT: gIsSelectingRfInterface=%d, sIsDisabling=%d",
           __func__, gIsSelectingRfInterface, sIsDisabling);
@@ -434,6 +450,7 @@
         /* T5T doesn't support multiproto detection logic */
         NfcTag::getInstance().setNumDiscNtf(0);
       }
+      NfcTag::getInstance().clearSelectRetryCount();
       if ((eventData->activated.activate_ntf.protocol !=
            NFA_PROTOCOL_NFC_DEP) &&
           (!isListenMode(eventData->activated))) {
@@ -442,47 +459,48 @@
         nativeNfcTag_setActivatedRfProtocol(activatedProtocol);
         nativeNfcTag_setActivatedRfMode(activatedMode);
       }
-      NfcTag::getInstance().setActive(true);
+      NfcTag::getInstance().setActive(notListen);
       if (sIsDisabling || !sIsNfaEnabled) break;
       gActivated = true;
 
-      updateNfcID0Param(
-          eventData->activated.activate_ntf.rf_tech_param.param.pb.nfcid0);
-      NfcTag::getInstance().setActivationState();
-      if (gIsSelectingRfInterface) {
-        nativeNfcTag_doConnectStatus(true);
-        break;
-      }
-
-      nativeNfcTag_resetPresenceCheck();
-      if (!isListenMode(eventData->activated) &&
-          (prevScreenState == NFA_SCREEN_STATE_OFF_LOCKED ||
-           prevScreenState == NFA_SCREEN_STATE_OFF_UNLOCKED)) {
-        if (!sIsAlwaysPolling) {
-          NFA_Deactivate(FALSE);
+      if (notListen) {
+        updateNfcID0Param(
+            eventData->activated.activate_ntf.rf_tech_param.param.pb.nfcid0);
+        NfcTag::getInstance().setActivationState();
+        if (gIsSelectingRfInterface) {
+          nativeNfcTag_doConnectStatus(true);
+          break;
         }
-      }
 
-      NfcTag::getInstance().connectionEventHandler(connEvent, eventData);
-      if (NfcTag::getInstance().getNumDiscNtf()) {
-        /*If its multiprotocol tag, deactivate tag with current selected
-        protocol to sleep . Select tag with next supported protocol after
-        deactivation event is received*/
-        if (((tNFA_INTF_TYPE)eventData->activated.activate_ntf.intf_param
-                 .type == NFA_INTERFACE_FRAME)) {
-          uint8_t RW_TAG_SLP_REQ[] = {0x50, 0x00};
-          SyncEvent waitSome;
-          SyncEventGuard g(waitSome);
-          NFA_SendRawFrame(RW_TAG_SLP_REQ, sizeof(RW_TAG_SLP_REQ), 0);
-          waitSome.wait(4);
+        nativeNfcTag_resetPresenceCheck();
+        if (!isListenMode(eventData->activated) &&
+            (prevScreenState == NFA_SCREEN_STATE_OFF_LOCKED ||
+             prevScreenState == NFA_SCREEN_STATE_OFF_UNLOCKED)) {
+          if (!sIsAlwaysPolling) {
+            NFA_Deactivate(FALSE);
+          }
         }
-        NFA_Deactivate(true);
-      }
 
-      // If it activated in
-      // listen mode then it is likely for an SE transaction.
-      // Send the RF Event.
-      if (isListenMode(eventData->activated)) {
+        NfcTag::getInstance().connectionEventHandler(connEvent, eventData);
+        if (NfcTag::getInstance().getNumDiscNtf()) {
+          /*If its multiprotocol tag, deactivate tag with current selected
+          protocol to sleep . Select tag with next supported protocol after
+          deactivation event is received*/
+          if (((tNFA_INTF_TYPE)eventData->activated.activate_ntf.intf_param
+                   .type == NFA_INTERFACE_FRAME)) {
+            uint8_t RW_TAG_SLP_REQ[] = {0x50, 0x00};
+            SyncEvent waitSome;
+            SyncEventGuard g(waitSome);
+            NFA_SendRawFrame(RW_TAG_SLP_REQ, sizeof(RW_TAG_SLP_REQ), 0);
+            waitSome.wait(4);
+          }
+          NFA_Deactivate(true);
+        }
+
+      } else {
+        // If it activated in
+        // listen mode then it is likely for an SE transaction.
+        // Send the RF Event.
         sSeRfActive = true;
         struct nfc_jni_native_data* nat = getNative(NULL, NULL);
         if (!nat) {
@@ -505,7 +523,7 @@
           "%s: NFA_DEACTIVATED_EVT   Type=%u, gIsTagDeactivating=%d", __func__,
           eventData->deactivated.type, gIsTagDeactivating);
       NfcTag::getInstance().setDeactivationState(eventData->deactivated);
-      NfcTag::getInstance().selectNextTagIfExists();
+
       if (eventData->deactivated.type != NFA_DEACTIVATE_TYPE_SLEEP) {
         {
           SyncEventGuard g(gDeactivatedEvent);
@@ -519,6 +537,8 @@
       } else if (gIsTagDeactivating) {
         NfcTag::getInstance().setActive(false);
         nativeNfcTag_doDeactivateStatus(0);
+      } else if (!sIsDisabling) {
+        NfcTag::getInstance().selectNextTagIfExists();
       }
 
       // If RF is activated for what we think is a Secure Element transaction
@@ -806,6 +826,12 @@
   gCachedNfcManagerOnRestartRfDiscovery =
       e->GetMethodID(cls.get(), "onRestartRfDiscovery", "()V");
 
+  gCachedNfcManagerOnObserveModeDisabledInFirmware =
+      e->GetMethodID(cls.get(), "onObserveModeDisabledInFirmware", "(I[B)V");
+
+  gCachedNfcManagerOnObserveModeEnabledInFirmware =
+      e->GetMethodID(cls.get(), "onObserveModeEnabledInFirmware", "()V");
+
   if (nfc_jni_cache_object(e, gNativeNfcTagClassName, &(nat->cached_NfcTag)) ==
       -1) {
     LOG(ERROR) << StringPrintf("%s: fail cache NativeNfcTag", __func__);
@@ -1209,7 +1235,64 @@
           e->CallVoidMethod(nat->manager,
                             android::gCachedNfcManagerNotifyPollingLoopFrame,
                             (jint)param_len, dataJavaArray.get());
-
+        } break;
+        case NCI_ANDROID_PASSIVE_OBSERVER_SUSPENDED_NTF: {
+          LOG(INFO) << "Observe mode suspended NTF received";
+          gObserveModeEnabled = false;
+          struct nfc_jni_native_data* nat = getNative(NULL, NULL);
+          if (!nat) {
+              LOG(ERROR) << StringPrintf("cached nat is null");
+              return;
+          }
+          JNIEnv* e = NULL;
+          ScopedAttach attach(nat->vm, &e);
+          if (e == NULL) {
+              LOG(ERROR) << StringPrintf("jni env is null");
+              return;
+          }
+          if (param_len <= 2) {
+              LOG(ERROR) <<
+                    "Cannot parse exit frame from NCI_ANDROID_PASSIVE_OBSERVER_SUSPENDED_NTF";
+              return;
+          }
+          jint exit_frame_type = (jint) p_param[4];
+          uint16_t exit_frame_len = p_param[5];
+          ScopedLocalRef<jobject> dataJavaArray(e, e->NewByteArray(exit_frame_len));
+          if (dataJavaArray.get() == NULL) {
+              LOG(ERROR) << "fail allocate array";
+              return;
+          }
+          if (exit_frame_len > 0) {
+              e->SetByteArrayRegion((jbyteArray)dataJavaArray.get(), 0, exit_frame_len,
+                                    (jbyte*)(p_param + 6));
+              if (e->ExceptionCheck()) {
+                  e->ExceptionClear();
+                  LOG(ERROR) << "failed to fill array";
+                  return;
+              }
+          }
+          e->CallVoidMethod(nat->manager,
+                            android::gCachedNfcManagerOnObserveModeDisabledInFirmware,
+                            exit_frame_type, dataJavaArray.get());
+          return;
+        } break;
+        case NCI_ANDROID_PASSIVE_OBSERVER_RESUMED_NTF: {
+          LOG(INFO) << "Observe mode resumed NTF received";
+          gObserveModeEnabled = true;
+          struct nfc_jni_native_data *nat = getNative(NULL, NULL);
+          if (!nat) {
+              LOG(ERROR) << StringPrintf("cached nat is null");
+              return;
+          }
+          JNIEnv *e = NULL;
+          ScopedAttach attach(nat->vm, &e);
+          if (e == NULL) {
+              LOG(ERROR) << StringPrintf("jni env is null");
+              return;
+          }
+          e->CallVoidMethod(nat->manager,
+                            android::gCachedNfcManagerOnObserveModeEnabledInFirmware);
+          return;
         } break;
         case NCI_ANDROID_RESTART_RF_DISCOVERY_REQUEST_NTF: {
                 struct nfc_jni_native_data* nat = getNative(NULL, NULL);
@@ -1698,26 +1781,30 @@
     }
 }
 
+static bool isReaderModeAnnotationSupported(JNIEnv* e, jobject o) {
+  ScopedLocalRef<jclass> cls(e, e->GetObjectClass(o));
+  jmethodID isSupported =
+      e->GetMethodID(cls.get(), "isReaderModeAnnotationSupportedCaps", "()Z");
+  return e->CallBooleanMethod(o, isSupported);
+}
+
 static tNFA_STATUS setTechAPollingLoopAnnotation(JNIEnv* env, jobject o,
-                                          jbyteArray tech_a_polling_loop_annotation) {
-    if (tech_a_polling_loop_annotation == NULL) {
-      LOG(WARNING) << __func__ << ": annotation is null, returning early";
-      return STATUS_SUCCESS;
-    }
+                                                  const uint8_t* annotation_data,
+                                                  size_t annotation_size) {
     std::vector<uint8_t> command;
     command.push_back(NCI_ANDROID_SET_TECH_A_POLLING_LOOP_ANNOTATION);
-    command.push_back(0x01);
-    command.push_back(0x00);
-
-    ScopedByteArrayRO annotationBytes(env, tech_a_polling_loop_annotation);
-    command.push_back(annotationBytes.size() + 3);
-    command.push_back(0x0a);
-    if (annotationBytes.size() > 0) {
-      command.insert(command.end(), &annotationBytes[0],
-                    &annotationBytes[annotationBytes.size()]);
+    if (annotation_data == NULL || annotation_size == 0) {
+      // Annotation is null or size is 0, setting 0 annotations
+      command.push_back(0x00);
+    } else {
+      command.push_back(0x01);                 // Number of frame entries.
+      command.push_back(0x21);                 // Position and type.
+      command.push_back(annotation_size + 3);  // Length
+      command.push_back(0x0a);                 // Waiting time
+      command.insert(command.end(), annotation_data, annotation_data + annotation_size);
+      command.push_back(0x00);
+      command.push_back(0x00);
     }
-    command.push_back(0x00);
-    command.push_back(0x00);
     SyncEventGuard guard(gNfaVsCommand);
     tNFA_STATUS status =
         NFA_SendVsCommand(NCI_MSG_PROP_ANDROID, command.size(), command.data(), nfaVSCallback);
@@ -1728,6 +1815,8 @@
             __FUNCTION__);
         gVSCmdStatus = NFA_STATUS_FAILED;
       }
+    } else {
+      gVSCmdStatus = status;
     }
     return gVSCmdStatus;
 }
@@ -1778,7 +1867,21 @@
   // Check polling configuration
   if (tech_mask != 0) {
     stopPolling_rfDiscoveryDisabled();
-    setTechAPollingLoopAnnotation(e, o, tech_a_polling_loop_annotation);
+    if (isReaderModeAnnotationSupported(e, o)) {
+      if (reader_mode) {
+        if (tech_a_polling_loop_annotation == NULL) {
+          setTechAPollingLoopAnnotation(e, o, NULL, 0);
+        } else {
+          ScopedByteArrayRO annotationBytes(e, tech_a_polling_loop_annotation);
+          setTechAPollingLoopAnnotation(e, o,
+                                        (const uint8_t*)annotationBytes.get(),
+                                        annotationBytes.size());
+        }
+      } else {
+        uint8_t ignoreFrame[] = {0x6a, 0x01, 0xcf, 0x00, 0x00};
+        setTechAPollingLoopAnnotation(e, 0, ignoreFrame, 5);
+      }
+    }
 
     startPolling_rfDiscoveryDisabled(tech_mask);
 
@@ -1917,7 +2020,8 @@
 *******************************************************************************/
 static jboolean nfcManager_doDeinitialize(JNIEnv*, jobject) {
   if (sIsShuttingDown) return false;
-  LOG(DEBUG) << StringPrintf("%s: enter", __func__);
+  LOG(DEBUG) << StringPrintf("%s: enter, sIsRecovering=%d", __func__,
+                             sIsRecovering);
   if (gPartialInitMode != ENABLE_MODE_DEFAULT) {
     return doPartialDeinit();
   }
@@ -1938,10 +2042,13 @@
       NFA_DisableDtamode();
     }
 
-    tNFA_STATUS stat = NFA_Disable(TRUE /* graceful */);
+    tNFA_STATUS stat = NFA_Disable(!sIsRecovering);
     if (stat == NFA_STATUS_OK) {
       LOG(DEBUG) << StringPrintf("%s: wait for completion", __func__);
-      sNfaDisableEvent.wait();  // wait for NFA command to finish
+      if (!sNfaDisableEvent.wait(5000)) {
+        LOG(ERROR) << StringPrintf(
+            "%s: NFA_Disable() timeout, keep disabling anyway", __func__);
+      }
     } else {
       LOG(ERROR) << StringPrintf("%s: fail disable; error=0x%X", __func__,
                                  stat);
@@ -1957,6 +2064,7 @@
   sIsDisabling = false;
   sReaderModeEnabled = false;
   gActivated = false;
+  sRfEnabled = false;
   sLfT3tMax = 0;
 
   {
@@ -1967,6 +2075,35 @@
 
   LOG(DEBUG) << StringPrintf("%s: deregister VS callbacks", __func__);
   NFA_RegVSCback(false, &nfaVSCallback);
+  // abort any active waits
+  {
+    SyncEventGuard guard(sNfaSetPowerSubState);
+    sNfaSetPowerSubState.notifyOne();
+  }
+  {
+    SyncEventGuard guard(sNfaEnableDisablePollingEvent);
+    sNfaEnableDisablePollingEvent.notifyOne();
+  }
+  {
+    SyncEventGuard guard(gNfaSetConfigEvent);
+    gNfaSetConfigEvent.notifyOne();
+  }
+  {
+    SyncEventGuard guard(gNfaGetConfigEvent);
+    gNfaGetConfigEvent.notifyOne();
+  }
+  {
+    SyncEventGuard guard(gNfaVsCommand);
+    gNfaVsCommand.notifyOne();
+  }
+  {
+    SyncEventGuard guard(gSendRawVsCmdEvent);
+    gSendRawVsCmdEvent.notifyOne();
+  }
+  {
+    SyncEventGuard guard(gNfaRemoveEpEvent);
+    gNfaRemoveEpEvent.notifyOne();
+  }
 
   NfcAdaptation& theInstance = NfcAdaptation::GetInstance();
   theInstance.Finalize();
@@ -2052,7 +2189,7 @@
 static void nfcManager_doResetTimeouts(JNIEnv*, jobject) {
   if (sIsShuttingDown) return;
   LOG(DEBUG) << StringPrintf("%s", __func__);
-  NfcTag::getInstance().resetAllTransceiveTimeouts();
+  NfcTag::getInstance().resetAllTransceiveTimeouts(true);
 }
 
 /*******************************************************************************
@@ -2997,6 +3134,12 @@
   std::vector<uint8_t> command;
   command.push_back(NCI_ANDROID_SET_PASSIVE_OBSERVER_EXIT_FRAME);
 
+  // TODO(b/380455428)
+  // Support more than 5 exit frames if firmware allows it. If we do so, might need to send second
+  // NCI command if one is too large.
+  uint8_t more = 0x00;
+  command.push_back(more);
+
   uint8_t timeout_len = env->GetArrayLength(timeout);
   auto* timeout_arr = (uint8_t*)env->GetByteArrayElements(timeout, nullptr);
 
@@ -3006,6 +3149,12 @@
   env->ReleaseByteArrayElements(timeout, (jbyte*)timeout_arr, JNI_ABORT);
 
   uint8_t num_exit_frames = env->GetArrayLength(exit_frames);
+  if (num_exit_frames > 5) {
+      LOG(INFO)
+        << "Truncating exit frame table to 5 frames so it fits in a single NCI command. "
+        << "Original size was " << num_exit_frames;
+      num_exit_frames = 5;
+  }
   command.push_back(num_exit_frames);
 
   if (num_exit_frames > 0) {
diff --git a/NfcNci/nci/jni/NativeNfcTag.cpp b/NfcNci/nci/jni/NativeNfcTag.cpp
index 2222172..896889c 100644
--- a/NfcNci/nci/jni/NativeNfcTag.cpp
+++ b/NfcNci/nci/jni/NativeNfcTag.cpp
@@ -42,6 +42,7 @@
 namespace android {
 extern nfc_jni_native_data* getNative(JNIEnv* e, jobject o);
 extern bool nfcManager_isNfcActive();
+extern bool sIsDisabling;
 }  // namespace android
 
 extern bool gActivated;
@@ -130,6 +131,7 @@
 static bool sReselectTagIdle = false;
 
 static int sPresCheckStatus = 0;
+static bool sIsDisconnecting = false;
 
 static int reSelect(tNFA_INTF_TYPE rfInterface, bool fSwitchIfNeeded);
 extern bool gIsDtaEnabled;
@@ -546,9 +548,18 @@
   int retCode = NFCSTATUS_SUCCESS;
   tNFA_INTF_TYPE intfType = NFA_INTERFACE_FRAME;
 
+  if (sIsDisabling) {
+    LOG(ERROR) << StringPrintf("%s: NFC disabling in progress", __func__);
+    return NFCSTATUS_FAILED;
+  }
   sIsoDepPresCheckCnt = 0;
   sPresCheckErrCnt = 0;
   sIsoDepPresCheckAlternate = false;
+  if (sIsDisconnecting) {
+    LOG(ERROR) << StringPrintf("%s: Disconnect in progress", __func__);
+    retCode = NFCSTATUS_FAILED;
+    goto TheEnd;
+  }
 
   if (i >= NfcTag::MAX_NUM_TECHNOLOGY) {
     LOG(ERROR) << StringPrintf("%s: Handle not found", __func__);
@@ -716,6 +727,9 @@
       if (!sReselectTagIdle) {
         LOG(DEBUG) << StringPrintf("%s: select interface 0x%x", __func__,
                                    rfInterface);
+        natTag.setLastSelectedTag(
+            natTag.mTechHandles[sCurrentConnectedTargetIdx],
+            natTag.mTechLibNfcTypes[sCurrentConnectedTargetIdx]);
         if (NFA_STATUS_OK !=
             (status =
                  NFA_Select(natTag.mTechHandles[sCurrentConnectedTargetIdx],
@@ -735,12 +749,14 @@
     }
 
     /*Retry logic in case of core Generic error while selecting a tag*/
-    if (sConnectOk == false) {
+    if ((sConnectOk == false) && !sIsDisabling) {
       LOG(ERROR) << StringPrintf("%s: waiting for Card to be activated",
                                  __func__);
       int retry = 0;
-      sConnectWaitingForComplete = JNI_TRUE;
       do {
+        // Nci retries on failures by restarting discovery, extend recovery
+        // duration till time out
+        sConnectWaitingForComplete = JNI_TRUE;
         SyncEventGuard reselectEvent(sReconnectEvent);
         if (sReconnectEvent.wait(500) == false) {  // if timeout occurred
           LOG(ERROR) << StringPrintf("%s: timeout ", __func__);
@@ -792,6 +808,15 @@
   int retCode = NFCSTATUS_SUCCESS;
   NfcTag& natTag = NfcTag::getInstance();
 
+  if (sIsDisabling) {
+    LOG(ERROR) << StringPrintf("%s: NFC disabling in progress", __func__);
+    return NFCSTATUS_FAILED;
+  }
+  if (sIsDisconnecting) {
+    LOG(ERROR) << StringPrintf("%s: Disconnect in progress", __func__);
+    retCode = NFCSTATUS_FAILED;
+    goto TheEnd;
+  }
   if (natTag.getActivationState() != NfcTag::Active) {
     LOG(ERROR) << StringPrintf("%s: tag already deactivated", __func__);
     retCode = NFCSTATUS_FAILED;
@@ -851,7 +876,12 @@
   LOG(DEBUG) << StringPrintf("%s: enter", __func__);
   tNFA_STATUS nfaStat = NFA_STATUS_OK;
 
-  NfcTag::getInstance().resetAllTransceiveTimeouts();
+  if (sIsDisabling) {
+    LOG(ERROR) << StringPrintf("%s: NFC disabling in progress", __func__);
+    return JNI_FALSE;
+  }
+  sIsDisconnecting = true;
+  NfcTag::getInstance().resetAllTransceiveTimeouts(false);
   sReselectTagIdle = false;
 
   if (NfcTag::getInstance().getActivationState() != NfcTag::Active &&
@@ -866,6 +896,7 @@
                                nfaStat);
 
 TheEnd:
+  sIsDisconnecting = false;
   LOG(DEBUG) << StringPrintf("%s: exit", __func__);
   return (nfaStat == NFA_STATUS_OK) ? JNI_TRUE : JNI_FALSE;
 }
@@ -934,6 +965,10 @@
   bool isNack = false;
   jint* targetLost = NULL;
   tNFA_STATUS status;
+  if (sIsDisabling) {
+    LOG(ERROR) << StringPrintf("%s: NFC disabling in progress", __func__);
+    return nullptr;
+  }
 
   if (NfcTag::getInstance().getActivationState() != NfcTag::Active) {
     if (statusTargetLost) {
@@ -1187,6 +1222,10 @@
   tNFA_STATUS status = NFA_STATUS_FAILED;
   jint* ndef = NULL;
 
+  if (sIsDisabling) {
+    LOG(ERROR) << StringPrintf("%s: NFC disabling in progress", __func__);
+    return NFA_STATUS_FAILED;
+  }
   LOG(DEBUG) << StringPrintf("%s: enter", __func__);
 
   // special case for Kovio
@@ -1324,6 +1363,10 @@
   LOG(DEBUG) << StringPrintf("%s", __func__);
   tNFA_STATUS status = NFA_STATUS_OK;
   bool isPresent = false;
+  if (sIsDisabling) {
+    LOG(ERROR) << StringPrintf("%s: NFC disabling in progress", __func__);
+    return JNI_FALSE;
+  }
 
   // Special case for Kovio.  The deactivation would have already occurred
   // but was ignored so that normal tag opertions could complete.  Now we
@@ -1574,6 +1617,10 @@
   LOG(DEBUG) << StringPrintf("%s: enter", __func__);
   tNFA_STATUS status = NFA_STATUS_OK;
 
+  if (sIsDisabling) {
+    LOG(ERROR) << StringPrintf("%s: NFC disabling in progress", __func__);
+    return JNI_FALSE;
+  }
   // Do not try to format if tag is already deactivated.
   if (NfcTag::getInstance().isActivated() == false) {
     LOG(DEBUG) << StringPrintf("%s: tag already deactivated(no need to format)",
@@ -1640,6 +1687,10 @@
 static jboolean nativeNfcTag_doMakeReadonly(JNIEnv* e, jobject o, jbyteArray) {
   jboolean result = JNI_FALSE;
   tNFA_STATUS status;
+  if (sIsDisabling) {
+    LOG(ERROR) << StringPrintf("%s: NFC disabling in progress", __func__);
+    return JNI_FALSE;
+  }
 
   LOG(DEBUG) << StringPrintf("%s", __func__);
 
diff --git a/NfcNci/nci/jni/NfcTag.cpp b/NfcNci/nci/jni/NfcTag.cpp
index 8d9239c..a20fda4 100755
--- a/NfcNci/nci/jni/NfcTag.cpp
+++ b/NfcNci/nci/jni/NfcTag.cpp
@@ -776,7 +776,11 @@
       pollBytes.reset(e->NewByteArray(2));
       e->SetByteArrayRegion(pollBytes.get(), 0, 2, (jbyte*)data);
     } else {
-      LOG(ERROR) << StringPrintf("%s: tech unknown ????", fn);
+      if (NFC_DISCOVERY_TYPE_POLL_KOVIO == mTechParams[i].mode) {
+        LOG(DEBUG) << StringPrintf("%s: Thinfilm", fn);
+      } else {
+        LOG(ERROR) << StringPrintf("%s: tech unknown ????", fn);
+      }
       pollBytes.reset(e->NewByteArray(0));
     }  // switch: every type of technology
     e->SetObjectArrayElement(techPollBytes.get(), i, pollBytes.get());
@@ -1075,13 +1079,14 @@
   mNumDiscTechList = 0;
   mTechListTail = 0;
   mIsMultiProtocolTag = false;
+  mSelectRetryCount = 0;
   memset(mTechList, 0, sizeof(mTechList));
   memset(mTechHandles, 0, sizeof(mTechHandles));
   memset(mTechLibNfcTypes, 0, sizeof(mTechLibNfcTypes));
   memset(mTechParams, 0, sizeof(mTechParams));
   mIsDynamicTagId = false;
   mIsFelicaLite = false;
-  resetAllTransceiveTimeouts();
+  resetAllTransceiveTimeouts(true);
 }
 
 /*******************************************************************************
@@ -1097,7 +1102,6 @@
 void NfcTag::selectFirstTag() {
   static const char fn[] = "NfcTag::selectFirstTag";
   int foundIdx = -1;
-  tNFA_INTF_TYPE rf_intf = NFA_INTERFACE_FRAME;
 
   for (int i = 0; i < mNumDiscTechList; i++) {
     LOG(DEBUG) << StringPrintf("%s: nfa target idx=%d h=0x%X; protocol=0x%X",
@@ -1111,15 +1115,7 @@
   }
 
   if (foundIdx != -1) {
-    if (mTechLibNfcTypesDiscData[foundIdx] == NFA_PROTOCOL_ISO_DEP) {
-      rf_intf = NFA_INTERFACE_ISO_DEP;
-    } else if (mTechLibNfcTypesDiscData[foundIdx] == NFC_PROTOCOL_MIFARE) {
-      rf_intf = NFA_INTERFACE_MIFARE;
-    } else
-      rf_intf = NFA_INTERFACE_FRAME;
-
-    tNFA_STATUS stat = NFA_Select(mTechHandlesDiscData[foundIdx],
-                                  mTechLibNfcTypesDiscData[foundIdx], rf_intf);
+    tNFA_STATUS stat = selectTagAtIndex(foundIdx);
     if (stat != NFA_STATUS_OK)
       LOG(ERROR) << StringPrintf("%s: fail select; error=0x%X", fn, stat);
   } else
@@ -1139,7 +1135,6 @@
 void NfcTag::selectNextTagIfExists() {
   static const char fn[] = "NfcTag::selectNextTagIfExists";
   int foundIdx = -1;
-  tNFA_INTF_TYPE rf_intf = NFA_INTERFACE_FRAME;
   tNFA_STATUS stat = NFA_STATUS_FAILED;
 
   if (mNumDiscNtf == 0) {
@@ -1164,16 +1159,7 @@
   }
 
   if (foundIdx != -1) {
-    if (mTechLibNfcTypesDiscData[foundIdx] == NFA_PROTOCOL_ISO_DEP) {
-      rf_intf = NFA_INTERFACE_ISO_DEP;
-    } else if (mTechLibNfcTypesDiscData[foundIdx] == NFC_PROTOCOL_MIFARE) {
-      rf_intf = NFA_INTERFACE_MIFARE;
-    } else {
-      rf_intf = NFA_INTERFACE_FRAME;
-    }
-
-    stat = NFA_Select(mTechHandlesDiscData[foundIdx],
-                      mTechLibNfcTypesDiscData[foundIdx], rf_intf);
+    stat = selectTagAtIndex(foundIdx);
     if (stat == NFA_STATUS_OK) {
       LOG(ERROR) << StringPrintf("%s: Select Success, wait for activated ntf",
                                  fn);
@@ -1187,6 +1173,107 @@
 
 /*******************************************************************************
 **
+** Function:        selectTagAtIndex
+**
+** Description:     When multiple tags are discovered, selects a tag at
+**                  specified index
+**
+** Returns:         Select result
+**
+*******************************************************************************/
+tNFA_STATUS NfcTag::selectTagAtIndex(int index) {
+  static const char fn[] = "NfcTag::selectTagAtIndex";
+
+  tNFA_INTF_TYPE rf_intf = NFA_INTERFACE_FRAME;
+  if (index < 0 || index >= MAX_NUM_TECHNOLOGY) {
+    LOG(ERROR) << StringPrintf("%s: Invalid index passed", fn);
+    return NFA_STATUS_FAILED;
+  }
+  if (mTechLibNfcTypesDiscData[index] == NFA_PROTOCOL_ISO_DEP) {
+    rf_intf = NFA_INTERFACE_ISO_DEP;
+  } else if (mTechLibNfcTypesDiscData[index] == NFC_PROTOCOL_MIFARE) {
+    rf_intf = NFA_INTERFACE_MIFARE;
+  } else
+    rf_intf = NFA_INTERFACE_FRAME;
+
+  return NFA_Select(mTechHandlesDiscData[index],
+                    mTechLibNfcTypesDiscData[index], rf_intf);
+}
+
+/*******************************************************************************
+**
+** Function:        setLastSelectedTag
+**
+** Description:     Set the last selected tag in case of multiprotocol tag
+**
+** Returns:         NFA_STATUS_FAILED if tag is not found.
+**
+*******************************************************************************/
+tNFA_STATUS NfcTag::setLastSelectedTag(int targetHandle, int nfcType) {
+  static const char fn[] = "NfcTag::setLastSelectedTag";
+
+  if (!mIsMultiProtocolTag) {
+    LOG(INFO) << StringPrintf("%s: Not a multiprotocol tag, returning", fn);
+    return NFA_STATUS_OK;
+  }
+  for (int i = 0; i < mNumDiscTechList; i++) {
+    if (mTechHandlesDiscData[i] == targetHandle &&
+        mTechLibNfcTypesDiscData[i] == nfcType) {
+      sLastSelectedTagId = i;
+      return NFA_STATUS_OK;
+    }
+  }
+  LOG(ERROR) << StringPrintf("%s: Couldn't find target Handle (%d)", fn,
+                             targetHandle);
+  return NFA_STATUS_FAILED;
+}
+
+/*******************************************************************************
+**
+** Function:        retrySelect
+**
+** Description:     Retry select last tag in case of multiprotocol tag
+**
+** Returns:         NFA_STATUS_FAILED if it is not a multiprotocol tag or
+**                  retry is already done. Otherwise it returns Select status.
+**
+*******************************************************************************/
+
+tNFA_STATUS NfcTag::retrySelect() {
+  static const char fn[] = "NfcTag::retrySelect";
+  tNFA_STATUS stat = NFA_STATUS_FAILED;
+
+  if (mSelectRetryCount != 0) {
+    LOG(ERROR) << StringPrintf("%s: Select retry already done, returning", fn);
+    return NFA_STATUS_FAILED;
+  }
+  if (!mIsMultiProtocolTag) {
+    LOG(INFO) << StringPrintf("%s: Not a multiprotocol tag, returning", fn);
+    return NFA_STATUS_FAILED;
+  }
+  stat = selectTagAtIndex(sLastSelectedTagId);
+  if (stat == NFA_STATUS_OK) {
+    LOG(INFO) << StringPrintf("%s: Select Success, wait for activated ntf", fn);
+  } else {
+    LOG(ERROR) << StringPrintf("%s: fail select; error=0x%X", fn, stat);
+  }
+  mSelectRetryCount++;
+  return stat;
+}
+
+/*******************************************************************************
+**
+** Function:        clearSelectRetryCount
+**
+** Description:     Clear select retry count.
+**
+** Returns:         None.
+**
+*******************************************************************************/
+void NfcTag::clearSelectRetryCount() { mSelectRetryCount = 0; }
+
+/*******************************************************************************
+**
 ** Function:        getT1tMaxMessageSize
 **
 ** Description:     Get the maximum size (octet) that a T1T can store.
@@ -1509,11 +1596,13 @@
 ** Returns:         none
 **
 *******************************************************************************/
-void NfcTag::resetAllTransceiveTimeouts() {
+void NfcTag::resetAllTransceiveTimeouts(bool includeType4) {
   mTechnologyTimeoutsTable[TARGET_TYPE_ISO14443_3A] = 618;   // NfcA
   mTechnologyTimeoutsTable[TARGET_TYPE_ISO14443_3B] = 1000;  // NfcB
-  mTechnologyTimeoutsTable[TARGET_TYPE_ISO14443_4] = 618;    // ISO-DEP
   mTechnologyTimeoutsTable[TARGET_TYPE_FELICA] = 255;        // Felica
+  if (includeType4) {
+    mTechnologyTimeoutsTable[TARGET_TYPE_ISO14443_4] = 618;  // ISO-DEP
+  }
   mTechnologyTimeoutsTable[TARGET_TYPE_V] = 1000;            // NfcV
   mTechnologyTimeoutsTable[TARGET_TYPE_NDEF] = 1000;
   mTechnologyTimeoutsTable[TARGET_TYPE_NDEF_FORMATABLE] = 1000;
@@ -1645,6 +1734,18 @@
 
 /*******************************************************************************
 **
+** Function:        getMultiProtocolTagSupport
+**
+** Description:     get mIsMultiProtocolTag
+**
+** Returns:         mIsMultiProtocolTag
+**
+*******************************************************************************/
+
+bool NfcTag::getMultiProtocolTagSupport() { return mIsMultiProtocolTag; }
+
+/*******************************************************************************
+**
 ** Function:        setNumDiscNtf
 **
 ** Description:     Update number of Discovery NTF received
@@ -1653,8 +1754,10 @@
 **
 *******************************************************************************/
 void NfcTag::setNumDiscNtf(int numDiscNtfValue) {
+  static const char fn[] = "NfcTag::setNumDiscNtf";
   if (numDiscNtfValue < MAX_NUM_TECHNOLOGY) {
     mNumDiscNtf = numDiscNtfValue;
+    LOG(DEBUG) << StringPrintf("%s: mNumDiscNtf=%u", fn, mNumDiscNtf);
   }
 }
 
diff --git a/NfcNci/nci/jni/NfcTag.h b/NfcNci/nci/jni/NfcTag.h
index 815b66d..0598070 100644
--- a/NfcNci/nci/jni/NfcTag.h
+++ b/NfcNci/nci/jni/NfcTag.h
@@ -200,6 +200,52 @@
 
   /*******************************************************************************
   **
+  ** Function:        setLastSelectedTag
+  **
+  ** Description:     Set the last selected tag in case of multiprotocol tag
+  **
+  ** Returns:         NFA_STATUS_FAILED if tag is not found.
+  **
+  *******************************************************************************/
+  tNFA_STATUS setLastSelectedTag(int targetHandle, int nfcType);
+
+  /*******************************************************************************
+  **
+  ** Function:        retrySelect
+  **
+  ** Description:     Retry select last tag in case of multiprotocol tag
+  **
+  ** Returns:         NFA_STATUS_FAILED if it is not a multiprotocol tag or
+  **                  retry is already done. Otherwise it returns Select status.
+  **
+  *******************************************************************************/
+  tNFA_STATUS retrySelect();
+
+  /*******************************************************************************
+  **
+  ** Function:        clearSelectRetryCount
+  **
+  ** Description:     Clear select retry count.
+  **
+  ** Returns:         None.
+  **
+  *******************************************************************************/
+  void clearSelectRetryCount();
+
+  /*******************************************************************************
+  **
+  ** Function:        selectTagAtIndex
+  **
+  ** Description:     When multiple tags are discovered, selects a tag at
+  **                  specified index
+  **
+  ** Returns:         Select result
+  **
+  *******************************************************************************/
+  tNFA_STATUS selectTagAtIndex(int index);
+
+  /*******************************************************************************
+  **
   ** Function:        getT1tMaxMessageSize
   **
   ** Description:     Get the maximum size (octet) that a T1T can store.
@@ -312,7 +358,7 @@
   ** Returns:         none
   **
   *******************************************************************************/
-  void resetAllTransceiveTimeouts();
+  void resetAllTransceiveTimeouts(bool includeType4);
 
   /*******************************************************************************
   **
@@ -402,6 +448,17 @@
 
   /*******************************************************************************
   **
+  ** Function:        getMultiProtocolTagSupport
+  **
+  ** Description:     get mIsMultiProtocolTag
+  **
+  ** Returns:         mIsMultiProtocolTag
+  **
+  *******************************************************************************/
+  bool getMultiProtocolTagSupport();
+
+  /*******************************************************************************
+  **
   ** Function:        setNumDiscNtf
   **
   ** Description:     Update mNumDiscNtf
@@ -475,6 +532,7 @@
   int mNumDiscTechList;
   int mTechListTail;  // Index of Last added entry in mTechList
   bool mIsMultiProtocolTag;
+  int mSelectRetryCount = 0;
   NfcStatsUtil* mNfcStatsUtil;
   JNIEnv* mJniEnv = NULL;
 
diff --git a/NfcNci/nci/jni/NfceeManager.cpp b/NfcNci/nci/jni/NfceeManager.cpp
index 620c0c3..0484b10 100644
--- a/NfcNci/nci/jni/NfceeManager.cpp
+++ b/NfcNci/nci/jni/NfceeManager.cpp
@@ -40,6 +40,7 @@
   mActualNumEe = MAX_NUM_NFCEE;
   eseName = "eSE";
   uiccName = "SIM";
+  ndefNfceeName = "NDEF-NFCEE";
   memset(&mNfceeData_t, 0, sizeof(mNfceeData));
 }
 
@@ -109,6 +110,14 @@
     nfceeMap[uiccRoute[i]] = uiccName + std::to_string(i + 1);
   }
 
+  if (NfcConfig::hasKey(NAME_T4T_NFCEE_ENABLE)) {
+    if (NfcConfig::getUnsigned(NAME_T4T_NFCEE_ENABLE)) {
+      uint8_t defaultNdefNfceeRoute =
+          NfcConfig::getUnsigned(NAME_DEFAULT_NDEF_NFCEE_ROUTE, 0x10);
+      nfceeMap[defaultNdefNfceeRoute] = ndefNfceeName;
+    }
+  }
+
   for (int i = 0; i < mNfceeData_t.mNfceePresent; i++) {
     uint8_t id = (mNfceeData_t.mNfceeID[i] & ~NFA_HANDLE_GROUP_EE);
     uint8_t status = mNfceeData_t.mNfceeStatus[i];
diff --git a/NfcNci/nci/jni/NfceeManager.h b/NfcNci/nci/jni/NfceeManager.h
index bb49c8b..99d3393 100644
--- a/NfcNci/nci/jni/NfceeManager.h
+++ b/NfcNci/nci/jni/NfceeManager.h
@@ -103,6 +103,7 @@
   static NfceeManager sNfceeManager;
   string eseName;
   string uiccName;
+  string ndefNfceeName;
   tNFA_EE_INFO mEeInfo[MAX_NUM_NFCEE];
   uint8_t mNumEePresent;
   uint8_t mActualNumEe;
diff --git a/NfcNci/nci/jni/RoutingManager.cpp b/NfcNci/nci/jni/RoutingManager.cpp
index 4e6270d..50d79f1 100755
--- a/NfcNci/nci/jni/RoutingManager.cpp
+++ b/NfcNci/nci/jni/RoutingManager.cpp
@@ -71,6 +71,8 @@
 
 static const uint8_t AID_ROUTE_QUAL_PREFIX = 0x10;
 
+static Mutex sEeInfoMutex;
+static Mutex sEeInfoChangedMutex;
 
 /*******************************************************************************
 **
@@ -225,7 +227,7 @@
     LOG(ERROR) << fn << ": Failed to register wildcard AID for DH";
 
   // Trigger RT update
-  mEeInfoChanged = true;
+  setEeInfoChangedFlag();
   mDefaultAidRouteAdded = false;
 
   return true;
@@ -396,13 +398,16 @@
 tNFA_STATUS RoutingManager::commitRouting() {
   static const char fn[] = "RoutingManager::commitRouting";
   tNFA_STATUS nfaStat = 0;
-  if (mAidRoutingConfigured || mEeInfoChanged) {
+  sEeInfoChangedMutex.lock();
+  bool eeChanged = mEeInfoChanged;
+  mEeInfoChanged = false;
+  sEeInfoChangedMutex.unlock();
+  if (eeChanged) {
+    clearRoutingEntry(CLEAR_PROTOCOL_ENTRIES | CLEAR_TECHNOLOGY_ENTRIES);
+    updateRoutingTable();
+  }
+  if (mAidRoutingConfigured || eeChanged) {
     LOG(DEBUG) << StringPrintf("%s: RT update needed", fn);
-    if (mEeInfoChanged) {
-      clearRoutingEntry(CLEAR_PROTOCOL_ENTRIES | CLEAR_TECHNOLOGY_ENTRIES);
-      updateRoutingTable();
-      mEeInfoChanged = false;
-    }
     {
       SyncEventGuard guard(mEeUpdateEvent);
       nfaStat = NFA_EeUpdateNow();
@@ -461,6 +466,27 @@
   } else {
     LOG(DEBUG) << fn << ": No active EEs found";
   }
+  //release waits
+  {
+    SyncEventGuard guard(mEeRegisterEvent);
+    mEeRegisterEvent.notifyOne();
+  }
+  {
+    SyncEventGuard guard(mRoutingEvent);
+    mRoutingEvent.notifyOne();
+  }
+  {
+    SyncEventGuard guard(mEeSetModeEvent);
+    mEeSetModeEvent.notifyOne();
+  }
+  {
+    SyncEventGuard guard(mEePwrAndLinkCtrlEvent);
+    mEePwrAndLinkCtrlEvent.notifyOne();
+  }
+  {
+    SyncEventGuard guard(mAidAddRemoveEvent);
+    mAidAddRemoveEvent.notifyOne();
+  }
 }
 
 /*******************************************************************************
@@ -829,7 +855,7 @@
 void RoutingManager::updateIsoDepProtocolRoute(int route) {
   static const char fn[] = "RoutingManager::updateIsoDepProtocolRoute";
   LOG(DEBUG) << StringPrintf("%s:  New default ISO-DEP route=0x%x", fn, route);
-  mEeInfoChanged = true;
+  setEeInfoChangedFlag();
   mDefaultIsoDepRoute = route;
 }
 
@@ -845,7 +871,7 @@
 void RoutingManager::updateSystemCodeRoute(int route) {
   static const char fn[] = "RoutingManager::updateSystemCodeRoute";
   LOG(DEBUG) << StringPrintf("%s:  New default SC route=0x%x", fn, route);
-  mEeInfoChanged = true;
+  setEeInfoChangedFlag();
   mDefaultSysCodeRoute = route;
   updateDefaultRoute();
 }
@@ -948,20 +974,18 @@
       defaultAidRoute = NFC_DH_ID;
     }
 
-    // Default AID route should be added only if different from ISO-DEP route
-    if ((defaultAidRoute != mDefaultIsoDepRoute) ||
-        (mDefaultIsoDepRoute == NFC_DH_ID)) {
-      removeAidRouting(nullptr, 0);
-      uint8_t powerState = 0x01;
-      if (!mSecureNfcEnabled)
-        powerState =
-            (defaultAidRoute != 0x00) ? mOffHostAidRoutingPowerState : 0x11;
-      nfaStat = NFA_EeAddAidRouting(defaultAidRoute, 0, NULL, powerState,
-                                    AID_ROUTE_QUAL_PREFIX);
-      if (nfaStat != NFA_STATUS_OK)
-        LOG(ERROR) << fn << ": failed to register zero length AID";
-      else
-        mDefaultAidRouteAdded = true;
+    removeAidRouting(nullptr, 0);
+    uint8_t powerState = 0x01;
+    if (!mSecureNfcEnabled) {
+      powerState =
+          (defaultAidRoute != 0x00) ? mOffHostAidRoutingPowerState : 0x11;
+    }
+    nfaStat = NFA_EeAddAidRouting(defaultAidRoute, 0, NULL, powerState,
+                                  AID_ROUTE_QUAL_PREFIX);
+    if (nfaStat != NFA_STATUS_OK) {
+      LOG(ERROR) << fn << ": failed to register zero length AID";
+    } else {
+      mDefaultAidRouteAdded = true;
     }
   }
 }
@@ -999,7 +1023,13 @@
   static const char fn[] = "RoutingManager::updateEeTechRouteSetting";
   tNFA_TECHNOLOGY_MASK allSeTechMask = 0x00, hostTechMask = 0x00;
 
-  LOG(DEBUG) << StringPrintf("%s:  Default route A/B=0x%x", fn,
+  // Get content of mEeInfo as it can change if a NTF is received during update
+  // of RT
+  sEeInfoMutex.lock();
+  tNFA_EE_DISCOVER_REQ localEeInfo;
+  memcpy(&localEeInfo, &mEeInfo, sizeof(mEeInfo));
+  sEeInfoMutex.unlock();
+  LOG(DEBUG) << StringPrintf("%s: Default route A/B: 0x%x", fn,
                              mDefaultOffHostRoute);
   LOG(DEBUG) << StringPrintf("%s:  Default route F=0x%x", fn,
                              mDefaultFelicaRoute);
@@ -1008,31 +1038,31 @@
 
   tNFA_STATUS nfaStat;
 
-  for (uint8_t i = 0; i < mEeInfo.num_ee; i++) {
-    tNFA_HANDLE eeHandle = mEeInfo.ee_disc_info[i].ee_handle;
+  for (uint8_t i = 0; i < localEeInfo.num_ee; i++) {
+    tNFA_HANDLE eeHandle = localEeInfo.ee_disc_info[i].ee_handle;
     tNFA_TECHNOLOGY_MASK seTechMask = 0;
 
     LOG(DEBUG) << StringPrintf(
-        "%s   EE[%u] Handle=0x%04x  techA=0x%02x  techB=0x%02x  techF=0x%02x  "
-        "techBprime=0x%02x",
-        fn, i, eeHandle, mEeInfo.ee_disc_info[i].la_protocol,
-        mEeInfo.ee_disc_info[i].lb_protocol,
-        mEeInfo.ee_disc_info[i].lf_protocol,
-        mEeInfo.ee_disc_info[i].lbp_protocol);
+        "%s:   EE[%u] Handle=0x%04x  techA=0x%02x  techB="
+        "0x%02x  techF=0x%02x  techBprime=0x%02x",
+        fn, i, eeHandle, localEeInfo.ee_disc_info[i].la_protocol,
+        localEeInfo.ee_disc_info[i].lb_protocol,
+        localEeInfo.ee_disc_info[i].lf_protocol,
+        localEeInfo.ee_disc_info[i].lbp_protocol);
 
     if ((mDefaultOffHostRoute != NFC_DH_ID) &&
         (eeHandle == (mDefaultOffHostRoute | NFA_HANDLE_GROUP_EE))) {
-      if (mEeInfo.ee_disc_info[i].la_protocol != 0) {
+      if (localEeInfo.ee_disc_info[i].la_protocol != 0) {
         seTechMask |= NFA_TECHNOLOGY_MASK_A;
       }
-      if (mEeInfo.ee_disc_info[i].lb_protocol != 0) {
+      if (localEeInfo.ee_disc_info[i].lb_protocol != 0) {
         seTechMask |= NFA_TECHNOLOGY_MASK_B;
       }
     }
 
     if ((mDefaultFelicaRoute != NFC_DH_ID) &&
         (eeHandle == (mDefaultFelicaRoute | NFA_HANDLE_GROUP_EE))) {
-      if (mEeInfo.ee_disc_info[i].lf_protocol != 0) {
+      if (localEeInfo.ee_disc_info[i].lf_protocol != 0) {
         seTechMask |= NFA_TECHNOLOGY_MASK_F;
       }
     }
@@ -1195,20 +1225,22 @@
 
     case NFA_EE_DISCOVER_REQ_EVT: {
       SyncEventGuard guard(routingManager.mEeInfoEvent);
+      sEeInfoMutex.lock();
       memcpy(&routingManager.mEeInfo, &eventData->discover_req,
              sizeof(routingManager.mEeInfo));
       for (int i = 0; i < eventData->discover_req.num_ee; i++) {
         LOG(DEBUG) << StringPrintf(
-            "%s; NFA_EE_DISCOVER_REQ_EVT; nfceeId=0x%X; la_proto=0x%X, "
+            "%s: NFA_EE_DISCOVER_REQ_EVT; nfceeId=0x%X; la_proto=0x%X, "
             "lb_proto=0x%x, lf_proto=0x%x",
             fn, eventData->discover_req.ee_disc_info[i].ee_handle,
             eventData->discover_req.ee_disc_info[i].la_protocol,
             eventData->discover_req.ee_disc_info[i].lb_protocol,
             eventData->discover_req.ee_disc_info[i].lf_protocol);
       }
+      sEeInfoMutex.unlock();
       if (!routingManager.mIsRFDiscoveryOptimized) {
         if (routingManager.mReceivedEeInfo && !routingManager.mDeinitializing) {
-          routingManager.mEeInfoChanged = true;
+          routingManager.setEeInfoChangedFlag();
           routingManager.notifyEeUpdated();
         }
       }
@@ -1222,7 +1254,7 @@
           eventData->discover_req.status, eventData->discover_req.num_ee);
       if (routingManager.mIsRFDiscoveryOptimized) {
         if (routingManager.mReceivedEeInfo && !routingManager.mDeinitializing) {
-          routingManager.mEeInfoChanged = true;
+          routingManager.setEeInfoChangedFlag();
           routingManager.notifyEeUpdated();
         }
       }
@@ -1344,7 +1376,7 @@
       return NFA_HANDLE_INVALID;
     }
     LOG(DEBUG) << StringPrintf("%s: Succeed to register system code on DH", fn);
-    mEeInfoChanged = true;
+    setEeInfoChangedFlag();
     // add handle and system code pair to the map
     mMapScbrHandle.emplace(mNfcFOnDhHandle, systemCode);
   } else {
@@ -1390,7 +1422,7 @@
         tNFA_STATUS nfaStat = NFA_EeRemoveSystemCodeRouting(systemCode);
         if (nfaStat == NFA_STATUS_OK) {
           mRoutingEvent.wait();
-          mEeInfoChanged = true;
+          setEeInfoChangedFlag();
           LOG(DEBUG) << StringPrintf(
               "%s: Succeeded in deregistering system Code on DH", fn);
         } else {
@@ -1558,7 +1590,7 @@
 
   // Setting flag for Ee info changed so that
   // routing table can be updated
-  mEeInfoChanged = true;
+  setEeInfoChangedFlag();
 }
 
 /*******************************************************************************
@@ -1577,6 +1609,23 @@
 
 /*******************************************************************************
 **
+** Function:        setEeInfoChangedFlag
+**
+** Description:     .
+**
+** Returns:         None
+**
+*******************************************************************************/
+void RoutingManager::setEeInfoChangedFlag() {
+  static const char fn[] = "RoutingManager::setEeInfoChangedFlag";
+  LOG(DEBUG) << StringPrintf("%s", fn);
+  sEeInfoChangedMutex.lock();
+  mEeInfoChanged = true;
+  sEeInfoChangedMutex.unlock();
+}
+
+/*******************************************************************************
+**
 ** Function:        registerJniFunctions
 **
 ** Description:     called at object creation to register JNI function
diff --git a/NfcNci/nci/jni/RoutingManager.h b/NfcNci/nci/jni/RoutingManager.h
index d38343c..d72351e 100755
--- a/NfcNci/nci/jni/RoutingManager.h
+++ b/NfcNci/nci/jni/RoutingManager.h
@@ -54,6 +54,7 @@
   void notifyEeProtocolSelected(uint8_t protocol, tNFA_HANDLE ee_handle);
   void notifyEeTechSelected(uint8_t tech, tNFA_HANDLE ee_handle);
   bool getNameOfEe(tNFA_HANDLE ee_handle, std::string& eeName);
+  void setEeInfoChangedFlag();
 
   static const int CLEAR_AID_ENTRIES = 0x01;
   static const int CLEAR_PROTOCOL_ENTRIES = 0x02;
diff --git a/NfcNci/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java b/NfcNci/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java
index 4de31c4..d525e8a 100644
--- a/NfcNci/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java
+++ b/NfcNci/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java
@@ -77,6 +77,9 @@
     private static final int NCI_OID_INDEX = 1;
     private static final int OP_CODE_INDEX = 3;
 
+    private static final int OBSERVE_MODE_SUSPENDED_FRAME_TYPE_A = 0x00;
+    private static final int OBSERVE_MODE_SUSPENDED_FRAME_TYPE_B = 0x01;
+
     private void loadLibrary() {
         System.loadLibrary("nfc_nci_jni");
     }
@@ -529,21 +532,21 @@
         Log.i(TAG, "notifyEeAidSelected: AID= " + HexFormat.of().formatHex(aid) + " selected by "
                 + eventSrc);
         if (com.android.nfc.flags.Flags.eeAidSelect()) {
-            mListener.onSeSelected();
+            mListener.onSeSelected(NfcService.SE_SELECTED_AID);
         }
     }
 
     private void notifyEeProtocolSelected(int protocol, String eventSrc) {
         Log.i(TAG, "notifyEeProtocolSelected: Protocol: " + protocol + " selected by " + eventSrc);
         if (com.android.nfc.flags.Flags.eeAidSelect()) {
-            mListener.onSeSelected();
+            mListener.onSeSelected(NfcService.SE_SELECTED_PROTOCOL);
         }
     }
 
     private void notifyEeTechSelected(int tech, String eventSrc) {
         Log.i(TAG, "notifyEeTechSelected: Tech: " + tech + " selected by " + eventSrc);
         if (com.android.nfc.flags.Flags.eeAidSelect()) {
-            mListener.onSeSelected();
+            mListener.onSeSelected(NfcService.SE_SELECTED_TECH);
         }
     }
 
@@ -629,6 +632,22 @@
         Trace.endSection();
     }
 
+    private void onObserveModeEnabledInFirmware() {
+        mListener.onObserveModeEnabledInFirmware();
+    }
+
+    private void onObserveModeDisabledInFirmware(int type, byte[] data) {
+        int pollingFrameType = PollingFrame.POLLING_LOOP_TYPE_UNKNOWN;
+        if (type == OBSERVE_MODE_SUSPENDED_FRAME_TYPE_A) {
+            pollingFrameType = PollingFrame.POLLING_LOOP_TYPE_A;
+        } else if (type == OBSERVE_MODE_SUSPENDED_FRAME_TYPE_B) {
+            pollingFrameType = PollingFrame.POLLING_LOOP_TYPE_B;
+        }
+
+        mListener.onObserveModeDisabledInFirmware(
+                new PollingFrame(pollingFrameType, data, -1, -1, true));
+    }
+
     private native boolean doDetectEpRemoval(int waiting_time_int);
 
     @Override
@@ -706,6 +725,15 @@
             != NfcProprietaryCaps.PassiveObserveMode.NOT_SUPPORTED;
     }
 
+    private  boolean isReaderModeAnnotationSupportedCaps() {
+        return mProprietaryCaps.isReaderModeAnnotationSupported();
+    }
+
+    @Override
+    public  boolean isReaderModeAnnotationSupported() {
+        return isReaderModeAnnotationSupportedCaps();
+    }
+
     private static void logProprietaryCaps(NfcProprietaryCaps proprietaryCaps) {
         int observeModeStatsd = CAPS_OBSERVE_MODE_UNKNOWN;
 
diff --git a/NfcNci/res/values/overlayable.xml b/NfcNci/res/values/overlayable.xml
index b500405..cb2ecce 100644
--- a/NfcNci/res/values/overlayable.xml
+++ b/NfcNci/res/values/overlayable.xml
@@ -26,6 +26,7 @@
             <item name="polling_disable_allowed" type="bool" />
             <item name="nfcc_always_on_allowed" type="bool" />
             <item name="enable_reader_option_support" type="bool" />
+            <item name="enable_service_for_category_other" type="bool" />
             <item name="payment_foreground_preference" type="bool" />
             <item name="tag_intent_app_pref_supported" type="bool" />
             <item name="max_antenna_blocked_failure_count" type="integer" />
diff --git a/NfcNci/res/values/strings.xml b/NfcNci/res/values/strings.xml
index 8a630df..47fc3f7 100755
--- a/NfcNci/res/values/strings.xml
+++ b/NfcNci/res/values/strings.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name">Nfc Service</string>
-    <string name="nfcUserLabel">Nfc</string>
+    <string name="app_name">NFC Service</string>
+    <string name="nfcUserLabel">NFC</string>
 
     <!-- Content description of the NFC enabled notification icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_nfc_enabled">NFC enabled.</string>
diff --git a/NfcNci/src/com/android/nfc/DeviceConfigFacade.java b/NfcNci/src/com/android/nfc/DeviceConfigFacade.java
index 1e14404..8c0a40e 100644
--- a/NfcNci/src/com/android/nfc/DeviceConfigFacade.java
+++ b/NfcNci/src/com/android/nfc/DeviceConfigFacade.java
@@ -49,11 +49,24 @@
     private boolean mReaderOptionDefault;
     private boolean mSecureNfcCapable;
     private boolean mSecureNfcDefault;
+    private boolean mEnableAutoPlay;
+    private boolean mPollingDisableAllowed;
+    private boolean mNfccAlwaysOnAllowed;
+    private boolean mEnableServiceOther;
+    private boolean mTagIntentAppPrefSupported;
+    private boolean mProprietaryGetcapsSupported;
+    private boolean mEnableOemExtension;
+    private boolean mEnableDeveloperNotification;
+    private boolean mCheckDisplayStateForScreenState;
+    private boolean mIndicateUserActivityForHce;
     private String mDefaultRoute;
     private String mDefaultIsoDepRoute;
     private String mDefaultOffHostRoute;
     private String mDefaultScRoute;
     private int mSlowTapThresholdMillis;
+    private int mUnknownTagPollingDelay;
+    private int mUnknownTagPollingDelayMax;
+    private int mUnknownTagPollingDelayLong;
 
     private static DeviceConfigFacade sInstance;
     public static DeviceConfigFacade getInstance(Context context, Handler handler) {
@@ -101,6 +114,46 @@
             KEY_SECURE_NFC_DEFAULT,
             mContext.getResources().getBoolean(R.bool.secure_nfc_default));
 
+        mEnableAutoPlay = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_NFC,
+                "enable_auto_play",
+                mContext.getResources().getBoolean(R.bool.enable_auto_play));
+
+        mPollingDisableAllowed = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_NFC,
+                "polling_disable_allowed",
+                mContext.getResources().getBoolean(R.bool.polling_disable_allowed));
+
+        mNfccAlwaysOnAllowed = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_NFC,
+                "nfcc_always_on_allowed",
+                mContext.getResources().getBoolean(R.bool.nfcc_always_on_allowed));
+
+        mEnableServiceOther = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_NFC,
+                "enable_service_for_category_other",
+                mContext.getResources().getBoolean(R.bool.enable_service_for_category_other));
+
+        mTagIntentAppPrefSupported = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_NFC,
+                "tag_intent_app_pref_supported",
+                mContext.getResources().getBoolean(R.bool.tag_intent_app_pref_supported));
+
+        mProprietaryGetcapsSupported = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_NFC,
+                "nfc_proprietary_getcaps_supported",
+                mContext.getResources().getBoolean(R.bool.nfc_proprietary_getcaps_supported));
+
+        mEnableOemExtension = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_NFC,
+                "enable_oem_extension",
+                mContext.getResources().getBoolean(R.bool.enable_oem_extension));
+
+        mEnableDeveloperNotification = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_NFC,
+                "enable_developer_option_notification",
+                mContext.getResources().getBoolean(R.bool.enable_developer_option_notification));
+
+        mCheckDisplayStateForScreenState = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_NFC,
+                "check_display_state_for_screen_state",
+                mContext.getResources().getBoolean(R.bool.check_display_state_for_screen_state));
+
+        mIndicateUserActivityForHce = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_NFC,
+                "indicate_user_activity_for_hce",
+                mContext.getResources().getBoolean(R.bool.indicate_user_activity_for_hce));
+
         mDefaultRoute = DeviceConfig.getString(DEVICE_CONFIG_NAMESPACE_NFC,
                 "nfc_default_route",
                 mContext.getResources().getString(R.string.nfc_default_route));
@@ -120,6 +173,19 @@
         mSlowTapThresholdMillis = DeviceConfig.getInt(DEVICE_CONFIG_NAMESPACE_NFC,
                 KEY_SLOW_TAP_THRESHOLD_MILLIS,
                 mContext.getResources().getInteger(R.integer.slow_tap_threshold_millis));
+
+        mUnknownTagPollingDelay = DeviceConfig.getInt(DEVICE_CONFIG_NAMESPACE_NFC,
+                "unknown_tag_polling_delay",
+                mContext.getResources().getInteger(R.integer.unknown_tag_polling_delay));
+
+        mUnknownTagPollingDelayMax = DeviceConfig.getInt(DEVICE_CONFIG_NAMESPACE_NFC,
+                "unknown_tag_polling_delay_count_max",
+                mContext.getResources().getInteger(R.integer.unknown_tag_polling_delay_count_max));
+
+        mUnknownTagPollingDelayLong = DeviceConfig.getInt(DEVICE_CONFIG_NAMESPACE_NFC,
+                "unknown_tag_polling_delay_long",
+                mContext.getResources().getInteger(R.integer.unknown_tag_polling_delay_long));
+
     }
 
     private boolean isSecureNfcCapableDefault() {
@@ -158,6 +224,16 @@
     public boolean getDefaultSecureNfcState() {
         return mSecureNfcDefault;
     }
+    public boolean getEnableAutoPlay() { return mEnableAutoPlay; }
+    public boolean getPollingDisableAllowed() { return mPollingDisableAllowed; }
+    public boolean getNfccAlwaysOnAllowed() { return mNfccAlwaysOnAllowed; }
+    public boolean getEnableServiceOther() { return mEnableServiceOther; }
+    public boolean getTagIntentAppPrefSupported() { return mTagIntentAppPrefSupported; }
+    public boolean getProprietaryGetcapsSupported() { return mProprietaryGetcapsSupported; }
+    public boolean getEnableOemExtension() { return mEnableOemExtension; }
+    public boolean getEnableDeveloperNotification() { return mEnableDeveloperNotification; }
+    public boolean getCheckDisplayStateForScreenState() { return mCheckDisplayStateForScreenState; }
+    public boolean getIndicateUserActivityForHce() { return mIndicateUserActivityForHce; }
     public String getDefaultRoute() {
         return mDefaultRoute;
     }
@@ -173,4 +249,7 @@
     public int getSlowTapThresholdMillis() {
         return mSlowTapThresholdMillis;
     }
+    public int getUnknownTagPollingDelay() { return mUnknownTagPollingDelay; }
+    public int getUnknownTagPollingDelayMax() { return mUnknownTagPollingDelayMax; }
+    public int getUnknownTagPollingDelayLong() { return mUnknownTagPollingDelayLong; }
 }
diff --git a/NfcNci/src/com/android/nfc/DeviceHost.java b/NfcNci/src/com/android/nfc/DeviceHost.java
index f08a41f..815bd90 100644
--- a/NfcNci/src/com/android/nfc/DeviceHost.java
+++ b/NfcNci/src/com/android/nfc/DeviceHost.java
@@ -48,6 +48,10 @@
 
         public void onPollingLoopDetected(List<PollingFrame> pollingFrames);
 
+        public void onObserveModeEnabledInFirmware();
+
+        public void onObserveModeDisabledInFirmware(PollingFrame exitFrame);
+
         public void onWlcStopped(int wpt_end_condition);
 
         public void onTagRfDiscovered(boolean discovered);
@@ -60,7 +64,7 @@
 
         public void onEeListenActivated(boolean isActivated);
 
-        public void onSeSelected();
+        public void onSeSelected(int type);
 
         public void onCommandTimeout();
 
@@ -268,6 +272,8 @@
 
     public boolean setNfcSecure(boolean enable);
 
+    public boolean isReaderModeAnnotationSupported();
+
     public boolean isObserveModeSupported();
 
     public boolean setObserveMode(boolean enable);
diff --git a/NfcNci/src/com/android/nfc/ExitFrame.java b/NfcNci/src/com/android/nfc/ExitFrame.java
index a840a51..1cc77d0 100644
--- a/NfcNci/src/com/android/nfc/ExitFrame.java
+++ b/NfcNci/src/com/android/nfc/ExitFrame.java
@@ -75,9 +75,9 @@
             }
         }
         mData = HexFormat.of().parseHex(String.valueOf(filterChars));
-        if (mData.length > 16) {
+        if (mData.length > 14) {
             throw new IllegalArgumentException(
-                    "Filter too long, firmware exit frames only support 16 byte filters.");
+                    "Filter too long, firmware exit frames only support 14 byte filters.");
         }
         mDataMask = HexFormat.of().parseHex(String.valueOf(maskChars));
 
diff --git a/NfcNci/src/com/android/nfc/NfcDispatcher.java b/NfcNci/src/com/android/nfc/NfcDispatcher.java
index 0604fd0..bf7f929 100644
--- a/NfcNci/src/com/android/nfc/NfcDispatcher.java
+++ b/NfcNci/src/com/android/nfc/NfcDispatcher.java
@@ -115,6 +115,7 @@
     private final Handler mMessageHandler = new MessageHandler();
     private final Messenger mMessenger = new Messenger(mMessageHandler);
     private final AtomicBoolean mBluetoothEnabledByNfc;
+    private final DeviceConfigFacade mDeviceConfigFacade;
 
     // Locked on this
     private PendingIntent mOverrideIntent;
@@ -131,7 +132,7 @@
     NfcDispatcher(Context context,
                   HandoverDataParser handoverDataParser,
                   NfcInjector nfcInjector,
-                  boolean provisionOnly) {
+                  boolean provisionOnly, DeviceConfigFacade deviceConfigFacade) {
         mContext = context;
         mTechListFilters = new RegisteredComponentCache(mContext,
                 NfcAdapter.ACTION_TECH_DISCOVERED, NfcAdapter.ACTION_TECH_DISCOVERED);
@@ -144,6 +145,7 @@
         mForegroundUid = Process.INVALID_UID;
         mForegroundUtils = ForegroundUtils.getInstance(
                 context.getSystemService(ActivityManager.class));
+        mDeviceConfigFacade = deviceConfigFacade;
         synchronized (this) {
             mProvisioningOnly = provisionOnly;
         }
@@ -359,18 +361,20 @@
                 String pkgName = activityInfo.packageName;
                 String appName = context.getPackageManager().getApplicationLabel(
                         activityInfo.applicationInfo).toString();
-                if (DBG) Log.d(TAG, "checkPrefList: activityInfo.packageName= " + pkgName);
                 Map<String, Boolean> preflist =
                         mNfcAdapter.getTagIntentAppPreferenceForUser(userId);
                 if (preflist.containsKey(pkgName)) {
                     if (!preflist.get(pkgName)) {
-                        if (DBG) Log.d(TAG, "checkPrefList: mute pkg:" + pkgName);
+                        if (DBG) Log.d(TAG, "checkPrefList: mute:" + pkgName);
                         muteAppCount++;
                         filtered.remove(resolveInfo);
                         logMuteApp(activityInfo.applicationInfo.uid);
+                    } else {
+                        if (DBG) Log.d(TAG, "checkPrefList: allow:" + pkgName);
                     }
                 } else {
                     // Default sets allow to the preference list
+                    if (DBG) Log.d(TAG, "checkPrefList: add:" + pkgName);
                     mNfcAdapter.setTagIntentAppPreferenceForUser(userId, pkgName, true);
                     if (Flags.nfcAlertTagAppLaunch()) {
                         notifyAppNames.add(appName);
@@ -594,8 +598,7 @@
         boolean screenUnlocked = false;
         if (!provisioningOnly &&
                 mScreenStateHelper.checkScreenState(
-                        mContext.getResources().getBoolean(
-                                R.bool.check_display_state_for_screen_state))
+                        mDeviceConfigFacade.getCheckDisplayStateForScreenState())
                         == ScreenStateHelper.SCREEN_STATE_ON_LOCKED) {
             screenUnlocked = handleNfcUnlock(tag);
             if (!screenUnlocked)
@@ -1074,12 +1077,17 @@
                                 matches.add(info.resolveInfo);
                                 if (!preflist.containsKey(pkgName)) {
                                     // Default sets allow to the preference list
+                                    if (DBG) Log.d(TAG, "tryTech: add:" + pkgName);
                                     mNfcAdapter.setTagIntentAppPreferenceForUser(userId,
                                             pkgName, true);
                                     if (Flags.nfcAlertTagAppLaunch()) {
                                         notifyAppNames.add(appName);
                                     }
+                                } else {
+                                    if (DBG) Log.d(TAG, "tryTech: allow:" + pkgName);
                                 }
+                            } else {
+                                if (DBG) Log.d(TAG, "tryTech: mute:" + pkgName);
                             }
                         }
                     }
diff --git a/NfcNci/src/com/android/nfc/NfcInjector.java b/NfcNci/src/com/android/nfc/NfcInjector.java
index 3abd3e0..8611ed2 100644
--- a/NfcNci/src/com/android/nfc/NfcInjector.java
+++ b/NfcNci/src/com/android/nfc/NfcInjector.java
@@ -110,7 +110,8 @@
         mHandoverDataParser = new HandoverDataParser();
         mDeviceConfigFacade = new DeviceConfigFacade(mContext, new Handler(mainLooper));
         mNfcDispatcher =
-            new NfcDispatcher(mContext, mHandoverDataParser, this, isInProvisionMode());
+            new NfcDispatcher(mContext, mHandoverDataParser, this,
+                    isInProvisionMode(), mDeviceConfigFacade);
         mVibrationEffect = VibrationEffect.createOneShot(200, VibrationEffect.DEFAULT_AMPLITUDE);
         mBackupManager = new BackupManager(mContext);
         mFeatureFlags = new com.android.nfc.flags.FeatureFlagsImpl();
diff --git a/NfcNci/src/com/android/nfc/NfcProprietaryCaps.java b/NfcNci/src/com/android/nfc/NfcProprietaryCaps.java
index 18f7336..9c87e2f 100644
--- a/NfcNci/src/com/android/nfc/NfcProprietaryCaps.java
+++ b/NfcNci/src/com/android/nfc/NfcProprietaryCaps.java
@@ -10,7 +10,7 @@
  * 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
+ * See the License for the specific language governing permIssions and
  * limitations under the License.
  */
 
@@ -27,11 +27,13 @@
     private static final int POWER_SAVING_MODE = 2;
     private static final int AUTOTRANSACT_POLLING_LOOP_FILTER = 3;
     private static final int NUMBER_OF_EXIT_FRAMES_SUPPORTED = 4;
+    private static final int READER_MODE_ANNOTATIONS_SUPPORTED = 5;
     private final PassiveObserveMode mPassiveObserveMode;
     private final boolean mIsPollingFrameNotificationSupported;
     private final boolean mIsPowerSavingModeSupported;
     private final boolean mIsAutotransactPollingLoopFilterSupported;
     private final int mNumberOfExitFramesSupported;
+    private final boolean mIsReaderModeAnnotationSupported;
 
     public enum PassiveObserveMode {
         NOT_SUPPORTED,
@@ -59,14 +61,20 @@
         return mNumberOfExitFramesSupported;
     }
 
+    public boolean isReaderModeAnnotationSupported() {
+        return mIsReaderModeAnnotationSupported;
+    }
+
     public NfcProprietaryCaps(PassiveObserveMode passiveObserveMode,
             boolean isPollingFrameNotificationSupported, boolean isPowerSavingModeSupported,
-            boolean isAutotransactPollingLoopFilterSupported, int numberOfExitFramesSupported) {
+            boolean isAutotransactPollingLoopFilterSupported, int numberOfExitFramesSupported,
+            boolean isReaderModeAnnotationSupported) {
         mPassiveObserveMode = passiveObserveMode;
         mIsPollingFrameNotificationSupported = isPollingFrameNotificationSupported;
         mIsPowerSavingModeSupported = isPowerSavingModeSupported;
         mIsAutotransactPollingLoopFilterSupported = isAutotransactPollingLoopFilterSupported;
         mNumberOfExitFramesSupported = numberOfExitFramesSupported;
+        mIsReaderModeAnnotationSupported = isReaderModeAnnotationSupported;
     }
 
     public static NfcProprietaryCaps createFromByteArray(byte[] caps) {
@@ -76,6 +84,7 @@
         boolean isPowerSavingModeSupported = false;
         boolean isAutotransactPollingLoopFilterSupported  = false;
         int numberOfExitFramesSupported = 0;
+        boolean isReaderModeAnnotationSupported = false;
         int offset = 0;
         while ((offset + 2) < caps.length) {
             int id = caps[offset++];
@@ -109,12 +118,15 @@
                     break;
                 case NUMBER_OF_EXIT_FRAMES_SUPPORTED:
                     numberOfExitFramesSupported = caps[value_offset];
+                case READER_MODE_ANNOTATIONS_SUPPORTED:
+                    isReaderModeAnnotationSupported = caps[value_offset] == 0x1;
+                    break;
 
             }
         }
         return new NfcProprietaryCaps(passiveObserveMode, isPollingFrameNotificationSupported,
                 isPowerSavingModeSupported, isAutotransactPollingLoopFilterSupported,
-                numberOfExitFramesSupported);
+                numberOfExitFramesSupported, isReaderModeAnnotationSupported);
     }
 
     @Override
@@ -128,6 +140,8 @@
                 + mIsPowerSavingModeSupported
                 + ", isAutotransactPollingLoopFilterSupported="
                 + mIsAutotransactPollingLoopFilterSupported
+                + ", mIsReaderModeAnnotationSupported="
+                + mIsReaderModeAnnotationSupported
                 + '}';
     }
 }
diff --git a/NfcNci/src/com/android/nfc/NfcService.java b/NfcNci/src/com/android/nfc/NfcService.java
index 04cd105..4065580 100644
--- a/NfcNci/src/com/android/nfc/NfcService.java
+++ b/NfcNci/src/com/android/nfc/NfcService.java
@@ -257,6 +257,11 @@
     static final int TASK_ENABLE_ALWAYS_ON = 4;
     static final int TASK_DISABLE_ALWAYS_ON = 5;
 
+    // SE selected types
+    public static final int SE_SELECTED_AID = 0x01;
+    public static final int SE_SELECTED_TECH = 0x02;
+    public static final int SE_SELECTED_PROTOCOL = 0x04;
+
     // Polling technology masks
     static final int NFC_POLL_A = 0x01;
     static final int NFC_POLL_B = 0x02;
@@ -777,20 +782,35 @@
         mRtUpdateScheduledTask =
                 mRtUpdateScheduler.schedule(
                     () -> {
-                        if (DBG) Log.d(TAG, "onEeUpdated: ApplyRoutingTask");
-                        new ApplyRoutingTask().execute();
+                        if (mIsHceCapable) {
+                            if (DBG) Log.d(TAG, "onEeUpdated: trigger routing table update");
+                            mCardEmulationManager.onTriggerRoutingTableUpdate();
+                        }
                     },
                     50,
                     TimeUnit.MILLISECONDS);
     }
 
     private void restartStack() {
+        synchronized (NfcService.this) {
+            if (DBG) {
+                Log.d(TAG, "restartStack: mIsRecovering=" + mIsRecovering);
+            }
+            if (!mIsRecovering) {
+                mIsRecovering = true;
+            } else {
+                return;
+            }
+        }
+
+        if (DBG) {
+            Log.d(TAG, "restartStack: Restarting NFC Service");
+        }
         try {
             mContext.unregisterReceiver(mReceiver);
         } catch (IllegalArgumentException e) {
             Log.w(TAG, "restartStack: Failed to unregisterScreenState BroadCastReceiver: " + e);
         }
-        mIsRecovering = true;
         new EnableDisableTask().execute(TASK_DISABLE);
         new EnableDisableTask().execute(TASK_ENABLE);
     }
@@ -834,6 +854,17 @@
     }
 
     @Override
+    public void onObserveModeDisabledInFirmware(PollingFrame exitFrame) {
+        mCardEmulationManager.onObserveModeDisabledInFirmware(exitFrame);
+        onObserveModeStateChanged(false);
+    }
+
+    @Override
+    public void onObserveModeEnabledInFirmware() {
+        onObserveModeStateChanged(true);
+    }
+
+    @Override
     public void onEeListenActivated(boolean isActivated) {
         mEeListenActivated = isActivated;
         mCardEmulationManager.onEeListenActivated(isActivated);
@@ -861,8 +892,8 @@
     }
 
     @Override
-    public void onSeSelected() {
-        sendMessage(MSG_SE_SELECTED_EVENT, null);
+    public void onSeSelected(int type) {
+        sendMessage(MSG_SE_SELECTED_EVENT, type);
     }
 
     @Override
@@ -1128,8 +1159,7 @@
 
         mAlarmManager = mContext.getSystemService(AlarmManager.class);
 
-        mCheckDisplayStateForScreenState =
-                mContext.getResources().getBoolean(R.bool.check_display_state_for_screen_state);
+        mCheckDisplayStateForScreenState = mDeviceConfigFacade.getCheckDisplayStateForScreenState();
         if (mInProvisionMode) {
             mScreenState = mScreenStateHelper.checkScreenStateProvisionMode();
         } else {
@@ -1217,13 +1247,11 @@
         }
 
         // Polling delay count for switching from stage one to stage two.
-        mPollDelayCountMax =
-                mContext.getResources().getInteger(R.integer.unknown_tag_polling_delay_count_max);
+        mPollDelayCountMax = mDeviceConfigFacade.getUnknownTagPollingDelayMax();
         // Stage one: polling delay time for the first few unknown tag detections
-        mPollDelayTime = mContext.getResources().getInteger(R.integer.unknown_tag_polling_delay);
+        mPollDelayTime = mDeviceConfigFacade.getUnknownTagPollingDelay();
         // Stage two: longer polling delay time after max_poll_delay_count
-        mPollDelayTimeLong =
-                mContext.getResources().getInteger(R.integer.unknown_tag_polling_delay_long);
+        mPollDelayTimeLong = mDeviceConfigFacade.getUnknownTagPollingDelayLong();
         // Polling delay if read error found more than max count.
         mReadErrorCountMax =
                 mContext.getResources().getInteger(R.integer.unknown_tag_read_error_count_max);
@@ -1231,7 +1259,7 @@
         mNotifyDispatchFailed = mContext.getResources().getBoolean(R.bool.enable_notify_dispatch_failed);
         mNotifyReadFailed = mContext.getResources().getBoolean(R.bool.enable_notify_read_failed);
 
-        mPollingDisableAllowed = mContext.getResources().getBoolean(R.bool.polling_disable_allowed);
+        mPollingDisableAllowed = mDeviceConfigFacade.getPollingDisableAllowed();
         mAppInActivityDetectionTime =
             mContext.getResources().getInteger(R.integer.inactive_presence_check_allowed_time);
         mTagRemovalDetectionWaitTime =
@@ -1239,8 +1267,7 @@
         // Make sure this is only called when object construction is complete.
         mNfcInjector.getNfcManagerRegisterer().register(mNfcAdapter);
 
-        mIsAlwaysOnSupported =
-            mContext.getResources().getBoolean(R.bool.nfcc_always_on_allowed);
+        mIsAlwaysOnSupported = mDeviceConfigFacade.getNfccAlwaysOnAllowed();
 
         mIsTagAppPrefSupported =
             mContext.getResources().getBoolean(R.bool.tag_intent_app_pref_supported);
@@ -1322,8 +1349,8 @@
         executeTaskBoot();  // do blocking boot tasks
 
         if ((NFC_SNOOP_LOG_MODE.equals(NfcProperties.snoop_log_mode_values.FULL) ||
-            NFC_VENDOR_DEBUG_ENABLED) && mContext.getResources().getBoolean(
-                    R.bool.enable_developer_option_notification)) {
+            NFC_VENDOR_DEBUG_ENABLED) &&
+                mDeviceConfigFacade.getEnableDeveloperNotification()) {
             new NfcDeveloperOptionNotification(mContext).startNotification();
         }
 
@@ -1337,7 +1364,7 @@
     private void executeTaskBoot() {
         // If overlay is set, delay the NFC boot up until the OEM extension indicates it is ready to
         // proceed with NFC bootup.
-        if (mContext.getResources().getBoolean(R.bool.enable_oem_extension)) {
+        if (mDeviceConfigFacade.getEnableOemExtension()) {
             // Send intent for OEM extension to initialize.
             Intent intent = new Intent(NfcOemExtension.ACTION_OEM_EXTENSION_INIT);
             mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT, BIND_NFC_SERVICE);
@@ -2291,6 +2318,11 @@
         }
 
         @Override
+        public boolean isReaderModeAnnotationSupported() {
+            return mDeviceHost.isReaderModeAnnotationSupported();
+        }
+
+        @Override
         public boolean isObserveModeSupported() {
             if (!isNfcEnabled()) {
                 Log.e(TAG, "isObserveModeSupported: NFC must be enabled but is: " + mState);
@@ -2490,7 +2522,7 @@
                 }
                 if (mIsHceCapable) {
                     // update HCE/HCEF routing and commitRouting if Nfc is enabled
-                    mCardEmulationManager.onSecureNfcToggled();
+                    mCardEmulationManager.onTriggerRoutingTableUpdate();
                 } else if (isNfcEnabled()) {
                     // commit only tech/protocol route without HCE support
                     mDeviceHost.commitRouting();
@@ -2791,6 +2823,12 @@
                 Log.e(TAG, "setReaderMode: called with invalid flag parameter.");
                 return;
             }
+            if (extras != null
+                    && extras.containsKey(NfcAdapter.EXTRA_READER_TECH_A_POLLING_LOOP_ANNOTATION)
+                    && !isReaderModeAnnotationSupported()) {
+                Log.e(TAG, "setReaderMode() called with annotation on an unsupported device.");
+                return;
+            }
             synchronized (NfcService.this) {
                 if (!isNfcEnabled() && !privilegedCaller) {
                     Log.e(TAG, "setReaderMode: called while NFC is not enabled.");
@@ -3536,6 +3574,11 @@
 
         @Override
         public int commitRouting() throws RemoteException {
+            if (isNfcDisabledOrDisabling()) {
+                Log.d(TAG, "Skip commit routing when NFCC is off "
+                        + "or turning off");
+                return STATUS_UNKNOWN_ERROR;
+            }
             if (DBG) Log.i(TAG, "commitRouting");
             NfcPermissions.enforceAdminPermissions(mContext);
             return mDeviceHost.commitRouting();
@@ -4248,6 +4291,12 @@
         }
     }
 
+    boolean isNfcDisabledOrDisabling() {
+        synchronized (this) {
+            return (mState == NfcAdapter.STATE_OFF || mState == NfcAdapter.STATE_TURNING_OFF);
+        }
+    }
+
     boolean isNfcEnabled() {
         synchronized (this) {
             return mState == NfcAdapter.STATE_ON;
@@ -4705,6 +4754,8 @@
 
     public int commitRouting(boolean isOverrideOrRecover) {
         if (!isOverrideOrRecover) {
+            // Clear the Handler queue, only last commit_msg is relevant
+            mHandler.removeMessages(MSG_COMMIT_ROUTING);
             mHandler.sendEmptyMessage(MSG_COMMIT_ROUTING);
             return STATUS_OK;
         }
@@ -4887,8 +4938,7 @@
                 case MSG_COMMIT_ROUTING: {
                     Log.d(TAG, "handleMessage: MSG_COMMIT_ROUTING");
                     synchronized (NfcService.this) {
-                        if (mState == NfcAdapter.STATE_OFF
-                                || mState == NfcAdapter.STATE_TURNING_OFF) {
+                        if (isNfcDisabledOrDisabling()) {
                             Log.d(TAG, "handleMessage: Skip commit routing when NFCC is off "
                                     + "or turning off");
                             if (mCommitRoutingCountDownLatch != null) {
@@ -5208,7 +5258,8 @@
 
                 case MSG_SE_SELECTED_EVENT:
                     Log.d(TAG, "handleMessage: MSG_SE_SELECTED_EVENT");
-                    if (mCardEmulationManager != null) {
+                    int type = (int) msg.obj;
+                    if (mCardEmulationManager != null && type == SE_SELECTED_AID) {
                         mCardEmulationManager.onOffHostAidSelected();
                     }
                     break;
@@ -5807,8 +5858,8 @@
                 applyScreenState(mScreenStateHelper.checkScreenState(mCheckDisplayStateForScreenState));
 
                 if ((NFC_SNOOP_LOG_MODE.equals(NfcProperties.snoop_log_mode_values.FULL) ||
-                        NFC_VENDOR_DEBUG_ENABLED) && mContext.getResources().getBoolean(
-                                R.bool.enable_developer_option_notification)) {
+                        NFC_VENDOR_DEBUG_ENABLED) &&
+                        mDeviceConfigFacade.getEnableDeveloperNotification()){
                     new NfcDeveloperOptionNotification(mContext.createContextAsUser(
                             UserHandle.of(ActivityManager.getCurrentUser()), /*flags=*/0))
                             .startNotification();
@@ -5822,8 +5873,8 @@
                 setPaymentForegroundPreference(userId);
 
                 if ((NFC_SNOOP_LOG_MODE.equals(NfcProperties.snoop_log_mode_values.FULL) ||
-                        NFC_VENDOR_DEBUG_ENABLED) && mContext.getResources().getBoolean(
-                        R.bool.enable_developer_option_notification)) {
+                        NFC_VENDOR_DEBUG_ENABLED) &&
+                        mDeviceConfigFacade.getEnableDeveloperNotification()) {
                     new NfcDeveloperOptionNotification(mContext.createContextAsUser(
                             UserHandle.of(ActivityManager.getCurrentUser()), /*flags=*/0))
                             .startNotification();
diff --git a/NfcNci/src/com/android/nfc/NfcShellCommand.java b/NfcNci/src/com/android/nfc/NfcShellCommand.java
index 2825f46..0f77f92 100644
--- a/NfcNci/src/com/android/nfc/NfcShellCommand.java
+++ b/NfcNci/src/com/android/nfc/NfcShellCommand.java
@@ -77,7 +77,10 @@
     @VisibleForTesting
     @Override
     public PrintWriter getOutPrintWriter() {
-        return mPrintWriter;
+        if( mPrintWriter != null )
+            return mPrintWriter;
+        else
+            return super.getOutPrintWriter();
     }
 
     @Override
diff --git a/NfcNci/src/com/android/nfc/cardemulation/AidRoutingManager.java b/NfcNci/src/com/android/nfc/cardemulation/AidRoutingManager.java
index d7250e0..fc8b688 100644
--- a/NfcNci/src/com/android/nfc/cardemulation/AidRoutingManager.java
+++ b/NfcNci/src/com/android/nfc/cardemulation/AidRoutingManager.java
@@ -443,41 +443,34 @@
                     }
                 }
 
-                // register default route in below cases:
-                // 1. mDefaultRoute is different with mDefaultIsoDepRoute
-                // 2. mDefaultRoute and mDefaultIsoDepRoute all equal to ROUTE_HOST
-                //    , which is used for screen off HCE scenarios
-                if (mDefaultRoute != mDefaultIsoDepRoute || mDefaultIsoDepRoute == ROUTE_HOST) {
-                    if (NfcService.getInstance().getNciVersion()
-                            >= NfcService.getInstance().NCI_VERSION_2_0) {
-                        String emptyAid = "";
-                        AidEntry entry = new AidEntry();
-                        int default_route_power_state;
-                        entry.route = mDefaultRoute;
-                        if (mDefaultRoute == ROUTE_HOST) {
-                            entry.isOnHost = true;
-                            default_route_power_state = RegisteredAidCache.POWER_STATE_SWITCH_ON
-                                    | RegisteredAidCache.POWER_STATE_SCREEN_ON_LOCKED;
-                            Set<String> aidsForDefaultRoute = mAidRoutingTable.get(mDefaultRoute);
-                            if (aidsForDefaultRoute != null) {
-                                for (String aid : aidsForDefaultRoute) {
-                                    default_route_power_state |= aidMap.get(aid).power;
-                                }
+                if (NfcService.getInstance().getNciVersion()
+                        >= NfcService.getInstance().NCI_VERSION_2_0) {
+                    String emptyAid = "";
+                    AidEntry entry = new AidEntry();
+                    int default_route_power_state;
+                    entry.route = mDefaultRoute;
+                    if (mDefaultRoute == ROUTE_HOST) {
+                        entry.isOnHost = true;
+                        default_route_power_state = RegisteredAidCache.POWER_STATE_SWITCH_ON
+                                | RegisteredAidCache.POWER_STATE_SCREEN_ON_LOCKED;
+                        Set<String> aidsForDefaultRoute = mAidRoutingTable.get(mDefaultRoute);
+                        if (aidsForDefaultRoute != null) {
+                            for (String aid : aidsForDefaultRoute) {
+                                default_route_power_state |= aidMap.get(aid).power;
                             }
-                        } else {
-                            entry.isOnHost = false;
-                            default_route_power_state = RegisteredAidCache.POWER_STATE_ALL;
                         }
-                        if (mPowerEmptyAid != default_route_power_state) {
-                            isPowerStateUpdated = true;
-                        }
-                        mPowerEmptyAid = default_route_power_state;
-                        entry.aidInfo = RegisteredAidCache.AID_ROUTE_QUAL_PREFIX;
-                        entry.power = default_route_power_state;
-
-                        aidRoutingTableCache.put(emptyAid, entry);
-                        if (DBG) Log.d(TAG, "configureRouting: Add emptyAid into AidRoutingTable");
+                    } else {
+                        entry.isOnHost = false;
+                        default_route_power_state = RegisteredAidCache.POWER_STATE_ALL;
                     }
+                    if (mPowerEmptyAid != default_route_power_state) {
+                        isPowerStateUpdated = true;
+                    }
+                    mPowerEmptyAid = default_route_power_state;
+                    entry.aidInfo = RegisteredAidCache.AID_ROUTE_QUAL_PREFIX;
+                    entry.power = default_route_power_state;
+                    aidRoutingTableCache.put(emptyAid, entry);
+                    if (DBG) Log.d(TAG, "configureRouting: Add emptyAid into AidRoutingTable");
                 }
 
                 // Register additional offhost AIDs when their support power states are
diff --git a/NfcNci/src/com/android/nfc/cardemulation/CardEmulationManager.java b/NfcNci/src/com/android/nfc/cardemulation/CardEmulationManager.java
index b03725b..67ab85c 100644
--- a/NfcNci/src/com/android/nfc/cardemulation/CardEmulationManager.java
+++ b/NfcNci/src/com/android/nfc/cardemulation/CardEmulationManager.java
@@ -68,6 +68,7 @@
 import com.android.nfc.NfcPermissions;
 import com.android.nfc.NfcService;
 import com.android.nfc.R;
+import com.android.nfc.cardemulation.util.StatsdUtils;
 import com.android.nfc.cardemulation.util.TelephonyUtils;
 import com.android.nfc.flags.Flags;
 import com.android.nfc.proto.NfcEventProto;
@@ -155,6 +156,9 @@
     private final int mVendorApiLevel;
     private PreferredSubscriptionService mPreferredSubscriptionService = null;
     private TelephonyUtils mTelephonyUtils = null;
+    @Nullable
+    private final StatsdUtils mStatsdUtils;
+    private final DeviceConfigFacade mDeviceConfigFacade;
 
     // TODO: Move this object instantiation and dependencies to NfcInjector.
     public CardEmulationManager(Context context, NfcInjector nfcInjector,
@@ -191,6 +195,8 @@
         mVendorApiLevel = SystemProperties.getInt(
                 "ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT);
         mPreferredSubscriptionService = new PreferredSubscriptionService(mContext, this);
+        mStatsdUtils = nfcInjector.getStatsdUtils();
+        mDeviceConfigFacade = deviceConfigFacade;
         initialize();
     }
 
@@ -209,7 +215,9 @@
             RoutingOptionManager routingOptionManager,
             PowerManager powerManager,
             NfcEventLog nfcEventLog,
-            PreferredSubscriptionService preferredSubscriptionService) {
+            PreferredSubscriptionService preferredSubscriptionService,
+            StatsdUtils statsdUtils,
+            DeviceConfigFacade deviceConfigFacade) {
         mContext = context;
         mCardEmulationInterface = new CardEmulationInterface();
         mNfcFCardEmulationInterface = new NfcFCardEmulationInterface();
@@ -231,6 +239,8 @@
         mVendorApiLevel = SystemProperties.getInt(
                 "ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT);
         mPreferredSubscriptionService = preferredSubscriptionService;
+        mStatsdUtils = statsdUtils;
+        mDeviceConfigFacade = deviceConfigFacade;
         initialize();
     }
 
@@ -287,7 +297,7 @@
                 Log.e(TAG, "onHostCardEmulationActivated: failed", e);
             }
         }
-        if (mContext.getResources().getBoolean(R.bool.indicate_user_activity_for_hce)
+        if (mDeviceConfigFacade.getIndicateUserActivityForHce()
                 && mPowerManager != null) {
             // Use USER_ACTIVITY_FLAG_INDIRECT to applying power hints without resets
             // the screen timeout
@@ -394,9 +404,10 @@
         mEnabledNfcFServices.onNfcDisabled();
     }
 
-    public void onSecureNfcToggled() {
-        mAidCache.onSecureNfcToggled();
-        mT3tIdentifiersCache.onSecureNfcToggled();
+    public void onTriggerRoutingTableUpdate() {
+        if (DBG) Log.d(TAG, "onTriggerRoutingTableUpdate");
+        mAidCache.onTriggerRoutingTableUpdate();
+        mT3tIdentifiersCache.onTriggerRoutingTableUpdate();
     }
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -465,6 +476,9 @@
         // Update the preferred services list
         mPreferredServices.onServicesUpdated();
         mHostEmulationManager.updatePollingLoopFilters(userId, services);
+        if (Flags.exitFrames()) {
+            updateFirmwareExitFramesForWalletRole(userId);
+        }
         NfcService.getInstance().onPreferredPaymentChanged(NfcAdapter.PREFERRED_PAYMENT_UPDATED);
     }
 
@@ -900,11 +914,6 @@
                                     .setPollingLoopFilter(pollingLoopFilter)
                                     .build())
                             .build());
-            if (Flags.exitFrames()
-                    && mAidCache.isDefaultOrAssociatedWalletPackage(service.getPackageName(),
-                    userId)) {
-                updateFirmwareExitFramesForWalletRole(userId);
-            }
             return true;
         }
 
@@ -940,11 +949,6 @@
                                     .setPollingLoopFilter(pollingLoopFilter)
                                     .build())
                             .build());
-            if (Flags.exitFrames()
-                    && mAidCache.isDefaultOrAssociatedWalletPackage(service.getPackageName(),
-                    userId)) {
-                updateFirmwareExitFramesForWalletRole(userId);
-            }
             return true;
         }
 
@@ -980,11 +984,6 @@
                                     .setPollingLoopFilter(pollingLoopPatternFilter)
                                     .build())
                             .build());
-            if (Flags.exitFrames()
-                    && mAidCache.isDefaultOrAssociatedWalletPackage(service.getPackageName(),
-                    userId)) {
-                updateFirmwareExitFramesForWalletRole(userId);
-            }
             return true;
         }
 
@@ -1020,11 +1019,6 @@
                                     .setPollingLoopFilter(pollingLoopPatternFilter)
                                     .build())
                             .build());
-            if (Flags.exitFrames()
-                    && mAidCache.isDefaultOrAssociatedWalletPackage(service.getPackageName(),
-                    userId)) {
-                updateFirmwareExitFramesForWalletRole(userId);
-            }
             return true;
         }
 
@@ -1149,7 +1143,7 @@
         @Override
         public int setServiceEnabledForCategoryOther(int userId,
                 ComponentName app, boolean status) throws RemoteException {
-            if (!mContext.getResources().getBoolean(R.bool.enable_service_for_category_other))
+            if (!mDeviceConfigFacade.getEnableServiceOther())
               return SET_SERVICE_ENABLED_STATUS_FAILURE_FEATURE_UNSUPPORTED;
             NfcPermissions.enforceUserPermissions(mContext);
 
@@ -1724,6 +1718,17 @@
         }
     }
 
+    public void onObserveModeDisabledInFirmware(PollingFrame exitFrame) {
+        if (android.nfc.Flags.nfcEventListener()) {
+            callNfcEventCallbacks(listener -> listener.onObserveModeDisabledInFirmware(exitFrame));
+        }
+        mHostEmulationManager.onObserveModeDisabledInFirmware(exitFrame);
+
+        if (mStatsdUtils != null) {
+            mStatsdUtils.logAutoTransactReported(StatsdUtils.PROCESSOR_NFCC, exitFrame.getData());
+        }
+    }
+
     @Override
     public void onWalletRoleHolderChanged(String holder, int userId) {
         mPreferredServices.onWalletRoleHolderChanged(holder, userId);
diff --git a/NfcNci/src/com/android/nfc/cardemulation/EnabledNfcFServices.java b/NfcNci/src/com/android/nfc/cardemulation/EnabledNfcFServices.java
index f45519b..13918e9 100644
--- a/NfcNci/src/com/android/nfc/cardemulation/EnabledNfcFServices.java
+++ b/NfcNci/src/com/android/nfc/cardemulation/EnabledNfcFServices.java
@@ -245,7 +245,7 @@
      * {@link ProtoOutputStream#end(long)} after.
      * Never reuse a proto field number. When removing a field, mark it as reserved.
      */
-    void dumpDebug(ProtoOutputStream proto) {
+    public void dumpDebug(ProtoOutputStream proto) {
         synchronized (mLock) {
             if (mForegroundComponent != null) {
                 Utils.dumpDebugComponentName(
diff --git a/NfcNci/src/com/android/nfc/cardemulation/HostEmulationManager.java b/NfcNci/src/com/android/nfc/cardemulation/HostEmulationManager.java
index 586bb24..506d199 100644
--- a/NfcNci/src/com/android/nfc/cardemulation/HostEmulationManager.java
+++ b/NfcNci/src/com/android/nfc/cardemulation/HostEmulationManager.java
@@ -208,6 +208,7 @@
 
     boolean mEnableObserveModeAfterTransaction = false;
     boolean mEnableObserveModeOnFieldOff = false;
+    PollingFrame mFirmwareExitFrame = null;
     ComponentName mPaymentServiceName = null;
     @UserIdInt int mPaymentServiceUserId; // The userId of the payment service
     ComponentName mLastBoundPaymentServiceName;
@@ -251,7 +252,12 @@
                 @Override
                 public void run() {
                     synchronized (mLock) {
-                        unbindInactiveServicesLocked();
+                        if (isHostCardEmulationActivated()) {
+                            // Skip in active state
+                            rescheduleInactivityChecks();
+                        } else {
+                            unbindInactiveServicesLocked();
+                        }
                     }
                 }
 
@@ -614,10 +620,21 @@
                         }
                         if (serviceInfo.getShouldAutoTransact(dataStr)) {
                             if (mStatsdUtils != null) {
+                                mStatsdUtils.logAutoTransactReported(
+                                    StatsdUtils.PROCESSOR_HOST, data);
                                 mStatsdUtils.setNextObserveModeTriggerSource(
                                     StatsdUtils.TRIGGER_SOURCE_AUTO_TRANSACT);
                             }
-                            allowOneTransaction();
+                            if (mFirmwareExitFrame != null && Arrays.equals(
+                                    mFirmwareExitFrame.getData(), pollingFrame.getData())) {
+                                mFirmwareExitFrame = null;
+                                mEnableObserveModeAfterTransaction = true;
+                                Log.d(TAG,
+                                        "Polling frame matches exit frame, leaving observe mode "
+                                                + "disabled");
+                            } else {
+                                allowOneTransaction();
+                            }
                             pollingFrame.setTriggeredAutoTransact(true);
                         }
                         UserHandle user = UserHandle.getUserHandleForUid(serviceInfo.getUid());
@@ -647,6 +664,7 @@
                     mStatsdUtils.logPollingFrames();
                 }
             }
+            mFirmwareExitFrame = null;
 
             if (mPollingLoopState == PollingLoopState.EVALUATING_POLLING_LOOP) {
                 if (mPendingPollingLoopFrames.size() >= 3) {
@@ -711,6 +729,15 @@
     }
 
     /**
+     * Observe mode was disabled in firmware, we shouldn't autotransact on the next frame.
+     *
+     * This assumes the exit frame will be in the next batch of processed polling frames.
+     */
+    public void onObserveModeDisabledInFirmware(PollingFrame exitFrame) {
+        mFirmwareExitFrame = exitFrame;
+    }
+
+    /**
      *  Preferred foreground service changed
      */
     public void onPreferredForegroundServiceChanged(ComponentNameAndUser serviceAndUser) {
diff --git a/NfcNci/src/com/android/nfc/cardemulation/PreferredSubscriptionService.java b/NfcNci/src/com/android/nfc/cardemulation/PreferredSubscriptionService.java
index 1b88ce4..de741ab 100644
--- a/NfcNci/src/com/android/nfc/cardemulation/PreferredSubscriptionService.java
+++ b/NfcNci/src/com/android/nfc/cardemulation/PreferredSubscriptionService.java
@@ -15,7 +15,6 @@
  */

 package com.android.nfc.cardemulation;

 

-import android.content.ContentResolver;

 import android.content.Context;

 import android.content.SharedPreferences;

 import android.content.pm.PackageManager;

@@ -32,13 +31,12 @@
     static final String TAG = "PreferredSubscriptionService";

     static final String PREF_SUBSCRIPTION = "SubscriptionPref";

     static final String PREF_PREFERRED_SUB_ID = "pref_sub_id";

-    private SharedPreferences mSubscriptionPrefs = null;;

+    private SharedPreferences mSubscriptionPrefs = null;

 

     Context mContext;

     Callback mCallback;

 

     int mDefaultSubscriptionId = TelephonyUtils.SUBSCRIPTION_ID_UNKNOWN;

-    private final ContentResolver mContentResolver;

     boolean mIsEuiccCapable;

     boolean mIsUiccCapable;

     TelephonyUtils mTelephonyUtils;

@@ -51,7 +49,6 @@
 

     public PreferredSubscriptionService(Context context, Callback callback) {

         mContext = context;

-        mContentResolver = mContext.getContentResolver();

         mCallback = callback;

 

         mIsUiccCapable = context.getPackageManager().hasSystemFeature(

@@ -59,7 +56,7 @@
         mIsEuiccCapable = mContext.getResources().getBoolean(R.bool.enable_euicc_support);

 

         mTelephonyUtils = TelephonyUtils.getInstance(context);

-        mSubscriptionPrefs =  mContext.getSharedPreferences(

+        mSubscriptionPrefs = mContext.getSharedPreferences(

                 PREF_SUBSCRIPTION, Context.MODE_PRIVATE);

 

         // Initialize default subscription to UICC if there is no preference

@@ -84,7 +81,7 @@
         Log.d(TAG, "getPreferredSubscriptionId: " + mDefaultSubscriptionId);

         return mSubscriptionPrefs.getInt(

                 PREF_PREFERRED_SUB_ID, TelephonyUtils.SUBSCRIPTION_ID_UNKNOWN);

-        }

+    }

 

     public void setPreferredSubscriptionId(int subscriptionId, boolean force) {

         Log.d(TAG, "setPreferredSubscriptionId: " + subscriptionId);

@@ -93,7 +90,7 @@
             mSubscriptionPrefs.edit().putInt(PREF_PREFERRED_SUB_ID, subscriptionId).commit();

             if (force) {

                 onDefaultSubscriptionChanged();

-    }

+            }

         }

     }

 

@@ -112,8 +109,7 @@
         if (isActivationStateChanged) {

             mCallback.onPreferredSubscriptionChanged(mDefaultSubscriptionId,

                     mActiveSubscriptoinState == TelephonyUtils.SUBSCRIPTION_STATE_ACTIVATE);

-        }

-        else {

+        } else {

             Log.i(TAG, "onActiveSubscriptionsUpdated: Active Subscription is not changed");

         }

     }

@@ -123,8 +119,8 @@
             Log.d(TAG, "isSubscriptionActivated: get active subscriptions is "

                     + "list because it's null");

             mActiveSubscriptions = mTelephonyUtils.getActiveSubscriptions().stream().filter(

-                    TelephonyUtils.SUBSCRIPTION_ACTIVE_CONDITION_FOR_UICC.or(

-                            TelephonyUtils.SUBSCRIPTION_ACTIVE_CONDITION_FOR_EUICC))

+                            TelephonyUtils.SUBSCRIPTION_ACTIVE_CONDITION_FOR_UICC.or(

+                                    TelephonyUtils.SUBSCRIPTION_ACTIVE_CONDITION_FOR_EUICC))

                     .collect(Collectors.toList());

         }

         boolean isEuiccSubscription = mTelephonyUtils.isEuiccSubscription(subscriptionId);

@@ -135,8 +131,8 @@
     private boolean checkSubscriptionStateChanged(List<SubscriptionInfo> activeSubscriptionList) {

         // filtered subscriptions

         mActiveSubscriptions = activeSubscriptionList.stream().filter(

-                TelephonyUtils.SUBSCRIPTION_ACTIVE_CONDITION_FOR_UICC.or(

-                        TelephonyUtils.SUBSCRIPTION_ACTIVE_CONDITION_FOR_EUICC))

+                        TelephonyUtils.SUBSCRIPTION_ACTIVE_CONDITION_FOR_UICC.or(

+                                TelephonyUtils.SUBSCRIPTION_ACTIVE_CONDITION_FOR_EUICC))

                 .collect(Collectors.toList());

         int previousActiveSubscriptionState = mActiveSubscriptoinState;

         int currentActiveSubscriptionState = isSubscriptionActivated(mDefaultSubscriptionId) ?

@@ -148,7 +144,6 @@
             mActiveSubscriptoinState = currentActiveSubscriptionState;

             return true;

         }

-

         return false;

     }

 }

diff --git a/NfcNci/src/com/android/nfc/cardemulation/RegisteredAidCache.java b/NfcNci/src/com/android/nfc/cardemulation/RegisteredAidCache.java
index 3082c8c..500b3a6 100644
--- a/NfcNci/src/com/android/nfc/cardemulation/RegisteredAidCache.java
+++ b/NfcNci/src/com/android/nfc/cardemulation/RegisteredAidCache.java
@@ -1516,7 +1516,7 @@
         }
     }
 
-    public void onSecureNfcToggled() {
+    public void onTriggerRoutingTableUpdate() {
         synchronized (mLock) {
             updateRoutingLocked(true, false);
         }
diff --git a/NfcNci/src/com/android/nfc/cardemulation/RegisteredServicesCache.java b/NfcNci/src/com/android/nfc/cardemulation/RegisteredServicesCache.java
index 1cf3ba1..b273741 100644
--- a/NfcNci/src/com/android/nfc/cardemulation/RegisteredServicesCache.java
+++ b/NfcNci/src/com/android/nfc/cardemulation/RegisteredServicesCache.java
@@ -1266,6 +1266,9 @@
                 Log.e(TAG, "removePollingLoopFilterForService: UID mismatch");
                 return false;
             }
+            DynamicSettings dynamicSettings =
+                    getOrCreateSettings(services, componentName, serviceInfo.getUid());
+            dynamicSettings.pollingLoopFilters.remove(pollingLoopFilter);
             serviceInfo.removePollingLoopFilter(pollingLoopFilter);
             newServices = new ArrayList<ApduServiceInfo>(services.services.values());
         }
@@ -1328,6 +1331,9 @@
                 Log.e(TAG, "removePollingLoopPatternFilterForService: UID mismatch");
                 return false;
             }
+            DynamicSettings dynamicSettings =
+                    getOrCreateSettings(services, componentName, serviceInfo.getUid());
+            dynamicSettings.pollingLoopPatternFilters.remove(pollingLoopPatternFilter);
             serviceInfo.removePollingLoopPatternFilter(pollingLoopPatternFilter);
             newServices = new ArrayList<ApduServiceInfo>(services.services.values());
         }
diff --git a/NfcNci/src/com/android/nfc/cardemulation/RegisteredT3tIdentifiersCache.java b/NfcNci/src/com/android/nfc/cardemulation/RegisteredT3tIdentifiersCache.java
index 1f2cb08..41e8866 100644
--- a/NfcNci/src/com/android/nfc/cardemulation/RegisteredT3tIdentifiersCache.java
+++ b/NfcNci/src/com/android/nfc/cardemulation/RegisteredT3tIdentifiersCache.java
@@ -181,10 +181,10 @@
         mRoutingManager.configureRouting(t3tIdentifiers);
     }
 
-    public void onSecureNfcToggled() {
+    public void onTriggerRoutingTableUpdate() {
         synchronized(mLock) {
             updateRoutingLocked(true);
-      }
+        }
     }
 
     public void onServicesUpdated(int userId, List<NfcFServiceInfo> services) {
diff --git a/NfcNci/src/com/android/nfc/cardemulation/util/StatsdUtils.java b/NfcNci/src/com/android/nfc/cardemulation/util/StatsdUtils.java
index 1ebab76..b67679c 100644
--- a/NfcNci/src/com/android/nfc/cardemulation/util/StatsdUtils.java
+++ b/NfcNci/src/com/android/nfc/cardemulation/util/StatsdUtils.java
@@ -84,6 +84,13 @@
     public static final int TRIGGER_SOURCE_AUTO_TRANSACT =
             NfcStatsLog.NFC_OBSERVE_MODE_STATE_CHANGED__TRIGGER_SOURCE__AUTO_TRANSACT;
 
+    public static final int PROCESSOR_UNKNOWN =
+            NfcStatsLog.NFC_AUTO_TRANSACT_REPORTED__AUTO_TRANSACT_PROCESSOR__PROCESSOR_UNKNOWN;
+    public static final int PROCESSOR_HOST =
+            NfcStatsLog.NFC_AUTO_TRANSACT_REPORTED__AUTO_TRANSACT_PROCESSOR__HOST;
+    public static final int PROCESSOR_NFCC =
+            NfcStatsLog.NFC_AUTO_TRANSACT_REPORTED__AUTO_TRANSACT_PROCESSOR__NFCC;
+
     /** Name of SE terminal to log in statsd */
     private String mSeName = "";
     /** Timestamp in millis when app binding starts */
@@ -333,6 +340,11 @@
         NfcStatsLog.write(NfcStatsLog.NFC_EXIT_FRAME_TABLE_CHANGED, tableSize, timeoutMs);
     }
 
+    public void logAutoTransactReported(int processor, byte[] data) {
+      NfcStatsLog.write(NfcStatsLog.NFC_AUTO_TRANSACT_REPORTED, processor, data.length,
+          getFrameType(data));
+    }
+
     private final HashMap<String, PollingFrameLog> pollingFrameMap = new HashMap<>();
 
     public void tallyPollingFrame(String frameDataHex, PollingFrame frame) {
diff --git a/NfcNci/src/com/android/nfc/handover/BluetoothPeripheralHandover.java b/NfcNci/src/com/android/nfc/handover/BluetoothPeripheralHandover.java
index 7648f51..ae9c808 100644
--- a/NfcNci/src/com/android/nfc/handover/BluetoothPeripheralHandover.java
+++ b/NfcNci/src/com/android/nfc/handover/BluetoothPeripheralHandover.java
@@ -43,6 +43,8 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import com.android.nfc.DeviceConfigFacade;
+import com.android.nfc.NfcInjector;
 import com.android.nfc.R;
 
 import java.lang.reflect.Method;
@@ -102,6 +104,7 @@
     final int mTransport;
     final boolean mProvisioning;
     final AudioManager mAudioManager;
+    private DeviceConfigFacade mDeviceConfigFacade;
 
     final Object mLock = new Object();
 
@@ -177,6 +180,8 @@
 
         mAudioManager = mContext.getSystemService(AudioManager.class);
 
+        mDeviceConfigFacade = NfcInjector.getInstance().getDeviceConfigFacade();
+
         mState = STATE_INIT;
     }
 
@@ -608,7 +613,7 @@
     }
 
     void startTheMusic() {
-        if (!mContext.getResources().getBoolean(R.bool.enable_auto_play) && !mIsMusicActive) {
+        if (!mDeviceConfigFacade.getEnableAutoPlay() && !mIsMusicActive) {
             return;
         }
 
diff --git a/NfcNci/tests/testcases/hostsidetests/exitframes/nfc_exit_frame_multi_device_test.py b/NfcNci/tests/testcases/hostsidetests/exitframes/nfc_exit_frame_multi_device_test.py
index 40c5f6c..793a2a7 100644
--- a/NfcNci/tests/testcases/hostsidetests/exitframes/nfc_exit_frame_multi_device_test.py
+++ b/NfcNci/tests/testcases/hostsidetests/exitframes/nfc_exit_frame_multi_device_test.py
@@ -80,7 +80,7 @@
 class NfcExitFrameMultiDeviceTestCases(base_test.BaseTestClass):
     def _set_up_emulator(self, *args, start_emulator_fun=None, service_list=[],
                  expected_service=None, is_payment=False, preferred_service=None,
-                 payment_default_service=None):
+                 payment_default_service=None, should_disable_services_on_destroy=True):
         """
         Sets up emulator device for multidevice tests.
         :param is_payment: bool
@@ -107,8 +107,9 @@
             start_emulator_fun(*args)
         else:
             if preferred_service is None:
-                self.emulator.nfc_emulator.startSimpleEmulatorActivity(service_list,
-                                                                       expected_service, is_payment)
+                self.emulator.nfc_emulator.startSimpleEmulatorActivity(
+                            service_list, expected_service, is_payment,
+                            should_disable_services_on_destroy)
             else:
                 self.emulator.nfc_emulator.startSimpleEmulatorActivityWithPreferredService(
                     service_list, expected_service, preferred_service, is_payment
@@ -156,7 +157,7 @@
         self._setup_failure_should_block_tests = True
 
         try:
-            devices = self.register_controller(android_device)[:2]
+            devices = self.register_controller(android_device)[:1]
             if len(devices) == 1:
                 self.emulator = devices[0]
             else:
@@ -203,17 +204,6 @@
                 self._setup_failure_reason = 'Failed to connect to PN532 board.'
                 self.pn532 = pn532.PN532(pn532_serial_path)
                 self.pn532.mute()
-                self._setup_failure_reason = (
-                    'Cannot load reader snippet. Is NfcReaderTestApp.apk '
-                    'installed on the reader?'
-                )
-                self.reader.load_snippet('nfc_reader', 'com.android.nfc.reader')
-                self.reader.adb.shell(['svc', 'nfc', 'enable'])
-                self.reader.debug_tag = 'reader'
-                if not self.reader.nfc_reader.isNfcSupported():
-                    self._setup_failure_reason = f'NFC is not supported on {self.reader}'
-                    self._setup_failure_should_block_tests = False
-                    return
         except Exception as e:
             _LOG.warning('setup_class failed with error %s', e)
             return
@@ -237,11 +227,8 @@
                                            " ***")
         self.emulator.nfc_emulator.turnScreenOn()
         self.emulator.nfc_emulator.pressMenu()
-        if not self.pn532:
-            self.reader.nfc_reader.turnScreenOn()
-            self.reader.nfc_reader.pressMenu()
 
-    """Tests the autotransact functionality.
+    """Tests the autotransact functionality with exit frames.
 
     Test Steps:
         1. Start emulator activity and set up payment HCE Service.
@@ -252,20 +239,20 @@
 
         Verifies:
         1. Observe mode is disabled and a transaction occurs.
-        2. After the first transaction, verifies that observe mode is reenabled.
-        3. After observe mode is reenabled, verifies that the tag is not
+        2. Verify correct exit frame was used for transaction.
+        3. After the first transaction, verifies that observe mode is reenabled.
+        4. After observe mode is reenabled, verifies that the tag is not
         detected.
-
-        TODO(johnrjohn) Add methods to register unique polling frames so we can
-        test different filters
     """
-    def test_exit_frames(self):
+    def test_exit_frames_manifest_filter(self):
         self._set_up_emulator(
-                    service_list=[_PAYMENT_SERVICE_1],
-                    expected_service=_PAYMENT_SERVICE_1,
-                    is_payment=True,
-                    payment_default_service=_PAYMENT_SERVICE_1
-                )
+            "41fbc7b9", [], True,
+            start_emulator_fun=self.emulator.nfc_emulator.startExitFrameActivity,
+            service_list=[_PAYMENT_SERVICE_1],
+            expected_service=_PAYMENT_SERVICE_1,
+            is_payment=True,
+            payment_default_service=_PAYMENT_SERVICE_1
+        )
         asserts.skip_if(
                     not self.emulator.nfc_emulator.isObserveModeSupported(),
                     f"{self.emulator} observe mode not supported",
@@ -277,12 +264,17 @@
 
         command_apdus, response_apdus = get_apdus(self.emulator.nfc_emulator,
                                                       _PAYMENT_SERVICE_1)
+        test_pass_handler = self.emulator.nfc_emulator.asyncWaitForTestPass(
+            'ExitFrameListenerSuccess'
+        )
         tag_detected, transacted = poll_and_transact(
                 self.pn532, command_apdus, response_apdus, "41fbc7b9")
         asserts.assert_true(
             tag_detected, _FAILED_TAG_MSG
         )
         asserts.assert_true(transacted, _FAILED_TRANSACTION_MSG)
+        test_pass_handler.waitAndGet('ExitFrameListenerSuccess', _NFC_TIMEOUT_SEC)
+
 
         time.sleep(_NFC_TIMEOUT_SEC)
 
@@ -296,11 +288,347 @@
                 self.pn532, command_apdus, response_apdus)
         asserts.assert_false(
                     tag_detected,
-                    "Reader detected emulator even though observemode was enabled."
+                    "Reader detected emulator even though observe mode was enabled."
                 )
 
         self.emulator.nfc_emulator.setObserveModeEnabled(False)
 
+    """Tests the autotransact functionality with exit frames.
+
+    Test Steps:
+        1. Start emulator activity and set up payment HCE Service.
+        2. Enable observe mode.
+        3. Poll with a broadcast frame, and attempt to transact.
+        4. Wait for observe mode to be reenabled.
+        5. Poll again and verify that the tag is not detected.
+
+        Verifies:
+        1. Observe mode is disabled and a transaction occurs.
+        2. Verify correct exit frame was used for transaction.
+        3. After the first transaction, verifies that observe mode is reenabled.
+        4. After observe mode is reenabled, verifies that the tag is not
+        detected.
+    """
+    def test_exit_frames_registered_filters(self):
+        self._set_up_emulator(
+            "12345678", ["12345678", "aaaa"], True,
+            start_emulator_fun=self.emulator.nfc_emulator.startExitFrameActivity,
+            service_list=[_PAYMENT_SERVICE_1],
+            expected_service=_PAYMENT_SERVICE_1,
+            is_payment=True,
+            payment_default_service=_PAYMENT_SERVICE_1
+        )
+        asserts.skip_if(
+                    not self.emulator.nfc_emulator.isObserveModeSupported(),
+                    f"{self.emulator} observe mode not supported",
+                )
+        asserts.assert_true(
+            self.emulator.nfc_emulator.setObserveModeEnabled(True),
+            f"{self.emulator} could not set observe mode",
+        )
+
+        command_apdus, response_apdus = get_apdus(self.emulator.nfc_emulator,
+                                                      _PAYMENT_SERVICE_1)
+        test_pass_handler = self.emulator.nfc_emulator.asyncWaitForTestPass(
+            'ExitFrameListenerSuccess'
+        )
+        tag_detected, transacted = poll_and_transact(
+                self.pn532, command_apdus, response_apdus, "12345678")
+        asserts.assert_true(
+            tag_detected, _FAILED_TAG_MSG
+        )
+        asserts.assert_true(transacted, _FAILED_TRANSACTION_MSG)
+        test_pass_handler.waitAndGet('ExitFrameListenerSuccess', _NFC_TIMEOUT_SEC)
+
+
+        time.sleep(_NFC_TIMEOUT_SEC)
+
+        # Poll again and see if tag is detected, observe mode should be enabled
+        # by now.
+        asserts.assert_true(
+                    self.emulator.nfc_emulator.isObserveModeEnabled(),
+                    f"{self.emulator} isObserveModeEnabled did not return True",
+                )
+        tag_detected, _ = poll_and_transact(
+                self.pn532, command_apdus, response_apdus)
+        asserts.assert_false(
+                    tag_detected,
+                    "Reader detected emulator even though observe mode was enabled."
+                )
+
+        self.emulator.nfc_emulator.setObserveModeEnabled(False)
+
+    """Tests the autotransact functionality with exit frames.
+
+    Test Steps:
+        1. Start emulator activity and set up payment HCE Service.
+        2. Enable observe mode.
+        3. Poll with a broadcast frame, and attempt to transact.
+        4. Wait for observe mode to be reenabled.
+        5. Poll again and verify that the tag is not detected.
+
+        Verifies:
+        1. Observe mode is disabled and a transaction occurs.
+        2. Verify correct exit frame was used for transaction.
+        3. After the first transaction, verifies that observe mode is reenabled.
+        4. After observe mode is reenabled, verifies that the tag is not
+        detected.
+    """
+    def test_exit_frames_prefix_match(self):
+        self._set_up_emulator(
+            "dd1234", ["12345678", "dd.*", "ee.*", "ff.."], True,
+            start_emulator_fun=self.emulator.nfc_emulator.startExitFrameActivity,
+            service_list=[_PAYMENT_SERVICE_1],
+            expected_service=_PAYMENT_SERVICE_1,
+            is_payment=True,
+            payment_default_service=_PAYMENT_SERVICE_1
+        )
+        asserts.skip_if(
+                    not self.emulator.nfc_emulator.isObserveModeSupported(),
+                    f"{self.emulator} observe mode not supported",
+                )
+        asserts.assert_true(
+            self.emulator.nfc_emulator.setObserveModeEnabled(True),
+            f"{self.emulator} could not set observe mode",
+        )
+
+        command_apdus, response_apdus = get_apdus(self.emulator.nfc_emulator,
+                                                      _PAYMENT_SERVICE_1)
+        test_pass_handler = self.emulator.nfc_emulator.asyncWaitForTestPass(
+            'ExitFrameListenerSuccess'
+        )
+        tag_detected, transacted = poll_and_transact(
+                self.pn532, command_apdus, response_apdus, "dd1234")
+        asserts.assert_true(
+            tag_detected, _FAILED_TAG_MSG
+        )
+        asserts.assert_true(transacted, _FAILED_TRANSACTION_MSG)
+        test_pass_handler.waitAndGet('ExitFrameListenerSuccess', _NFC_TIMEOUT_SEC)
+
+
+        time.sleep(_NFC_TIMEOUT_SEC)
+
+        # Poll again and see if tag is detected, observe mode should be enabled
+        # by now.
+        asserts.assert_true(
+                    self.emulator.nfc_emulator.isObserveModeEnabled(),
+                    f"{self.emulator} isObserveModeEnabled did not return True",
+                )
+        tag_detected, _ = poll_and_transact(
+                self.pn532, command_apdus, response_apdus)
+        asserts.assert_false(
+                    tag_detected,
+                    "Reader detected emulator even though observe mode was enabled."
+                )
+
+        self.emulator.nfc_emulator.setObserveModeEnabled(False)
+
+    """Tests the autotransact functionality with exit frames.
+
+    Test Steps:
+        1. Start emulator activity and set up payment HCE Service.
+        2. Enable observe mode.
+        3. Poll with a broadcast frame, and attempt to transact.
+        4. Wait for observe mode to be reenabled.
+        5. Poll again and verify that the tag is not detected.
+
+        Verifies:
+        1. Observe mode is disabled and a transaction occurs.
+        2. Verify correct exit frame was used for transaction.
+        3. After the first transaction, verifies that observe mode is reenabled.
+        4. After observe mode is reenabled, verifies that the tag is not
+        detected.
+    """
+    def test_exit_frames_mask_match(self):
+        self._set_up_emulator(
+            "ff11", ["12345678", "ff.."], True,
+            start_emulator_fun=self.emulator.nfc_emulator.startExitFrameActivity,
+            service_list=[_PAYMENT_SERVICE_1],
+            expected_service=_PAYMENT_SERVICE_1,
+            is_payment=True,
+            payment_default_service=_PAYMENT_SERVICE_1
+        )
+        asserts.skip_if(
+                    not self.emulator.nfc_emulator.isObserveModeSupported(),
+                    f"{self.emulator} observe mode not supported",
+                )
+        asserts.assert_true(
+            self.emulator.nfc_emulator.setObserveModeEnabled(True),
+            f"{self.emulator} could not set observe mode",
+        )
+
+        command_apdus, response_apdus = get_apdus(self.emulator.nfc_emulator,
+                                                      _PAYMENT_SERVICE_1)
+        test_pass_handler = self.emulator.nfc_emulator.asyncWaitForTestPass(
+            'ExitFrameListenerSuccess'
+        )
+        tag_detected, transacted = poll_and_transact(
+                self.pn532, command_apdus, response_apdus, "ff11")
+        asserts.assert_true(
+            tag_detected, _FAILED_TAG_MSG
+        )
+        asserts.assert_true(transacted, _FAILED_TRANSACTION_MSG)
+        test_pass_handler.waitAndGet('ExitFrameListenerSuccess', _NFC_TIMEOUT_SEC)
+
+
+        time.sleep(_NFC_TIMEOUT_SEC)
+
+        # Poll again and see if tag is detected, observe mode should be enabled
+        # by now.
+        asserts.assert_true(
+                    self.emulator.nfc_emulator.isObserveModeEnabled(),
+                    f"{self.emulator} isObserveModeEnabled did not return True",
+                )
+        tag_detected, _ = poll_and_transact(
+                self.pn532, command_apdus, response_apdus)
+        asserts.assert_false(
+                    tag_detected,
+                    "Reader detected emulator even though observe mode was enabled."
+                )
+
+        self.emulator.nfc_emulator.setObserveModeEnabled(False)
+
+    """Tests the autotransact functionality with exit frames.
+
+    Test Steps:
+        1. Start emulator activity and set up payment HCE Service.
+        2. Enable observe mode.
+        3. Poll with a broadcast frame, and attempt to transact.
+        4. Wait for observe mode to be reenabled.
+        5. Poll again and verify that the tag is not detected.
+
+        Verifies:
+        1. Observe mode is disabled and a transaction occurs.
+        2. Verify correct exit frame was used for transaction.
+        3. After the first transaction, verifies that observe mode is reenabled.
+        4. After observe mode is reenabled, verifies that the tag is not
+        detected.
+    """
+    def test_exit_frames_mask_and_prefix_match(self):
+        self._set_up_emulator(
+            "ddfe1134", ["12345678", "dd..11.*", "ee.*", "ff.."], True,
+            start_emulator_fun=self.emulator.nfc_emulator.startExitFrameActivity,
+            service_list=[_PAYMENT_SERVICE_1],
+            expected_service=_PAYMENT_SERVICE_1,
+            is_payment=True,
+            payment_default_service=_PAYMENT_SERVICE_1
+        )
+        asserts.skip_if(
+                    not self.emulator.nfc_emulator.isObserveModeSupported(),
+                    f"{self.emulator} observe mode not supported",
+                )
+        asserts.assert_true(
+            self.emulator.nfc_emulator.setObserveModeEnabled(True),
+            f"{self.emulator} could not set observe mode",
+        )
+
+        command_apdus, response_apdus = get_apdus(self.emulator.nfc_emulator,
+                                                      _PAYMENT_SERVICE_1)
+        test_pass_handler = self.emulator.nfc_emulator.asyncWaitForTestPass(
+            'ExitFrameListenerSuccess'
+        )
+        tag_detected, transacted = poll_and_transact(
+                self.pn532, command_apdus, response_apdus, "ddfe1134")
+        asserts.assert_true(
+            tag_detected, _FAILED_TAG_MSG
+        )
+        asserts.assert_true(transacted, _FAILED_TRANSACTION_MSG)
+        test_pass_handler.waitAndGet('ExitFrameListenerSuccess', _NFC_TIMEOUT_SEC)
+
+
+        time.sleep(_NFC_TIMEOUT_SEC)
+
+        # Poll again and see if tag is detected, observe mode should be enabled
+        # by now.
+        asserts.assert_true(
+                    self.emulator.nfc_emulator.isObserveModeEnabled(),
+                    f"{self.emulator} isObserveModeEnabled did not return True",
+                )
+        tag_detected, _ = poll_and_transact(
+                self.pn532, command_apdus, response_apdus)
+        asserts.assert_false(
+                    tag_detected,
+                    "Reader detected emulator even though observe mode was enabled."
+                )
+
+        self.emulator.nfc_emulator.setObserveModeEnabled(False)
+
+    """Tests the autotransact functionality with exit frames.
+
+    Test Steps:
+        1. Start emulator activity and set up payment HCE Service.
+        2. Enable observe mode.
+        3. Poll with a broadcast frame, don't transact though.
+        4. Wait for observe mode to be reenabled.
+        5. Poll again and verify that the tag is not detected.
+
+        Verifies:
+        1. Observe mode is disabled.
+        2. Verify correct exit frame was used for transaction.
+        3. After the first transaction, verifies that observe mode is reenabled.
+        4. After observe mode is reenabled, verifies that the tag is not
+        detected.
+    """
+    def test_exit_frames_no_transaction_observe_mode_reenabled(self):
+        self._set_up_emulator(
+            "12345678", ["12345678", "aaaa"], False,
+            start_emulator_fun=self.emulator.nfc_emulator.startExitFrameActivity,
+            service_list=[_PAYMENT_SERVICE_1],
+            expected_service=_PAYMENT_SERVICE_1,
+            is_payment=True,
+            payment_default_service=_PAYMENT_SERVICE_1
+        )
+        asserts.skip_if(
+                    not self.emulator.nfc_emulator.isObserveModeSupported(),
+                    f"{self.emulator} observe mode not supported",
+                )
+        asserts.assert_true(
+            self.emulator.nfc_emulator.setObserveModeEnabled(True),
+            f"{self.emulator} could not set observe mode",
+        )
+
+        command_apdus, response_apdus = get_apdus(self.emulator.nfc_emulator,
+                                                      _PAYMENT_SERVICE_1)
+        test_pass_handler = self.emulator.nfc_emulator.asyncWaitForTestPass(
+            'ExitFrameListenerSuccess'
+        )
+        tag_detected, transacted = poll_and_transact(
+                self.pn532, [], [], "12345678")
+        asserts.assert_true(
+            tag_detected, _FAILED_TAG_MSG
+        )
+        test_pass_handler.waitAndGet('ExitFrameListenerSuccess', _NFC_TIMEOUT_SEC)
+
+
+        time.sleep(_NFC_TIMEOUT_SEC)
+
+        # Poll again and see if tag is detected, observe mode should be enabled
+        # by now.
+        asserts.assert_true(
+                    self.emulator.nfc_emulator.isObserveModeEnabled(),
+                    f"{self.emulator} isObserveModeEnabled did not return True",
+                )
+        tag_detected, _ = poll_and_transact(
+                self.pn532, [], [])
+        asserts.assert_false(
+                    tag_detected,
+                    "Reader detected emulator even though observe mode was enabled."
+                )
+
+        self.emulator.nfc_emulator.setObserveModeEnabled(False)
+
+    def teardown_test(self):
+        if hasattr(self, 'emulator') and hasattr(self.emulator, 'nfc_emulator'):
+            self.emulator.nfc_emulator.closeActivity()
+            self.emulator.nfc_emulator.logInfo(
+                "*** TEST END: " + self.current_test_info.name + " ***")
+        self.pn532.reset_buffers()
+        self.pn532.mute()
+        param_list = [[self.emulator]]
+        utils.concurrent_exec(lambda d: d.services.create_output_excerpts_all(
+            self.current_test_info),
+                              param_list=param_list,
+                              raise_on_exception=True)
 
 if __name__ == '__main__':
     # Take test args
diff --git a/NfcNci/tests/testcases/src/android/nfc/test/TestUtils.java b/NfcNci/tests/testcases/src/android/nfc/test/TestUtils.java
index 6cc5fa9..4e0da92 100644
--- a/NfcNci/tests/testcases/src/android/nfc/test/TestUtils.java
+++ b/NfcNci/tests/testcases/src/android/nfc/test/TestUtils.java
@@ -19,8 +19,10 @@
 import static org.junit.Assume.assumeFalse;
 
 import android.app.Activity;
+import android.app.ActivityManager;
 import android.app.Instrumentation;
 import android.app.KeyguardManager;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -54,11 +56,15 @@
 
   static Activity createAndResumeActivity(Class<? extends Activity> activityClass) {
     ensureUnlocked();
-    Intent intent = new Intent(ApplicationProvider.getApplicationContext(), activityClass);
+    Context context = ApplicationProvider.getApplicationContext();
+    Intent intent = new Intent(context, activityClass);
     intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
     Activity activity = InstrumentationRegistry.getInstrumentation().startActivitySync(intent);
     InstrumentationRegistry.getInstrumentation().callActivityOnResume(activity);
-
+    ComponentName topComponentName = context.getSystemService(ActivityManager.class)
+        .getRunningTasks(1).get(0).topActivity;
+    Assert.assertEquals("Foreground activity not in the foreground",
+        activityClass.getName(), topComponentName.getClassName());
     return activity;
   }
 
diff --git a/NfcNci/tests/unit/src/com/android/nfc/EnableNfcFServiceTest.java b/NfcNci/tests/unit/src/com/android/nfc/EnableNfcFServiceTest.java
index d6524e2..f676d19 100644
--- a/NfcNci/tests/unit/src/com/android/nfc/EnableNfcFServiceTest.java
+++ b/NfcNci/tests/unit/src/com/android/nfc/EnableNfcFServiceTest.java
@@ -16,25 +16,29 @@
 
 package com.android.nfc;
 
-import static org.mockito.ArgumentMatchers.isA;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.app.ActivityManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.ContextWrapper;
-import android.content.pm.PackageManager;
 import android.nfc.cardemulation.NfcFServiceInfo;
 import android.os.UserHandle;
-import android.util.Log;
+import android.util.proto.ProtoOutputStream;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.dx.mockito.inline.extended.ExtendedMockito;
-import com.android.nfc.cardemulation.AidRoutingManager;
 import com.android.nfc.cardemulation.EnabledNfcFServices;
+import com.android.nfc.cardemulation.EnabledNfcFServicesProto;
 import com.android.nfc.cardemulation.RegisteredNfcFServicesCache;
 import com.android.nfc.cardemulation.RegisteredT3tIdentifiersCache;
 import com.android.nfc.cardemulation.RoutingOptionManager;
@@ -47,6 +51,10 @@
 import org.mockito.MockitoSession;
 import org.mockito.quality.Strictness;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.lang.reflect.Field;
+
 @RunWith(AndroidJUnit4.class)
 public class EnableNfcFServiceTest {
 
@@ -56,6 +64,7 @@
     private NfcFServiceInfo mNfcFServiceInfo;
     private EnabledNfcFServices mEnabledNfcFServices;
     private ForegroundUtils mForegroundUtils;
+    private EnabledNfcFServices.Callback mCallback;
 
     @Before
     public void setUp() throws Exception {
@@ -85,13 +94,12 @@
 
         RoutingOptionManager routingOptionManager = mock(RoutingOptionManager.class);
         when(RoutingOptionManager.getInstance()).thenReturn(routingOptionManager);
+
+        mCallback = mock(EnabledNfcFServices.Callback.class);
         InstrumentationRegistry.getInstrumentation().runOnMainSync(
                 () -> mEnabledNfcFServices = new EnabledNfcFServices(mockContext,
                         registeredNfcFServicesCache, registeredT3tIdentifiersCache,
-                        (userId, service) -> {
-                            Log.d(TAG, "CallBack is Received for userid " + userId);
-
-                        }));
+                        mCallback));
         Assert.assertNotNull(mEnabledNfcFServices);
     }
 
@@ -106,14 +114,14 @@
         Assert.assertFalse(isActivated);
         mEnabledNfcFServices.onHostEmulationActivated();
         isActivated = mEnabledNfcFServices.isActivated();
-        Assert.assertTrue(isActivated);
+        assertTrue(isActivated);
     }
 
     @Test
     public void testOnHostEmulationDeactivated() {
         mEnabledNfcFServices.onHostEmulationActivated();
         boolean isActivated = mEnabledNfcFServices.isActivated();
-        Assert.assertTrue(isActivated);
+        assertTrue(isActivated);
         mEnabledNfcFServices.onHostEmulationDeactivated();
         isActivated = mEnabledNfcFServices.isActivated();
         Assert.assertFalse(isActivated);
@@ -131,7 +139,7 @@
                 true);
         boolean isRegistered = mEnabledNfcFServices.registerEnabledForegroundService(mComponentName,
                 1);
-        Assert.assertTrue(isRegistered);
+        assertTrue(isRegistered);
     }
 
 
@@ -139,14 +147,152 @@
     public void testOnNfcDisabled() {
         mEnabledNfcFServices.onNfcDisabled();
         boolean isNfcDisabled = mEnabledNfcFServices.isNfcDisabled();
-        Assert.assertTrue(isNfcDisabled);
+        assertTrue(isNfcDisabled);
     }
 
     @Test
     public void testOnUserSwitched() {
         mEnabledNfcFServices.onUserSwitched(0);
         boolean isUserSwitched = mEnabledNfcFServices.isUserSwitched();
-        Assert.assertTrue(isUserSwitched);
+        assertTrue(isUserSwitched);
 
     }
+
+    @Test
+    public void testDumpDebug() throws NoSuchFieldException, IllegalAccessException {
+        ProtoOutputStream proto = mock(ProtoOutputStream.class);
+        ComponentName mForegroundComponent = mock(ComponentName.class);
+        ComponentName mForegroundRequested = mock(ComponentName.class);
+        Field fieldForegroundComp = EnabledNfcFServices.class.getDeclaredField(
+                "mForegroundComponent");
+        fieldForegroundComp.setAccessible(true);
+        fieldForegroundComp.set(mEnabledNfcFServices, mForegroundComponent);
+        Field fieldForegroundReq = EnabledNfcFServices.class.getDeclaredField(
+                "mForegroundRequested");
+        fieldForegroundReq.setAccessible(true);
+        fieldForegroundReq.set(mEnabledNfcFServices, mForegroundRequested);
+        mEnabledNfcFServices.dump(mock(FileDescriptor.class), mock(PrintWriter.class),
+                new String[]{});
+
+        mEnabledNfcFServices.dumpDebug(proto);
+        verify(proto).write(eq(EnabledNfcFServicesProto.ACTIVATED), anyBoolean());
+    }
+
+    @Test
+    public void testUnRegisterForegroundService()
+            throws NoSuchFieldException, IllegalAccessException {
+        int mForegroundUid = 1;
+        int userId = 1;
+        ComponentName mForegroundComponent = mock(ComponentName.class);
+        ComponentName mForegroundRequested = mock(ComponentName.class);
+        UserHandle userHandle = mock(UserHandle.class);
+        Field fieldForegroundUid = EnabledNfcFServices.class.getDeclaredField(
+                "mForegroundUid");
+        fieldForegroundUid.setAccessible(true);
+        fieldForegroundUid.set(mEnabledNfcFServices, mForegroundUid);
+        Field fieldForegroundComp = EnabledNfcFServices.class.getDeclaredField(
+                "mForegroundComponent");
+        fieldForegroundComp.setAccessible(true);
+        fieldForegroundComp.set(mEnabledNfcFServices, mForegroundComponent);
+        Field fieldForegroundReq = EnabledNfcFServices.class.getDeclaredField(
+                "mForegroundRequested");
+        fieldForegroundReq.setAccessible(true);
+        fieldForegroundReq.set(mEnabledNfcFServices, mForegroundRequested);
+        when(UserHandle.getUserHandleForUid(anyInt())).thenReturn(userHandle);
+        when(userHandle.getIdentifier()).thenReturn(userId);
+
+        mEnabledNfcFServices.onUidToBackground(mForegroundUid);
+        verify(mCallback).onEnabledForegroundNfcFServiceChanged(userId, null);
+        verify(userHandle).getIdentifier();
+    }
+
+    @Test
+    public void testUnregisteredEnabledForegroundService()
+            throws NoSuchFieldException, IllegalAccessException {
+        int callingId = 1;
+        int mForegroundUid = 1;
+        int userId = 1;
+        ComponentName mForegroundComponent = mock(ComponentName.class);
+        ComponentName mForegroundRequested = mock(ComponentName.class);
+        UserHandle userHandle = mock(UserHandle.class);
+        Field fieldForegroundUid = EnabledNfcFServices.class.getDeclaredField(
+                "mForegroundUid");
+        fieldForegroundUid.setAccessible(true);
+        fieldForegroundUid.set(mEnabledNfcFServices, mForegroundUid);
+        Field fieldForegroundComp = EnabledNfcFServices.class.getDeclaredField(
+                "mForegroundComponent");
+        fieldForegroundComp.setAccessible(true);
+        fieldForegroundComp.set(mEnabledNfcFServices, mForegroundComponent);
+        Field fieldForegroundReq = EnabledNfcFServices.class.getDeclaredField(
+                "mForegroundRequested");
+        fieldForegroundReq.setAccessible(true);
+        fieldForegroundReq.set(mEnabledNfcFServices, mForegroundRequested);
+        when(UserHandle.getUserHandleForUid(anyInt())).thenReturn(userHandle);
+        when(userHandle.getIdentifier()).thenReturn(userId);
+        when(mForegroundUtils.isInForeground(callingId)).thenReturn(true);
+
+        assertTrue(mEnabledNfcFServices.unregisteredEnabledForegroundService(callingId));
+        verify(mCallback).onEnabledForegroundNfcFServiceChanged(userId, null);
+        verify(mForegroundUtils).isInForeground(callingId);
+    }
+
+    @Test
+    public void testUnregisteredEnabledForegroundServiceNonForegroundUid() {
+        int callingId = 1;
+        when(mForegroundUtils.isInForeground(callingId)).thenReturn(false);
+
+        assertFalse(mEnabledNfcFServices.unregisteredEnabledForegroundService(callingId));
+        verify(mForegroundUtils).isInForeground(callingId);
+    }
+
+    @Test
+    public void testOnServiceUpdate() throws NoSuchFieldException, IllegalAccessException {
+        int userId = 1;
+        ComponentName mForegroundComponent = mock(ComponentName.class);
+        ComponentName mForegroundRequested = mock(ComponentName.class);
+        UserHandle userHandle = mock(UserHandle.class);
+        Field fieldForegroundComp = EnabledNfcFServices.class.getDeclaredField(
+                "mForegroundComponent");
+        fieldForegroundComp.setAccessible(true);
+        fieldForegroundComp.set(mEnabledNfcFServices, mForegroundComponent);
+        Field fieldForegroundReq = EnabledNfcFServices.class.getDeclaredField(
+                "mForegroundRequested");
+        fieldForegroundReq.setAccessible(true);
+        fieldForegroundReq.set(mEnabledNfcFServices, mForegroundRequested);
+        when(UserHandle.getUserHandleForUid(anyInt())).thenReturn(userHandle);
+        when(userHandle.getIdentifier()).thenReturn(userId);
+
+        mEnabledNfcFServices.onServicesUpdated();
+        verify(mCallback).onEnabledForegroundNfcFServiceChanged(userId, null);
+        verify(userHandle).getIdentifier();
+    }
+
+    @Test
+    public void testOnHostEmulationDeactivatedWithPostponedConfiguration()
+            throws NoSuchFieldException, IllegalAccessException {
+        boolean mComputeFgRequested = true;
+        int userId = 1;
+        ComponentName mForegroundRequested = mock(ComponentName.class);
+        UserHandle userHandle = mock(UserHandle.class);
+        Field fieldForegroundUid = EnabledNfcFServices.class.getDeclaredField(
+                "mComputeFgRequested");
+        fieldForegroundUid.setAccessible(true);
+        fieldForegroundUid.set(mEnabledNfcFServices, mComputeFgRequested);
+        Field fieldForegroundComp = EnabledNfcFServices.class.getDeclaredField(
+                "mForegroundComponent");
+        fieldForegroundComp.setAccessible(true);
+        fieldForegroundComp.set(mEnabledNfcFServices, null);
+        Field fieldForegroundReq = EnabledNfcFServices.class.getDeclaredField(
+                "mForegroundRequested");
+        fieldForegroundReq.setAccessible(true);
+        fieldForegroundReq.set(mEnabledNfcFServices, mForegroundRequested);
+        when(UserHandle.getUserHandleForUid(anyInt())).thenReturn(userHandle);
+        when(userHandle.getIdentifier()).thenReturn(userId);
+
+        mEnabledNfcFServices.onHostEmulationDeactivated();
+        verify(mCallback).onEnabledForegroundNfcFServiceChanged(userId, mForegroundRequested);
+        verify(userHandle).getIdentifier();
+        verify(mForegroundRequested).equals(null);
+    }
+
 }
diff --git a/NfcNci/tests/unit/src/com/android/nfc/ExitFrameTest.java b/NfcNci/tests/unit/src/com/android/nfc/ExitFrameTest.java
index b0cb06f..a15ec50 100644
--- a/NfcNci/tests/unit/src/com/android/nfc/ExitFrameTest.java
+++ b/NfcNci/tests/unit/src/com/android/nfc/ExitFrameTest.java
@@ -53,9 +53,9 @@
 
     @Test
     public void testPrefixMatchingMaxLength() {
-        ExitFrame frame = new ExitFrame("00112233445566778899AABBCCDDEEFF.*");
+        ExitFrame frame = new ExitFrame("00112233445566778899AABBCCDD.*");
 
-        assertArrayEquals(HexFormat.of().parseHex("00112233445566778899AABBCCDDEEFF"),
+        assertArrayEquals(HexFormat.of().parseHex("00112233445566778899AABBCCDD"),
                 frame.getData());
         assertTrue(frame.isPrefixMatchingAllowed());
     }
diff --git a/NfcNci/tests/unit/src/com/android/nfc/NfcDispatcherTest.java b/NfcNci/tests/unit/src/com/android/nfc/NfcDispatcherTest.java
index a347930..9b98ad8 100644
--- a/NfcNci/tests/unit/src/com/android/nfc/NfcDispatcherTest.java
+++ b/NfcNci/tests/unit/src/com/android/nfc/NfcDispatcherTest.java
@@ -116,6 +116,8 @@
     ForegroundUtils mForegroundUtils;
     @Mock
     AtomicBoolean mAtomicBoolean;
+    @Mock
+    DeviceConfigFacade mDeviceConfigFacade;
 
     @Before
     public void setUp() throws PackageManager.NameNotFoundException {
@@ -152,7 +154,7 @@
         when(mNfcInjector.createAtomicBoolean()).thenReturn(mAtomicBoolean);
 
         mNfcDispatcher = new NfcDispatcher(mockContext,
-                new HandoverDataParser(), mNfcInjector, true);
+                new HandoverDataParser(), mNfcInjector, true, mDeviceConfigFacade);
         mLooper.dispatchAll();
     }
 
diff --git a/NfcNci/tests/unit/src/com/android/nfc/NfcProprietaryCapsTest.java b/NfcNci/tests/unit/src/com/android/nfc/NfcProprietaryCapsTest.java
index 0fe2031..82c0d4f 100644
--- a/NfcNci/tests/unit/src/com/android/nfc/NfcProprietaryCapsTest.java
+++ b/NfcNci/tests/unit/src/com/android/nfc/NfcProprietaryCapsTest.java
@@ -126,13 +126,15 @@
                 true,
                 false,
                 true,
-                5
+                5,
+                false
         );
         String expected = "NfcProprietaryCaps{" +
                 "passiveObserveMode=SUPPORT_WITHOUT_RF_DEACTIVATION, " +
                 "isPollingFrameNotificationSupported=true, " +
                 "isPowerSavingModeSupported=false, " +
-                "isAutotransactPollingLoopFilterSupported=true}";
+                "isAutotransactPollingLoopFilterSupported=true, " +
+                "mIsReaderModeAnnotationSupported=false}";
 
         assertEquals(expected, caps.toString());
     }
diff --git a/NfcNci/tests/unit/src/com/android/nfc/NfcReaderConflictOccurredTest.java b/NfcNci/tests/unit/src/com/android/nfc/NfcReaderConflictOccurredTest.java
index 8f1218e..d8a6e4d 100644
--- a/NfcNci/tests/unit/src/com/android/nfc/NfcReaderConflictOccurredTest.java
+++ b/NfcNci/tests/unit/src/com/android/nfc/NfcReaderConflictOccurredTest.java
@@ -61,6 +61,7 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
 import org.mockito.MockitoSession;
 import org.mockito.quality.Strictness;
 
@@ -70,6 +71,8 @@
     private static final String TAG = NfcReaderConflictOccurredTest.class.getSimpleName();
     private NfcInjector mNfcInjector;
     AtomicBoolean mAtomicBoolean;
+    @Mock
+    DeviceConfigFacade mDeviceConfigFacade;
 
     private MockitoSession mStaticMockSession;
     private NfcDispatcher mNfcDispatcher;
@@ -80,7 +83,8 @@
                 .mockStatic(NfcStatsLog.class)
                 .strictness(Strictness.LENIENT)
                 .startMocking();
-	Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        MockitoAnnotations.initMocks(this);
+        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
         PackageManager mockPackageManager = Mockito.mock(PackageManager.class);
         // multiple resolveInfos for Tag
         when(mockPackageManager.queryIntentActivitiesAsUser(
@@ -128,7 +132,8 @@
         when(mNfcInjector.createAtomicBoolean()).thenReturn(mAtomicBoolean);
         InstrumentationRegistry.getInstrumentation().runOnMainSync(
               () -> mNfcDispatcher = new NfcDispatcher(
-                      mockContext, new HandoverDataParser(), mNfcInjector, false));
+                      mockContext, new HandoverDataParser(), mNfcInjector, false,
+                      mDeviceConfigFacade));
         Assert.assertNotNull(mNfcDispatcher);
     }
 
diff --git a/NfcNci/tests/unit/src/com/android/nfc/NfcServiceTest.java b/NfcNci/tests/unit/src/com/android/nfc/NfcServiceTest.java
index 31f7af1..6bafec4 100644
--- a/NfcNci/tests/unit/src/com/android/nfc/NfcServiceTest.java
+++ b/NfcNci/tests/unit/src/com/android/nfc/NfcServiceTest.java
@@ -254,7 +254,7 @@
         when(mApplication.getSystemService(KeyguardManager.class)).thenReturn(mKeyguardManager);
         when(mApplication.getSystemService(AlarmManager.class)).thenReturn(mAlarmManager);
         when(mApplication.getPackageManager()).thenReturn(mPackageManager);
-        when(mResources.getBoolean(R.bool.check_display_state_for_screen_state)).thenReturn(true);
+        when(mDeviceConfigFacade.getCheckDisplayStateForScreenState()).thenReturn(true);
         when(mApplication.getResources()).thenReturn(mResources);
         when(mApplication.createContextAsUser(any(), anyInt())).thenReturn(mApplication);
         when(mApplication.getContentResolver()).thenReturn(mContentResolver);
@@ -264,7 +264,7 @@
         when(mUserManager.getUserRestrictions()).thenReturn(mUserRestrictions);
         when(mResources.getStringArray(R.array.nfc_allow_list)).thenReturn(new String[0]);
         when(mResources.getBoolean(R.bool.tag_intent_app_pref_supported)).thenReturn(true);
-        when(mResources.getBoolean(R.bool.nfcc_always_on_allowed)).thenReturn(true);
+        when(mDeviceConfigFacade.getNfccAlwaysOnAllowed()).thenReturn(true);
         when(mPreferences.edit()).thenReturn(mPreferencesEditor);
         when(mPowerManager.newWakeLock(anyInt(), anyString()))
                 .thenReturn(mock(PowerManager.WakeLock.class));
@@ -344,7 +344,7 @@
 
     @Test
     public void testEnable_WheOemExtensionEnabledAndNotInitialized() throws Exception {
-        when(mResources.getBoolean(R.bool.enable_oem_extension)).thenReturn(true);
+        when(mDeviceConfigFacade.getEnableOemExtension()).thenReturn(true);
         when(NfcProperties.initialized()).thenReturn(Optional.of(Boolean.FALSE));
 
         createNfcService();
@@ -371,7 +371,7 @@
 
     @Test
     public void testBootupWithNfcOn_WhenOemExtensionEnabled() throws Exception {
-        when(mResources.getBoolean(R.bool.enable_oem_extension)).thenReturn(true);
+        when(mDeviceConfigFacade.getEnableOemExtension()).thenReturn(true);
         createNfcService();
 
         verifyNoMoreInteractions(mDeviceHost);
@@ -1375,7 +1375,7 @@
 
     @Test
     public void testOnSeSelected() {
-        mNfcService.onSeSelected();
+        mNfcService.onSeSelected(NfcService.SE_SELECTED_AID);
         mLooper.dispatchAll();
         verify(mCardEmulationManager).onOffHostAidSelected();
     }
@@ -2068,7 +2068,7 @@
         verify(mBackupManager).dataChanged();
         verify(mDeviceHost).setNfcSecure(true);
         verify(mNfcEventLog, times(2)).logEvent(any());
-        verify(mCardEmulationManager).onSecureNfcToggled();
+        verify(mCardEmulationManager).onTriggerRoutingTableUpdate();
     }
 
     @Test
diff --git a/NfcNci/tests/unit/src/com/android/nfc/cardemulation/CardEmulationManagerTest.java b/NfcNci/tests/unit/src/com/android/nfc/cardemulation/CardEmulationManagerTest.java
index ae8f2fd..574ad68 100644
--- a/NfcNci/tests/unit/src/com/android/nfc/cardemulation/CardEmulationManagerTest.java
+++ b/NfcNci/tests/unit/src/com/android/nfc/cardemulation/CardEmulationManagerTest.java
@@ -20,6 +20,7 @@
 import static android.nfc.cardemulation.CardEmulation.SET_SERVICE_ENABLED_STATUS_OK;
 
 import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -42,13 +43,17 @@
 
 import android.app.ActivityManager;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
-import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.nfc.ComponentNameAndUser;
+import android.nfc.Constants;
 import android.nfc.INfcCardEmulation;
+import android.nfc.INfcOemExtensionCallback;
 import android.nfc.NfcAdapter;
+import android.nfc.NfcOemExtension;
 import android.nfc.PackageAndUser;
 import android.nfc.cardemulation.AidGroup;
 import android.nfc.cardemulation.ApduServiceInfo;
@@ -61,17 +66,20 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
-import android.util.Pair;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.nfc.DeviceConfigFacade;
 import com.android.nfc.ExitFrame;
 import com.android.nfc.ForegroundUtils;
 import com.android.nfc.NfcEventLog;
 import com.android.nfc.NfcInjector;
 import com.android.nfc.NfcPermissions;
 import com.android.nfc.NfcService;
-import com.android.nfc.R;
+import com.android.nfc.cardemulation.util.StatsdUtils;
+import com.android.nfc.cardemulation.util.TelephonyUtils;
 import com.android.nfc.flags.Flags;
 
 import org.junit.After;
@@ -85,20 +93,23 @@
 import org.mockito.MockitoSession;
 import org.mockito.quality.Strictness;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.HexFormat;
 import java.util.List;
-import java.util.Objects;
+import java.util.Optional;
 import java.util.regex.Pattern;
 
 public class CardEmulationManagerTest {
 
     private static final int USER_ID = 0;
     private static final UserHandle USER_HANDLE = UserHandle.of(USER_ID);
-    private static final byte[] TEST_DATA_1 = new byte[] {(byte) 0xd2};
-    private static final byte[] TEST_DATA_2 = new byte[] {(byte) 0xd3};
+    private static final byte[] TEST_DATA_1 = new byte[]{(byte) 0xd2};
+    private static final byte[] TEST_DATA_2 = new byte[]{(byte) 0xd3};
     private static final byte[] PROPER_SKIP_DATA_NDF1_HEADER =
-            new byte[] {
+            new byte[]{
                     0x00,
                     (byte) 0xa4,
                     0x04,
@@ -113,7 +124,7 @@
                     0x00
             };
     private static final byte[] PROPER_SKIP_DATA_NDF2_HEADER =
-            new byte[] {
+            new byte[]{
                     0x00,
                     (byte) 0xa4,
                     0x04,
@@ -137,29 +148,56 @@
                     "com.android.test.walletroleholder.WalletRoleHolderApduService");
     private static final String PAYMENT_AID_1 = "A000000004101012";
 
-    @Mock private Context mContext;
-    @Mock private Resources mResources;
-    @Mock private ForegroundUtils mForegroundUtils;
-    @Mock private WalletRoleObserver mWalletRoleObserver;
-    @Mock private RegisteredAidCache mRegisteredAidCache;
-    @Mock private RegisteredT3tIdentifiersCache mRegisteredT3tIdentifiersCache;
-    @Mock private HostEmulationManager mHostEmulationManager;
-    @Mock private HostNfcFEmulationManager mHostNfcFEmulationManager;
-    @Mock private RegisteredServicesCache mRegisteredServicesCache;
-    @Mock private RegisteredNfcFServicesCache mRegisteredNfcFServicesCache;
-    @Mock private PreferredServices mPreferredServices;
-    @Mock private EnabledNfcFServices mEnabledNfcFServices;
-    @Mock private RoutingOptionManager mRoutingOptionManager;
-    @Mock private PowerManager mPowerManager;
-    @Mock private NfcService mNfcService;
-    @Mock private UserManager mUserManager;
-    @Mock private NfcAdapter mNfcAdapter;
-    @Mock private NfcEventLog mNfcEventLog;
-    @Mock private PreferredSubscriptionService mPreferredSubscriptionService;
-    @Captor private ArgumentCaptor<List<PollingFrame>> mPollingLoopFrameCaptor;
-    @Captor private ArgumentCaptor<byte[]> mDataCaptor;
-    @Captor private ArgumentCaptor<List<ApduServiceInfo>> mServiceListCaptor;
-    @Captor private ArgumentCaptor<List<NfcFServiceInfo>> mNfcServiceListCaptor;
+    @Mock
+    private Context mContext;
+    @Mock
+    private Resources mResources;
+    @Mock
+    private ForegroundUtils mForegroundUtils;
+    @Mock
+    private WalletRoleObserver mWalletRoleObserver;
+    @Mock
+    private RegisteredAidCache mRegisteredAidCache;
+    @Mock
+    private RegisteredT3tIdentifiersCache mRegisteredT3tIdentifiersCache;
+    @Mock
+    private HostEmulationManager mHostEmulationManager;
+    @Mock
+    private HostNfcFEmulationManager mHostNfcFEmulationManager;
+    @Mock
+    private RegisteredServicesCache mRegisteredServicesCache;
+    @Mock
+    private RegisteredNfcFServicesCache mRegisteredNfcFServicesCache;
+    @Mock
+    private PreferredServices mPreferredServices;
+    @Mock
+    private EnabledNfcFServices mEnabledNfcFServices;
+    @Mock
+    private RoutingOptionManager mRoutingOptionManager;
+    @Mock
+    private PowerManager mPowerManager;
+    @Mock
+    private NfcService mNfcService;
+    @Mock
+    private UserManager mUserManager;
+    @Mock
+    private NfcAdapter mNfcAdapter;
+    @Mock
+    private NfcEventLog mNfcEventLog;
+    @Mock
+    private PreferredSubscriptionService mPreferredSubscriptionService;
+    @Mock
+    private StatsdUtils mStatsdUtils;
+    @Mock
+    private DeviceConfigFacade mDeviceConfigFacade;
+    @Captor
+    private ArgumentCaptor<List<PollingFrame>> mPollingLoopFrameCaptor;
+    @Captor
+    private ArgumentCaptor<byte[]> mDataCaptor;
+    @Captor
+    private ArgumentCaptor<List<ApduServiceInfo>> mServiceListCaptor;
+    @Captor
+    private ArgumentCaptor<List<NfcFServiceInfo>> mNfcServiceListCaptor;
     private MockitoSession mStaticMockSession;
     private CardEmulationManager mCardEmulationManager;
 
@@ -187,7 +225,7 @@
         when(mContext.createContextAsUser(any(), anyInt())).thenReturn(mContext);
         when(mContext.getResources()).thenReturn(mResources);
         when(mContext.getSystemService(eq(UserManager.class))).thenReturn(mUserManager);
-        when(mResources.getBoolean(R.bool.indicate_user_activity_for_hce)).thenReturn(true);
+        when(mDeviceConfigFacade.getIndicateUserActivityForHce()).thenReturn(true);
         when(android.nfc.Flags.nfcEventListener()).thenReturn(true);
         when(android.nfc.Flags.enableCardEmulationEuicc()).thenReturn(true);
         mCardEmulationManager = createInstanceWithMockParams();
@@ -397,15 +435,18 @@
 
     @Test
     public void testOnSecureNfcToggled() {
-        mCardEmulationManager.onSecureNfcToggled();
+        mCardEmulationManager.onTriggerRoutingTableUpdate();
 
-        verify(mRegisteredAidCache).onSecureNfcToggled();
-        verify(mRegisteredT3tIdentifiersCache).onSecureNfcToggled();
+        verify(mRegisteredAidCache).onTriggerRoutingTableUpdate();
+        verify(mRegisteredT3tIdentifiersCache).onTriggerRoutingTableUpdate();
     }
 
     @Test
     public void testOnServicesUpdated_walletEnabledPollingLoopEnabled() {
         when(mWalletRoleObserver.isWalletRoleFeatureEnabled()).thenReturn(true);
+        when(Flags.exitFrames()).thenReturn(true);
+        when(mNfcService.isFirmwareExitFramesSupported()).thenReturn(true);
+        when(mNfcService.getNumberOfFirmwareExitFramesSupported()).thenReturn(5);
 
         mCardEmulationManager.onServicesUpdated(USER_ID, UPDATED_SERVICES, false);
 
@@ -414,6 +455,7 @@
         verify(mPreferredServices).onServicesUpdated();
         verify(mHostEmulationManager)
                 .updatePollingLoopFilters(eq(USER_ID), mServiceListCaptor.capture());
+        verify(mNfcService).setFirmwareExitFrameTable(any(), anyInt());
         verify(mNfcService).onPreferredPaymentChanged(eq(NfcAdapter.PREFERRED_PAYMENT_UPDATED));
         assertEquals(UPDATED_SERVICES, mServiceListCaptor.getAllValues().getFirst());
         assertEquals(UPDATED_SERVICES, mServiceListCaptor.getAllValues().getLast());
@@ -1467,7 +1509,7 @@
     @Test
     public void testCardEmulationSetServiceEnabledForCategoryOther_resourceTrue()
             throws RemoteException {
-        when(mResources.getBoolean(R.bool.enable_service_for_category_other)).thenReturn(true);
+        when(mDeviceConfigFacade.getEnableServiceOther()).thenReturn(true);
         when(mRegisteredServicesCache.registerOtherForService(anyInt(), any(), anyBoolean()))
                 .thenReturn(SET_SERVICE_ENABLED_STATUS_OK);
 
@@ -1490,7 +1532,7 @@
     @Test
     public void testCardEmulationSetServiceEnabledForCategoryOther_resourceFalse()
             throws RemoteException {
-        when(mResources.getBoolean(R.bool.enable_service_for_category_other)).thenReturn(false);
+        when(mDeviceConfigFacade.getEnableServiceOther()).thenReturn(false);
         when(mRegisteredServicesCache.registerOtherForService(anyInt(), any(), anyBoolean()))
                 .thenReturn(SET_SERVICE_ENABLED_STATUS_OK);
 
@@ -2232,7 +2274,9 @@
                 mRoutingOptionManager,
                 mPowerManager,
                 mNfcEventLog,
-                mPreferredSubscriptionService);
+                mPreferredSubscriptionService,
+                mStatsdUtils,
+                mDeviceConfigFacade);
     }
 
     @Test
@@ -2428,7 +2472,7 @@
         INfcCardEmulation iNfcCardEmulation = mCardEmulationManager.getNfcCardEmulationInterface();
         assertThat(iNfcCardEmulation).isNotNull();
         ApduServiceInfo apduServiceInfo = mock(ApduServiceInfo.class);
-        List<ApduServiceInfo> apduServiceInfoList =  new ArrayList<>();
+        List<ApduServiceInfo> apduServiceInfoList = new ArrayList<>();
         apduServiceInfoList.add(apduServiceInfo);
         when(mRegisteredServicesCache.getServicesForCategory(1, "payment"))
                 .thenReturn(apduServiceInfoList);
@@ -2448,7 +2492,7 @@
     }
 
     @Test
-    public void testSupportsAidPrefixRegistration()  throws RemoteException {
+    public void testSupportsAidPrefixRegistration() throws RemoteException {
         INfcCardEmulation iNfcCardEmulation = mCardEmulationManager.getNfcCardEmulationInterface();
         assertThat(iNfcCardEmulation).isNotNull();
         when(mRegisteredAidCache
@@ -2481,8 +2525,7 @@
         assertThat(iNfcCardEmulation).isNotNull();
         ComponentName componentName = ComponentName
                 .unflattenFromString("com.android.test.component/.Component");
-        when(mResources.getBoolean(R.bool.enable_service_for_category_other))
-                .thenReturn(true);
+        when(mDeviceConfigFacade.getEnableServiceOther()).thenReturn(true);
         when(mRegisteredServicesCache.registerOtherForService(1,
                 componentName, true)).thenReturn(1);
         int result = iNfcCardEmulation
@@ -2680,163 +2723,513 @@
     }
 
     @Test
-    public void registerPollingLoopFilterForService_roleService_setsExitFrames() throws Exception {
-        when(Flags.exitFrames()).thenReturn(true);
-        when(mNfcService.isFirmwareExitFramesSupported()).thenReturn(true);
-        when(mNfcService.getNumberOfFirmwareExitFramesSupported()).thenReturn(5);
-        when(mRegisteredServicesCache.hasService(eq(USER_ID), any())).thenReturn(true);
-        when(mRegisteredServicesCache.registerPollingLoopFilterForService(anyInt(), anyInt(), any(),
-                any(), anyBoolean())).thenReturn(true);
-        when(mRegisteredAidCache.isDefaultOrAssociatedWalletPackage(
-                eq(WALLET_PAYMENT_SERVICE.getPackageName()), eq(USER_ID))).thenReturn(true);
-        when(mRegisteredServicesCache.getServices(USER_ID)).thenReturn(List.of());
+    public void testDump() {
+        FileDescriptor fd = mock(FileDescriptor.class);
+        PrintWriter pw = mock(PrintWriter.class);
+        String[] args = new String[]{"test"};
 
-        mCardEmulationManager.getNfcCardEmulationInterface().registerPollingLoopFilterForService(
-                USER_ID, WALLET_PAYMENT_SERVICE, "aa", true);
-
-        verify(mNfcService).setFirmwareExitFrameTable(any(), anyInt());
+        mCardEmulationManager.dump(fd, pw, args);
+        verify(mRegisteredServicesCache).dump(fd, pw, args);
     }
 
     @Test
-    public void registerPollingLoopFilterForService_notRoleService_doesNotSetExitFrames()
-            throws Exception {
-        when(Flags.exitFrames()).thenReturn(true);
-        when(mNfcService.isFirmwareExitFramesSupported()).thenReturn(true);
-        when(mNfcService.getNumberOfFirmwareExitFramesSupported()).thenReturn(5);
-        when(mRegisteredServicesCache.hasService(eq(USER_ID), any())).thenReturn(true);
-        when(mRegisteredServicesCache.registerPollingLoopFilterForService(anyInt(), anyInt(), any(),
-                any(), anyBoolean())).thenReturn(true);
-        when(mRegisteredAidCache.isDefaultOrAssociatedWalletPackage(
-                eq("com.android.test"), eq(USER_ID))).thenReturn(false);
-        when(mRegisteredServicesCache.getServices(USER_ID)).thenReturn(List.of());
+    public void testDumpDebug() {
+        ProtoOutputStream proto = mock(ProtoOutputStream.class);
+        when(proto.start(CardEmulationManagerProto.REGISTERED_SERVICES_CACHE)).thenReturn((long) 1);
 
-        mCardEmulationManager.getNfcCardEmulationInterface().registerPollingLoopFilterForService(
-                USER_ID, new ComponentName("com.android.test", "com.android.test.Service"), "aa",
+        mCardEmulationManager.dumpDebug(proto);
+        verify(mRegisteredServicesCache).dumpDebug(proto);
+    }
+
+    @Test
+    public void testOnPreferredSubscriptionChangedWithSimEuicc1()
+            throws NoSuchFieldException, IllegalAccessException {
+        int subscriptionId = 1;
+        boolean isActive = true;
+        TelephonyUtils telephonyUtils = mock(TelephonyUtils.class);
+        SubscriptionInfo subscriptionInfo = mock(SubscriptionInfo.class);
+        Optional<SubscriptionInfo> optionalInfo = Optional.of(subscriptionInfo);
+        Field field = CardEmulationManager.class.getDeclaredField("mTelephonyUtils");
+        field.setAccessible(true);
+        field.set(mCardEmulationManager, telephonyUtils);
+        when(subscriptionInfo.isEmbedded()).thenReturn(true);
+        when(subscriptionInfo.getPortIndex()).thenReturn(0);
+        when(telephonyUtils.getActiveSubscriptionInfoById(subscriptionId)).thenReturn(optionalInfo);
+        when(mRoutingOptionManager.getSecureElementForRoute(anyInt())).thenReturn("");
+
+        mCardEmulationManager.onPreferredSubscriptionChanged(subscriptionId, isActive);
+        verify(mRoutingOptionManager).onPreferredSimChanged(TelephonyUtils.SIM_TYPE_EUICC_1);
+        verify(mRegisteredAidCache).onPreferredSimChanged(TelephonyUtils.SIM_TYPE_EUICC_1);
+    }
+
+    @Test
+    public void testOnPreferredSubscriptionChangedWithSimEuicc2()
+            throws NoSuchFieldException, IllegalAccessException {
+        int subscriptionId = 1;
+        boolean isActive = true;
+        TelephonyUtils telephonyUtils = mock(TelephonyUtils.class);
+        SubscriptionInfo subscriptionInfo = mock(SubscriptionInfo.class);
+        Optional<SubscriptionInfo> optionalInfo = Optional.of(subscriptionInfo);
+        Field field = CardEmulationManager.class.getDeclaredField("mTelephonyUtils");
+        field.setAccessible(true);
+        field.set(mCardEmulationManager, telephonyUtils);
+        when(subscriptionInfo.isEmbedded()).thenReturn(true);
+        when(subscriptionInfo.getPortIndex()).thenReturn(1);
+        when(telephonyUtils.getActiveSubscriptionInfoById(subscriptionId)).thenReturn(optionalInfo);
+        when(mRoutingOptionManager.getSecureElementForRoute(anyInt())).thenReturn("");
+
+        mCardEmulationManager.onPreferredSubscriptionChanged(subscriptionId, isActive);
+        verify(mRoutingOptionManager).onPreferredSimChanged(TelephonyUtils.SIM_TYPE_EUICC_2);
+        verify(mRegisteredAidCache).onPreferredSimChanged(TelephonyUtils.SIM_TYPE_EUICC_2);
+    }
+
+    @Test
+    public void testOnPreferredSubscriptionChangedWithSimUicc()
+            throws NoSuchFieldException, IllegalAccessException {
+        int subscriptionId = 1;
+        boolean isActive = true;
+        TelephonyUtils telephonyUtils = mock(TelephonyUtils.class);
+        SubscriptionInfo subscriptionInfo = mock(SubscriptionInfo.class);
+        Optional<SubscriptionInfo> optionalInfo = Optional.of(subscriptionInfo);
+        Field field = CardEmulationManager.class.getDeclaredField("mTelephonyUtils");
+        field.setAccessible(true);
+        field.set(mCardEmulationManager, telephonyUtils);
+        when(subscriptionInfo.isEmbedded()).thenReturn(false);
+        when(telephonyUtils.getActiveSubscriptionInfoById(subscriptionId)).thenReturn(optionalInfo);
+        when(mRoutingOptionManager.getSecureElementForRoute(anyInt())).thenReturn("");
+
+        mCardEmulationManager.onPreferredSubscriptionChanged(subscriptionId, isActive);
+        verify(mRoutingOptionManager).onPreferredSimChanged(TelephonyUtils.SIM_TYPE_UICC);
+        verify(mRegisteredAidCache).onPreferredSimChanged(TelephonyUtils.SIM_TYPE_UICC);
+    }
+
+    @Test
+    public void testOnPreferredSubscriptionChangedWithSimUnknown()
+            throws NoSuchFieldException, IllegalAccessException {
+        int subscriptionId = 1;
+        boolean isActive = true;
+        TelephonyUtils telephonyUtils = mock(TelephonyUtils.class);
+        Optional<SubscriptionInfo> optionalInfo = Optional.empty();
+        Field field = CardEmulationManager.class.getDeclaredField("mTelephonyUtils");
+        field.setAccessible(true);
+        field.set(mCardEmulationManager, telephonyUtils);
+        when(telephonyUtils.getActiveSubscriptionInfoById(subscriptionId)).thenReturn(optionalInfo);
+
+        mCardEmulationManager.onPreferredSubscriptionChanged(subscriptionId, isActive);
+        verify(mRoutingOptionManager).onPreferredSimChanged(TelephonyUtils.SIM_TYPE_UNKNOWN);
+        verify(mRegisteredAidCache).onPreferredSimChanged(TelephonyUtils.SIM_TYPE_UNKNOWN);
+    }
+
+    @Test
+    public void testOnPreferredSubscriptionChangedWithSimInActive()
+            throws NoSuchFieldException, IllegalAccessException {
+        int subscriptionId = 1;
+        boolean isActive = false;
+        TelephonyUtils telephonyUtils = mock(TelephonyUtils.class);
+        Field field = CardEmulationManager.class.getDeclaredField("mTelephonyUtils");
+        field.setAccessible(true);
+        field.set(mCardEmulationManager, telephonyUtils);
+
+        mCardEmulationManager.onPreferredSubscriptionChanged(subscriptionId, isActive);
+        verify(mRoutingOptionManager).onPreferredSimChanged(TelephonyUtils.SIM_TYPE_UNKNOWN);
+        verify(mRegisteredAidCache).onPreferredSimChanged(TelephonyUtils.SIM_TYPE_UNKNOWN);
+    }
+
+    @Test
+    public void testOnEeListenActivated() {
+        mCardEmulationManager.onEeListenActivated(false);
+
+        verify(mPreferredServices).onHostEmulationDeactivated();
+    }
+
+    @Test
+    public void testOnFieldChangeDetected() {
+        mCardEmulationManager.onFieldChangeDetected(true);
+        verify(mHostEmulationManager).onFieldChangeDetected(true);
+    }
+
+    @Test
+    public void testOnHostCardEmulationDataWithApdu() throws RemoteException {
+        INfcOemExtensionCallback nfcOemExtensionCallback = mock(INfcOemExtensionCallback.class);
+        mCardEmulationManager.setOemExtension(nfcOemExtensionCallback);
+
+        mCardEmulationManager.onHostCardEmulationData(
+                CardEmulationManager.NFC_HCE_APDU, PROPER_SKIP_DATA_NDF1_HEADER);
+        verify(nfcOemExtensionCallback).onHceEventReceived(NfcOemExtension.HCE_DATA_TRANSFERRED);
+        verify(mHostEmulationManager).onHostEmulationData(PROPER_SKIP_DATA_NDF1_HEADER);
+    }
+
+    @Test
+    public void testOnHostCardEmulationDataWithNfcf() throws RemoteException {
+        INfcOemExtensionCallback nfcOemExtensionCallback = mock(INfcOemExtensionCallback.class);
+        mCardEmulationManager.setOemExtension(nfcOemExtensionCallback);
+
+        mCardEmulationManager.onHostCardEmulationData(
+                CardEmulationManager.NFC_HCE_NFCF, PROPER_SKIP_DATA_NDF1_HEADER);
+        verify(nfcOemExtensionCallback).onHceEventReceived(NfcOemExtension.HCE_DATA_TRANSFERRED);
+        verify(mHostNfcFEmulationManager).onHostEmulationData(PROPER_SKIP_DATA_NDF1_HEADER);
+        verify(mPowerManager).userActivity(anyLong(), eq(PowerManager.USER_ACTIVITY_EVENT_TOUCH),
+                eq(0));
+    }
+
+    @Test
+    public void testOnHostCardEmulationDeactivatedWithApdu() throws RemoteException {
+        INfcOemExtensionCallback nfcOemExtensionCallback = mock(INfcOemExtensionCallback.class);
+        mCardEmulationManager.setOemExtension(nfcOemExtensionCallback);
+        ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(Integer.class);
+
+        mCardEmulationManager.onHostCardEmulationDeactivated(CardEmulationManager.NFC_HCE_APDU);
+        verify(mHostEmulationManager).onHostEmulationDeactivated();
+        verify(mPreferredServices).onHostEmulationDeactivated();
+        verify(nfcOemExtensionCallback).onHceEventReceived(captor.capture());
+        assertEquals(NfcOemExtension.HCE_DEACTIVATE, captor.getValue().intValue());
+    }
+
+    @Test
+    public void testSetDefaultServiceForCategoryChecked() {
+        int userId = 1;
+        ComponentName componentName = new ComponentName("com.example.nfc", "ExampleNfcClass");
+        String category = CardEmulation.CATEGORY_PAYMENT;
+        Context context = mock(Context.class);
+        ContentResolver contentResolver = mock(ContentResolver.class);
+        UserHandle userHandle = mock(UserHandle.class);
+        when(UserHandle.of(userId)).thenReturn(userHandle);
+        when(mRegisteredServicesCache.hasService(userId, componentName)).thenReturn(true);
+        when(mContext.createContextAsUser(userHandle, 0)).thenReturn(context);
+        when(context.getContentResolver()).thenReturn(contentResolver);
+
+        assertTrue(mCardEmulationManager.setDefaultServiceForCategoryChecked(userId, componentName,
+                category));
+        verify(mRegisteredServicesCache).hasService(userId, componentName);
+    }
+
+    @Test
+    public void testSetDefaultServiceForCategoryCheckedWithOtherCategory() {
+        assertFalse(mCardEmulationManager.setDefaultServiceForCategoryChecked(1,
+                new ComponentName("com.example.nfc", "ExampleNfcClass"),
+                CardEmulation.CATEGORY_OTHER));
+    }
+
+    @Test
+    public void testUpdateForDefaultSwpToEuicc() throws NoSuchFieldException,
+            IllegalAccessException {
+        int subscriptionId = 1;
+        when(android.nfc.Flags.enableCardEmulationEuicc()).thenReturn(true);
+        Resources resources = mock(Resources.class);
+        when(mContext.getResources()).thenReturn(resources);
+        when(resources.getBoolean(anyInt())).thenReturn(true);
+        when(NfcInjector.NfcProperties.isEuiccSupported()).thenReturn(true);
+        when(mPreferredSubscriptionService.getPreferredSubscriptionId()).thenReturn(subscriptionId);
+        TelephonyUtils telephonyUtils = mock(TelephonyUtils.class);
+        SubscriptionInfo subscriptionInfo = mock(SubscriptionInfo.class);
+        Optional<SubscriptionInfo> optionalInfo = Optional.of(subscriptionInfo);
+        Field field = CardEmulationManager.class.getDeclaredField("mTelephonyUtils");
+        field.setAccessible(true);
+        field.set(mCardEmulationManager, telephonyUtils);
+        when(subscriptionInfo.isEmbedded()).thenReturn(true);
+        when(subscriptionInfo.getPortIndex()).thenReturn(0);
+        when(telephonyUtils.getActiveSubscriptionInfoById(subscriptionId)).thenReturn(optionalInfo);
+        when(telephonyUtils.updateSwpStatusForEuicc(TelephonyUtils.SIM_TYPE_EUICC_1)).thenReturn(
+                "6F02839000");
+
+        mCardEmulationManager.updateForDefaultSwpToEuicc();
+        verify(mPreferredSubscriptionService).getPreferredSubscriptionId();
+        verify(telephonyUtils).updateSwpStatusForEuicc(TelephonyUtils.SIM_TYPE_EUICC_1);
+        verify(mContext).getResources();
+    }
+
+    @Test
+    public void testUpdateForDefaultSwpToEuiccWithCmdFail() throws NoSuchFieldException,
+            IllegalAccessException {
+        int subscriptionId = 3;
+        when(android.nfc.Flags.enableCardEmulationEuicc()).thenReturn(true);
+        Resources resources = mock(Resources.class);
+        when(mContext.getResources()).thenReturn(resources);
+        when(resources.getBoolean(anyInt())).thenReturn(true);
+        when(NfcInjector.NfcProperties.isEuiccSupported()).thenReturn(true);
+        when(mPreferredSubscriptionService.getPreferredSubscriptionId()).thenReturn(subscriptionId);
+        TelephonyUtils telephonyUtils = mock(TelephonyUtils.class);
+        SubscriptionInfo subscriptionInfo = mock(SubscriptionInfo.class);
+        Optional<SubscriptionInfo> optionalInfo = Optional.of(subscriptionInfo);
+        Field field = CardEmulationManager.class.getDeclaredField("mTelephonyUtils");
+        field.setAccessible(true);
+        field.set(mCardEmulationManager, telephonyUtils);
+        when(subscriptionInfo.isEmbedded()).thenReturn(true);
+        when(subscriptionInfo.getPortIndex()).thenReturn(0);
+        when(telephonyUtils.getActiveSubscriptionInfoById(subscriptionId)).thenReturn(optionalInfo);
+        when(telephonyUtils.updateSwpStatusForEuicc(TelephonyUtils.SIM_TYPE_EUICC_1)).thenReturn(
+                "6F0283FFFF");
+
+        mCardEmulationManager.updateForDefaultSwpToEuicc();
+        verify(mPreferredSubscriptionService).getPreferredSubscriptionId();
+        verify(telephonyUtils).updateSwpStatusForEuicc(TelephonyUtils.SIM_TYPE_EUICC_1);
+        verify(mContext).getResources();
+        verify(resources).getBoolean(anyInt());
+    }
+
+    @Test
+    public void testUpdateForDefaultSwpToEuiccWithWrongLength() throws NoSuchFieldException,
+            IllegalAccessException {
+        int subscriptionId = 3;
+        when(android.nfc.Flags.enableCardEmulationEuicc()).thenReturn(true);
+        Resources resources = mock(Resources.class);
+        when(mContext.getResources()).thenReturn(resources);
+        when(resources.getBoolean(anyInt())).thenReturn(true);
+        when(NfcInjector.NfcProperties.isEuiccSupported()).thenReturn(true);
+        when(mPreferredSubscriptionService.getPreferredSubscriptionId()).thenReturn(subscriptionId);
+        TelephonyUtils telephonyUtils = mock(TelephonyUtils.class);
+        SubscriptionInfo subscriptionInfo = mock(SubscriptionInfo.class);
+        Optional<SubscriptionInfo> optionalInfo = Optional.of(subscriptionInfo);
+        Field field = CardEmulationManager.class.getDeclaredField("mTelephonyUtils");
+        field.setAccessible(true);
+        field.set(mCardEmulationManager, telephonyUtils);
+        when(subscriptionInfo.isEmbedded()).thenReturn(true);
+        when(subscriptionInfo.getPortIndex()).thenReturn(0);
+        when(telephonyUtils.getActiveSubscriptionInfoById(subscriptionId)).thenReturn(optionalInfo);
+        when(telephonyUtils.updateSwpStatusForEuicc(TelephonyUtils.SIM_TYPE_EUICC_1)).thenReturn(
+                "6FF");
+
+        mCardEmulationManager.updateForDefaultSwpToEuicc();
+        verify(mPreferredSubscriptionService).getPreferredSubscriptionId();
+        verify(telephonyUtils).updateSwpStatusForEuicc(TelephonyUtils.SIM_TYPE_EUICC_1);
+        verify(mContext).getResources();
+        verify(resources).getBoolean(anyInt());
+    }
+
+    @Test
+    public void testUpdateForDefaultSwpToEuiccWithEmulationDisabled() {
+        when(android.nfc.Flags.enableCardEmulationEuicc()).thenReturn(false);
+
+        mCardEmulationManager.updateForDefaultSwpToEuicc();
+        verify(mContext, never()).getResources();
+    }
+
+    @Test
+    public void testUpdateForDefaultSwpToEuiccWithEmulationNotSupport() {
+        when(android.nfc.Flags.enableCardEmulationEuicc()).thenReturn(true);
+        Resources resources = mock(Resources.class);
+        when(mContext.getResources()).thenReturn(resources);
+        when(resources.getBoolean(anyInt())).thenReturn(false);
+        when(NfcInjector.NfcProperties.isEuiccSupported()).thenReturn(false);
+
+        mCardEmulationManager.updateForDefaultSwpToEuicc();
+        verify(mContext).getResources();
+        verify(mPreferredSubscriptionService, never()).getPreferredSubscriptionId();
+    }
+
+    @Test
+    public void testWasServicePreInstalled() throws PackageManager.NameNotFoundException {
+        PackageManager packageManager = mock(PackageManager.class);
+        ComponentName service = new ComponentName("com.example.nfc", "NfcClass");
+        ApplicationInfo ai = mock(ApplicationInfo.class);
+        ai.flags = 1;
+        when(packageManager.getApplicationInfo("com.example.nfc", 0)).thenReturn(ai);
+
+        assertTrue(mCardEmulationManager.wasServicePreInstalled(packageManager, service));
+    }
+
+    @Test
+    public void testWasServicePreInstalledWithoutService()
+            throws PackageManager.NameNotFoundException {
+        PackageManager packageManager = mock(PackageManager.class);
+        ComponentName service = new ComponentName("com.example.nfc", "NfcClass");
+        when(packageManager.getApplicationInfo("com.example.nfc", 0)).thenThrow(
+                PackageManager.NameNotFoundException.class);
+
+        assertFalse(mCardEmulationManager.wasServicePreInstalled(packageManager, service));
+    }
+
+    @Test
+    public void testWasServicePreInstalledWithServiceNotPreInstalled()
+            throws PackageManager.NameNotFoundException {
+        PackageManager packageManager = mock(PackageManager.class);
+        ComponentName service = new ComponentName("com.example.nfc", "NfcClass");
+        ApplicationInfo ai = mock(ApplicationInfo.class);
+        ai.flags = 0;
+        when(packageManager.getApplicationInfo("com.example.nfc", 0)).thenReturn(ai);
+
+        assertFalse(mCardEmulationManager.wasServicePreInstalled(packageManager, service));
+    }
+
+    @Test
+    public void testVerifyDefaults() {
+        int userId = 1;
+        List<ApduServiceInfo> services = new ArrayList<>();
+        List<UserHandle> luh = new ArrayList<>();
+        boolean validateInstalled = true;
+        UserHandle userHandle = mock(UserHandle.class);
+        UserHandle secondUserHandle = mock(UserHandle.class);
+        Context context = mock(Context.class);
+        UserManager um = mock(UserManager.class);
+        ContentResolver contentResolver = mock(ContentResolver.class);
+        luh.add(userHandle);
+        luh.add(secondUserHandle);
+        String compName = "com.nfc/.NfcClass";
+        ComponentName service = ComponentName.unflattenFromString(compName);
+        //"com.nfc/.NfcClass" becomes package="com.nfc" class="com.nfc.NfcClass".
+        when(UserHandle.of(userId)).thenReturn(userHandle);
+        when(mContext.createContextAsUser(userHandle, 0)).thenReturn(context);
+        when(context.getSystemService(UserManager.class)).thenReturn(um);
+        when(um.getEnabledProfiles()).thenReturn(luh);
+        when(userHandle.getIdentifier()).thenReturn(userId);
+        when(secondUserHandle.getIdentifier()).thenReturn(userId);
+        when(context.getContentResolver()).thenReturn(contentResolver);
+        when(Settings.Secure.getString(contentResolver,
+                Constants.SETTINGS_SECURE_NFC_PAYMENT_DEFAULT_COMPONENT)).thenReturn(
+                compName);
+        when(mRegisteredServicesCache.hasService(userId, service)).thenReturn(true);
+
+        mCardEmulationManager.verifyDefaults(userId, services, validateInstalled);
+        verify(um).getEnabledProfiles();
+        verify(context).getSystemService(UserManager.class);
+        verify(mRegisteredServicesCache, times(2)).hasService(userId, service);
+    }
+
+    @Test
+    public void testVerifyDefaultsWithMorePaymentService()
+            throws PackageManager.NameNotFoundException {
+        int userId = 1;
+        List<ApduServiceInfo> services = new ArrayList<>();
+        List<UserHandle> luh = new ArrayList<>();
+        boolean validateInstalled = true;
+        UserHandle userHandle = mock(UserHandle.class);
+        UserHandle secondUserHandle = mock(UserHandle.class);
+        Context context = mock(Context.class);
+        UserManager um = mock(UserManager.class);
+        ContentResolver contentResolver = mock(ContentResolver.class);
+        luh.add(userHandle);
+        luh.add(secondUserHandle);
+        String compName = "com.nfc/.NfcClass";
+        ComponentName service = ComponentName.unflattenFromString(compName);
+        PackageManager pm = mock(PackageManager.class);
+        ApduServiceInfo apduService = mock(ApduServiceInfo.class);
+        ApduServiceInfo apduService2 = mock(ApduServiceInfo.class);
+        services.add(apduService);
+        services.add(apduService2);
+        ApplicationInfo ai = mock(ApplicationInfo.class);
+        ai.flags = 1;
+
+        when(UserHandle.of(userId)).thenReturn(userHandle);
+        when(mContext.createContextAsUser(userHandle, 0)).thenReturn(context);
+        when(context.getSystemService(UserManager.class)).thenReturn(um);
+        when(um.getEnabledProfiles()).thenReturn(luh);
+        when(userHandle.getIdentifier()).thenReturn(userId);
+        when(secondUserHandle.getIdentifier()).thenReturn(userId);
+        when(context.getContentResolver()).thenReturn(contentResolver);
+        when(Settings.Secure.getString(contentResolver,
+                Constants.SETTINGS_SECURE_NFC_PAYMENT_DEFAULT_COMPONENT)).thenReturn(
+                "");
+        when(mContext.createPackageContextAsUser("android", 0, userHandle)).thenReturn(context);
+        when(context.getPackageManager()).thenReturn(pm);
+        when(apduService.hasCategory(CardEmulation.CATEGORY_PAYMENT)).thenReturn(true);
+        when(apduService2.hasCategory(CardEmulation.CATEGORY_PAYMENT)).thenReturn(true);
+        when(apduService.getComponent()).thenReturn(service);
+        when(apduService2.getComponent()).thenReturn(service);
+        when(pm.getApplicationInfo("com.nfc", 0)).thenReturn(ai);
+        when(mRegisteredServicesCache.hasService(userId, service)).thenReturn(true);
+
+        mCardEmulationManager.verifyDefaults(userId, services, validateInstalled);
+        verify(um).getEnabledProfiles();
+        verify(mContext).createPackageContextAsUser("android", 0, userHandle);
+        verify(pm, times(2)).getApplicationInfo("com.nfc", 0);
+    }
+
+    @Test
+    public void testVerifyDefaultsWithSinglePaymentService()
+            throws PackageManager.NameNotFoundException {
+        int userId = 1;
+        List<ApduServiceInfo> services = new ArrayList<>();
+        List<UserHandle> luh = new ArrayList<>();
+        boolean validateInstalled = true;
+        UserHandle userHandle = mock(UserHandle.class);
+        UserHandle secondUserHandle = mock(UserHandle.class);
+        Context context = mock(Context.class);
+        UserManager um = mock(UserManager.class);
+        ContentResolver contentResolver = mock(ContentResolver.class);
+        luh.add(userHandle);
+        luh.add(secondUserHandle);
+        String compName = "com.nfc/.NfcClass";
+        ComponentName service = ComponentName.unflattenFromString(compName);
+        PackageManager pm = mock(PackageManager.class);
+        ApduServiceInfo apduService = mock(ApduServiceInfo.class);
+        services.add(apduService);
+        ApplicationInfo ai = mock(ApplicationInfo.class);
+        ai.flags = 1;
+        when(UserHandle.of(userId)).thenReturn(userHandle);
+        when(mContext.createContextAsUser(userHandle, 0)).thenReturn(context);
+        when(context.getSystemService(UserManager.class)).thenReturn(um);
+        when(um.getEnabledProfiles()).thenReturn(luh);
+        when(userHandle.getIdentifier()).thenReturn(userId);
+        when(secondUserHandle.getIdentifier()).thenReturn(userId);
+        when(context.getContentResolver()).thenReturn(contentResolver);
+        when(Settings.Secure.getString(contentResolver,
+                Constants.SETTINGS_SECURE_NFC_PAYMENT_DEFAULT_COMPONENT)).thenReturn(
+                "");
+        when(mContext.createPackageContextAsUser("android", 0, userHandle)).thenReturn(context);
+        when(context.getPackageManager()).thenReturn(pm);
+        when(apduService.hasCategory(CardEmulation.CATEGORY_PAYMENT)).thenReturn(true);
+        when(apduService.getComponent()).thenReturn(service);
+        when(pm.getApplicationInfo("com.nfc", 0)).thenReturn(ai);
+        when(mRegisteredServicesCache.hasService(userId, service)).thenReturn(true);
+
+        mCardEmulationManager.verifyDefaults(userId, services, validateInstalled);
+        verify(um).getEnabledProfiles();
+        verify(mContext).createPackageContextAsUser("android", 0, userHandle);
+        verify(pm, times(1)).getApplicationInfo("com.nfc", 0);
+    }
+
+    @Test
+    public void testVerifyDefaultsWithNoPaymentService()
+            throws PackageManager.NameNotFoundException {
+        int userId = 1;
+        List<ApduServiceInfo> services = new ArrayList<>();
+        List<UserHandle> luh = new ArrayList<>();
+        boolean validateInstalled = true;
+        UserHandle userHandle = mock(UserHandle.class);
+        UserHandle secondUserHandle = mock(UserHandle.class);
+        Context context = mock(Context.class);
+        UserManager um = mock(UserManager.class);
+        ContentResolver contentResolver = mock(ContentResolver.class);
+        luh.add(userHandle);
+        luh.add(secondUserHandle);
+        String compName = "com.nfc/.NfcClass";
+        ComponentName service = ComponentName.unflattenFromString(compName);
+        PackageManager pm = mock(PackageManager.class);
+        ApplicationInfo ai = mock(ApplicationInfo.class);
+        ai.flags = 1;
+        when(UserHandle.of(userId)).thenReturn(userHandle);
+        when(mContext.createContextAsUser(userHandle, 0)).thenReturn(context);
+        when(context.getSystemService(UserManager.class)).thenReturn(um);
+        when(um.getEnabledProfiles()).thenReturn(luh);
+        when(userHandle.getIdentifier()).thenReturn(userId);
+        when(secondUserHandle.getIdentifier()).thenReturn(userId);
+        when(context.getContentResolver()).thenReturn(contentResolver);
+        when(Settings.Secure.getString(contentResolver,
+                Constants.SETTINGS_SECURE_NFC_PAYMENT_DEFAULT_COMPONENT)).thenReturn(
+                "");
+        when(mContext.createPackageContextAsUser("android", 0, userHandle)).thenReturn(context);
+        when(context.getPackageManager()).thenReturn(pm);
+        when(mRegisteredServicesCache.hasService(userId, service)).thenReturn(true);
+
+        mCardEmulationManager.verifyDefaults(userId, services, validateInstalled);
+        verify(um).getEnabledProfiles();
+        verify(mContext).createPackageContextAsUser("android", 0, userHandle);
+        verify(pm, never()).getApplicationInfo(anyString(), eq(0));
+    }
+
+    @Test
+    public void testOnObserveModeDisabledInFirmware() {
+        PollingFrame exitFrame = new PollingFrame(
+                PollingFrame.POLLING_LOOP_TYPE_UNKNOWN,
+                HexFormat.of().parseHex("42123456"),
+                0,
+                0,
                 true);
 
-        verify(mNfcService, never()).setFirmwareExitFrameTable(any(), anyInt());
+        mCardEmulationManager.onObserveModeDisabledInFirmware(exitFrame);
+
+        verify(mHostEmulationManager).onObserveModeDisabledInFirmware(exitFrame);
+        verify(mStatsdUtils).logAutoTransactReported(StatsdUtils.PROCESSOR_NFCC,
+            exitFrame.getData());
     }
-
-    @Test
-    public void removePollingLoopFilterForService_roleService_setsExitFrames()
-            throws Exception {
-        when(Flags.exitFrames()).thenReturn(true);
-        when(mNfcService.isFirmwareExitFramesSupported()).thenReturn(true);
-        when(mNfcService.getNumberOfFirmwareExitFramesSupported()).thenReturn(5);
-        when(mRegisteredServicesCache.hasService(eq(USER_ID), any())).thenReturn(true);
-        when(mRegisteredServicesCache.removePollingLoopFilterForService(anyInt(), anyInt(), any(),
-                any())).thenReturn(true);
-        when(mRegisteredAidCache.isDefaultOrAssociatedWalletPackage(
-                eq(WALLET_PAYMENT_SERVICE.getPackageName()), eq(USER_ID))).thenReturn(true);
-        when(mRegisteredServicesCache.getServices(USER_ID)).thenReturn(List.of());
-
-        mCardEmulationManager.getNfcCardEmulationInterface().removePollingLoopFilterForService(
-                USER_ID, WALLET_PAYMENT_SERVICE, "aa");
-
-        verify(mNfcService).setFirmwareExitFrameTable(any(), anyInt());
-    }
-
-    @Test
-    public void removePollingLoopFilterForService_notRoleService_doesNotSetExitFrames()
-            throws Exception {
-        when(Flags.exitFrames()).thenReturn(true);
-        when(mNfcService.isFirmwareExitFramesSupported()).thenReturn(true);
-        when(mNfcService.getNumberOfFirmwareExitFramesSupported()).thenReturn(5);
-        when(mRegisteredServicesCache.hasService(eq(USER_ID), any())).thenReturn(true);
-        when(mRegisteredServicesCache.removePollingLoopFilterForService(anyInt(), anyInt(), any(),
-                any())).thenReturn(true);
-        when(mRegisteredAidCache.isDefaultOrAssociatedWalletPackage(
-                eq("com.android.test"), eq(USER_ID))).thenReturn(false);
-        when(mRegisteredServicesCache.getServices(USER_ID)).thenReturn(List.of());
-
-        mCardEmulationManager.getNfcCardEmulationInterface().removePollingLoopFilterForService(
-                USER_ID, new ComponentName("com.android.test", "com.android.test.Service"), "aa");
-
-        verify(mNfcService, never()).setFirmwareExitFrameTable(any(), anyInt());
-    }
-
-    @Test
-    public void registerPollingLoopPatternFilterForService_roleService_setsExitFrames()
-            throws Exception {
-        when(Flags.exitFrames()).thenReturn(true);
-        when(mNfcService.isFirmwareExitFramesSupported()).thenReturn(true);
-        when(mNfcService.getNumberOfFirmwareExitFramesSupported()).thenReturn(5);
-        when(mRegisteredServicesCache.hasService(eq(USER_ID), any())).thenReturn(true);
-        when(mRegisteredServicesCache.registerPollingLoopPatternFilterForService(anyInt(), anyInt(),
-                any(), any(), anyBoolean())).thenReturn(true);
-        when(mRegisteredAidCache.isDefaultOrAssociatedWalletPackage(
-                eq(WALLET_PAYMENT_SERVICE.getPackageName()), eq(USER_ID))).thenReturn(true);
-        when(mRegisteredServicesCache.getServices(USER_ID)).thenReturn(List.of());
-
-        mCardEmulationManager.getNfcCardEmulationInterface()
-                .registerPollingLoopPatternFilterForService(
-                        USER_ID, WALLET_PAYMENT_SERVICE, "aa", true);
-
-        verify(mNfcService).setFirmwareExitFrameTable(any(), anyInt());
-    }
-
-    @Test
-    public void registerPollingLoopPatternFilterForService_notRoleService_doesNotSetExitFrames()
-            throws Exception {
-        when(Flags.exitFrames()).thenReturn(true);
-        when(mNfcService.isFirmwareExitFramesSupported()).thenReturn(true);
-        when(mNfcService.getNumberOfFirmwareExitFramesSupported()).thenReturn(5);
-        when(mRegisteredServicesCache.hasService(eq(USER_ID), any())).thenReturn(true);
-        when(mRegisteredServicesCache.registerPollingLoopPatternFilterForService(anyInt(), anyInt(),
-                any(), any(), anyBoolean())).thenReturn(true);
-        when(mRegisteredAidCache.isDefaultOrAssociatedWalletPackage(
-                eq("com.android.test"), eq(USER_ID))).thenReturn(false);
-        when(mRegisteredServicesCache.getServices(USER_ID)).thenReturn(List.of());
-
-        mCardEmulationManager.getNfcCardEmulationInterface()
-                .registerPollingLoopPatternFilterForService(
-                        USER_ID,
-                        new ComponentName("com.android.test", "com.android.test.Service"),
-                        "aa",
-                        true);
-
-        verify(mNfcService, never()).setFirmwareExitFrameTable(any(), anyInt());
-    }
-
-    @Test
-    public void removePollingLoopPatternFilterForService_roleService_setsExitFrames()
-            throws Exception {
-        when(Flags.exitFrames()).thenReturn(true);
-        when(mNfcService.isFirmwareExitFramesSupported()).thenReturn(true);
-        when(mNfcService.getNumberOfFirmwareExitFramesSupported()).thenReturn(5);
-        when(mRegisteredServicesCache.hasService(eq(USER_ID), any())).thenReturn(true);
-        when(mRegisteredServicesCache.removePollingLoopPatternFilterForService(anyInt(), anyInt(),
-                any(), any())).thenReturn(true);
-        when(mRegisteredAidCache.isDefaultOrAssociatedWalletPackage(
-                eq(WALLET_PAYMENT_SERVICE.getPackageName()), eq(USER_ID))).thenReturn(true);
-        when(mRegisteredServicesCache.getServices(USER_ID)).thenReturn(List.of());
-
-        mCardEmulationManager.getNfcCardEmulationInterface()
-                .removePollingLoopPatternFilterForService(
-                        USER_ID, WALLET_PAYMENT_SERVICE, "aa");
-
-        verify(mNfcService).setFirmwareExitFrameTable(any(), anyInt());
-    }
-
-    @Test
-    public void removePollingLoopPatternFilterForService_notRoleService_doesNotSetExitFrames()
-            throws Exception {
-        when(Flags.exitFrames()).thenReturn(true);
-        when(mNfcService.isFirmwareExitFramesSupported()).thenReturn(true);
-        when(mNfcService.getNumberOfFirmwareExitFramesSupported()).thenReturn(5);
-        when(mRegisteredServicesCache.hasService(eq(USER_ID), any())).thenReturn(true);
-        when(mRegisteredServicesCache.removePollingLoopPatternFilterForService(anyInt(), anyInt(),
-                any(), any())).thenReturn(true);
-        when(mRegisteredAidCache.isDefaultOrAssociatedWalletPackage(
-                eq("com.android.test"), eq(USER_ID))).thenReturn(false);
-        when(mRegisteredServicesCache.getServices(USER_ID)).thenReturn(List.of());
-
-        mCardEmulationManager.getNfcCardEmulationInterface()
-                .removePollingLoopPatternFilterForService(
-                        USER_ID,
-                        new ComponentName("com.android.test", "com.android.test.Service"),
-                        "aa");
-
-        verify(mNfcService, never()).setFirmwareExitFrameTable(any(), anyInt());
-    }
- }
+}
diff --git a/NfcNci/tests/unit/src/com/android/nfc/cardemulation/HostEmulationManagerTest.java b/NfcNci/tests/unit/src/com/android/nfc/cardemulation/HostEmulationManagerTest.java
index 795e59b..5612d77 100644
--- a/NfcNci/tests/unit/src/com/android/nfc/cardemulation/HostEmulationManagerTest.java
+++ b/NfcNci/tests/unit/src/com/android/nfc/cardemulation/HostEmulationManagerTest.java
@@ -116,7 +116,7 @@
     @Mock private NfcService mNfcService;
     @Mock private NfcInjector mNfcInjector;
     @Mock private NfcEventLog mNfcEventLog;
-    @Mock private StatsdUtils mStatsUtils;
+    @Mock private StatsdUtils mStatsdUtils;
     @Mock private DeviceConfigFacade mDeviceConfigFacade;
     @Captor private ArgumentCaptor<Intent> mIntentArgumentCaptor;
     @Captor private ArgumentCaptor<ServiceConnection> mServiceConnectionArgumentCaptor;
@@ -159,7 +159,7 @@
         when(mDeviceConfigFacade.getSlowTapThresholdMillis()).thenReturn(5);
         mHostEmulationManager =
                 new HostEmulationManager(
-                        mContext, mTestableLooper.getLooper(), mRegisteredAidCache, mStatsUtils,
+                        mContext, mTestableLooper.getLooper(), mRegisteredAidCache, mStatsdUtils,
                         mNfcInjector);
     }
 
@@ -327,6 +327,9 @@
         assertTrue(mHostEmulationManager.mEnableObserveModeAfterTransaction);
         assertTrue(frame1.getTriggeredAutoTransact());
         assertEquals(HostEmulationManager.STATE_POLLING_LOOP, mHostEmulationManager.mState);
+        verify(mStatsdUtils).logAutoTransactReported(StatsdUtils.PROCESSOR_HOST, data.getBytes());
+        verify(mStatsdUtils).setNextObserveModeTriggerSource(
+                StatsdUtils.TRIGGER_SOURCE_AUTO_TRANSACT);
     }
 
     @Test
@@ -584,9 +587,9 @@
         mHostEmulationManager.onHostEmulationData(mockAidData);
 
         verify(apduServiceInfo, times(2)).getUid();
-        verify(mStatsUtils).setCardEmulationEventCategory(eq(CardEmulation.CATEGORY_PAYMENT));
-        verify(mStatsUtils).setCardEmulationEventUid(eq(USER_ID));
-        verify(mStatsUtils).logCardEmulationWrongSettingEvent();
+        verify(mStatsdUtils).setCardEmulationEventCategory(eq(CardEmulation.CATEGORY_PAYMENT));
+        verify(mStatsdUtils).setCardEmulationEventUid(eq(USER_ID));
+        verify(mStatsdUtils).logCardEmulationWrongSettingEvent();
         verify(mRegisteredAidCache).resolveAid(eq(MOCK_AID));
         verify(mNfcService).sendRequireUnlockIntent();
         verify(mNfcService).sendData(eq(HostEmulationManager.AID_NOT_FOUND));
@@ -614,9 +617,9 @@
         mHostEmulationManager.onHostEmulationData(mockAidData);
 
         verify(apduServiceInfo, times(2)).getUid();
-        verify(mStatsUtils).setCardEmulationEventCategory(eq(CardEmulation.CATEGORY_PAYMENT));
-        verify(mStatsUtils).setCardEmulationEventUid(eq(USER_ID));
-        verify(mStatsUtils).logCardEmulationWrongSettingEvent();
+        verify(mStatsdUtils).setCardEmulationEventCategory(eq(CardEmulation.CATEGORY_PAYMENT));
+        verify(mStatsdUtils).setCardEmulationEventUid(eq(USER_ID));
+        verify(mStatsdUtils).logCardEmulationWrongSettingEvent();
         verify(mRegisteredAidCache).resolveAid(eq(MOCK_AID));
         verify(mNfcService).sendRequireUnlockIntent();
         verify(mNfcService).sendData(eq(HostEmulationManager.AID_NOT_FOUND));
@@ -646,9 +649,9 @@
         mHostEmulationManager.onHostEmulationData(mockAidData);
 
         verify(apduServiceInfo).getUid();
-        verify(mStatsUtils).setCardEmulationEventCategory(eq(CardEmulation.CATEGORY_PAYMENT));
-        verify(mStatsUtils).setCardEmulationEventUid(eq(USER_ID));
-        verify(mStatsUtils).logCardEmulationWrongSettingEvent();
+        verify(mStatsdUtils).setCardEmulationEventCategory(eq(CardEmulation.CATEGORY_PAYMENT));
+        verify(mStatsdUtils).setCardEmulationEventUid(eq(USER_ID));
+        verify(mStatsdUtils).logCardEmulationWrongSettingEvent();
         verify(mRegisteredAidCache).resolveAid(eq(MOCK_AID));
         verify(mNfcService).sendData(eq(HostEmulationManager.AID_NOT_FOUND));
         verify(mContext).getSystemService(eq(PowerManager.class));
@@ -677,9 +680,9 @@
         mHostEmulationManager.onHostEmulationData(mockAidData);
 
         verify(apduServiceInfo).getUid();
-        verify(mStatsUtils).setCardEmulationEventCategory(eq(CardEmulation.CATEGORY_PAYMENT));
-        verify(mStatsUtils).setCardEmulationEventUid(eq(USER_ID));
-        verify(mStatsUtils).logCardEmulationNoRoutingEvent();
+        verify(mStatsdUtils).setCardEmulationEventCategory(eq(CardEmulation.CATEGORY_PAYMENT));
+        verify(mStatsdUtils).setCardEmulationEventUid(eq(USER_ID));
+        verify(mStatsdUtils).logCardEmulationNoRoutingEvent();
         verify(mRegisteredAidCache).resolveAid(eq(MOCK_AID));
         verify(mNfcService).sendData(eq(HostEmulationManager.AID_NOT_FOUND));
         verify(mContext).getSystemService(eq(PowerManager.class));
@@ -705,8 +708,8 @@
                 () -> {
                     NfcStatsLog.write(NfcStatsLog.NFC_AID_CONFLICT_OCCURRED, MOCK_AID);
                 });
-        verify(mStatsUtils).setCardEmulationEventCategory(eq(CardEmulation.CATEGORY_OTHER));
-        verify(mStatsUtils).logCardEmulationWrongSettingEvent();
+        verify(mStatsdUtils).setCardEmulationEventCategory(eq(CardEmulation.CATEGORY_OTHER));
+        verify(mStatsdUtils).logCardEmulationWrongSettingEvent();
         assertEquals(HostEmulationManager.STATE_W4_DEACTIVATE, mHostEmulationManager.getState());
         verify(mRegisteredAidCache).resolveAid(eq(MOCK_AID));
         verify(mContext).getSystemService(eq(PowerManager.class));
@@ -746,9 +749,9 @@
 
         assertEquals(HostEmulationManager.STATE_XFER, mHostEmulationManager.getState());
         verify(apduServiceInfo).getUid();
-        verify(mStatsUtils).setCardEmulationEventCategory(eq(CardEmulation.CATEGORY_PAYMENT));
-        verify(mStatsUtils).setCardEmulationEventUid(eq(USER_ID));
-        verify(mStatsUtils).notifyCardEmulationEventWaitingForResponse();
+        verify(mStatsdUtils).setCardEmulationEventCategory(eq(CardEmulation.CATEGORY_PAYMENT));
+        verify(mStatsdUtils).setCardEmulationEventUid(eq(USER_ID));
+        verify(mStatsdUtils).notifyCardEmulationEventWaitingForResponse();
         verify(mRegisteredAidCache).resolveAid(eq(MOCK_AID));
         verify(mContext).getSystemService(eq(PowerManager.class));
         verify(mContext).getSystemService(eq(KeyguardManager.class));
@@ -790,9 +793,9 @@
         assertEquals(HostEmulationManager.STATE_W4_SERVICE, mHostEmulationManager.getState());
         assertEquals(mockAidData, mHostEmulationManager.mSelectApdu);
         verify(apduServiceInfo, atLeastOnce()).getUid();
-        verify(mStatsUtils).setCardEmulationEventCategory(eq(CardEmulation.CATEGORY_PAYMENT));
-        verify(mStatsUtils).setCardEmulationEventUid(eq(USER_ID));
-        verify(mStatsUtils).notifyCardEmulationEventWaitingForResponse();
+        verify(mStatsdUtils).setCardEmulationEventCategory(eq(CardEmulation.CATEGORY_PAYMENT));
+        verify(mStatsdUtils).setCardEmulationEventUid(eq(USER_ID));
+        verify(mStatsdUtils).notifyCardEmulationEventWaitingForResponse();
         verify(mRegisteredAidCache).resolveAid(eq(MOCK_AID));
         verify(mContext).getSystemService(eq(PowerManager.class));
         verify(mContext).getSystemService(eq(KeyguardManager.class));
@@ -998,7 +1001,7 @@
         assertEquals(
                 mHostEmulationManager.getServiceConnection(),
                 mServiceConnectionArgumentCaptor.getValue());
-        verify(mStatsUtils).logCardEmulationDeactivatedEvent();
+        verify(mStatsdUtils).logCardEmulationDeactivatedEvent();
 
         mTestableLooper.moveTimeForward(5000);
         mTestableLooper.processAllMessages();
@@ -1032,7 +1035,7 @@
         verifyZeroInteractions(mMessenger);
         verifyNoMoreInteractions(mMessenger);
         verifyNoMoreInteractions(mContext);
-        verify(mStatsUtils).logCardEmulationDeactivatedEvent();
+        verify(mStatsdUtils).logCardEmulationDeactivatedEvent();
     }
 
     @Test
@@ -1122,7 +1125,7 @@
         assertEquals(WALLET_PAYMENT_SERVICE, mHostEmulationManager.mServiceName);
         assertNotNull(mHostEmulationManager.mService);
         assertTrue(mHostEmulationManager.mServiceBound);
-        verify(mStatsUtils).notifyCardEmulationEventServiceBound();
+        verify(mStatsdUtils).notifyCardEmulationEventServiceBound();
         assertEquals(HostEmulationManager.STATE_XFER, mHostEmulationManager.getState());
         assertNull(mHostEmulationManager.mSelectApdu);
         verify(service).transact(eq(1), any(), eq(null), eq(1));
diff --git a/NfcNci/tests/unit/src/com/android/nfc/cardemulation/PreferredSubscriptionServiceTest.java b/NfcNci/tests/unit/src/com/android/nfc/cardemulation/PreferredSubscriptionServiceTest.java
new file mode 100644
index 0000000..ff5bffc
--- /dev/null
+++ b/NfcNci/tests/unit/src/com/android/nfc/cardemulation/PreferredSubscriptionServiceTest.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.nfc.cardemulation;
+
+import static com.android.nfc.cardemulation.PreferredSubscriptionService.PREF_PREFERRED_SUB_ID;
+import static com.android.nfc.cardemulation.PreferredSubscriptionService.PREF_SUBSCRIPTION;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.telephony.SubscriptionInfo;
+
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.nfc.cardemulation.util.TelephonyUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+
+public class PreferredSubscriptionServiceTest {
+    @Mock
+    private Context mContext;
+    @Mock
+    private PreferredSubscriptionService.Callback mCallback;
+    @Mock
+    private TelephonyUtils mTelephonyUtils;
+    @Mock
+    private SharedPreferences mSubscriptionPrefs;
+    @Mock
+    private SharedPreferences.Editor mEditor;
+    @Mock
+    private SubscriptionInfo mSubscriptionInfo;
+    @Mock
+    private PackageManager mPackageManager;
+    @Mock
+    private Resources mResources;
+    private MockitoSession mStaticMockSession;
+    private PreferredSubscriptionService mPreferredSubscriptionService;
+
+    @Before
+    public void setUp() {
+        mStaticMockSession =
+                ExtendedMockito.mockitoSession()
+                        .mockStatic(TelephonyUtils.class).strictness(
+                                Strictness.LENIENT).startMocking();
+        MockitoAnnotations.initMocks(this);
+        SharedPreferences.Editor editor = mock(SharedPreferences.Editor.class);
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+        when(mPackageManager.hasSystemFeature(
+                PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC)).thenReturn(true);
+        when(mContext.getResources()).thenReturn(mResources);
+        when(mResources.getBoolean(anyInt())).thenReturn(true);
+        when(TelephonyUtils.getInstance(mContext)).thenReturn(mTelephonyUtils);
+        when(mContext.getSharedPreferences(PREF_SUBSCRIPTION, Context.MODE_PRIVATE)).thenReturn(
+                mSubscriptionPrefs);
+        when(mSubscriptionPrefs.getInt(PREF_PREFERRED_SUB_ID,
+                TelephonyUtils.SUBSCRIPTION_ID_UNKNOWN)).thenReturn(
+                TelephonyUtils.SUBSCRIPTION_ID_UNKNOWN);
+        when(mSubscriptionPrefs.edit()).thenReturn(mEditor);
+        when(mEditor.putInt(PREF_PREFERRED_SUB_ID, TelephonyUtils.SUBSCRIPTION_ID_UICC)).thenReturn(
+                editor);
+        when(editor.commit()).thenReturn(true);
+        mPreferredSubscriptionService = new PreferredSubscriptionService(mContext, mCallback);
+    }
+
+    @After
+    public void tearDown() {
+        mStaticMockSession.finishMocking();
+    }
+
+    @Test
+    public void testGetPreferredSubscriptionId() {
+        when(mSubscriptionPrefs.getInt(PREF_PREFERRED_SUB_ID,
+                TelephonyUtils.SUBSCRIPTION_ID_UNKNOWN)).thenReturn(
+                TelephonyUtils.SUBSCRIPTION_ID_UICC);
+
+        assertEquals(TelephonyUtils.SUBSCRIPTION_ID_UICC,
+                mPreferredSubscriptionService.getPreferredSubscriptionId());
+    }
+
+    @Test
+    public void testSetPreferredSubscriptionId() throws IllegalAccessException,
+            NoSuchFieldException {
+        SharedPreferences.Editor editor = mock(SharedPreferences.Editor.class);
+        List<SubscriptionInfo> infos = new ArrayList<>();
+        Field fieldForegroundComp = PreferredSubscriptionService.class.getDeclaredField(
+                "mDefaultSubscriptionId");
+        fieldForegroundComp.setAccessible(true);
+        fieldForegroundComp.set(mPreferredSubscriptionService,
+                TelephonyUtils.SUBSCRIPTION_ID_UNKNOWN);
+        when(mSubscriptionInfo.isEmbedded()).thenReturn(false);
+        when(mSubscriptionInfo.areUiccApplicationsEnabled()).thenReturn(true);
+        infos.add(mSubscriptionInfo);
+        when(mSubscriptionPrefs.edit()).thenReturn(mEditor);
+        when(mEditor.putInt(PREF_PREFERRED_SUB_ID,
+                TelephonyUtils.SUBSCRIPTION_ID_UICC)).thenReturn(
+                editor);
+        when(editor.commit()).thenReturn(true);
+        when(mTelephonyUtils.getActiveSubscriptions()).thenReturn(infos);
+        when(mTelephonyUtils.isEuiccSubscription(
+                TelephonyUtils.SUBSCRIPTION_ID_UICC)).thenReturn(
+                false);
+
+        mPreferredSubscriptionService.setPreferredSubscriptionId(
+                TelephonyUtils.SUBSCRIPTION_ID_UICC, true);
+        verify(mTelephonyUtils).isEuiccSubscription(TelephonyUtils.SUBSCRIPTION_ID_UICC);
+        verify(editor).commit();
+    }
+
+    @Test
+    public void testOnActiveSubscriptionsUpdated()
+            throws NoSuchFieldException, IllegalAccessException {
+        List<SubscriptionInfo> infos = new ArrayList<>();
+        Field fieldForegroundComp = PreferredSubscriptionService.class.getDeclaredField(
+                "mDefaultSubscriptionId");
+        fieldForegroundComp.setAccessible(true);
+        fieldForegroundComp.set(mPreferredSubscriptionService,
+                TelephonyUtils.SUBSCRIPTION_ID_UICC);
+        when(mSubscriptionInfo.isEmbedded()).thenReturn(false);
+        when(mSubscriptionInfo.areUiccApplicationsEnabled()).thenReturn(true);
+        infos.add(mSubscriptionInfo);
+        when(mTelephonyUtils.getActiveSubscriptions()).thenReturn(infos);
+        when(mTelephonyUtils.isEuiccSubscription(TelephonyUtils.SUBSCRIPTION_ID_UICC)).thenReturn(
+                false);
+
+        mPreferredSubscriptionService.onActiveSubscriptionsUpdated(infos);
+        verify(mTelephonyUtils).isEuiccSubscription(TelephonyUtils.SUBSCRIPTION_ID_UICC);
+        verify(mCallback).onPreferredSubscriptionChanged(TelephonyUtils.SUBSCRIPTION_ID_UICC,
+                false);
+    }
+
+    @Test
+    public void testInitialize() throws NoSuchFieldException, IllegalAccessException {
+        List<SubscriptionInfo> infos = new ArrayList<>();
+        Field fieldForegroundComp = PreferredSubscriptionService.class.getDeclaredField(
+                "mDefaultSubscriptionId");
+        fieldForegroundComp.setAccessible(true);
+        fieldForegroundComp.set(mPreferredSubscriptionService,
+                TelephonyUtils.SUBSCRIPTION_ID_UNKNOWN);
+        when(mSubscriptionInfo.isEmbedded()).thenReturn(false);
+        when(mSubscriptionInfo.areUiccApplicationsEnabled()).thenReturn(true);
+        infos.add(mSubscriptionInfo);
+        when(mTelephonyUtils.getActiveSubscriptions()).thenReturn(infos);
+        when(mTelephonyUtils.isEuiccSubscription(anyInt())).thenReturn(false);
+
+        mPreferredSubscriptionService.initialize();
+        verify(mTelephonyUtils).isEuiccSubscription(anyInt());
+        verify(mTelephonyUtils).registerSubscriptionChangedCallback(
+                any(TelephonyUtils.Callback.class));
+
+    }
+
+}
diff --git a/NfcNci/tests/unit/src/com/android/nfc/cardemulation/RegisteredT3tIdentifiersCacheTest.java b/NfcNci/tests/unit/src/com/android/nfc/cardemulation/RegisteredT3tIdentifiersCacheTest.java
index b9f6f1e..63e04aa 100644
--- a/NfcNci/tests/unit/src/com/android/nfc/cardemulation/RegisteredT3tIdentifiersCacheTest.java
+++ b/NfcNci/tests/unit/src/com/android/nfc/cardemulation/RegisteredT3tIdentifiersCacheTest.java
@@ -38,11 +38,6 @@
 import com.android.dx.mockito.inline.extended.ExtendedMockito;
 import com.android.nfc.cardemulation.RegisteredT3tIdentifiersCache.T3tIdentifier;
 
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -50,11 +45,15 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.Captor;
 import org.mockito.Mock;
-import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.mockito.MockitoSession;
 import org.mockito.quality.Strictness;
 
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
 @RunWith(AndroidJUnit4.class)
 public class RegisteredT3tIdentifiersCacheTest {
 
@@ -155,7 +154,7 @@
     cache = new RegisteredT3tIdentifiersCache(mContext, mRoutingManager);
     cache.mNfcEnabled = false;
 
-    cache.onSecureNfcToggled();
+    cache.onTriggerRoutingTableUpdate();
 
     verify(mRoutingManager, never()).configureRouting(any());
   }
@@ -166,7 +165,7 @@
     cache.mNfcEnabled = true;
     cache.mForegroundT3tIdentifiersCache.put(NFCID2, mNfcFServiceInfo);
 
-    cache.onSecureNfcToggled();
+    cache.onTriggerRoutingTableUpdate();
 
     verify(mRoutingManager, times(2)).configureRouting(identifiersCaptor.capture());
     List<T3tIdentifier> firstList = identifiersCaptor.getAllValues().get(0);
@@ -331,4 +330,4 @@
     list.add(mNfcFServiceInfo);
     return list;
   }
-}
\ No newline at end of file
+}
diff --git a/NfcNci/tests/unit/src/com/android/nfc/handover/BluetoothPeripheralHandoverTest.java b/NfcNci/tests/unit/src/com/android/nfc/handover/BluetoothPeripheralHandoverTest.java
index 1d88fe3..d8aeb8a 100644
--- a/NfcNci/tests/unit/src/com/android/nfc/handover/BluetoothPeripheralHandoverTest.java
+++ b/NfcNci/tests/unit/src/com/android/nfc/handover/BluetoothPeripheralHandoverTest.java
@@ -69,6 +69,8 @@
 import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.nfc.DeviceConfigFacade;
+import com.android.nfc.NfcInjector;
 
 import org.junit.After;
 import org.junit.Before;
@@ -114,18 +116,25 @@
     Intent mockIntent;
     @Mock
     BluetoothA2dp mockA2dp;
+    @Mock
+    DeviceConfigFacade mDeviceConfigFacade;
     private MockitoSession mStaticMockSession;
     BluetoothPeripheralHandover bluetoothPeripheralHandover;
 
     @Before
     public void setUp() {
-        mStaticMockSession = ExtendedMockito.mockitoSession().mockStatic(
-                Settings.Global.class).mockStatic(Toast.class).strictness(
-                Strictness.LENIENT).startMocking();
+        mStaticMockSession = ExtendedMockito.mockitoSession()
+                .mockStatic(Settings.Global.class)
+                .mockStatic(Toast.class)
+                .mockStatic(NfcInjector.class)
+                .strictness(Strictness.LENIENT).startMocking();
         MockitoAnnotations.initMocks(this);
         when(mockContext.getSystemService(AudioManager.class)).thenReturn(mockAudioManager);
         when(mockContext.getContentResolver()).thenReturn(mockContentResolver);
         when(mockContext.getResources()).thenReturn(mockResources);
+        NfcInjector nfcInjector = mock(NfcInjector.class);
+        when(NfcInjector.getInstance()).thenReturn(nfcInjector);
+        when(nfcInjector.getDeviceConfigFacade()).thenReturn(mDeviceConfigFacade);
         when(Toast.makeText(any(), anyString(), anyInt())).thenReturn(mockToast);
         bluetoothPeripheralHandover = createBluetoothPerHandOvrInstance(
                 BluetoothDevice.TRANSPORT_LE);
diff --git a/NfcNci/testutils/Android.bp b/NfcNci/testutils/Android.bp
index 089218c..3865297 100644
--- a/NfcNci/testutils/Android.bp
+++ b/NfcNci/testutils/Android.bp
@@ -23,6 +23,35 @@
     ],
 }
 
+android_app {
+    name: "NfcEmulatorApduAppNonTest",
+    sdk_version: "test_current",
+    min_sdk_version: "35",
+    srcs: [
+        "src/com/android/nfc/emulatorapp/**/*.kt",
+    ],
+    assets: ["src/com/android/nfc/emulatorapp/parsed_files/**/*.txt"],
+    resource_dirs: ["src/com/android/nfc/emulatorapp/res"],
+    manifest: "src/com/android/nfc/emulatorapp/AndroidManifest.xml",
+    static_libs: [
+        "guava",
+        "androidx.appcompat_appcompat",
+        "kotlinx-coroutines-android",
+        "androidx.annotation_annotation",
+        "androidx.compose.ui_ui",
+        "com.google.android.material_material",
+        "kotlinx_serialization_core",
+        "kotlinx_serialization_json",
+        "nfc-multidevice-utils",
+    ],
+    visibility: [
+        "//cts:__subpackages__",
+        "//packages/modules/Nfc/NfcNci:__subpackages__",
+        "//packages/modules/Nfc:__subpackages__",
+        "//vendor:__subpackages__",
+    ],
+}
+
 android_test {
     name: "NfcEmulatorApduApp",
     sdk_version: "test_current",
diff --git a/NfcNci/testutils/README.md b/NfcNci/testutils/README.md
index 78a84f0..a94d227 100644
--- a/NfcNci/testutils/README.md
+++ b/NfcNci/testutils/README.md
@@ -56,6 +56,47 @@
 commands and responses received and sent by the Host APDU service displayed on
 the emulator app.
 
+To use the emulator app outside of a generated test, perform the following steps:
+
+1\. To prepare a snoop log to be replayed with the app:
+
+```
+python3 nfcreplay.py -f $SNOOP_FILE --parse_only
+```
+
+The script will produce the name of the parsed log, which will be located within
+the folder emulatorapp/parsed_files. Save the name for Step 3.
+
+2\. Build and install the emulator app. The following commands are specific to
+the Pixel 6 Pro (Raven). Non-Raven devices should substitute "raven" for the
+appropriate value.
+
+```
+mma NfcEmulatorApduAppNonTest
+adb install -r -g ~/aosp-main-with-phones/out/target/product/raven/system/app/emulatorapp/NfcEmulatorApduAppNonTest.apk
+
+```
+
+3\. Start the activity. Make sure that $PARSED_SNOOP_FILE is the name of the
+file, rather than its path. It is assumed that this file is located within
+emulatorapp/parsed_files, where it was originally created.
+
+```
+adb shell am start -n com.android.nfc.emulatorapp/.MainActivity --es "snoop_file" "$PARSED_SNOOP_FILE"
+```
+
+When you are ready to start the transaction, press the "Start Host APDU Service"
+button.
+
+4\. To replay the transaction with the PN532 module, follow the steps above to
+generate and replay a test case, though you should make sure to append the flag
+`--replay_with_app` to the end of each command.
+
+When the transaction is replayed, you should be able to see a list of APDU
+commands and responses received and sent by the Host APDU service displayed on
+the emulator app. Additionally, the replay script will output similar
+information.
+
 ### Creating a Snoop Log
 
 To create a snoop log from your Android device, you should first go to Developer
diff --git a/NfcNci/testutils/pn532/pn532.py b/NfcNci/testutils/pn532/pn532.py
index 6006ea9..c3fa37c 100644
--- a/NfcNci/testutils/pn532/pn532.py
+++ b/NfcNci/testutils/pn532/pn532.py
@@ -355,7 +355,11 @@
             },
         )
         self.log.debug("Serial port: %s", path)
-        self.device = serial.Serial(path, 115200, timeout=0.5)
+        try:
+            self.device = serial.Serial(path, 115200, timeout=0.5)
+        except Exception as e:
+            self.log.debug("Failed to connect to serial port %s", path)
+            return False
 
         self.device.flush()
         self._send_ack_frame()
diff --git a/NfcNci/testutils/src/com/android/nfc/emulator/AndroidManifest.xml b/NfcNci/testutils/src/com/android/nfc/emulator/AndroidManifest.xml
index 1e8bc3d..d36f846 100644
--- a/NfcNci/testutils/src/com/android/nfc/emulator/AndroidManifest.xml
+++ b/NfcNci/testutils/src/com/android/nfc/emulator/AndroidManifest.xml
@@ -127,6 +127,11 @@
             android:label="Event Listener Activity"
             android:exported="true">
         </activity>
+        <activity
+            android:name=".ExitFrameEmulatorActivity"
+            android:label="Exit Frame Activity"
+            android:exported="true">
+        </activity>
         <service android:name="com.android.nfc.service.PollingLoopService" android:exported="true"
             android:permission="android.permission.BIND_NFC_SERVICE"
             android:enabled="true">
diff --git a/NfcNci/testutils/src/com/android/nfc/emulator/ExitFrameEmulatorActivity.java b/NfcNci/testutils/src/com/android/nfc/emulator/ExitFrameEmulatorActivity.java
new file mode 100644
index 0000000..143cae2
--- /dev/null
+++ b/NfcNci/testutils/src/com/android/nfc/emulator/ExitFrameEmulatorActivity.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.nfc.emulator;
+
+import android.content.ComponentName;
+import android.nfc.cardemulation.CardEmulation;
+import android.nfc.cardemulation.PollingFrame;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.android.nfc.service.PaymentService1;
+
+import java.util.ArrayList;
+import java.util.HexFormat;
+import java.util.List;
+import java.util.regex.Pattern;
+
+public class ExitFrameEmulatorActivity extends BaseEmulatorActivity {
+    private static final String TAG = "ExitFrameEmulatorActivity";
+
+    public static final String EXIT_FRAME_KEY = "EXIT_FRAME";
+    public static final String REGISTER_PATTERNS_KEY = "REGISTER_PATTERNS";
+    public static final String WAIT_FOR_TRANSACTION_KEY = "WAIT_FOR_TRANSACTION";
+
+    private String mReceivedExitFrame = null;
+    private String mIntendedExitFrameData = null;
+    private final List<String> mRegisteredPatterns = new ArrayList<>();
+    private boolean mWaitForTransaction = true;
+    private ComponentName mServiceName = null;
+
+    private final CardEmulation.NfcEventCallback mEventListener =
+            new CardEmulation.NfcEventCallback() {
+                public void onObserveModeDisabledInFirmware(PollingFrame exitFrame) {
+                    if (exitFrame != null) {
+                        mReceivedExitFrame = HexFormat.of().formatHex(exitFrame.getData());
+                        Log.d(TAG, "Received exit frame: " + mReceivedExitFrame);
+                    }
+
+                    if (!mWaitForTransaction) {
+                        verifyExitFrameAndPassTest();
+                    }
+                }
+            };
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mIntendedExitFrameData = getIntent().getStringExtra(EXIT_FRAME_KEY);
+        mWaitForTransaction = getIntent().getBooleanExtra(WAIT_FOR_TRANSACTION_KEY, true);
+
+        setupServices(PaymentService1.COMPONENT);
+        makeDefaultWalletRoleHolder();
+    }
+
+    public void onResume() {
+        super.onResume();
+        mServiceName =
+                new ComponentName(this.getApplicationContext(), PaymentService1.class);
+        mCardEmulation.setPreferredService(this, mServiceName);
+        waitForPreferredService();
+
+        mReceivedExitFrame = null;
+        registerEventListener(mEventListener);
+
+        if (getIntent().hasExtra(REGISTER_PATTERNS_KEY)) {
+            getIntent().getStringArrayListExtra(REGISTER_PATTERNS_KEY).forEach(
+                    plpf -> {
+                        mCardEmulation.registerPollingLoopPatternFilterForService(mServiceName,
+                                plpf, true);
+                        mRegisteredPatterns.add(plpf);
+                    }
+            );
+        }
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+
+        mRegisteredPatterns.forEach(
+                plpf -> mCardEmulation.removePollingLoopPatternFilterForService(mServiceName,
+                        plpf));
+        mCardEmulation.unsetPreferredService(this);
+    }
+
+    @Override
+    public void onApduSequenceComplete(ComponentName component, long duration) {
+        verifyExitFrameAndPassTest();
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        mCardEmulation.unregisterNfcEventCallback(mEventListener);
+    }
+
+    @Override
+    public ComponentName getPreferredServiceComponent() {
+        return PaymentService1.COMPONENT;
+    }
+
+    private void verifyExitFrameAndPassTest() {
+        if (mIntendedExitFrameData == null || mReceivedExitFrame == null) {
+            return;
+        }
+
+        boolean success =
+                Pattern.compile(mIntendedExitFrameData).matcher(mReceivedExitFrame).matches();
+
+        if (success) {
+            setTestPassed();
+        }
+    }
+}
\ No newline at end of file
diff --git a/NfcNci/testutils/src/com/android/nfc/emulator/NfcEmulatorDeviceSnippet.java b/NfcNci/testutils/src/com/android/nfc/emulator/NfcEmulatorDeviceSnippet.java
index 4db71ee..832c803 100644
--- a/NfcNci/testutils/src/com/android/nfc/emulator/NfcEmulatorDeviceSnippet.java
+++ b/NfcNci/testutils/src/com/android/nfc/emulator/NfcEmulatorDeviceSnippet.java
@@ -29,6 +29,7 @@
 import androidx.test.uiautomator.UiScrollable;
 import androidx.test.uiautomator.UiSelector;
 
+import com.android.compatibility.common.util.CommonTestUtils;
 import com.android.nfc.service.AccessServiceTurnObserveModeOnProcessApdu;
 import com.android.nfc.utils.CommandApdu;
 import com.android.nfc.utils.HceUtils;
@@ -412,6 +413,23 @@
         mActivity = (EventListenerEmulatorActivity) instrumentation.startActivitySync(intent);
     }
 
+    @Rpc(description = "Opens the Exit Frame Activity")
+    public void startExitFrameActivity(String intendedExitFrame, String[] plpfs,
+            boolean waitForTransaction) {
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.setClassName(instrumentation.getTargetContext(),
+                ExitFrameEmulatorActivity.class.getName());
+        intent.putExtra(ExitFrameEmulatorActivity.EXIT_FRAME_KEY, intendedExitFrame);
+        intent.putStringArrayListExtra(ExitFrameEmulatorActivity.REGISTER_PATTERNS_KEY,
+                new ArrayList<>(Arrays.asList(plpfs)));
+        intent.putExtra(ExitFrameEmulatorActivity.WAIT_FOR_TRANSACTION_KEY, waitForTransaction);
+
+        mActivity = (ExitFrameEmulatorActivity) instrumentation.startActivitySync(intent);
+    }
+
     /** Registers receiver that waits for RF field broadcast */
     @AsyncRpc(description = "Waits for RF field detected broadcast")
     public void asyncWaitForRfOnBroadcast(String callbackId, String eventName) {
@@ -546,6 +564,14 @@
     public void closeActivity() {
         if (mActivity != null) {
             mActivity.finish();
+            try {
+                CommonTestUtils.waitUntil(
+                        "Activity didn't finish in 5 seconds",
+                        5,
+                        () -> mActivity.isDestroyed()
+                );
+            } catch (InterruptedException | AssertionError e) {
+            }
         }
     }
 
diff --git a/NfcNci/testutils/src/com/android/nfc/emulatorapp/MainActivity.kt b/NfcNci/testutils/src/com/android/nfc/emulatorapp/MainActivity.kt
index fc20c60..107b3cd 100644
--- a/NfcNci/testutils/src/com/android/nfc/emulatorapp/MainActivity.kt
+++ b/NfcNci/testutils/src/com/android/nfc/emulatorapp/MainActivity.kt
@@ -48,11 +48,23 @@
     viewModel.uiState.observe(this, observer)
     EmulatorHostApduService.viewModel = viewModel
 
+    findViewById<MaterialButton>(R.id.service_button).setOnClickListener {
+      startHostApduService()
+      findViewById<MaterialButton>(R.id.service_button).isEnabled = false
+    }
+
     val snoopData = intent.getStringExtra(SNOOP_DATA_FLAG)
-    if (snoopData != null) {
+    if (snoopData != null && snoopData.length > 0) {
       val apdus = parseJsonString(snoopData)
       updateService(apdus)
     }
+
+    val snoopFile = intent.getStringExtra(SNOOP_FILE_FLAG)
+    if (snoopFile != null && snoopFile.length > 0) {
+      val apdus = openAndParseFile(PARSED_FILES_DIR + snoopFile)
+      updateService(apdus)
+      viewModel.setSnoopFile(snoopFile)
+    }
     startHostApduService()
   }
 
@@ -64,6 +76,30 @@
     )
   }
 
+  /* Opens the snoop file and extracts all APDU commands and responses. */
+  private fun openAndParseFile(file: String): List<ApduPair> {
+    val apduPairs = mutableListOf<ApduPair>()
+    val text = BufferedReader(InputStreamReader(getAssets().open(file))).use { it.readText() }
+    val lines = text.split("\n").toTypedArray()
+    for (line in lines) {
+      val arr = line.split(";").toTypedArray()
+      if (arr.size != 2) { // Should contain commands, followed by responses
+        continue
+      }
+      val commands = arr[0].split(",").toTypedArray()
+      val responses = arr[1].split(",").toTypedArray()
+      if (commands.size != responses.size) {
+        continue
+      }
+      for (i in commands.indices) {
+        val command = standardize(commands[i])
+        val response = standardize(responses[i])
+        apduPairs.add(ApduPair(command, response))
+      }
+    }
+    return apduPairs
+  }
+
   /** Extracts all APDU commands and responses from JSON string. */
   private fun parseJsonString(text: String): List<ApduPair> {
     val apduPairs = mutableListOf<ApduPair>()
@@ -106,6 +142,7 @@
   companion object {
     private const val TAG = "EmulatorHostApduServiceLog"
     const val SNOOP_DATA_FLAG = "snoop_data"
+    const val SNOOP_FILE_FLAG = "snoop_file"
     private const val PARSED_FILES_DIR = "src/com/android/nfc/emulatorapp/parsed_files/"
   }
 }
\ No newline at end of file
diff --git a/framework/api/current.txt b/framework/api/current.txt
index f69d436..ef327ae 100644
--- a/framework/api/current.txt
+++ b/framework/api/current.txt
@@ -77,6 +77,7 @@
     method public boolean isEnabled();
     method public boolean isObserveModeEnabled();
     method public boolean isObserveModeSupported();
+    method @FlaggedApi("com.android.nfc.module.flags.reader_mode_annotations") public boolean isReaderModeAnnotationSupported();
     method @FlaggedApi("android.nfc.enable_nfc_reader_option") public boolean isReaderOptionEnabled();
     method @FlaggedApi("android.nfc.enable_nfc_reader_option") public boolean isReaderOptionSupported();
     method public boolean isSecureNfcEnabled();
diff --git a/framework/java/android/nfc/INfcAdapter.aidl b/framework/java/android/nfc/INfcAdapter.aidl
index ac0a5aa..43d601f 100644
--- a/framework/java/android/nfc/INfcAdapter.aidl
+++ b/framework/java/android/nfc/INfcAdapter.aidl
@@ -91,6 +91,7 @@
     boolean isReaderOptionSupported();
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)")
     boolean enableReaderOption(boolean enable, in String pkg);
+    boolean isReaderModeAnnotationSupported();
     boolean isObserveModeSupported();
     boolean isObserveModeEnabled();
     boolean setObserveMode(boolean enabled, String pkg);
diff --git a/framework/java/android/nfc/INfcEventCallback.aidl b/framework/java/android/nfc/INfcEventCallback.aidl
index af1fa2f..17b0d58 100644
--- a/framework/java/android/nfc/INfcEventCallback.aidl
+++ b/framework/java/android/nfc/INfcEventCallback.aidl
@@ -1,6 +1,7 @@
 package android.nfc;
 
 import android.nfc.ComponentNameAndUser;
+import android.nfc.cardemulation.PollingFrame;
 
 /**
  * @hide
@@ -8,6 +9,7 @@
 oneway interface INfcEventCallback {
     void onPreferredServiceChanged(in ComponentNameAndUser ComponentNameAndUser);
     void onObserveModeStateChanged(boolean isEnabled);
+    void onObserveModeDisabledInFirmware(in PollingFrame exitFrame);
     void onAidConflictOccurred(in String aid);
     void onAidNotRouted(in String aid);
     void onNfcStateChanged(in int nfcState);
diff --git a/framework/java/android/nfc/NfcAdapter.java b/framework/java/android/nfc/NfcAdapter.java
index f330437..c8e19cf 100644
--- a/framework/java/android/nfc/NfcAdapter.java
+++ b/framework/java/android/nfc/NfcAdapter.java
@@ -52,7 +52,6 @@
 import android.os.UserHandle;
 import android.util.Log;
 
-import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
@@ -624,7 +623,6 @@
     final Object mLock;
     final NfcOemExtension mNfcOemExtension;
 
-    ITagRemovedCallback mTagRemovedListener; // protected by mLock
 
     /**
      * A callback to be invoked when the system finds a tag while the foreground activity is
@@ -942,7 +940,6 @@
         mContext = context;
         mNfcActivityManager = new NfcActivityManager(this);
         mNfcUnlockHandlers = new HashMap<NfcUnlockHandler, INfcUnlockHandler>();
-        mTagRemovedListener = null;
         mLock = new Object();
         mControllerAlwaysOnListener = new NfcControllerAlwaysOnListener();
         mNfcWlcStateListener = new NfcWlcStateListener(getService());
@@ -1195,6 +1192,21 @@
         callService(() -> sService.pausePolling(timeoutInMs));
     }
 
+    /**
+     * Returns whether the device supports setting annotation frames when enabling reader
+     * mode by passing an extras bundle that includes a
+     * {@link #EXTRA_READER_TECH_A_POLLING_LOOP_ANNOTATION} key to
+     * {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}. These annotations frames
+     * will be reported as unknown frames via
+     * {@link android.nfc.cardemulation.HostApduService#processPollingFrames(List)} on another
+     * Android device that has set enabled observe mode by passing true to
+     * {@link #setObserveModeEnabled(boolean)} .
+     * @return true if the mode is supported, false otherwise.
+     */
+    @FlaggedApi(com.android.nfc.module.flags.Flags.FLAG_READER_MODE_ANNOTATIONS)
+    public boolean isReaderModeAnnotationSupported() {
+        return callServiceReturn(() ->  sService.isReaderModeAnnotationSupported(), false);
+    }
 
     /**
      * Returns whether the device supports observe mode or not. When observe mode is enabled, the
@@ -2202,15 +2214,9 @@
                     } else {
                         tagRemovedListener.onTagRemoved();
                     }
-                    synchronized (mLock) {
-                        mTagRemovedListener = null;
-                    }
                 }
             };
         }
-        synchronized (mLock) {
-            mTagRemovedListener = iListener;
-        }
         final ITagRemovedCallback.Stub passedListener = iListener;
         return callServiceReturn(() ->
                 sService.ignore(tag.getServiceHandle(), debounceMs, passedListener), false);
diff --git a/framework/java/android/nfc/cardemulation/CardEmulation.java b/framework/java/android/nfc/cardemulation/CardEmulation.java
index daecb35..c68c262 100644
--- a/framework/java/android/nfc/cardemulation/CardEmulation.java
+++ b/framework/java/android/nfc/cardemulation/CardEmulation.java
@@ -27,6 +27,7 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.annotation.UserHandleAware;
 import android.annotation.UserIdInt;
 import android.app.Activity;
@@ -1350,6 +1351,16 @@
         default void onObserveModeStateChanged(boolean isEnabled) {}
 
         /**
+         * This method is called when observe mode has been disabled in the firmware.
+         *
+         * @param exitFrame The polling frame that caused the firmware to exit observe mode. Null
+         *                  when we were unable to parse the exit frame from the NFCC.
+         * @hide
+         */
+        @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
+        default void onObserveModeDisabledInFirmware(@Nullable PollingFrame exitFrame) {}
+
+        /**
          * This method is called when an AID conflict is detected during an NFC transaction. This
          * can happen when multiple services are registered for the same AID. If your service is
          * registered for this AID you may want to instruct users to bring your app to the
@@ -1429,6 +1440,13 @@
                     callListeners(listener -> listener.onObserveModeStateChanged(isEnabled));
                 }
 
+                public void onObserveModeDisabledInFirmware(PollingFrame exitFrame) {
+                    if (!android.nfc.Flags.nfcEventListener()) {
+                        return;
+                    }
+                    callListeners(listener -> listener.onObserveModeDisabledInFirmware(exitFrame));
+                }
+
                 public void onAidConflictOccurred(String aid) {
                     if (!android.nfc.Flags.nfcEventListener()) {
                         return;
diff --git a/libnfc-nci/src/adaptation/NfcAdaptation.cc b/libnfc-nci/src/adaptation/NfcAdaptation.cc
index 5beb02a..2cb10dc 100644
--- a/libnfc-nci/src/adaptation/NfcAdaptation.cc
+++ b/libnfc-nci/src/adaptation/NfcAdaptation.cc
@@ -711,6 +711,7 @@
     }
     AIBinder_unlinkToDeath(mAidlHal->asBinder().get(), mDeathRecipient.get(),
                            nullptr);
+    mAidlHal = nullptr;
   } else if (mHal != nullptr) {
     if (sVndExtnsPresent) {
       sNfcVendorExtn->finalize();
@@ -1004,6 +1005,9 @@
 void NfcAdaptation::HalClose() {
   const char* func = "NfcAdaptation::HalClose";
   LOG(VERBOSE) << StringPrintf("%s", func);
+  if (sVndExtnsPresent) {
+    sNfcVendorExtn->processEvent(HANDLE_NFC_HAL_CLOSE, HAL_NFC_STATUS_OK);
+  }
   if (mAidlHal != nullptr) {
     mAidlHal->close(NfcCloseType::DISABLE);
   } else if (mHal != nullptr) {
@@ -1055,6 +1059,10 @@
                                        uint8_t* p_core_init_rsp_params) {
   const char* func = "NfcAdaptation::HalCoreInitialized";
   LOG(VERBOSE) << StringPrintf("%s", func);
+  if (sVndExtnsPresent) {
+    sNfcVendorExtn->processEvent(HANDLE_NFC_HAL_CORE_INITIALIZE,
+                                 HAL_NFC_STATUS_OK);
+  }
   if (mAidlHal != nullptr) {
     // AIDL coreInitialized doesn't send data to HAL.
     mAidlHal->coreInitialized();
@@ -1139,6 +1147,9 @@
 void NfcAdaptation::HalPowerCycle() {
   const char* func = "NfcAdaptation::HalPowerCycle";
   LOG(VERBOSE) << StringPrintf("%s", func);
+  if (sVndExtnsPresent) {
+    sNfcVendorExtn->processEvent(HANDLE_NFC_HAL_POWER_CYCLE, HAL_NFC_STATUS_OK);
+  }
   if (mAidlHal != nullptr) {
     mAidlHal->powerCycle();
   } else if (mHal != nullptr) {
@@ -1158,7 +1169,9 @@
 uint8_t NfcAdaptation::HalGetMaxNfcee() {
   const char* func = "NfcAdaptation::HalGetMaxNfcee";
   LOG(VERBOSE) << StringPrintf("%s", func);
-
+  if (sVndExtnsPresent) {
+    sNfcVendorExtn->processEvent(HANDLE_NFC_GET_MAX_NFCEE, HAL_NFC_STATUS_OK);
+  }
   return nfa_ee_max_ee_cfg;
 }
 
diff --git a/libnfc-nci/src/adaptation/nfc_config.cc b/libnfc-nci/src/adaptation/nfc_config.cc
index 46c2409..ce4f0a9 100644
--- a/libnfc-nci/src/adaptation/nfc_config.cc
+++ b/libnfc-nci/src/adaptation/nfc_config.cc
@@ -22,6 +22,8 @@
 #include <android-base/strings.h>
 #include <config.h>
 
+#include <mutex>
+
 #include "NfcAdaptation.h"
 
 using namespace ::std;
@@ -29,6 +31,8 @@
 
 #define PATH_NCI_UPDATE_CONF "/data/vendor/nfc/libnfc-nci-update.conf"
 
+static std::mutex config_mutex;
+
 namespace {
 std::string searchConfigPath(std::string file_name) {
   const std::vector<std::string> search_path = {
@@ -87,9 +91,8 @@
   }
 }
 
-NfcConfig::NfcConfig() { loadConfig(); }
-
 NfcConfig& NfcConfig::getInstance() {
+  std::lock_guard<std::mutex> lock(config_mutex);
   static NfcConfig theInstance;
   if (theInstance.config_.isEmpty()) {
     theInstance.loadConfig();
diff --git a/libnfc-nci/src/gki/common/gki_buffer.cc b/libnfc-nci/src/gki/common/gki_buffer.cc
index 5a69ca6..b461382 100644
--- a/libnfc-nci/src/gki/common/gki_buffer.cc
+++ b/libnfc-nci/src/gki/common/gki_buffer.cc
@@ -120,7 +120,10 @@
 **
 *******************************************************************************/
 void gki_buffer_init(void) {
-  uint8_t i, tt, mb;
+#if (GKI_NUM_FIXED_BUF_POOLS > 0)
+  uint8_t i;
+#endif
+  uint8_t tt, mb;
   tGKI_COM_CB* p_cb = &gki_cb.com;
 
   /* Initialize mailboxes */
@@ -211,10 +214,12 @@
   gki_init_free_queue(15, GKI_BUF15_SIZE, GKI_BUF15_MAX, p_cb->bufpool15);
 #endif
 
-  /* add pools to the pool_list which is arranged in the order of size */
+/* add pools to the pool_list which is arranged in the order of size */
+#if (GKI_NUM_FIXED_BUF_POOLS > 0)
   for (i = 0; i < GKI_NUM_FIXED_BUF_POOLS; i++) {
     p_cb->pool_list[i] = i;
   }
+#endif
 
   p_cb->curr_total_no_of_pools = GKI_NUM_FIXED_BUF_POOLS;
 
diff --git a/libnfc-nci/src/include/nci_defs.h b/libnfc-nci/src/include/nci_defs.h
index 084ce1a..736494a 100644
--- a/libnfc-nci/src/include/nci_defs.h
+++ b/libnfc-nci/src/include/nci_defs.h
@@ -230,19 +230,13 @@
  **********************************************/
 #define NCI_MSG_PROP_ANDROID 0x0C
 
-#define NCI_ANDROID_SIGNAL_STRENGTH_NTF 0x01
-#define NCI_ANDROID_FIELD_CHANGE_NTF 0x02
-#define NCI_ANDROID_POLLING_FRAME_NTF 0x03
-#define NCI_ANDROID_GET_PASSIVE_OBSERVER_EXIT_FRAME_NTF 0x04
-#define NCI_ANDROID_PASSIVE_OBSERVER_SUSPENDED_NTF 0x05
-#define NCI_ANDROID_PASSIVE_OBSERVER_RESUMED_NTF 0x06
 #define NCI_ANDROID_RESTART_RF_DISCOVERY_REQUEST_NTF 0x07
 
 /* Android Opcodes */
 #define NCI_ANDROID_GET_CAPS 0x0
 #define NCI_ANDROID_POWER_SAVING 0x1
 #define NCI_ANDROID_PASSIVE_OBSERVE 0x2
-#define NCI_ANDROID_POLLING_FRAME 0x3
+#define NCI_ANDROID_POLLING_FRAME_NTF 0x03
 #define NCI_QUERY_ANDROID_PASSIVE_OBSERVE 0x4
 #define NCI_ANDROID_SET_PASSIVE_OBSERVER_TECH 0x05
 #define NCI_ANDROID_SET_PASSIVE_OBSERVER_EXIT_FRAME 0x06
@@ -250,6 +244,8 @@
 #define NCI_ANDROID_BLANK_NCI 0x8
 #define NCI_ANDROID_SET_TECH_A_POLLING_LOOP_ANNOTATION 0x9
 #define NCI_QUERY_ANDROID_POWER_SAVING 0x0A
+#define NCI_ANDROID_PASSIVE_OBSERVER_SUSPENDED_NTF 0x0B
+#define NCI_ANDROID_PASSIVE_OBSERVER_RESUMED_NTF 0x0C
 
 /* Android Get Proprietary Caps */
 #define NCI_ANDROID_GET_CAPS_PARAM_SIZE 0x1
diff --git a/libnfc-nci/src/include/nfc_config.h b/libnfc-nci/src/include/nfc_config.h
index 906d0c2..f478179 100644
--- a/libnfc-nci/src/include/nfc_config.h
+++ b/libnfc-nci/src/include/nfc_config.h
@@ -87,7 +87,7 @@
  private:
   void loadConfig();
   static NfcConfig& getInstance();
-  NfcConfig();
+  NfcConfig() {};
 
   ConfigFile config_;
 };
diff --git a/libnfc-nci/src/nfa/dm/nfa_dm_act.cc b/libnfc-nci/src/nfa/dm/nfa_dm_act.cc
index 0604492..95769ea 100644
--- a/libnfc-nci/src/nfa/dm/nfa_dm_act.cc
+++ b/libnfc-nci/src/nfa/dm/nfa_dm_act.cc
@@ -29,6 +29,7 @@
 #include "nci_hmsgs.h"
 #include "nfa_api.h"
 #include "nfa_ce_int.h"
+#include "nfa_hci_int.h"
 #include "nfa_rw_api.h"
 #include "nfa_rw_int.h"
 #include "nfa_wlc_int.h"
@@ -1135,7 +1136,8 @@
 
   LOG(VERBOSE) << __func__;
 
-  if (nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_ENABLED) {
+  if ((nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_ENABLED) ||
+      (nfa_hci_cb.hci_state == NFA_HCI_STATE_EE_RECOVERY)) {
     evt_data.status = NFA_STATUS_OK;
     nfa_dm_conn_cback_event_notify(NFA_RF_DISCOVERY_STARTED_EVT, &evt_data);
   } else if (nfa_dm_cb.disc_cb.disc_state != NFA_DM_RFST_IDLE) {
diff --git a/libnfc-nci/src/nfa/hci/nfa_hci_utils.cc b/libnfc-nci/src/nfa/hci/nfa_hci_utils.cc
index 98f7822..ca2f119 100644
--- a/libnfc-nci/src/nfa/hci/nfa_hci_utils.cc
+++ b/libnfc-nci/src/nfa/hci/nfa_hci_utils.cc
@@ -303,6 +303,10 @@
   bool first_pkt = true;
   uint16_t data_len;
   tNFA_STATUS status = NFA_STATUS_OK;
+  if ((msg_len != 0) && (p_msg == nullptr)) {
+    LOG(ERROR) << StringPrintf("%s: msg_len is 0 and p_msg is null", __func__);
+    return NFA_STATUS_FAILED;
+  }
   uint16_t max_seg_hcp_pkt_size;
   if (nfa_hci_cb.buff_size > (NCI_DATA_HDR_SIZE + 2)) {
     max_seg_hcp_pkt_size = nfa_hci_cb.buff_size - NCI_DATA_HDR_SIZE;
diff --git a/libnfc-nci/src/nfc/nfc/nfc_ncif.cc b/libnfc-nci/src/nfc/nfc/nfc_ncif.cc
index a1595ca..47be304 100644
--- a/libnfc-nci/src/nfc/nfc/nfc_ncif.cc
+++ b/libnfc-nci/src/nfc/nfc/nfc_ncif.cc
@@ -1775,7 +1775,10 @@
 
       data_cevt.p_data = p_evt;
       /* adjust payload, if needed */
-      if (p_cb->conn_id == NFC_RF_CONN_ID && p_evt->len) {
+      // On RF raw fragmented frames, data status is present
+      // only on last fragment
+      if ((p_cb->conn_id == NFC_RF_CONN_ID) &&
+          (p_evt->layer_specific & NFC_RAS_FRAGMENTED) && p_evt->len) {
         /* if NCI_PROTOCOL_T1T/NCI_PROTOCOL_T2T/NCI_PROTOCOL_T3T, the status
          * byte needs to be removed
          */
diff --git a/libnfc-nci/src/nfc/tags/ce_t4t.cc b/libnfc-nci/src/nfc/tags/ce_t4t.cc
index 4e9c135..42a9742 100644
--- a/libnfc-nci/src/nfc/tags/ce_t4t.cc
+++ b/libnfc-nci/src/nfc/tags/ce_t4t.cc
@@ -567,8 +567,6 @@
 
   LOG(VERBOSE) << StringPrintf("%s: conn_id = 0x%02X", __func__, conn_id);
 
-  p_cmd = (uint8_t*)(p_c_apdu + 1) + p_c_apdu->offset;
-
   if (p_c_apdu->len == 0) {
     LOG(ERROR) << StringPrintf("%s: Wrong length in ce_t4t_data_cback",
                                __func__);
@@ -577,7 +575,7 @@
     GKI_freebuf(p_c_apdu);
     return;
   }
-
+  p_cmd = (uint8_t*)(p_c_apdu + 1) + p_c_apdu->offset;
   /* Class Byte */
   BE_STREAM_TO_UINT8(cla, p_cmd);
 
diff --git a/libnfc-nci/src/nfc/tags/rw_i93.cc b/libnfc-nci/src/nfc/tags/rw_i93.cc
index 06e5d20..ee482fc 100644
--- a/libnfc-nci/src/nfc/tags/rw_i93.cc
+++ b/libnfc-nci/src/nfc/tags/rw_i93.cc
@@ -3417,7 +3417,7 @@
 *******************************************************************************/
 tNFC_STATUS rw_i93_select(uint8_t* p_uid) {
   tRW_I93_CB* p_i93 = &rw_cb.tcb.i93;
-  uint8_t uid[I93_UID_BYTE_LEN], *p;
+  uint8_t uid[I93_UID_BYTE_LEN] = {0}, *p;
 
   LOG(VERBOSE) << __func__;
 
diff --git a/libnfc-nci/src/nfc_vendor_extn/NfcVendorExtn.cc b/libnfc-nci/src/nfc_vendor_extn/NfcVendorExtn.cc
index e7fe62a..602f43f 100644
--- a/libnfc-nci/src/nfc_vendor_extn/NfcVendorExtn.cc
+++ b/libnfc-nci/src/nfc_vendor_extn/NfcVendorExtn.cc
@@ -16,22 +16,19 @@
 
 #include "NfcVendorExtn.h"
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android/log.h>
 #include <dlfcn.h>
 #include <error.h>
 #include <log/log.h>
+#include <string>
 
 using android::base::StringPrintf;
 #define UNUSED_PROP(X) (void)(X);
 
-std::string mLibName = "libnfc_vendor_extn.so";
-#if (defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64))
-std::string mLibPathName = "/system/lib64/" + mLibName;
-#else
-std::string mLibPathName = "/system/lib/" + mLibName;
-#endif
 const std::string vendor_nfc_init_name = "vendor_nfc_init";
 const std::string vendor_nfc_de_init_name = "vendor_nfc_de_init";
 const std::string vendor_nfc_handle_event_name = "vendor_nfc_handle_event";
@@ -52,9 +49,47 @@
 fp_extn_on_config_update_t fp_extn_on_config_update = NULL;
 
 NfcExtEventData_t mNfcExtEventData;
+std::string mLibPathName = "";
 
 void* p_oem_extn_handle = NULL;
 
+namespace {
+  std::string searchLibPath(std::string file_name) {
+    const std::vector<std::string> search_path = {
+        "/system/lib/", "/system/lib64/"
+    };
+    for (std::string path : search_path) {
+      path.append(file_name);
+      struct stat file_stat;
+      if (stat(path.c_str(), &file_stat) != 0) continue;
+      if (S_ISREG(file_stat.st_mode)) return path;
+    }
+    return "";
+  }
+  // Extension library file Search sequence
+  // 1. If prop_lib_file_name is defined.(where prop_config_file_name is the
+  //   value of the property persist.nfc_vendor_extn.lib_file_name)
+  //   Search a file matches prop_lib_file_name.
+  // 2. If SKU is defined (where SKU is the value of the property
+  //   ro.boot.product.hardware.sku)
+  //   Search a file matches libnfc_vendor_extn-SKU.so
+  // 3. If none of 1,2 is defined, search a default file name "libnfc_vendor_extn.so".
+  std::string findLibPath() {
+    std::string f_path = searchLibPath(
+        android::base::GetProperty("persist.nfc_vendor_extn.lib_file_name", ""));
+    if (!f_path.empty()) return f_path;
+
+    // Search for libnfc_vendor_extn-SKU.so
+    f_path = searchLibPath(
+        "libnfc_vendor_extn-" +
+        android::base::GetProperty("ro.boot.product.hardware.sku", "") + ".so");
+    if (!f_path.empty()) return f_path;
+
+    // load default file if the desired file not found.
+    return searchLibPath("libnfc_vendor_extn.so");
+  }
+}  // namespace
+
 NfcVendorExtn::NfcVendorExtn() {}
 
 NfcVendorExtn::~NfcVendorExtn() { sNfcVendorExtn = nullptr; }
@@ -78,6 +113,12 @@
 
 bool NfcExtn_LibSetup() {
   LOG(VERBOSE) << __func__;
+  mLibPathName = findLibPath();
+  if (mLibPathName.empty()) {
+    LOG(ERROR) << StringPrintf("%s: Failed to find %s !!", __func__,
+                               mLibPathName.c_str());
+    return false;
+  }
   p_oem_extn_handle = dlopen(mLibPathName.c_str(), RTLD_NOW);
   if (p_oem_extn_handle == NULL) {
     LOG(DEBUG) << StringPrintf(
@@ -120,7 +161,12 @@
   LOG(VERBOSE) << StringPrintf("%s:", __func__);
   mVendorExtnCb.hidlHal = hidlHal;
   mVendorExtnCb.aidlHal = aidlHal;
-  return NfcExtn_LibSetup();
+  if (!NfcExtn_LibSetup()) {
+    mVendorExtnCb.hidlHal = nullptr;
+    mVendorExtnCb.aidlHal = nullptr;
+    return false;
+  }
+  return true;
 }
 
 void NfcVendorExtn::setNciCallback(tHAL_NFC_CBACK* pHalCback,
@@ -204,7 +250,7 @@
     }
   }
   if (p_oem_extn_handle != NULL) {
-    LOG(DEBUG) << StringPrintf("%s: Closing %s!!", __func__, mLibName.c_str());
+    LOG(DEBUG) << StringPrintf("%s: Closing %s!!", __func__, mLibPathName.c_str());
     dlclose(p_oem_extn_handle);
     p_oem_extn_handle = NULL;
   }
@@ -213,5 +259,7 @@
 bool NfcVendorExtn::finalize(void) {
   LOG(VERBOSE) << __func__;
   phNfcExtn_LibClose();
+  mVendorExtnCb.hidlHal = nullptr;
+  mVendorExtnCb.aidlHal = nullptr;
   return true;
 }
diff --git a/libnfc-nci/src/nfc_vendor_extn/include/NfcVendorExtn.h b/libnfc-nci/src/nfc_vendor_extn/include/NfcVendorExtn.h
index 95ab51b..7d35fa8 100644
--- a/libnfc-nci/src/nfc_vendor_extn/include/NfcVendorExtn.h
+++ b/libnfc-nci/src/nfc_vendor_extn/include/NfcVendorExtn.h
@@ -90,6 +90,10 @@
   HANDLE_DOWNLOAD_FIRMWARE_REQUEST,
   HANDLE_NFC_ADAPTATION_INIT,
   HANDLE_NFC_PRE_DISCOVER,
+  HANDLE_NFC_HAL_CORE_INITIALIZE,
+  HANDLE_NFC_HAL_POWER_CYCLE,
+  HANDLE_NFC_GET_MAX_NFCEE,
+  HANDLE_NFC_HAL_CLOSE,
 } NfcExtEvent_t;
 
 typedef enum {
diff --git a/libnfc-nci/tools/casimir/src/controller.rs b/libnfc-nci/tools/casimir/src/controller.rs
index b14e14d..a23bb02 100644
--- a/libnfc-nci/tools/casimir/src/controller.rs
+++ b/libnfc-nci/tools/casimir/src/controller.rs
@@ -1744,7 +1744,16 @@
             self.state.last_observe_mode_state = Some(self.state.passive_observe_mode);
             self.state.passive_observe_mode = nci::PassiveObserveMode::Disable.into();
             self.state.exit_frame_start_time = Some(Instant::now());
-            // TODO(johnrjohn) send NCI_ANDROID_PASSIVE_OBSERVER_SUSPENDED_NTF
+
+            self.send_control(nci::PassiveObserverSuspendedNotificationBuilder {
+                exit_frame_type: match technology {
+                    rf::Technology::NfcA => 0x00,
+                    rf::Technology::NfcB => 0x01,
+                    _ => panic!(),
+                },
+                payload: Some(data.clone().into()),
+            })
+            .await?;
         }
 
         self.send_control(nci::AndroidPollingLoopNotificationBuilder {
@@ -2286,7 +2295,7 @@
                 self.state.passive_observe_mode =
                     self.state.last_observe_mode_state.unwrap_or(nci::TechnologyMask::AllOn.into());
                 info!("Turning observe mode back on, exit frame timeout has passed.");
-                // TODO(johnrjohn) send NCI_ANDROID_PASSIVE_OBSERVER_RESUMED_NTF
+                self.send_control(nci::PassiveObserverResumedNotificationBuilder {}).await?;
             }
         }
 
diff --git a/libnfc-nci/tools/casimir/src/nci_packets.pdl b/libnfc-nci/tools/casimir/src/nci_packets.pdl
index ec90b89..cd1269b 100644
--- a/libnfc-nci/tools/casimir/src/nci_packets.pdl
+++ b/libnfc-nci/tools/casimir/src/nci_packets.pdl
@@ -84,7 +84,9 @@
   BLANK_NCI = 0x8,
   SET_TECH_A_POLLING_LOOP_ANNOTATION = 0x09,
   QUERY_POWER_SAVING_MODE = 0x0A,
-}
+  ANDROID_PASSIVE_OBSERVER_SUSPENDED = 0xB,
+  ANDROID_PASSIVE_OBSERVER_RESUMED = 0xC,
+ }
 
 enum Status : 8 {
   OK = 0x00,
@@ -954,6 +956,7 @@
 }
 
 packet AndroidSetPassiveObserverExitFrameCommand : AndroidPacket(mt = COMMAND, android_sub_oid = SET_PASSIVE_OBSERVER_EXIT_FRAME) {
+  more: 8,
   timeout: 16,
   _count_(exit_frames): 8,
   exit_frames: ExitFrameEntry[]
@@ -962,3 +965,11 @@
 packet AndroidSetPassiveObserverExitFrameResponse : AndroidPacket(mt = RESPONSE, android_sub_oid = SET_PASSIVE_OBSERVER_EXIT_FRAME) {
   status: Status,
 }
+
+packet PassiveObserverSuspendedNotification : AndroidPacket(mt = NOTIFICATION, android_sub_oid = ANDROID_PASSIVE_OBSERVER_SUSPENDED) {
+  exit_frame_type: 8,
+  _size_(_payload_): 8,
+  _payload_
+}
+
+packet PassiveObserverResumedNotification : AndroidPacket(mt = NOTIFICATION, android_sub_oid = ANDROID_PASSIVE_OBSERVER_RESUMED) {}
\ No newline at end of file
diff --git a/tests/cts/hostsidetests/multidevices/AndroidTest.xml b/tests/cts/hostsidetests/multidevices/AndroidTest.xml
index 8b9f799..5621803 100644
--- a/tests/cts/hostsidetests/multidevices/AndroidTest.xml
+++ b/tests/cts/hostsidetests/multidevices/AndroidTest.xml
@@ -22,6 +22,9 @@
     <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
 
     <device name="AndroidDevice">
+        <target_preparer class="AndroidDeviceFeaturesCheckDecorator">
+            <option name="required_feature" value="android.hardware.nfc.hce" />
+        </target_preparer>
         <target_preparer class="AndroidMinSdkVersionCheckDecorator">
             <option name="min_sdk_version" value="35" />
         </target_preparer>
diff --git a/tests/cts/hostsidetests/multidevices/cts_nfc_hce_multi_device_test.py b/tests/cts/hostsidetests/multidevices/cts_nfc_hce_multi_device_test.py
index db82993..2f32090 100644
--- a/tests/cts/hostsidetests/multidevices/cts_nfc_hce_multi_device_test.py
+++ b/tests/cts/hostsidetests/multidevices/cts_nfc_hce_multi_device_test.py
@@ -36,6 +36,7 @@
 import logging
 import ssl
 import sys
+import time
 
 from android.platform.test.annotations import CddTest
 from android.platform.test.annotations import ApiTest
@@ -154,14 +155,12 @@
             start_emulator_fun(*args)
         else:
             if preferred_service is None:
-                self.emulator.nfc_emulator.startSimpleEmulatorActivity(service_list,
-                                                                       expected_service, is_payment,
-                                                                       should_disable_services_on_destroy)
+                self.emulator.nfc_emulator.startSimpleEmulatorActivity(
+                        service_list, expected_service, is_payment,
+                        should_disable_services_on_destroy)
             else:
                 self.emulator.nfc_emulator.startSimpleEmulatorActivityWithPreferredService(
-                    service_list, expected_service, preferred_service, is_payment,
-                    should_disable_services_on_destroy
-                )
+                        service_list, expected_service, preferred_service, is_payment)
 
         if is_payment:
             role_held_handler.waitAndGet('RoleHeld', _NFC_TIMEOUT_SEC)
@@ -236,10 +235,6 @@
             )
             self.emulator.adb.shell(['svc', 'nfc', 'enable'])
             self.emulator.debug_tag = 'emulator'
-            if not self.emulator.nfc_emulator.isNfcHceSupported():
-                self._setup_failure_reason = f'NFC HCE is not supported on {self.emulator}'
-                self._setup_failure_should_block_tests = False
-                return
 
             if (
                 hasattr(self.emulator, 'dimensions')
@@ -1201,6 +1196,7 @@
 
         _LOG.debug(f"Polling frame gain results {results_for_power_level}")
 
+        issues = []
         for power_level in power_levels:
             # No value to compare to
             if power_level == 0:
@@ -1209,16 +1205,27 @@
             for type_ in polling_frame_types:
                 previous_gain = results_for_power_level[power_level - 1][type_]
                 current_gain = results_for_power_level[power_level][type_]
-                asserts.assert_greater_equal(
-                    current_gain, previous_gain,
-                    _FAILED_VENDOR_GAIN_VALUE_DROPPED_ON_POWER_INCREASE,
-                    {
-                        "type": type_,
-                        "power_level": power_level * 20,
-                        "previous_gain": previous_gain,
-                        "current_gain": current_gain,
-                    }
+                if current_gain >= previous_gain:
+                    continue
+                sample = {
+                    "type": type_,
+                    "power_level": power_level * 20,
+                    "previous_gain": previous_gain,
+                    "current_gain": current_gain,
+                }
+                _LOG.warning(
+                    f"Reported gain level dropped" + \
+                    f" between power steps {sample}"
                 )
+                issues.append(sample)
+
+        # Allow up to 2 reported gain decreases out of (5 * 3) = 15 test samples
+        # Theoretically, this could happen
+        # due to automatic power/gain/load management feature of chipsets
+        asserts.assert_true(
+            len(issues) <= 2,
+            _FAILED_VENDOR_GAIN_VALUE_DROPPED_ON_POWER_INCREASE,
+        )
 
     @CddTest(requirements = ["7.4.4/C-1-13"])
     def test_polling_frame_type(self):
@@ -1336,13 +1343,15 @@
             self.emulator.nfc_emulator.closeActivity()
             self.emulator.nfc_emulator.logInfo(
                 "*** TEST END: " + self.current_test_info.name + " ***")
-        self.pn532.reset_buffers()
-        self.pn532.mute()
-        param_list = [[self.emulator]]
-        utils.concurrent_exec(lambda d: d.services.create_output_excerpts_all(
-            self.current_test_info),
-                              param_list=param_list,
-                              raise_on_exception=True)
+        if hasattr(self, 'pn532'):
+            self.pn532.reset_buffers()
+            self.pn532.mute()
+        if hasattr(self, 'emulator'):
+            param_list = [[self.emulator]]
+            utils.concurrent_exec(lambda d: d.services.create_output_excerpts_all(
+                self.current_test_info),
+                                  param_list=param_list,
+                                  raise_on_exception=True)
 
     #@CddTest(requirements = {"7.4.4/C-2-2", "7.4.4/C-1-2"})
     def test_single_non_payment_service_with_listen_tech_disabled(self):
diff --git a/tests/cts/tests/src/android/nfc/cts/CardEmulationTest.java b/tests/cts/tests/src/android/nfc/cts/CardEmulationTest.java
index 12fdd5d..8c6d853 100644
--- a/tests/cts/tests/src/android/nfc/cts/CardEmulationTest.java
+++ b/tests/cts/tests/src/android/nfc/cts/CardEmulationTest.java
@@ -1,5 +1,7 @@
 package android.nfc.cts;
 
+import static android.nfc.cts.NfcUtils.assumeObserveModeSupported;
+import static android.nfc.cts.NfcUtils.assumeVsrApiGreaterThanUdc;
 import static android.nfc.cts.WalletRoleTestUtils.CTS_PACKAGE_NAME;
 import static android.nfc.cts.WalletRoleTestUtils.WALLET_HOLDER_PACKAGE_NAME;
 import static android.nfc.cts.WalletRoleTestUtils.WALLET_HOLDER_SERVICE_DESC;
@@ -7,14 +9,22 @@
 import static android.nfc.cts.WalletRoleTestUtils.runWithRole;
 import static android.nfc.cts.WalletRoleTestUtils.runWithRoleNone;
 
-import static com.android.compatibility.common.util.PropertyUtil.getVsrApiLevel;
 import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
 
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
 
 import android.annotation.NonNull;
 import android.app.Activity;
+import android.app.ActivityManager;
 import android.app.Instrumentation;
 import android.app.KeyguardManager;
 import android.content.BroadcastReceiver;
@@ -33,7 +43,6 @@
 import android.nfc.cardemulation.CardEmulation;
 import android.nfc.cardemulation.PollingFrame;
 import android.nfc.cardemulation.PollingFrame.PollingFrameType;
-import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
@@ -46,6 +55,7 @@
 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.provider.Settings;
 import android.testing.PollingCheck;
+import android.util.Log;
 import android.view.KeyEvent;
 
 import androidx.test.InstrumentationRegistry;
@@ -101,33 +111,36 @@
     }
 
     @Before
-    public void setUp() throws NoSuchFieldException, RemoteException {
+    public void setUp() throws NoSuchFieldException, RemoteException, InterruptedException {
         assumeTrue("Device must support NFC HCE", supportsHardware());
         mContext = InstrumentationRegistry.getContext();
         mAdapter = NfcAdapter.getDefaultAdapter(mContext);
-        Assert.assertNotNull("NFC Adapter is null", mAdapter);
-        Assert.assertTrue("NFC Adapter could not be enabled",
-            NfcUtils.enableNfc(mAdapter, mContext));
+        assertNotNull("NFC Adapter is null", mAdapter);
+        assertTrue("NFC Adapter could not be enabled", NfcUtils.enableNfc(mAdapter, mContext));
     }
 
     @After
     public void tearDown() throws Exception {
+        if (mAdapter != null && mContext != null) {
+            Assert.assertTrue("Failed to enable NFC in test cleanup",
+                NfcUtils.enableNfc(mAdapter, mContext));
+        } else {
+            Log.w("CardEmulationTest", "mAdapter or mContext is null");
+        }
         sCurrentPollLoopReceiver = null;
     }
 
     @Test
     public void getNonNullInstance() {
         CardEmulation instance = CardEmulation.getInstance(mAdapter);
-        Assert.assertNotNull("CardEmulation instance is null", instance);
+        assertNotNull("CardEmulation instance is null", instance);
     }
 
     @Test
     public void testCategoryAllowsForegroundPreference() {
         CardEmulation instance = CardEmulation.getInstance(mAdapter);
-        Assert.assertTrue(
-            instance.categoryAllowsForegroundPreference(CardEmulation.CATEGORY_PAYMENT));
-        Assert.assertTrue(
-            instance.categoryAllowsForegroundPreference(CardEmulation.CATEGORY_OTHER));
+        assertTrue(instance.categoryAllowsForegroundPreference(CardEmulation.CATEGORY_PAYMENT));
+        assertTrue(instance.categoryAllowsForegroundPreference(CardEmulation.CATEGORY_OTHER));
     }
 
     @Test
@@ -139,14 +152,14 @@
 
         int result = instance.getSelectionModeForCategory(CardEmulation.CATEGORY_PAYMENT);
 
-        Assert.assertTrue(validResults.contains(result));
+        assertTrue(validResults.contains(result));
     }
 
     @Test
     public void testGetSelectionModeForCategoryWithCategoryOther() {
         CardEmulation instance = CardEmulation.getInstance(mAdapter);
         int result = instance.getSelectionModeForCategory(CardEmulation.CATEGORY_OTHER);
-        Assert.assertEquals(CardEmulation.SELECTION_MODE_ASK_IF_CONFLICT, result);
+        assertEquals(CardEmulation.SELECTION_MODE_ASK_IF_CONFLICT, result);
     }
 
     @Test
@@ -156,13 +169,11 @@
         ComponentName offHostService = new ComponentName(mContext, CtsMyOffHostApduService.class);
 
         try {
-            Assert.assertTrue(instance.setOffHostForService(offHostService, "eSE"));
-            Assert.assertTrue(
-                    instance.setShouldDefaultToObserveModeForService(offHostService, true));
-            Assert.assertTrue(instance.unsetOffHostForService(offHostService));
+            assertTrue(instance.setOffHostForService(offHostService, "eSE"));
+            assertTrue(instance.setShouldDefaultToObserveModeForService(offHostService, true));
+            assertTrue(instance.unsetOffHostForService(offHostService));
         } finally {
-            Assert.assertTrue(
-                    instance.setShouldDefaultToObserveModeForService(offHostService, false));
+            assertTrue(instance.setShouldDefaultToObserveModeForService(offHostService, false));
         }
     }
 
@@ -170,15 +181,14 @@
     public void testRegisterAndGetAids() throws RemoteException {
         CardEmulation instance = CardEmulation.getInstance(mAdapter);
 
-        Assert.assertTrue(
-            instance.registerAidsForService(
+        assertTrue(instance.registerAidsForService(
                 mService, CardEmulation.CATEGORY_PAYMENT, PAYMENT_AIDS));
         List<String> result = instance.getAidsForService(mService, CardEmulation.CATEGORY_PAYMENT);
-        Assert.assertEquals(result, PAYMENT_AIDS);
+        assertEquals(result, PAYMENT_AIDS);
 
         // Unregister AIDs from service
-        Assert.assertTrue(instance.removeAidsForService(mService, CardEmulation.CATEGORY_PAYMENT));
-        Assert.assertNull(instance.getAidsForService(mService, CardEmulation.CATEGORY_PAYMENT));
+        assertTrue(instance.removeAidsForService(mService, CardEmulation.CATEGORY_PAYMENT));
+        assertNull(instance.getAidsForService(mService, CardEmulation.CATEGORY_PAYMENT));
     }
 
     @Test
@@ -186,64 +196,63 @@
         CardEmulation instance = CardEmulation.getInstance(mAdapter);
         Activity activity = createAndResumeActivity();
 
-        Assert.assertTrue(instance.setPreferredService(activity, mService));
-        Assert.assertTrue(instance.unsetPreferredService(activity));
+        assertTrue(instance.setPreferredService(activity, mService));
+        assertTrue(instance.unsetPreferredService(activity));
     }
 
     @Test
     public void testSupportsAidPrefixRegistration() throws RemoteException {
         CardEmulation instance = CardEmulation.getInstance(mAdapter);
         boolean result = instance.supportsAidPrefixRegistration();
-        Assert.assertTrue(result);
+        assertTrue(result);
     }
 
     @Test
     public void testGetAidsForPreferredPaymentService() throws RemoteException {
         CardEmulation instance = CardEmulation.getInstance(mAdapter);
         Activity activity = createAndResumeActivity();
-        Assert.assertTrue(instance.setPreferredService(activity, mService));
+        assertTrue(instance.setPreferredService(activity, mService));
 
         List<String> result = instance.getAidsForPreferredPaymentService();
 
-        Assert.assertEquals(result, PAYMENT_AIDS);
+        assertEquals(result, PAYMENT_AIDS);
     }
 
     @Test
     public void testGetRouteDestinationForHostService() throws RemoteException {
         CardEmulation instance = CardEmulation.getInstance(mAdapter);
         Activity activity = createAndResumeActivity();
-        Assert.assertTrue(instance.setPreferredService(activity, mService));
+        assertTrue(instance.setPreferredService(activity, mService));
 
         String result = instance.getRouteDestinationForPreferredPaymentService();
 
-        Assert.assertEquals("Host", result);
+        assertEquals("Host", result);
     }
 
     @Test
     public void testGetRouteDestinationForOffHostService() throws RemoteException {
         CardEmulation instance = CardEmulation.getInstance(mAdapter);
         Activity activity = createAndResumeActivity();
-        Assert.assertTrue(
-            instance.setPreferredService(activity,
+        assertTrue(instance.setPreferredService(activity,
                 new ComponentName(mContext, CtsMyOffHostApduService.class)));
 
         String result = instance.getRouteDestinationForPreferredPaymentService();
 
-        Assert.assertEquals("OffHost", result);
+        assertEquals("OffHost", result);
 
         // Unset preferred service
-        Assert.assertTrue(instance.unsetPreferredService(activity));
+        assertTrue(instance.unsetPreferredService(activity));
     }
 
     @Test
     public void testGetDescriptionForPreferredPaymentService() throws RemoteException {
         CardEmulation instance = CardEmulation.getInstance(mAdapter);
         Activity activity = createAndResumeActivity();
-        Assert.assertTrue(instance.setPreferredService(activity, mService));
+        assertTrue(instance.setPreferredService(activity, mService));
 
         CharSequence result = instance.getDescriptionForPreferredPaymentService();
 
-        Assert.assertEquals(result.toString(),
+        assertEquals(result.toString(),
             mContext.getResources().getString(getResIdForServiceClass(CtsMyHostApduService.class)));
     }
 
@@ -256,7 +265,7 @@
             instance.getServices(
                 CardEmulation.CATEGORY_PAYMENT, mContext.getUser().getIdentifier());
 
-        Assert.assertNotNull(result);
+        assertNotNull(result);
     }
 
     @Test
@@ -267,7 +276,7 @@
         List<ApduServiceInfo> result =
             instance.getServices(CardEmulation.CATEGORY_OTHER, mContext.getUser().getIdentifier());
 
-        Assert.assertNotNull(result);
+        assertNotNull(result);
     }
 
     @Test
@@ -280,8 +289,7 @@
         ComponentName paymentService = CardEmulation.getPreferredPaymentService(
                 ApplicationProvider.getApplicationContext());
 
-        Assert.assertEquals(paymentService,
-                ComponentName.unflattenFromString(expectedPaymentService));
+        assertEquals(paymentService, ComponentName.unflattenFromString(expectedPaymentService));
     }
 
     @Test
@@ -344,7 +352,7 @@
                     String testName = new Object() {
                     }.getClass().getEnclosingMethod().getName();
                     String annotationStringHex = HexFormat.of().toHexDigits(testName.hashCode());
-                    Assert.assertTrue(cardEmulation.registerPollingLoopFilterForService(
+                    assertTrue(cardEmulation.registerPollingLoopFilterForService(
                             customServiceName,
                             annotationStringHex, false));
                     ArrayList<PollingFrame> frames = new ArrayList<PollingFrame>(6);
@@ -364,7 +372,7 @@
                         Arrays.asList(frames.get(2), frames.get(6)));
                     notifyPollingLoopAndWait(/* framesToSend = */ frames, framesToReceive,
                         CustomHostApduService.class.getName());
-                    Assert.assertTrue(cardEmulation.removePollingLoopFilterForService(
+                    assertTrue(cardEmulation.removePollingLoopFilterForService(
                         customServiceName, annotationStringHex));
                     adapter.notifyHceDeactivated();
                 });
@@ -441,7 +449,7 @@
                     handler, Activity.RESULT_OK, null, null);
             try {
                 if (!latch.await(5, TimeUnit.SECONDS)) {
-                    Assert.fail("Did not receive the expected broadcast within the elapsed time");
+                    fail("Did not receive the expected broadcast within the elapsed time");
                 }
             } catch (InterruptedException ie) {
             }
@@ -524,7 +532,7 @@
         void waitForEvents() {
             try {
                 if (!mLatch.await(5, TimeUnit.SECONDS)) {
-                    Assert.fail("Did not receive all events within the elapsed time");
+                    fail("Did not receive all events within the elapsed time");
                 }
             } catch (InterruptedException ie) {
             }
@@ -533,7 +541,7 @@
         void waitForEvents(int type) {
             try {
                 if (!mLatches[type].await(5, TimeUnit.SECONDS)) {
-                    Assert.fail("Did not receive all events within the elapsed time");
+                    fail("Did not receive all events within the elapsed time");
                 }
             } catch (InterruptedException ie) {
             }
@@ -614,52 +622,46 @@
         sCurrentPollLoopReceiver = eventPollLoopReceiver;
         Activity activity = createAndResumeActivity();
         try {
-            Assert.assertTrue(
-                    cardEmulation.setPreferredService(
+            assertTrue(cardEmulation.setPreferredService(
                             activity, new ComponentName(mContext, CustomHostApduService.class)));
             ensurePreferredService(CustomHostApduService.class);
             eventPollLoopReceiver.setNumEventsToWaitFor(1);
-            Assert.assertTrue(
-                    cardEmulation.setPreferredService(
+            assertTrue(cardEmulation.setPreferredService(
                             activity, new ComponentName(mContext, CtsMyHostApduService.class)));
             eventPollLoopReceiver.waitForEvents();
             ensurePreferredService(CtsMyHostApduService.class);
 
             EventPollLoopReceiver.EventLogEntry event = eventPollLoopReceiver.mEvents.getLast();
-            Assert.assertEquals(
-                    CtsMyHostApduService.class.getPackageName(), event.mServicePackageName);
-            Assert.assertEquals(EventPollLoopReceiver.PREFERRED_SERVICE, event.mEventType);
-            Assert.assertTrue((boolean)event.mState);
+            assertEquals(CtsMyHostApduService.class.getPackageName(), event.mServicePackageName);
+            assertEquals(EventPollLoopReceiver.PREFERRED_SERVICE, event.mEventType);
+            assertTrue((boolean)event.mState);
 
-            Assert.assertFalse(adapter.isObserveModeEnabled());
+            assertFalse(adapter.isObserveModeEnabled());
             eventPollLoopReceiver.setNumEventsToWaitFor(1);
 
-            Assert.assertTrue(adapter.setObserveModeEnabled(true));
+            assertTrue(adapter.setObserveModeEnabled(true));
             eventPollLoopReceiver.waitForEvents();
             event = eventPollLoopReceiver.mEvents.getLast();
-            Assert.assertEquals(
-                    CtsMyHostApduService.class.getPackageName(), event.mServicePackageName);
-            Assert.assertEquals(EventPollLoopReceiver.OBSERVE_MODE, event.mEventType);
-            Assert.assertTrue((boolean)event.mState);
-            Assert.assertTrue(adapter.isObserveModeEnabled());
+            assertEquals(CtsMyHostApduService.class.getPackageName(), event.mServicePackageName);
+            assertEquals(EventPollLoopReceiver.OBSERVE_MODE, event.mEventType);
+            assertTrue((boolean)event.mState);
+            assertTrue(adapter.isObserveModeEnabled());
             eventPollLoopReceiver.setNumEventsToWaitFor(1);
 
-            Assert.assertTrue(adapter.setObserveModeEnabled(false));
+            assertTrue(adapter.setObserveModeEnabled(false));
             eventPollLoopReceiver.waitForEvents();
             event = eventPollLoopReceiver.mEvents.getLast();
-            Assert.assertEquals(
-                    CtsMyHostApduService.class.getPackageName(), event.mServicePackageName);
-            Assert.assertEquals(EventPollLoopReceiver.OBSERVE_MODE, event.mEventType);
-            Assert.assertFalse((boolean)event.mState);
-            Assert.assertFalse(adapter.isObserveModeEnabled());
+            assertEquals(CtsMyHostApduService.class.getPackageName(), event.mServicePackageName);
+            assertEquals(EventPollLoopReceiver.OBSERVE_MODE, event.mEventType);
+            assertFalse((boolean)event.mState);
+            assertFalse(adapter.isObserveModeEnabled());
             eventPollLoopReceiver.setNumEventsToWaitFor(1);
-            Assert.assertTrue(cardEmulation.unsetPreferredService(activity));
+            assertTrue(cardEmulation.unsetPreferredService(activity));
             eventPollLoopReceiver.waitForEvents();
             event = eventPollLoopReceiver.mEvents.getLast();
-            Assert.assertEquals(
-                    CtsMyHostApduService.class.getPackageName(), event.mServicePackageName);
-            Assert.assertEquals(EventPollLoopReceiver.PREFERRED_SERVICE, event.mEventType);
-            Assert.assertFalse((boolean)event.mState);
+            assertEquals(CtsMyHostApduService.class.getPackageName(), event.mServicePackageName);
+            assertEquals(EventPollLoopReceiver.PREFERRED_SERVICE, event.mEventType);
+            assertFalse((boolean)event.mState);
         } finally {
             cardEmulation.unsetPreferredService(activity);
             activity.finish();
@@ -699,8 +701,7 @@
                 WalletRoleTestUtils.WALLET_HOLDER_PACKAGE_NAME,
                 () -> {
                     eventPollLoopReceiver.waitForEvents();
-                    Assert.assertTrue(
-                            "Didn't receive any events",
+                    assertTrue("Didn't receive any events",
                             startingEvents < eventPollLoopReceiver.mEvents.size());
                     int numEvents = eventPollLoopReceiver.mEvents.size();
                     int numWalletEvents =
@@ -709,19 +710,16 @@
 
                     eventPollLoopReceiver.setNumEventsToWaitFor(1);
                     walletRolePollLoopReceiver.setNumEventsToWaitFor(1);
-                    Assert.assertTrue(
-                            cardEmulation.setPreferredService(
+                    assertTrue(cardEmulation.setPreferredService(
                                     activity,
                                     new ComponentName(mContext, CtsMyHostApduService.class)));
 
                     try {
                         eventPollLoopReceiver.waitForEvents();
                         walletRolePollLoopReceiver.waitForEvents();
-                        Assert.assertTrue(
-                                "Didn't receive event",
+                        assertTrue("Didn't receive event",
                                 numEvents < eventPollLoopReceiver.mEvents.size());
-                        Assert.assertTrue(
-                                "Didn't receive event",
+                        assertTrue("Didn't receive event",
                                 numWalletEvents < walletRolePollLoopReceiver.mEvents.size());
 
                         EventPollLoopReceiver.EventLogEntry lostEvent =
@@ -729,44 +727,40 @@
                         EventPollLoopReceiver.EventLogEntry gainedEvent =
                                 eventPollLoopReceiver.mEvents.getLast();
 
-                        Assert.assertEquals(WALLET_HOLDER_PACKAGE_NAME,
-                                            lostEvent.mServicePackageName);
-                        Assert.assertEquals(
-                                EventPollLoopReceiver.PREFERRED_SERVICE, lostEvent.mEventType);
-                        Assert.assertFalse((boolean)lostEvent.mState);
+                        assertEquals(WALLET_HOLDER_PACKAGE_NAME, lostEvent.mServicePackageName);
+                        assertEquals(EventPollLoopReceiver.PREFERRED_SERVICE, lostEvent.mEventType);
+                        assertFalse((boolean)lostEvent.mState);
 
-                        Assert.assertEquals(
+                        assertEquals(
                                 CtsMyHostApduService.class.getPackageName(),
                                 gainedEvent.mServicePackageName);
-                        Assert.assertEquals(
+                        assertEquals(
                                 EventPollLoopReceiver.PREFERRED_SERVICE, gainedEvent.mEventType);
-                        Assert.assertTrue((boolean)gainedEvent.mState);
+                        assertTrue((boolean)gainedEvent.mState);
 
-                        Assert.assertFalse(adapter.isObserveModeEnabled());
+                        assertFalse(adapter.isObserveModeEnabled());
                         eventPollLoopReceiver.setNumEventsToWaitFor(1);
-                        Assert.assertTrue(adapter.setObserveModeEnabled(true));
+                        assertTrue(adapter.setObserveModeEnabled(true));
                         eventPollLoopReceiver.waitForEvents();
                         EventPollLoopReceiver.EventLogEntry event =
                                 eventPollLoopReceiver.mEvents.getLast();
-                        Assert.assertEquals(
-                                CtsMyHostApduService.class.getPackageName(),
+                        assertEquals(CtsMyHostApduService.class.getPackageName(),
                                 event.mServicePackageName);
-                        Assert.assertEquals(EventPollLoopReceiver.OBSERVE_MODE, event.mEventType);
-                        Assert.assertTrue((boolean)event.mState);
-                        Assert.assertTrue(adapter.isObserveModeEnabled());
+                        assertEquals(EventPollLoopReceiver.OBSERVE_MODE, event.mEventType);
+                        assertTrue((boolean)event.mState);
+                        assertTrue(adapter.isObserveModeEnabled());
 
                         eventPollLoopReceiver.setNumEventsToWaitFor(1,
                                 EventPollLoopReceiver.OBSERVE_MODE);
-                        Assert.assertTrue(adapter.setObserveModeEnabled(false));
+                        assertTrue(adapter.setObserveModeEnabled(false));
                         eventPollLoopReceiver.waitForEvents(EventPollLoopReceiver.OBSERVE_MODE);
                         event = eventPollLoopReceiver
                                 .mSpecificEvents[EventPollLoopReceiver.OBSERVE_MODE].getLast();
-                        Assert.assertEquals(
-                                CtsMyHostApduService.class.getPackageName(),
+                        assertEquals(CtsMyHostApduService.class.getPackageName(),
                                 event.mServicePackageName);
-                        Assert.assertEquals(EventPollLoopReceiver.OBSERVE_MODE, event.mEventType);
-                        Assert.assertFalse((boolean)event.mState);
-                        Assert.assertFalse(adapter.isObserveModeEnabled());
+                        assertEquals(EventPollLoopReceiver.OBSERVE_MODE, event.mEventType);
+                        assertFalse((boolean)event.mState);
+                        assertFalse(adapter.isObserveModeEnabled());
                         numEvents = eventPollLoopReceiver.mEvents.size();
                         numWalletEvents =
                         walletRolePollLoopReceiver
@@ -774,15 +768,13 @@
                         eventPollLoopReceiver.setNumEventsToWaitFor(1);
                         walletRolePollLoopReceiver
                                 .setNumEventsToWaitFor(1, EventPollLoopReceiver.PREFERRED_SERVICE);
-                        Assert.assertTrue(cardEmulation.unsetPreferredService(activity));
+                        assertTrue(cardEmulation.unsetPreferredService(activity));
                         eventPollLoopReceiver.waitForEvents();
                         walletRolePollLoopReceiver
                                 .waitForEvents(EventPollLoopReceiver.PREFERRED_SERVICE);
-                        Assert.assertTrue(
-                                "Didn't receive event",
+                        assertTrue("Didn't receive event",
                                 numEvents < eventPollLoopReceiver.mEvents.size());
-                        Assert.assertTrue(
-                                "Didn't receive event",
+                        assertTrue("Didn't receive event",
                                 numWalletEvents < walletRolePollLoopReceiver
                                         .mSpecificEvents[EventPollLoopReceiver.PREFERRED_SERVICE]
                                                 .size());
@@ -791,17 +783,14 @@
                                 .mSpecificEvents[EventPollLoopReceiver.PREFERRED_SERVICE].getLast();
                         lostEvent = eventPollLoopReceiver.mEvents.getLast();
 
-                        Assert.assertEquals(
-                                CtsMyHostApduService.class.getPackageName(),
+                        assertEquals(CtsMyHostApduService.class.getPackageName(),
                                 lostEvent.mServicePackageName);
-                        Assert.assertEquals(
-                                EventPollLoopReceiver.PREFERRED_SERVICE, lostEvent.mEventType);
-                        Assert.assertFalse((boolean)lostEvent.mState);
+                        assertEquals(EventPollLoopReceiver.PREFERRED_SERVICE, lostEvent.mEventType);
+                        assertFalse((boolean)lostEvent.mState);
 
-                        Assert.assertEquals(WALLET_HOLDER_PACKAGE_NAME,
-                                            gainedEvent.mServicePackageName);
-                        Assert.assertEquals(
-                                EventPollLoopReceiver.PREFERRED_SERVICE, gainedEvent.mEventType);
+                        assertEquals(WALLET_HOLDER_PACKAGE_NAME, gainedEvent.mServicePackageName);
+                        assertEquals(
+                            EventPollLoopReceiver.PREFERRED_SERVICE, gainedEvent.mEventType);
                     } finally {
                         if (activity != null) {
                             cardEmulation.unsetPreferredService(activity);
@@ -847,29 +836,29 @@
 
             runAndWaitForNfcAdapterStateChange(
                     () -> {
-                        Assert.assertTrue(adapter.disable());
+                        assertTrue(adapter.disable());
                     },
                     NfcAdapter.STATE_OFF);
 
             eventPollLoopReceiver.waitForEvents();
-            Assert.assertFalse(adapter.isEnabled());
+            assertFalse(adapter.isEnabled());
             EventPollLoopReceiver.EventLogEntry event = eventPollLoopReceiver.mEvents.getLast();
-            Assert.assertEquals(EventPollLoopReceiver.NFC_STATE_CHANGED, event.mEventType);
-            Assert.assertEquals(NfcAdapter.STATE_OFF, event.mState);
+            assertEquals(EventPollLoopReceiver.NFC_STATE_CHANGED, event.mEventType);
+            assertEquals(NfcAdapter.STATE_OFF, event.mState);
 
             eventPollLoopReceiver.setNumEventsToWaitFor(2);
 
             runAndWaitForNfcAdapterStateChange(
                     () -> {
-                        Assert.assertTrue(adapter.enable());
+                        assertTrue(adapter.enable());
                     },
                     NfcAdapter.STATE_ON);
 
             eventPollLoopReceiver.waitForEvents();
-            Assert.assertTrue(adapter.isEnabled());
+            assertTrue(adapter.isEnabled());
             event = eventPollLoopReceiver.mEvents.getLast();
-            Assert.assertEquals(EventPollLoopReceiver.NFC_STATE_CHANGED, event.mEventType);
-            Assert.assertEquals(NfcAdapter.STATE_ON, event.mState);
+            assertEquals(EventPollLoopReceiver.NFC_STATE_CHANGED, event.mEventType);
+            assertEquals(NfcAdapter.STATE_ON, event.mState);
         } finally {
             adapter.enable();
             activity.finish();
@@ -932,7 +921,7 @@
              * and OID as not a VS response, so this will cause a hardware error */
             adapter.sendVendorNciMessage(0x00, 0x03, 0x00, new byte[0]);
             if (!callback.mErrorLatch.await(5, TimeUnit.SECONDS)) {
-                Assert.fail("Did not receive internal error event within the elapsed time");
+                fail("Did not receive internal error event within the elapsed time");
             }
             // ToDo: can we query the recovery_option from the NfcConfig to make sure
             // the error matches the config?
@@ -945,13 +934,12 @@
 
                     // The NFC service has died, so we should wait for it to come back up.
                     if (!adapterStateLatch.await(20, TimeUnit.SECONDS)) {
-                        Assert.fail("NFC service did not come back up within the elapsed time");
+                        fail("NFC service did not come back up within the elapsed time");
                     }
 
-                    Assert.assertEquals(adapter.getAdapterState(), NfcAdapter.STATE_ON);
-                    Assert.assertTrue(NfcUtils.enableNfc(adapter, mContext));
-                    Assert.assertTrue(
-                            cardEmulation.setPreferredService(
+                    assertEquals(adapter.getAdapterState(), NfcAdapter.STATE_ON);
+                    assertTrue(NfcUtils.enableNfc(adapter, mContext));
+                    assertTrue(cardEmulation.setPreferredService(
                                     activity, new ComponentName(mContext,
                                     CustomHostApduService.class)));
                 }
@@ -961,11 +949,11 @@
                     // send a hardware error. Wait for the adapter to come back up to prevent
                     // other tests from failing.
                     if (!adapterStateLatch.await(20, TimeUnit.SECONDS)) {
-                        Assert.fail("NFC service did not come back up within the elapsed time");
+                        fail("NFC service did not come back up within the elapsed time");
                     }
                     break;
                 default:
-                    Assert.fail("Expected a hardware error or timeout error but got: "
+                    fail("Expected a hardware error or timeout error but got: "
                                     + callback.mErrorType);
             }
         } finally {
@@ -984,7 +972,7 @@
         Activity activity = createAndResumeActivity();
         final CardEmulation cardEmulation = CardEmulation.getInstance(adapter);
         try {
-            Assert.assertTrue(cardEmulation.setPreferredService(activity,
+            assertTrue(cardEmulation.setPreferredService(activity,
                     new ComponentName(mContext,
                             CtsMyHostApduService.class)));
             ArrayList<PollingFrame> frames = new ArrayList<PollingFrame>(6);
@@ -997,7 +985,7 @@
             ensurePreferredService(CtsMyHostApduService.class);
             notifyPollingLoopAndWait(frames, CtsMyHostApduService.class.getName());
         } finally {
-            Assert.assertTrue(cardEmulation.unsetPreferredService(activity));
+            assertTrue(cardEmulation.unsetPreferredService(activity));
             activity.finish();
             adapter.notifyHceDeactivated();
         }
@@ -1014,29 +1002,27 @@
         try {
             ComponentName backgroundService =
                     new ComponentName(mContext, BackgroundHostApduService.class);
-            Assert.assertTrue(
-                    cardEmulation.setShouldDefaultToObserveModeForService(
+            assertTrue(cardEmulation.setShouldDefaultToObserveModeForService(
                             backgroundService, false));
 
-            Assert.assertTrue(cardEmulation.setPreferredService(activity, backgroundService));
+            assertTrue(cardEmulation.setPreferredService(activity, backgroundService));
             ensurePreferredService(BackgroundHostApduService.class);
 
-            Assert.assertFalse(adapter.isObserveModeEnabled());
-            Assert.assertTrue(
-                    cardEmulation.setShouldDefaultToObserveModeForService(backgroundService, true));
+            assertFalse(adapter.isObserveModeEnabled());
+            assertTrue(
+                cardEmulation.setShouldDefaultToObserveModeForService(backgroundService, true));
             // Observe mode is set asynchronously, so just wait a bit to let it happen.
             try {
                 CommonTestUtils.waitUntil(
                         "Observe mode hasn't been set", 1, () -> adapter.isObserveModeEnabled());
             } catch (InterruptedException|AssertionError e) {
             }
-            Assert.assertTrue(adapter.isObserveModeEnabled());
+            assertTrue(adapter.isObserveModeEnabled());
         } finally {
-            Assert.assertTrue(cardEmulation.unsetPreferredService(activity));
+            assertTrue(cardEmulation.unsetPreferredService(activity));
             ComponentName backgroundService =
                     new ComponentName(mContext, BackgroundHostApduService.class);
-            Assert.assertTrue(
-                    cardEmulation.setShouldDefaultToObserveModeForService(
+            assertTrue(cardEmulation.setShouldDefaultToObserveModeForService(
                             backgroundService, false));
             activity.finish();
             adapter.notifyHceDeactivated();
@@ -1053,12 +1039,12 @@
         final CardEmulation cardEmulation = CardEmulation.getInstance(adapter);
         try {
             ComponentName ctsService = new ComponentName(mContext, CtsMyHostApduService.class);
-            Assert.assertTrue(cardEmulation.setPreferredService(activity, ctsService));
+            assertTrue(cardEmulation.setPreferredService(activity, ctsService));
             ensurePreferredService(CtsMyHostApduService.class);
 
-            Assert.assertFalse(adapter.isObserveModeEnabled());
+            assertFalse(adapter.isObserveModeEnabled());
         } finally {
-            Assert.assertTrue(cardEmulation.unsetPreferredService(activity));
+            assertTrue(cardEmulation.unsetPreferredService(activity));
             activity.finish();
             adapter.notifyHceDeactivated();
         }
@@ -1075,15 +1061,14 @@
         try {
             ComponentName backgroundService =
                     new ComponentName(mContext, BackgroundHostApduService.class);
-            Assert.assertTrue(
-                    cardEmulation.setShouldDefaultToObserveModeForService(
+            assertTrue(cardEmulation.setShouldDefaultToObserveModeForService(
                             backgroundService, true));
-            Assert.assertTrue(cardEmulation.setPreferredService(activity, backgroundService));
+            assertTrue(cardEmulation.setPreferredService(activity, backgroundService));
             ensurePreferredService(BackgroundHostApduService.class);
 
-            Assert.assertTrue(adapter.isObserveModeEnabled());
+            assertTrue(adapter.isObserveModeEnabled());
         } finally {
-            Assert.assertTrue(cardEmulation.unsetPreferredService(activity));
+            assertTrue(cardEmulation.unsetPreferredService(activity));
             activity.finish();
             adapter.notifyHceDeactivated();
         }
@@ -1099,12 +1084,12 @@
         final CardEmulation cardEmulation = CardEmulation.getInstance(adapter);
         try {
             ComponentName ctsService = new ComponentName(mContext, CtsMyOffHostApduService.class);
-            Assert.assertTrue(cardEmulation.setPreferredService(activity, ctsService));
+            assertTrue(cardEmulation.setPreferredService(activity, ctsService));
             ensurePreferredService(CtsMyOffHostApduService.class);
 
-            Assert.assertFalse(adapter.isObserveModeEnabled());
+            assertFalse(adapter.isObserveModeEnabled());
         } finally {
-            Assert.assertTrue(cardEmulation.unsetPreferredService(activity));
+            assertTrue(cardEmulation.unsetPreferredService(activity));
             activity.finish();
             adapter.notifyHceDeactivated();
         }
@@ -1121,12 +1106,12 @@
         try {
             ComponentName offhostService =
                     new ComponentName(mContext, CtsMyOffHostDefaultToObserveApduService.class);
-            Assert.assertTrue(cardEmulation.setPreferredService(activity, offhostService));
+            assertTrue(cardEmulation.setPreferredService(activity, offhostService));
             ensurePreferredService(CtsMyOffHostDefaultToObserveApduService.class);
 
-            Assert.assertTrue(adapter.isObserveModeEnabled());
+            assertTrue(adapter.isObserveModeEnabled());
         } finally {
-            Assert.assertTrue(cardEmulation.unsetPreferredService(activity));
+            assertTrue(cardEmulation.unsetPreferredService(activity));
             activity.finish();
             adapter.notifyHceDeactivated();
         }
@@ -1140,7 +1125,7 @@
         Activity activity = createAndResumeActivity();
         final CardEmulation cardEmulation = CardEmulation.getInstance(adapter);
         try {
-            Assert.assertTrue(cardEmulation.setPreferredService(activity,
+            assertTrue(cardEmulation.setPreferredService(activity,
                     new ComponentName(mContext,
                             CtsMyHostApduService.class)));
             ArrayList<PollingFrame> frames = new ArrayList<PollingFrame>(4);
@@ -1157,7 +1142,7 @@
                 try {
                     sCurrentPollLoopReceiver.wait(5000);
                 } catch (InterruptedException ie) {
-                    Assert.assertNull(ie);
+                    assertNull(ie);
                 }
             }
             sCurrentPollLoopReceiver.test();
@@ -1205,7 +1190,7 @@
         final CardEmulation cardEmulation = CardEmulation.getInstance(adapter);
         WalletRoleTestUtils.runWithRole(mContext, WalletRoleTestUtils.WALLET_HOLDER_PACKAGE_NAME,
                 () -> {
-                    Assert.assertTrue(cardEmulation.setPreferredService(activity,
+                    assertTrue(cardEmulation.setPreferredService(activity,
                             new ComponentName(mContext,
                                     CtsMyHostApduService.class)));
                     ArrayList<PollingFrame> frames = new ArrayList<PollingFrame>(6);
@@ -1217,7 +1202,7 @@
                     frames.add(createFrame(PollingFrame.POLLING_LOOP_TYPE_OFF));
                     ensurePreferredService(CtsMyHostApduService.class);
                     notifyPollingLoopAndWait(frames, CtsMyHostApduService.class.getName());
-                    Assert.assertTrue(cardEmulation.unsetPreferredService(activity));
+                    assertTrue(cardEmulation.unsetPreferredService(activity));
                     activity.finish();
                     adapter.notifyHceDeactivated();
                 });
@@ -1264,11 +1249,11 @@
         CardEmulation cardEmulation = CardEmulation.getInstance(adapter);
         Activity activity = createAndResumeActivity();
         try {
-            Assert.assertTrue(cardEmulation.setPreferredService(activity,
+            assertTrue(cardEmulation.setPreferredService(activity,
                     new ComponentName(mContext, CustomHostApduService.class)));
 
             ensurePreferredService(CustomHostApduService.class);
-            Assert.assertTrue(adapter.setObserveModeEnabled(true));
+            assertTrue(adapter.setObserveModeEnabled(true));
 
             ComponentName backgroundServiceName = new ComponentName(mContext,
                     BackgroundHostApduService.class);
@@ -1276,7 +1261,7 @@
             }.getClass().getEnclosingMethod().getName();
             String annotationStringHex1 =
                     HexFormat.of().toHexDigits((testName + "background").hashCode());
-            Assert.assertTrue(cardEmulation.registerPollingLoopFilterForService(
+            assertTrue(cardEmulation.registerPollingLoopFilterForService(
                     backgroundServiceName, annotationStringHex1, false));
             ArrayList<PollingFrame> frames = new ArrayList<PollingFrame>(2);
             frames.add(createFrameWithData(PollingFrame.POLLING_LOOP_TYPE_UNKNOWN,
@@ -1287,15 +1272,15 @@
 
             String annotationStringHex2 =
                     HexFormat.of().toHexDigits((testName + "custom").hashCode());
-            Assert.assertTrue(cardEmulation.registerPollingLoopFilterForService(
+            assertTrue(cardEmulation.registerPollingLoopFilterForService(
                     customServiceName, annotationStringHex2, false));
             frames.add(createFrameWithData(PollingFrame.POLLING_LOOP_TYPE_UNKNOWN,
                     HexFormat.of().parseHex(annotationStringHex2)));
 
             notifyPollingLoopAndWait(frames, /* serviceName = */ null);
-            Assert.assertTrue(cardEmulation.removePollingLoopFilterForService(
+            assertTrue(cardEmulation.removePollingLoopFilterForService(
                 backgroundServiceName, annotationStringHex1));
-            Assert.assertTrue(cardEmulation.removePollingLoopFilterForService(
+            assertTrue(cardEmulation.removePollingLoopFilterForService(
                 customServiceName, annotationStringHex2));
         } finally {
             cardEmulation.unsetPreferredService(activity);
@@ -1312,11 +1297,11 @@
         CardEmulation cardEmulation = CardEmulation.getInstance(adapter);
         Activity activity = createAndResumeActivity();
         try {
-            Assert.assertTrue(cardEmulation.setPreferredService(activity,
+            assertTrue(cardEmulation.setPreferredService(activity,
                     new ComponentName(mContext, CtsMyHostApduService.class)));
 
             ensurePreferredService(CtsMyHostApduService.class);
-            Assert.assertTrue(adapter.setObserveModeEnabled(true));
+            assertTrue(adapter.setObserveModeEnabled(true));
 
             ComponentName backgroundServiceName = new ComponentName(mContext,
                     BackgroundHostApduService.class);
@@ -1324,7 +1309,7 @@
             }.getClass().getEnclosingMethod().getName();
             String annotationStringHex1 =
                     HexFormat.of().toHexDigits((testName + "background").hashCode());
-            Assert.assertTrue(cardEmulation.registerPollingLoopFilterForService(
+            assertTrue(cardEmulation.registerPollingLoopFilterForService(
                     backgroundServiceName, annotationStringHex1, false));
             ArrayList<PollingFrame> frames = new ArrayList<PollingFrame>(2);
             frames.add(createFrameWithData(PollingFrame.POLLING_LOOP_TYPE_UNKNOWN,
@@ -1335,15 +1320,15 @@
 
             String annotationStringHex2 =
                     HexFormat.of().toHexDigits((testName + "custom").hashCode());
-            Assert.assertTrue(cardEmulation.registerPollingLoopFilterForService(
+            assertTrue(cardEmulation.registerPollingLoopFilterForService(
                     customServiceName, annotationStringHex2, false));
             frames.add(createFrameWithData(PollingFrame.POLLING_LOOP_TYPE_UNKNOWN,
                     HexFormat.of().parseHex(annotationStringHex2)));
 
             notifyPollingLoopAndWait(frames, /* serviceName = */ null);
-            Assert.assertTrue(cardEmulation.removePollingLoopFilterForService(
+            assertTrue(cardEmulation.removePollingLoopFilterForService(
                 backgroundServiceName, annotationStringHex1));
-            Assert.assertTrue(cardEmulation.removePollingLoopFilterForService(
+            assertTrue(cardEmulation.removePollingLoopFilterForService(
                 customServiceName, annotationStringHex2));
         } finally {
             cardEmulation.unsetPreferredService(activity);
@@ -1362,7 +1347,7 @@
         String testName = new Object() {
         }.getClass().getEnclosingMethod().getName();
         String annotationStringHex = HexFormat.of().toHexDigits(testName.hashCode());
-        Assert.assertTrue(cardEmulation.registerPollingLoopFilterForService(customServiceName,
+        assertTrue(cardEmulation.registerPollingLoopFilterForService(customServiceName,
                 annotationStringHex, false));
         ArrayList<PollingFrame> frames = new ArrayList<PollingFrame>(1);
         frames.add(createFrameWithData(PollingFrame.POLLING_LOOP_TYPE_UNKNOWN,
@@ -1373,7 +1358,7 @@
         notifyPollingLoopAndWait(/* framesToSend = */ frames,
             /* framesToReceive = */ new ArrayList<PollingFrame>(Arrays.asList(frames.get(0))),
             CustomHostApduService.class.getName());
-        Assert.assertTrue(cardEmulation.removePollingLoopFilterForService(customServiceName,
+        assertTrue(cardEmulation.removePollingLoopFilterForService(customServiceName,
             annotationStringHex));
         adapter.notifyHceDeactivated();
     }
@@ -1390,7 +1375,7 @@
         String annotationStringHexPrefix = HexFormat.of().toHexDigits(testName.hashCode());
         String annotationStringHex = annotationStringHexPrefix + "123456789ABCDF";
         String annotationStringHexPattern = annotationStringHexPrefix + ".*";
-        Assert.assertTrue(cardEmulation.registerPollingLoopPatternFilterForService(
+        assertTrue(cardEmulation.registerPollingLoopPatternFilterForService(
                 customServiceName, annotationStringHexPattern, false));
         ArrayList<PollingFrame> frames = new ArrayList<PollingFrame>(1);
         frames.add(createFrameWithData(PollingFrame.POLLING_LOOP_TYPE_UNKNOWN,
@@ -1400,7 +1385,7 @@
         notifyPollingLoopAndWait(/* framesToSend = */ frames,
                 /* framesToReceive = */ new ArrayList<PollingFrame>(Arrays.asList(frames.get(0))),
                 CustomHostApduService.class.getName());
-        Assert.assertTrue(cardEmulation.removePollingLoopPatternFilterForService(customServiceName,
+        assertTrue(cardEmulation.removePollingLoopPatternFilterForService(customServiceName,
                 annotationStringHexPrefix));
         adapter.notifyHceDeactivated();
     }
@@ -1418,7 +1403,7 @@
             originalDefault = setDefaultPaymentService(CustomHostApduService.class);
             ComponentName ctsMyServiceName = new ComponentName(mContext,
                     CtsMyHostApduService.class);
-            Assert.assertTrue(cardEmulation.setPreferredService(activity, ctsMyServiceName));
+            assertTrue(cardEmulation.setPreferredService(activity, ctsMyServiceName));
             ComponentName customServiceName = new ComponentName(mContext,
                     CustomHostApduService.class);
             ComponentName backgroundServiceName = new ComponentName(mContext,
@@ -1426,11 +1411,11 @@
             String testName = new Object() {
             }.getClass().getEnclosingMethod().getName();
             String annotationStringHex = HexFormat.of().toHexDigits(testName.hashCode());
-            Assert.assertTrue(cardEmulation.registerPollingLoopFilterForService(customServiceName,
+            assertTrue(cardEmulation.registerPollingLoopFilterForService(customServiceName,
                     annotationStringHex, false));
-            Assert.assertTrue(cardEmulation.registerPollingLoopFilterForService(
+            assertTrue(cardEmulation.registerPollingLoopFilterForService(
                     backgroundServiceName, annotationStringHex, false));
-            Assert.assertTrue(cardEmulation.registerPollingLoopFilterForService(ctsMyServiceName,
+            assertTrue(cardEmulation.registerPollingLoopFilterForService(ctsMyServiceName,
                     annotationStringHex, false));
             ArrayList<PollingFrame> frames = new ArrayList<PollingFrame>(1);
             frames.add(createFrameWithData(PollingFrame.POLLING_LOOP_TYPE_UNKNOWN,
@@ -1438,7 +1423,7 @@
             ensurePreferredService(CtsMyHostApduService.class);
             notifyPollingLoopAndWait(frames, CtsMyHostApduService.class.getName());
         } finally {
-            Assert.assertTrue(cardEmulation.unsetPreferredService(activity));
+            assertTrue(cardEmulation.unsetPreferredService(activity));
             activity.finish();
             setDefaultPaymentService(originalDefault);
             adapter.notifyHceDeactivated();
@@ -1455,25 +1440,25 @@
         ComponentName ctsServiceName = new ComponentName(mContext,
                 CtsMyHostApduService.class);
         try {
-            Assert.assertTrue(cardEmulation.setPreferredService(activity, ctsServiceName));
+            assertTrue(cardEmulation.setPreferredService(activity, ctsServiceName));
             ComponentName backgroundServiceName = new ComponentName(mContext,
                     BackgroundHostApduService.class);
             String testName = new Object() {
             }.getClass().getEnclosingMethod().getName();
             String annotationStringHex = HexFormat.of().toHexDigits(testName.hashCode());
-            Assert.assertTrue(cardEmulation.registerPollingLoopFilterForService(ctsServiceName,
+            assertTrue(cardEmulation.registerPollingLoopFilterForService(ctsServiceName,
                     annotationStringHex, false));
-            Assert.assertTrue(cardEmulation.registerPollingLoopFilterForService(
+            assertTrue(cardEmulation.registerPollingLoopFilterForService(
                     backgroundServiceName, annotationStringHex, false));
             ArrayList<PollingFrame> frames = new ArrayList<PollingFrame>(1);
             frames.add(createFrameWithData(PollingFrame.POLLING_LOOP_TYPE_UNKNOWN,
                     HexFormat.of().parseHex(annotationStringHex)));
             ensurePreferredService(CtsMyHostApduService.class);
             notifyPollingLoopAndWait(frames, CtsMyHostApduService.class.getName());
-            Assert.assertTrue(cardEmulation.removePollingLoopFilterForService(ctsServiceName,
+            assertTrue(cardEmulation.removePollingLoopFilterForService(ctsServiceName,
                     annotationStringHex));
         } finally {
-            Assert.assertTrue(cardEmulation.unsetPreferredService(activity));
+            assertTrue(cardEmulation.unsetPreferredService(activity));
             activity.finish();
             adapter.notifyHceDeactivated();
         }
@@ -1492,23 +1477,23 @@
             originalDefault = setDefaultPaymentService(customServiceName);
             CardEmulation cardEmulation = CardEmulation.getInstance(adapter);
 
-            Assert.assertTrue(cardEmulation.isDefaultServiceForCategory(customServiceName,
+            assertTrue(cardEmulation.isDefaultServiceForCategory(customServiceName,
                     CardEmulation.CATEGORY_PAYMENT));
             ComponentName backgroundServiceName = new ComponentName(mContext,
                     BackgroundHostApduService.class);
             String testName = new Object() {
             }.getClass().getEnclosingMethod().getName();
             String annotationStringHex = HexFormat.of().toHexDigits(testName.hashCode());
-            Assert.assertTrue(cardEmulation.registerPollingLoopFilterForService(customServiceName,
+            assertTrue(cardEmulation.registerPollingLoopFilterForService(customServiceName,
                     annotationStringHex, false));
-            Assert.assertTrue(cardEmulation.registerPollingLoopFilterForService(
+            assertTrue(cardEmulation.registerPollingLoopFilterForService(
                     backgroundServiceName, annotationStringHex, false));
             ArrayList<PollingFrame> frames = new ArrayList<PollingFrame>(1);
             frames.add(createFrameWithData(PollingFrame.POLLING_LOOP_TYPE_UNKNOWN,
                     HexFormat.of().parseHex(annotationStringHex)));
             ensurePreferredService(CustomHostApduService.class);
             notifyPollingLoopAndWait(frames, CustomHostApduService.class.getName());
-            Assert.assertTrue(cardEmulation.removePollingLoopFilterForService(customServiceName,
+            assertTrue(cardEmulation.removePollingLoopFilterForService(customServiceName,
                     annotationStringHex));
         } finally {
             setDefaultPaymentService(originalDefault);
@@ -1542,7 +1527,7 @@
         CardEmulation cardEmulation = CardEmulation.getInstance(adapter);
         try {
             originalDefault = setDefaultPaymentService(CustomHostApduService.class);
-            Assert.assertTrue(cardEmulation.setPreferredService(activity,
+            assertTrue(cardEmulation.setPreferredService(activity,
                     new ComponentName(mContext, CtsMyHostApduService.class)));
             String testName = new Object() {
             }.getClass().getEnclosingMethod().getName();
@@ -1553,7 +1538,7 @@
             ensurePreferredService(CtsMyHostApduService.class);
             notifyPollingLoopAndWait(frames, CtsMyHostApduService.class.getName());
         } finally {
-            Assert.assertTrue(cardEmulation.unsetPreferredService(activity));
+            assertTrue(cardEmulation.unsetPreferredService(activity));
             activity.finish();
             setDefaultPaymentService(originalDefault);
             adapter.notifyHceDeactivated();
@@ -1570,7 +1555,7 @@
         CardEmulation cardEmulation = CardEmulation.getInstance(adapter);
         WalletRoleTestUtils.runWithRole(mContext, WalletRoleTestUtils.WALLET_HOLDER_PACKAGE_NAME,
                 () -> {
-                    Assert.assertTrue(cardEmulation.setPreferredService(activity,
+                    assertTrue(cardEmulation.setPreferredService(activity,
                             new ComponentName(mContext, CtsMyHostApduService.class)));
                     String testName = new Object() {
                     }.getClass().getEnclosingMethod().getName();
@@ -1580,7 +1565,7 @@
                             HexFormat.of().parseHex(annotationStringHex)));
                     ensurePreferredService(CtsMyHostApduService.class);
                     notifyPollingLoopAndWait(frames, CtsMyHostApduService.class.getName());
-                    Assert.assertTrue(cardEmulation.unsetPreferredService(activity));
+                    assertTrue(cardEmulation.unsetPreferredService(activity));
                     activity.finish();
                     adapter.notifyHceDeactivated();
                 });
@@ -1594,7 +1579,7 @@
         CardEmulation cardEmulation = CardEmulation.getInstance(adapter);
         Activity activity = createAndResumeActivity();
         try {
-            Assert.assertTrue(cardEmulation.setPreferredService(activity,
+            assertTrue(cardEmulation.setPreferredService(activity,
                     new ComponentName(mContext, CtsMyHostApduService.class)));
             String testName = new Object() {
             }.getClass().getEnclosingMethod().getName();
@@ -1605,7 +1590,7 @@
             ensurePreferredService(CtsMyHostApduService.class);
             notifyPollingLoopAndWait(frames, CtsMyHostApduService.class.getName());
         } finally {
-            Assert.assertTrue(cardEmulation.unsetPreferredService(activity));
+            assertTrue(cardEmulation.unsetPreferredService(activity));
             activity.finish();
             adapter.notifyHceDeactivated();
         }
@@ -1662,7 +1647,7 @@
         assumeVsrApiGreaterThanUdc();
         runWithRole(mContext, CTS_PACKAGE_NAME, () -> {
             NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
-            Assert.assertTrue(NfcUtils.enableNfc(adapter, mContext));
+            assertTrue(NfcUtils.enableNfc(adapter, mContext));
             assumeObserveModeSupported(adapter);
             adapter.notifyHceDeactivated();
             String testName = new Object() {
@@ -1674,11 +1659,11 @@
             final CardEmulation cardEmulation = CardEmulation.getInstance(adapter);
             try {
                 ensurePreferredService(CtsMyHostApduService.class);
-                Assert.assertTrue(adapter.setObserveModeEnabled(true));
-                Assert.assertTrue(adapter.isObserveModeEnabled());
+                assertTrue(adapter.setObserveModeEnabled(true));
+                assertTrue(adapter.isObserveModeEnabled());
                 List<PollingFrame> receivedFrames =
                         notifyPollingLoopAndWait(frames, CtsMyHostApduService.class.getName());
-                Assert.assertFalse(receivedFrames.get(0).getTriggeredAutoTransact());
+                assertFalse(receivedFrames.get(0).getTriggeredAutoTransact());
                 PollingCheck.check("Observe mode not disabled", 4000,
                         () -> !adapter.isObserveModeEnabled());
                 adapter.notifyHceDeactivated();
@@ -1696,7 +1681,7 @@
     public void testDontAutoDisableObserveModeInForeground() throws Exception {
         assumeVsrApiGreaterThanUdc();
         NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
-        Assert.assertTrue(NfcUtils.enableNfc(adapter, mContext));
+        assertTrue(NfcUtils.enableNfc(adapter, mContext));
         assumeObserveModeSupported(adapter);
         adapter.notifyHceDeactivated();
         String testName = new Object() {
@@ -1708,16 +1693,16 @@
         final CardEmulation cardEmulation = CardEmulation.getInstance(adapter);
         final Activity activity = createAndResumeActivity();
         try {
-            Assert.assertTrue(cardEmulation.setPreferredService(activity,
+            assertTrue(cardEmulation.setPreferredService(activity,
                 new ComponentName(mContext, CtsMyHostApduService.class)));
             ensurePreferredService(CtsMyHostApduService.class);
-            Assert.assertTrue(adapter.setObserveModeEnabled(true));
-            Assert.assertTrue(adapter.isObserveModeEnabled());
+            assertTrue(adapter.setObserveModeEnabled(true));
+            assertTrue(adapter.isObserveModeEnabled());
             List<PollingFrame> receivedFrames =
                     notifyPollingLoopAndWait(frames, CtsMyHostApduService.class.getName());
-            Assert.assertFalse(receivedFrames.get(0).getTriggeredAutoTransact());
+            assertFalse(receivedFrames.get(0).getTriggeredAutoTransact());
             Thread.currentThread().sleep(4000);
-            Assert.assertTrue(adapter.isObserveModeEnabled());
+            assertTrue(adapter.isObserveModeEnabled());
             adapter.notifyHceDeactivated();
         } catch (Exception ex) {
             throw new RuntimeException(ex);
@@ -1732,7 +1717,7 @@
     public void testDontAutoDisableObserveModeInForegroundTwoServices() throws Exception {
         assumeVsrApiGreaterThanUdc();
         NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
-        Assert.assertTrue(NfcUtils.enableNfc(adapter, mContext));
+        assertTrue(NfcUtils.enableNfc(adapter, mContext));
         assumeObserveModeSupported(adapter);
         adapter.notifyHceDeactivated();
         String testName = new Object() {
@@ -1745,27 +1730,27 @@
         ComponentName walletServiceName = WalletRoleTestUtils.getWalletRoleHolderService();
         String annotationStringHex2 = HexFormat.of().toHexDigits((testName).hashCode());
         ComponentName ctsComponentName = new ComponentName(mContext, CtsMyHostApduService.class);
-        Assert.assertTrue(cardEmulation.registerPollingLoopFilterForService(ctsComponentName,
+        assertTrue(cardEmulation.registerPollingLoopFilterForService(ctsComponentName,
                         annotationStringHex2, false));
         ArrayList<PollingFrame> frames2 = new ArrayList<PollingFrame>(1);
         frames2.add(createFrameWithData(PollingFrame.POLLING_LOOP_TYPE_UNKNOWN,
                         HexFormat.of().parseHex(annotationStringHex2)));
         final Activity activity = createAndResumeActivity();
         try {
-            Assert.assertTrue(cardEmulation.setPreferredService(activity, ctsComponentName));
+            assertTrue(cardEmulation.setPreferredService(activity, ctsComponentName));
             ensurePreferredService(CtsMyHostApduService.class);
-            Assert.assertTrue(adapter.setObserveModeEnabled(true));
-            Assert.assertTrue(adapter.isObserveModeEnabled());
+            assertTrue(adapter.setObserveModeEnabled(true));
+            assertTrue(adapter.isObserveModeEnabled());
             List<PollingFrame> receivedFrames =
                     notifyPollingLoopAndWait(frames1,
                             WalletRoleTestUtils.getWalletRoleHolderService().getClassName());
-            Assert.assertFalse(receivedFrames.get(0).getTriggeredAutoTransact());
+            assertFalse(receivedFrames.get(0).getTriggeredAutoTransact());
             receivedFrames =
                     notifyPollingLoopAndWait(frames2, CtsMyHostApduService.class.getName());
-            Assert.assertFalse(receivedFrames.get(0).getTriggeredAutoTransact());
+            assertFalse(receivedFrames.get(0).getTriggeredAutoTransact());
             Thread.currentThread().sleep(5000);
-            Assert.assertTrue(adapter.isObserveModeEnabled());
-            Assert.assertTrue(cardEmulation.removePollingLoopFilterForService(ctsComponentName,
+            assertTrue(adapter.isObserveModeEnabled());
+            assertTrue(cardEmulation.removePollingLoopFilterForService(ctsComponentName,
                     annotationStringHex2));
             adapter.notifyHceDeactivated();
         } catch (Exception ex) {
@@ -1779,7 +1764,7 @@
     public void testAutoTransact() throws Exception {
         assumeVsrApiGreaterThanUdc();
         NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
-        Assert.assertTrue(NfcUtils.enableNfc(adapter, mContext));
+        assertTrue(NfcUtils.enableNfc(adapter, mContext));
         assumeObserveModeSupported(adapter);
         adapter.notifyHceDeactivated();
         final Activity activity = createAndResumeActivity();
@@ -1791,14 +1776,14 @@
                 HexFormat.of().parseHex(annotationStringHex)));
         final CardEmulation cardEmulation = CardEmulation.getInstance(adapter);
         try {
-            Assert.assertTrue(cardEmulation.setPreferredService(activity,
+            assertTrue(cardEmulation.setPreferredService(activity,
                     new ComponentName(mContext, CtsMyHostApduService.class)));
             ensurePreferredService(CtsMyHostApduService.class);
-            Assert.assertTrue(adapter.setObserveModeEnabled(true));
-            Assert.assertTrue(adapter.isObserveModeEnabled());
+            assertTrue(adapter.setObserveModeEnabled(true));
+            assertTrue(adapter.isObserveModeEnabled());
             List<PollingFrame> receivedFrames =
                     notifyPollingLoopAndWait(frames, CustomHostApduService.class.getName());
-            Assert.assertTrue(receivedFrames.get(0).getTriggeredAutoTransact());
+            assertTrue(receivedFrames.get(0).getTriggeredAutoTransact());
             PollingCheck.check("Observe mode not disabled", 200,
                     () -> !adapter.isObserveModeEnabled());
             adapter.notifyHceDeactivated();
@@ -1816,7 +1801,7 @@
         assumeVsrApiGreaterThanUdc();
         runWithRole(mContext, CTS_PACKAGE_NAME, () -> {
             NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
-            Assert.assertTrue(NfcUtils.enableNfc(adapter, mContext));
+            assertTrue(NfcUtils.enableNfc(adapter, mContext));
             assumeObserveModeSupported(adapter);
             adapter.notifyHceDeactivated();
             createAndResumeActivity();
@@ -1826,11 +1811,11 @@
             ArrayList<PollingFrame> frames = new ArrayList<PollingFrame>(1);
             frames.add(createFrameWithData(PollingFrame.POLLING_LOOP_TYPE_UNKNOWN,
                     HexFormat.of().parseHex(annotationStringHex)));
-            Assert.assertTrue(adapter.setObserveModeEnabled(true));
-            Assert.assertTrue(adapter.isObserveModeEnabled());
+            assertTrue(adapter.setObserveModeEnabled(true));
+            assertTrue(adapter.isObserveModeEnabled());
             List<PollingFrame> receivedFrames =
                     notifyPollingLoopAndWait(frames, CustomHostApduService.class.getName());
-            Assert.assertTrue(receivedFrames.get(0).getTriggeredAutoTransact());
+            assertTrue(receivedFrames.get(0).getTriggeredAutoTransact());
             try {
                 PollingCheck.check("Observe mode not disabled", 200,
                         () -> !adapter.isObserveModeEnabled());
@@ -1848,7 +1833,7 @@
     public void testAutoTransactDynamic() throws Exception {
         assumeVsrApiGreaterThanUdc();
         NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
-        Assert.assertTrue(NfcUtils.enableNfc(adapter, mContext));
+        assertTrue(NfcUtils.enableNfc(adapter, mContext));
         assumeObserveModeSupported(adapter);
         adapter.notifyHceDeactivated();
         final Activity activity = createAndResumeActivity();
@@ -1857,23 +1842,23 @@
         String annotationStringHex = HexFormat.of().toHexDigits(testName.hashCode());
         CardEmulation cardEmulation = CardEmulation.getInstance(adapter);
         ComponentName customServiceName = new ComponentName(mContext, CustomHostApduService.class);
-        Assert.assertTrue(cardEmulation.registerPollingLoopFilterForService(customServiceName,
+        assertTrue(cardEmulation.registerPollingLoopFilterForService(customServiceName,
                 annotationStringHex, true));
         ArrayList<PollingFrame> frames = new ArrayList<PollingFrame>(1);
         frames.add(createFrameWithData(PollingFrame.POLLING_LOOP_TYPE_UNKNOWN,
                 HexFormat.of().parseHex(annotationStringHex)));
         ComponentName ctsComponentName = new ComponentName(mContext, CtsMyHostApduService.class);
         try {
-            Assert.assertTrue(cardEmulation.setPreferredService(activity, ctsComponentName));
+            assertTrue(cardEmulation.setPreferredService(activity, ctsComponentName));
             ensurePreferredService(CtsMyHostApduService.class);
-            Assert.assertTrue(adapter.setObserveModeEnabled(true));
-            Assert.assertTrue(adapter.isObserveModeEnabled());
+            assertTrue(adapter.setObserveModeEnabled(true));
+            assertTrue(adapter.isObserveModeEnabled());
             List<PollingFrame> receivedFrames =
                     notifyPollingLoopAndWait(frames, CustomHostApduService.class.getName());
-            Assert.assertTrue(receivedFrames.get(0).getTriggeredAutoTransact());
+            assertTrue(receivedFrames.get(0).getTriggeredAutoTransact());
             PollingCheck.check("Observe mode not disabled", 200,
                     () -> !adapter.isObserveModeEnabled());
-            Assert.assertTrue(cardEmulation.removePollingLoopFilterForService(customServiceName,
+            assertTrue(cardEmulation.removePollingLoopFilterForService(customServiceName,
                     annotationStringHex));
             adapter.notifyHceDeactivated();
             PollingCheck.check("Observe mode not enabled", 3000, adapter::isObserveModeEnabled);
@@ -1889,7 +1874,7 @@
     public void testOffHostAutoTransactDynamic() throws Exception {
         assumeVsrApiGreaterThanUdc();
         NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
-        Assert.assertTrue(NfcUtils.enableNfc(adapter, mContext));
+        assertTrue(NfcUtils.enableNfc(adapter, mContext));
         assumeObserveModeSupported(adapter);
         adapter.notifyHceDeactivated();
         final Activity activity = createAndResumeActivity();
@@ -1899,18 +1884,18 @@
         CardEmulation cardEmulation = CardEmulation.getInstance(adapter);
         ComponentName offhostServiceName = new ComponentName(mContext,
                 CtsMyOffHostApduService.class);
-        Assert.assertFalse(cardEmulation.registerPollingLoopFilterForService(offhostServiceName,
+        assertFalse(cardEmulation.registerPollingLoopFilterForService(offhostServiceName,
                 "1234567890", false));
-        Assert.assertTrue(cardEmulation.registerPollingLoopFilterForService(offhostServiceName,
+        assertTrue(cardEmulation.registerPollingLoopFilterForService(offhostServiceName,
                 annotationStringHex, true));
         PollingFrame frame = createFrameWithData(PollingFrame.POLLING_LOOP_TYPE_UNKNOWN,
                 HexFormat.of().parseHex(annotationStringHex));
         ComponentName ctsComponentName = new ComponentName(mContext, CtsMyHostApduService.class);
         try {
-            Assert.assertTrue(cardEmulation.setPreferredService(activity, ctsComponentName));
+            assertTrue(cardEmulation.setPreferredService(activity, ctsComponentName));
             ensurePreferredService(CtsMyHostApduService.class);
-            Assert.assertTrue(adapter.setObserveModeEnabled(true));
-            Assert.assertTrue(adapter.isObserveModeEnabled());
+            assertTrue(adapter.setObserveModeEnabled(true));
+            assertTrue(adapter.isObserveModeEnabled());
             adapter.notifyPollingLoop(frame);
             PollingCheck.check("Observe mode not disabled", 200,
                     () -> !adapter.isObserveModeEnabled());
@@ -1928,11 +1913,11 @@
     public void testDisallowNonDefaultSetObserveMode() throws NoSuchFieldException {
         runWithRole(mContext,  WalletRoleTestUtils.WALLET_HOLDER_PACKAGE_NAME, () -> {
             NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
-            Assert.assertTrue(NfcUtils.enableNfc(adapter, mContext));
+            assertTrue(NfcUtils.enableNfc(adapter, mContext));
             assumeObserveModeSupported(adapter);
             adapter.notifyHceDeactivated();
-            Assert.assertFalse(adapter.setObserveModeEnabled(true));
-            Assert.assertFalse(adapter.isObserveModeEnabled());
+            assertFalse(adapter.setObserveModeEnabled(true));
+            assertFalse(adapter.isObserveModeEnabled());
         });
     }
 
@@ -1943,7 +1928,7 @@
         runWithRole(mContext, CTS_PACKAGE_NAME, () -> {
             NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
             assumeObserveModeSupported(adapter);
-            Assert.assertTrue(NfcUtils.enableNfc(adapter, mContext));
+            assertTrue(NfcUtils.enableNfc(adapter, mContext));
             adapter.notifyHceDeactivated();
             createAndResumeActivity();
             String testName = new Object() {
@@ -1952,16 +1937,16 @@
             CardEmulation cardEmulation = CardEmulation.getInstance(adapter);
             ComponentName customServiceName = new ComponentName(mContext,
                     CtsMyHostApduService.class);
-            Assert.assertTrue(cardEmulation.registerPollingLoopFilterForService(customServiceName,
+            assertTrue(cardEmulation.registerPollingLoopFilterForService(customServiceName,
                     annotationStringHex, true));
             ArrayList<PollingFrame> frames = new ArrayList<PollingFrame>(1);
             frames.add(createFrameWithData(PollingFrame.POLLING_LOOP_TYPE_UNKNOWN,
                     HexFormat.of().parseHex(annotationStringHex)));
-            Assert.assertTrue(adapter.setObserveModeEnabled(true));
-            Assert.assertTrue(adapter.isObserveModeEnabled());
+            assertTrue(adapter.setObserveModeEnabled(true));
+            assertTrue(adapter.isObserveModeEnabled());
             List<PollingFrame> receivedFrames =
                     notifyPollingLoopAndWait(frames, CtsMyHostApduService.class.getName());
-            Assert.assertTrue(receivedFrames.get(0).getTriggeredAutoTransact());
+            assertTrue(receivedFrames.get(0).getTriggeredAutoTransact());
             try {
                 PollingCheck.check("Observe mode not disabled", 200,
                         () -> !adapter.isObserveModeEnabled());
@@ -1981,13 +1966,13 @@
         NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
         CardEmulation cardEmulation = CardEmulation.getInstance(adapter);
         ComponentName customServiceName = new ComponentName(mContext, CustomHostApduService.class);
-        Assert.assertThrows(IllegalArgumentException.class,
+        assertThrows(IllegalArgumentException.class,
                 () -> cardEmulation.registerPollingLoopFilterForService(customServiceName,
                         "", false));
-        Assert.assertThrows(IllegalArgumentException.class,
+        assertThrows(IllegalArgumentException.class,
                 () ->cardEmulation.registerPollingLoopFilterForService(customServiceName,
                     "????", false));
-        Assert.assertThrows(IllegalArgumentException.class,
+        assertThrows(IllegalArgumentException.class,
                 () ->cardEmulation.registerPollingLoopFilterForService(customServiceName,
                     "123", false));
 
@@ -2094,21 +2079,21 @@
 
         void test() {
             if (mReceivedFrames.size() > mExpectedFrames.size()) {
-                Assert.fail("received more frames than sent");
+                fail("received more frames than sent");
             } else if (mReceivedFrames.size() < mExpectedFrames.size()) {
-                Assert.fail("received fewer frames than sent");
+                fail("received fewer frames than sent");
             }
             for (PollingFrame receivedFrame : mReceivedFrames) {
                 PollingFrame expectedFrame = mExpectedFrames.get(mFrameIndex);
-                Assert.assertEquals(expectedFrame.getType(), receivedFrame.getType());
-                Assert.assertEquals(expectedFrame.getVendorSpecificGain(),
-                        receivedFrame.getVendorSpecificGain());
-                Assert.assertEquals(expectedFrame.getTimestamp(), receivedFrame.getTimestamp());
-                Assert.assertArrayEquals(expectedFrame.getData(), receivedFrame.getData());
+                assertEquals(expectedFrame.getType(), receivedFrame.getType());
+                assertEquals(expectedFrame.getVendorSpecificGain(),
+                    receivedFrame.getVendorSpecificGain());
+                assertEquals(expectedFrame.getTimestamp(), receivedFrame.getTimestamp());
+                assertArrayEquals(expectedFrame.getData(), receivedFrame.getData());
                 mFrameIndex++;
             }
             if (mExpectedServiceName != null) {
-                Assert.assertEquals(mExpectedServiceName, mReceivedServiceName);
+                assertEquals(mExpectedServiceName, mReceivedServiceName);
             }
         }
         public void onObserveModeStateChanged(String className, boolean isEnabled) {
@@ -2145,7 +2130,7 @@
             try {
                 pollLoopReceiver.wait(10000);
             } catch (InterruptedException ie) {
-                Assert.assertNull(ie);
+                assertNull(ie);
             }
         }
         pollLoopReceiver.test();
@@ -2183,19 +2168,19 @@
             * The foreground app does not have NON_PAYMENT_AID_1. Neither does the role holder.
             * So an app in the background (Non Payment App) gets the routing.
             **/
-            Assert.assertTrue(instance.isDefaultServiceForAid(
+            assertTrue(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getForegroundService(),
                     WalletRoleTestUtils.PAYMENT_AID_1));
-            Assert.assertFalse(instance.isDefaultServiceForAid(
+            assertFalse(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getForegroundService(),
                     WalletRoleTestUtils.NON_PAYMENT_AID_1));
-            Assert.assertFalse(instance.isDefaultServiceForAid(
+            assertFalse(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getWalletRoleHolderService(),
                     WalletRoleTestUtils.PAYMENT_AID_1));
-            Assert.assertTrue(instance.isDefaultServiceForAid(
+            assertTrue(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getNonPaymentService(),
                     WalletRoleTestUtils.NON_PAYMENT_AID_1));
-            Assert.assertTrue(instance.unsetPreferredService(activity));
+            assertTrue(instance.unsetPreferredService(activity));
             activity.finish();
         });
     }
@@ -2222,13 +2207,13 @@
              * PAYMENT_AID_2.
              **/
             CardEmulation instance = CardEmulation.getInstance(mAdapter);
-            Assert.assertTrue(instance.isDefaultServiceForAid(
+            assertTrue(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getWalletRoleHolderService(),
                     WalletRoleTestUtils.PAYMENT_AID_1));
-            Assert.assertTrue(instance.isDefaultServiceForAid(
+            assertTrue(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getWalletRoleHolderService(),
                     WalletRoleTestUtils.PAYMENT_AID_2));
-            Assert.assertTrue(instance.isDefaultServiceForAid(
+            assertTrue(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getAssociatedService(),
                     WalletRoleTestUtils.PAYMENT_AID_3));
         });
@@ -2259,13 +2244,13 @@
              * PAYMENT_AID_2.
              **/
             CardEmulation instance = CardEmulation.getInstance(mAdapter);
-            Assert.assertTrue(instance.isDefaultServiceForAid(
+            assertTrue(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getWalletRoleHolderService(),
                     WalletRoleTestUtils.PAYMENT_AID_1));
-            Assert.assertTrue(instance.isDefaultServiceForAid(
+            assertTrue(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getWalletRoleHolderService(),
                     WalletRoleTestUtils.PAYMENT_AID_2));
-            Assert.assertFalse(instance.isDefaultServiceForAid(
+            assertFalse(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getAssociatedService(),
                     WalletRoleTestUtils.PAYMENT_AID_3));
         });
@@ -2300,25 +2285,25 @@
              * A background app that is not the wallet role holder has the NON_PAYMENT_AID_1.
              * So that app gets the routing for NON_PAYMENT_AID_1.
              **/
-            Assert.assertTrue(instance.isDefaultServiceForAid(
+            assertTrue(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getWalletRoleHolderService(),
                     WalletRoleTestUtils.PAYMENT_AID_1));
-            Assert.assertTrue(instance.isDefaultServiceForAid(
+            assertTrue(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getWalletRoleHolderService(),
                     WalletRoleTestUtils.PAYMENT_AID_2));
-            Assert.assertFalse(instance.isDefaultServiceForAid(
+            assertFalse(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getWalletRoleHolderXService(),
                     WalletRoleTestUtils.PAYMENT_AID_1));
-            Assert.assertFalse(instance.isDefaultServiceForAid(
+            assertFalse(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getWalletRoleHolderXService(),
                     WalletRoleTestUtils.PAYMENT_AID_2));
-            Assert.assertFalse(instance.isDefaultServiceForAid(
+            assertFalse(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getForegroundService(),
                     WalletRoleTestUtils.PAYMENT_AID_1));
-            Assert.assertFalse(instance.isDefaultServiceForAid(
+            assertFalse(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getWalletRoleHolderService(),
                     WalletRoleTestUtils.NON_PAYMENT_AID_1));
-            Assert.assertTrue(instance.isDefaultServiceForAid(
+            assertTrue(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getNonPaymentService(),
                     WalletRoleTestUtils.NON_PAYMENT_AID_1));
         });
@@ -2349,25 +2334,25 @@
              *  The rest of the apps will always need to disambig and will not be set as defaults.
              *
              **/
-            Assert.assertFalse(instance.isDefaultServiceForAid(
+            assertFalse(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getWalletRoleHolderService(),
                     WalletRoleTestUtils.PAYMENT_AID_1));
-            Assert.assertFalse(instance.isDefaultServiceForAid(
+            assertFalse(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getWalletRoleHolderService(),
                     WalletRoleTestUtils.PAYMENT_AID_2));
-            Assert.assertFalse(instance.isDefaultServiceForAid(
+            assertFalse(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getWalletRoleHolderXService(),
                     WalletRoleTestUtils.PAYMENT_AID_1));
-            Assert.assertFalse(instance.isDefaultServiceForAid(
+            assertFalse(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getWalletRoleHolderXService(),
                     WalletRoleTestUtils.PAYMENT_AID_2));
-            Assert.assertFalse(instance.isDefaultServiceForAid(
+            assertFalse(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getForegroundService(),
                     WalletRoleTestUtils.PAYMENT_AID_1));
-            Assert.assertFalse(instance.isDefaultServiceForAid(
+            assertFalse(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getWalletRoleHolderService(),
                     WalletRoleTestUtils.NON_PAYMENT_AID_1));
-            Assert.assertTrue(instance.isDefaultServiceForAid(
+            assertTrue(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getNonPaymentService(),
                     WalletRoleTestUtils.NON_PAYMENT_AID_1));
         });
@@ -2397,25 +2382,25 @@
              * for those AIDs.
              *
              **/
-            Assert.assertTrue(instance.isDefaultServiceForAid(
+            assertTrue(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getNonPaymentService(),
                     WalletRoleTestUtils.NON_PAYMENT_AID_1));
-            Assert.assertFalse(instance.isDefaultServiceForAid(
+            assertFalse(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getWalletRoleHolderService(),
                     WalletRoleTestUtils.PAYMENT_AID_1));
-            Assert.assertFalse(instance.isDefaultServiceForAid(
+            assertFalse(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getWalletRoleHolderService(),
                     WalletRoleTestUtils.PAYMENT_AID_2));
-            Assert.assertFalse(instance.isDefaultServiceForAid(
+            assertFalse(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getWalletRoleHolderXService(),
                     WalletRoleTestUtils.PAYMENT_AID_2));
-            Assert.assertFalse(instance.isDefaultServiceForAid(
+            assertFalse(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getWalletRoleHolderService(),
                     WalletRoleTestUtils.PAYMENT_AID_1));
-            Assert.assertFalse(instance.isDefaultServiceForAid(
+            assertFalse(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getForegroundService(),
                     WalletRoleTestUtils.PAYMENT_AID_1));
-            Assert.assertFalse(instance.isDefaultServiceForAid(
+            assertFalse(instance.isDefaultServiceForAid(
                     WalletRoleTestUtils.getForegroundService(),
                     WalletRoleTestUtils.PAYMENT_AID_2));
         });
@@ -2425,10 +2410,10 @@
     @Test
     public void testOverrideRoutingTable() {
         NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
-        Assert.assertTrue(NfcUtils.enableNfc(adapter, mContext));
+        assertTrue(NfcUtils.enableNfc(adapter, mContext));
         final Activity activity = createAndResumeActivity();
         CardEmulation instance = CardEmulation.getInstance(adapter);
-        Assert.assertThrows(SecurityException.class,
+        assertThrows(SecurityException.class,
                 () -> instance.overrideRoutingTable(activity,
                         CardEmulation.PROTOCOL_AND_TECHNOLOGY_ROUTE_DH,
                         CardEmulation.PROTOCOL_AND_TECHNOLOGY_ROUTE_UNSET));
@@ -2443,7 +2428,7 @@
     @Test
     public void testRecoverRoutingTable() {
         NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
-        Assert.assertTrue(NfcUtils.enableNfc(adapter, mContext));
+        assertTrue(NfcUtils.enableNfc(adapter, mContext));
         final Activity activity = createAndResumeActivity();
         CardEmulation instance = CardEmulation.getInstance(adapter);
         instance.recoverRoutingTable(activity);
@@ -2453,7 +2438,7 @@
     @Test
     public void testIsEuiccSupported() {
         NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
-        Assert.assertTrue(NfcUtils.enableNfc(adapter, mContext));
+        assertTrue(NfcUtils.enableNfc(adapter, mContext));
         CardEmulation instance = CardEmulation.getInstance(adapter);
         instance.isEuiccSupported();
     }
@@ -2462,11 +2447,11 @@
     @Test
     public void testGetSetDefaultNfcSubscriptionId() {
         NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
-        Assert.assertTrue(NfcUtils.enableNfc(adapter, mContext));
+        assertTrue(NfcUtils.enableNfc(adapter, mContext));
         CardEmulation instance = CardEmulation.getInstance(adapter);
 
         instance.setDefaultNfcSubscriptionId(SUBSCRIPTION_ID_UICC);
-        Assert.assertEquals(SUBSCRIPTION_ID_UICC, instance.getDefaultNfcSubscriptionId());
+        assertEquals(SUBSCRIPTION_ID_UICC, instance.getDefaultNfcSubscriptionId());
     }
 
     @RequiresFlagsEnabled(Flags.FLAG_NFC_APDU_SERVICE_INFO_CONSTRUCTOR)
@@ -2494,15 +2479,6 @@
                         "test");
     }
 
-    private void assumeObserveModeSupported(@NonNull NfcAdapter adapter) {
-        assumeTrue("Observe mode must be supported", adapter.isObserveModeSupported());
-    }
-
-    private void assumeVsrApiGreaterThanUdc() {
-        assumeTrue("Device VSR API level must be greater than UDC",
-            getVsrApiLevel() > Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
-    }
-
     private Activity createAndResumeActivity() {
         ensureUnlocked();
         Intent intent
@@ -2511,6 +2487,10 @@
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         Activity activity = InstrumentationRegistry.getInstrumentation().startActivitySync(intent);
         InstrumentationRegistry.getInstrumentation().callActivityOnResume(activity);
+        ComponentName topComponentName = mContext.getSystemService(ActivityManager.class)
+                .getRunningTasks(1).get(0).topActivity;
+        Assert.assertEquals("Foreground activity not in the foreground",
+                NfcFCardEmulationActivity.class.getName(), topComponentName.getClassName());
         return activity;
     }
 }
diff --git a/tests/cts/tests/src/android/nfc/cts/DefaultPaymentProviderTestUtils.java b/tests/cts/tests/src/android/nfc/cts/DefaultPaymentProviderTestUtils.java
index 8771bf2..c186d9f 100644
--- a/tests/cts/tests/src/android/nfc/cts/DefaultPaymentProviderTestUtils.java
+++ b/tests/cts/tests/src/android/nfc/cts/DefaultPaymentProviderTestUtils.java
@@ -16,6 +16,8 @@
 
 package android.nfc.cts;
 
+import static org.junit.Assert.assertTrue;
+
 import android.content.ComponentName;
 import android.content.Context;
 import android.nfc.Constants;
@@ -80,8 +82,8 @@
                     count++;
                 }
             }
-            Assert.assertTrue(count < 10);
-            Assert.assertTrue(serviceName == null
+            assertTrue(count < 10);
+            assertTrue(serviceName == null
                     ? null == CardEmulation.getPreferredPaymentService(context)
                     : serviceName.equals(cardEmulation.getPreferredPaymentService(context)));
             return originalValue;
diff --git a/tests/cts/tests/src/android/nfc/cts/HostApduServiceTest.java b/tests/cts/tests/src/android/nfc/cts/HostApduServiceTest.java
index ead3399..2c3205a 100644
--- a/tests/cts/tests/src/android/nfc/cts/HostApduServiceTest.java
+++ b/tests/cts/tests/src/android/nfc/cts/HostApduServiceTest.java
@@ -1,5 +1,8 @@
 package android.nfc.cts;
 
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
 import android.content.Intent;
 import android.nfc.cardemulation.PollingFrame;
 import android.os.Bundle;
@@ -32,7 +35,7 @@
   public void testOnBind() {
     Intent serviceIntent
           = new Intent(CtsMyHostApduService.SERVICE_INTERFACE);
-    Assert.assertNotNull(service.onBind(serviceIntent));
+    assertNotNull(service.onBind(serviceIntent));
   }
 
   @Test
@@ -67,8 +70,8 @@
   @Test
   public void testProcessCommandApdu() {
     byte[] result = service.processCommandApdu(new byte[0], new Bundle());
-    Assert.assertNotNull(result);
-    Assert.assertTrue(result.length == 0);
+    assertNotNull(result);
+    assertTrue(result.length == 0);
   }
 
   @Test
diff --git a/tests/cts/tests/src/android/nfc/cts/HostNfcFServiceTest.java b/tests/cts/tests/src/android/nfc/cts/HostNfcFServiceTest.java
index cf41790..df63f37 100644
--- a/tests/cts/tests/src/android/nfc/cts/HostNfcFServiceTest.java
+++ b/tests/cts/tests/src/android/nfc/cts/HostNfcFServiceTest.java
@@ -1,5 +1,8 @@
 package android.nfc.cts;
 
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.Looper;
@@ -25,7 +28,7 @@
     public void testOnBind() {
         Intent serviceIntent
             = new Intent(CtsMyHostNfcFService.SERVICE_INTERFACE);
-        Assert.assertNotNull(service.onBind(serviceIntent));
+        assertNotNull(service.onBind(serviceIntent));
     }
 
     @Test
@@ -41,8 +44,8 @@
     @Test
     public void testProcessNfcFPacket() {
         byte[] result = service.processNfcFPacket(new byte[0], new Bundle());
-        Assert.assertNotNull(result);
-        Assert.assertTrue(result.length == 0);
+        assertNotNull(result);
+        assertTrue(result.length == 0);
     }
 
     @Test
diff --git a/tests/cts/tests/src/android/nfc/cts/NfcAdapterTest.java b/tests/cts/tests/src/android/nfc/cts/NfcAdapterTest.java
index f0faaf5..b5ee863 100644
--- a/tests/cts/tests/src/android/nfc/cts/NfcAdapterTest.java
+++ b/tests/cts/tests/src/android/nfc/cts/NfcAdapterTest.java
@@ -8,12 +8,13 @@
 import static android.nfc.NfcRoutingTableEntry.TYPE_TECHNOLOGY;
 import static android.nfc.cardemulation.CardEmulation.PROTOCOL_AND_TECHNOLOGY_ROUTE_ESE;
 import static android.nfc.cardemulation.CardEmulation.PROTOCOL_AND_TECHNOLOGY_ROUTE_UNSET;
-
-import static com.android.compatibility.common.util.PropertyUtil.getVsrApiLevel;
+import static android.nfc.cts.NfcUtils.assumeObserveModeSupported;
+import static android.nfc.cts.NfcUtils.assumeVsrApiGreaterThanUdc;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
@@ -24,6 +25,7 @@
 import static org.mockito.Mockito.when;
 
 import android.app.Activity;
+import android.app.ActivityManager;
 import android.app.PendingIntent;
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
@@ -51,7 +53,6 @@
 import android.nfc.cardemulation.CardEmulation;
 import android.nfc.tech.IsoDep;
 import android.nfc.tech.TagTechnology;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
@@ -69,6 +70,7 @@
 import org.junit.Assert;
 import org.junit.Assume;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -105,17 +107,16 @@
         MockitoAnnotations.initMocks(this);
         mContext = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
         assumeTrue("Device must support NFC", supportsHardware());
-        // Backup the original service. It is being overridden
-        // when creating a mocked adapter.
+
         NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
-        Assume.assumeNotNull("NFC Adapter is null", adapter);
-        assumeTrue("NFC Adapter could not be enabled", NfcUtils.enableNfc(adapter, mContext));
+        assertNotNull("NFC Adapter is null", adapter);
+        assertTrue("NFC Adapter could not be enabled", NfcUtils.enableNfc(adapter, mContext));
     }
 
     @Test
     public void testGetDefaultAdapter() {
         NfcAdapter adapter = getDefaultAdapter();
-        Assert.assertNotNull(adapter);
+        assertNotNull(adapter);
     }
 
     @Test
@@ -130,29 +131,29 @@
     @Test
     public void testEnableAndDisable() throws NoSuchFieldException, RemoteException {
         NfcAdapter adapter = getDefaultAdapter();
-        Assert.assertTrue(adapter.isEnabled());
+        assertTrue(adapter.isEnabled());
 
         // Disable NFC
-        Assert.assertTrue(NfcUtils.disableNfc(adapter, mContext));
-        Assert.assertFalse(adapter.isEnabled());
+        assertTrue(NfcUtils.disableNfc(adapter, mContext));
+        assertFalse(adapter.isEnabled());
 
         // Re-enable NFC
-        Assert.assertTrue(NfcUtils.enableNfc(adapter, mContext));
-        Assert.assertTrue(adapter.isEnabled());
+        assertTrue(NfcUtils.enableNfc(adapter, mContext));
+        assertTrue(adapter.isEnabled());
     }
 
     @Test
     public void testEnableAndDisablePersist() throws NoSuchFieldException, RemoteException {
         NfcAdapter adapter = getDefaultAdapter();
-        Assert.assertTrue(adapter.isEnabled());
+        assertTrue(adapter.isEnabled());
 
         // Disable NFC
-        Assert.assertTrue(NfcUtils.disableNfc(adapter, mContext, /* persist = */ false));
-        Assert.assertFalse(adapter.isEnabled());
+        assertTrue(NfcUtils.disableNfc(adapter, mContext, /* persist = */ false));
+        assertFalse(adapter.isEnabled());
 
         // Re-enable NFC
-        Assert.assertTrue(NfcUtils.enableNfc(adapter, mContext));
-        Assert.assertTrue(adapter.isEnabled());
+        assertTrue(NfcUtils.enableNfc(adapter, mContext));
+        assertTrue(adapter.isEnabled());
     }
 
     @Test
@@ -194,32 +195,32 @@
     @RequiresFlagsEnabled(Flags.FLAG_ENABLE_NFC_READER_OPTION)
     public void testEnableAndDisableReaderOption() throws NoSuchFieldException, RemoteException {
         NfcAdapter adapter = getDefaultAdapter();
-        assumeTrue(adapter.isReaderOptionSupported());
+        assumeTrue("Device must support reader option", adapter.isReaderOptionSupported());
 
-        Assert.assertTrue(adapter.enableReaderOption(/* enable = */ true));
-        Assert.assertTrue(adapter.isReaderOptionEnabled());
+        assertTrue(adapter.enableReaderOption(/* enable = */ true));
+        assertTrue(adapter.isReaderOptionEnabled());
 
-        Assert.assertTrue(adapter.enableReaderOption(/* enable = */ false));
-        Assert.assertFalse(adapter.isReaderOptionEnabled());
+        assertTrue(adapter.enableReaderOption(/* enable = */ false));
+        assertFalse(adapter.isReaderOptionEnabled());
     }
 
     @Test
     public void testEnableAndDisableSecureNfc() throws RemoteException {
         NfcAdapter adapter = getDefaultAdapter();
-        assumeTrue(adapter.isSecureNfcSupported());
+        assumeTrue("Device must support secure NFC", adapter.isSecureNfcSupported());
 
-        Assert.assertTrue(adapter.enableSecureNfc(/* enable = */ true));
-        Assert.assertTrue(adapter.isSecureNfcEnabled());
+        assertTrue(adapter.enableSecureNfc(/* enable = */ true));
+        assertTrue(adapter.isSecureNfcEnabled());
 
-        Assert.assertTrue(adapter.enableSecureNfc(/* enable = */ false));
-        Assert.assertFalse(adapter.isSecureNfcEnabled());
+        assertTrue(adapter.enableSecureNfc(/* enable = */ false));
+        assertFalse(adapter.isSecureNfcEnabled());
     }
 
     @Test
     public void testGetNfcAntennaInfo() throws NoSuchFieldException, RemoteException {
         NfcAdapter adapter = getDefaultAdapter();
         NfcAntennaInfo antenna = adapter.getNfcAntennaInfo();
-        Assert.assertNotNull(antenna);
+        assertNotNull(antenna);
     }
 
     @Test
@@ -229,14 +230,14 @@
         sTagRemoved = false;
         IsoDep isoDep = createIsoDepTag();
 
-        Assert.assertTrue(adapter.ignore(isoDep.getTag(), 0, listener, null));
+        assertTrue(adapter.ignore(isoDep.getTag(), 0, listener, null));
         // Wait a second to make sure listener callback fired
         try {
             Thread.sleep(1000);
         } catch (InterruptedException e) {
             // Ignore
         }
-        Assert.assertTrue(sTagRemoved);
+        assertTrue(sTagRemoved);
     }
 
     @Test
@@ -245,24 +246,25 @@
         NfcAdapter adapter = getDefaultAdapter();
         androidx.test.platform.app.InstrumentationRegistry.getInstrumentation()
             .getUiAutomation().adoptShellPermissionIdentity(NFC_SET_CONTROLLER_ALWAYS_ON);
-        assumeTrue(adapter.isControllerAlwaysOnSupported());
+        assumeTrue("Device must support controller always on",
+            adapter.isControllerAlwaysOnSupported());
         NfcControllerAlwaysOnListener cb = null;
         CountDownLatch countDownLatch;
         try {
             countDownLatch = new CountDownLatch(1);
             cb = new NfcControllerAlwaysOnListener(countDownLatch);
             adapter.registerControllerAlwaysOnListener(Executors.newSingleThreadExecutor(), cb);
-            Assert.assertTrue(adapter.setControllerAlwaysOn(true));
+            assertTrue(adapter.setControllerAlwaysOn(true));
             assertTrue(countDownLatch.await(1, TimeUnit.SECONDS));
-            Assert.assertTrue(adapter.isControllerAlwaysOn());
+            assertTrue(adapter.isControllerAlwaysOn());
             adapter.unregisterControllerAlwaysOnListener(cb);
 
             countDownLatch = new CountDownLatch(1);
             cb = new NfcControllerAlwaysOnListener(countDownLatch);
             adapter.registerControllerAlwaysOnListener(Executors.newSingleThreadExecutor(), cb);
-            Assert.assertTrue(adapter.setControllerAlwaysOn(false));
+            assertTrue(adapter.setControllerAlwaysOn(false));
             assertTrue(countDownLatch.await(1, TimeUnit.SECONDS));
-            Assert.assertFalse(adapter.isControllerAlwaysOn());
+            assertFalse(adapter.isControllerAlwaysOn());
             adapter.unregisterControllerAlwaysOnListener(cb);
         } finally {
             if (cb != null)
@@ -278,11 +280,11 @@
     public void testAdapterState() throws NoSuchFieldException, RemoteException {
         NfcAdapter adapter = getDefaultAdapter();
 
-        Assert.assertTrue(NfcUtils.enableNfc(adapter, mContext));
-        Assert.assertTrue(adapter.getAdapterState() == NfcAdapter.STATE_ON);
+        assertTrue(NfcUtils.enableNfc(adapter, mContext));
+        assertTrue(adapter.getAdapterState() == NfcAdapter.STATE_ON);
 
-        Assert.assertTrue(NfcUtils.disableNfc(adapter, mContext));
-        Assert.assertTrue(adapter.getAdapterState() == NfcAdapter.STATE_OFF);
+        assertTrue(NfcUtils.disableNfc(adapter, mContext));
+        assertTrue(adapter.getAdapterState() == NfcAdapter.STATE_OFF);
     }
 
     @Test
@@ -343,9 +345,9 @@
         try {
             originalDefault = setDefaultPaymentService(CtsMyHostApduService.class);
             CardEmulationTest.ensurePreferredService(CtsMyHostApduService.class, mContext);
-            assumeTrue(adapter.isObserveModeSupported());
+            assumeObserveModeSupported(adapter);
             boolean result = adapter.setObserveModeEnabled(false);
-            Assert.assertTrue(result);
+            assertTrue(result);
         } finally {
             setDefaultPaymentService(originalDefault);
             adapter.notifyHceDeactivated();
@@ -362,9 +364,9 @@
         try {
             originalDefault = setDefaultPaymentService(CtsMyHostApduService.class);
 
-            assumeTrue(adapter.isObserveModeSupported());
+            assumeObserveModeSupported(adapter);
             boolean result = adapter.setObserveModeEnabled(true);
-            Assert.assertTrue(result);
+            assertTrue(result);
         } finally {
             setDefaultPaymentService(originalDefault);
             adapter.notifyHceDeactivated();
@@ -385,10 +387,10 @@
                     CustomHostApduService.class), true);
             originalDefault = setDefaultPaymentService(CustomHostApduService.class);
             CardEmulationTest.ensurePreferredService(CustomHostApduService.class, mContext);
-            Assert.assertTrue(adapter.isObserveModeEnabled());
+            assertTrue(adapter.isObserveModeEnabled());
             setDefaultPaymentService(CtsMyHostApduService.class);
             CardEmulationTest.ensurePreferredService(CtsMyHostApduService.class, mContext);
-            Assert.assertFalse(adapter.isObserveModeEnabled());
+            assertFalse(adapter.isObserveModeEnabled());
         } finally {
             cardEmulation.setShouldDefaultToObserveModeForService(new ComponentName(mContext,
                     CustomHostApduService.class), false);
@@ -402,7 +404,7 @@
     public void testDefaultObserveModeForegroundDynamic() {
         NfcAdapter adapter = getDefaultAdapter();
         adapter.notifyHceDeactivated();
-        assumeTrue(adapter.isObserveModeSupported());
+        assumeObserveModeSupported(adapter);
         CardEmulation cardEmulation = CardEmulation.getInstance(adapter);
         try {
             Activity activity = createAndResumeActivity();
@@ -410,15 +412,15 @@
                     CustomHostApduService.class), true);
             cardEmulation.setShouldDefaultToObserveModeForService(new ComponentName(mContext,
                     CtsMyHostApduService.class), false);
-            Assert.assertTrue(cardEmulation.setPreferredService(activity,
+            assertTrue(cardEmulation.setPreferredService(activity,
                     new ComponentName(mContext, CustomHostApduService.class)));
             CardEmulationTest.ensurePreferredService(CustomHostApduService.class, mContext);
-            Assert.assertTrue(adapter.isObserveModeEnabled());
-            Assert.assertTrue(cardEmulation.setPreferredService(activity,
+            assertTrue(adapter.isObserveModeEnabled());
+            assertTrue(cardEmulation.setPreferredService(activity,
                     new ComponentName(mContext, CtsMyHostApduService.class)));
             CardEmulationTest.ensurePreferredService(CtsMyHostApduService.class, mContext);
             adapter.notifyHceDeactivated();
-            Assert.assertFalse(adapter.isObserveModeEnabled());
+            assertFalse(adapter.isObserveModeEnabled());
         } finally {
             cardEmulation.setShouldDefaultToObserveModeForService(new ComponentName(mContext,
                     CustomHostApduService.class), false);
@@ -431,27 +433,27 @@
     public void testDefaultObserveModeOnlyWithServiceChange() {
         NfcAdapter adapter = getDefaultAdapter();
         adapter.notifyHceDeactivated();
-        assumeTrue(adapter.isObserveModeSupported());
+        assumeObserveModeSupported(adapter);
         CardEmulation cardEmulation = CardEmulation.getInstance(adapter);
         cardEmulation.setShouldDefaultToObserveModeForService(new ComponentName(mContext,
                 CtsMyHostApduService.class), true);
         WalletRoleTestUtils.runWithRole(mContext, WalletRoleTestUtils.CTS_PACKAGE_NAME, () -> {
             CardEmulationTest.ensurePreferredService(CtsMyHostApduService.class, mContext);
-            Assert.assertTrue(adapter.isObserveModeEnabled());
-            Assert.assertTrue(adapter.setObserveModeEnabled(false));
-            Assert.assertFalse(adapter.isObserveModeEnabled());
+            assertTrue(adapter.isObserveModeEnabled());
+            assertTrue(adapter.setObserveModeEnabled(false));
+            assertFalse(adapter.isObserveModeEnabled());
             try {
                 Activity activity = createAndResumeActivity();
-                Assert.assertTrue(cardEmulation.setPreferredService(activity,
+                assertTrue(cardEmulation.setPreferredService(activity,
                         new ComponentName(mContext, CtsMyHostApduService.class)));
                 CardEmulationTest.ensurePreferredService(CtsMyHostApduService.class, mContext);
-                Assert.assertFalse(adapter.isObserveModeEnabled());
-                Assert.assertTrue(adapter.setObserveModeEnabled(true));
-                Assert.assertTrue(adapter.isObserveModeEnabled());
-                Assert.assertTrue(cardEmulation.setPreferredService(activity,
+                assertFalse(adapter.isObserveModeEnabled());
+                assertTrue(adapter.setObserveModeEnabled(true));
+                assertTrue(adapter.isObserveModeEnabled());
+                assertTrue(cardEmulation.setPreferredService(activity,
                         new ComponentName(mContext, CustomHostApduService.class)));
                 CardEmulationTest.ensurePreferredService(CustomHostApduService.class, mContext);
-                Assert.assertFalse(adapter.isObserveModeEnabled());
+                assertFalse(adapter.isObserveModeEnabled());
             } finally {
                 cardEmulation.setShouldDefaultToObserveModeForService(new ComponentName(mContext,
                         CustomHostApduService.class), false);
@@ -472,10 +474,10 @@
         try {
             originalDefault = setDefaultPaymentService(BackgroundHostApduService.class);
             CardEmulationTest.ensurePreferredService(BackgroundHostApduService.class, mContext);
-            Assert.assertTrue(adapter.isObserveModeEnabled());
+            assertTrue(adapter.isObserveModeEnabled());
             setDefaultPaymentService(CtsMyHostApduService.class);
             CardEmulationTest.ensurePreferredService(CtsMyHostApduService.class, mContext);
-            Assert.assertFalse(adapter.isObserveModeEnabled());
+            assertFalse(adapter.isObserveModeEnabled());
         } finally {
             setDefaultPaymentService(originalDefault);
             adapter.notifyHceDeactivated();
@@ -491,15 +493,15 @@
             new ComponentName(mContext, CtsMyHostApduService.class), false);
         Activity activity = createAndResumeActivity();
         adapter.notifyHceDeactivated();
-        assumeTrue(adapter.isObserveModeSupported());
-        Assert.assertTrue(cardEmulation.setPreferredService(activity,
+        assumeObserveModeSupported(adapter);
+        assertTrue(cardEmulation.setPreferredService(activity,
                 new ComponentName(mContext, BackgroundHostApduService.class)));
         CardEmulationTest.ensurePreferredService(BackgroundHostApduService.class, mContext);
-        Assert.assertTrue(adapter.isObserveModeEnabled());
-        Assert.assertTrue(cardEmulation.setPreferredService(activity,
+        assertTrue(adapter.isObserveModeEnabled());
+        assertTrue(cardEmulation.setPreferredService(activity,
                 new ComponentName(mContext, CtsMyHostApduService.class)));
         CardEmulationTest.ensurePreferredService(CtsMyHostApduService.class, mContext);
-        Assert.assertFalse(adapter.isObserveModeEnabled());
+        assertFalse(adapter.isObserveModeEnabled());
     }
 
     @Test
@@ -509,9 +511,9 @@
         WalletRoleTestUtils.runWithRole(mContext, WalletRoleTestUtils.CTS_PACKAGE_NAME, () -> {
             NfcAdapter adapter = getDefaultAdapter();
             adapter.notifyHceDeactivated();
-            assumeTrue(adapter.isObserveModeSupported());
+            assumeObserveModeSupported(adapter);
             adapter.setObserveModeEnabled(false);
-            Assert.assertFalse(adapter.isObserveModeEnabled());
+            assertFalse(adapter.isObserveModeEnabled());
             adapter.notifyHceDeactivated();
         });
     }
@@ -523,9 +525,9 @@
         WalletRoleTestUtils.runWithRole(mContext, WalletRoleTestUtils.CTS_PACKAGE_NAME, () -> {
             NfcAdapter adapter = getDefaultAdapter();
             adapter.notifyHceDeactivated();
-            assumeTrue(adapter.isObserveModeSupported());
+            assumeObserveModeSupported(adapter);
             adapter.setObserveModeEnabled(true);
-            Assert.assertTrue(adapter.isObserveModeEnabled());
+            assertTrue(adapter.isObserveModeEnabled());
             adapter.notifyHceDeactivated();
         });
     }
@@ -536,22 +538,22 @@
         NfcAdapter adapter = getDefaultAdapter();
 
         // Disable charging feature
-        Assert.assertTrue(adapter.setWlcEnabled(false));
-        Assert.assertFalse(adapter.isWlcEnabled());
+        assertTrue(adapter.setWlcEnabled(false));
+        assertFalse(adapter.isWlcEnabled());
 
         // Enable charging feature
-        Assert.assertTrue(adapter.setWlcEnabled(true));
-        Assert.assertTrue(adapter.isWlcEnabled());
+        assertTrue(adapter.setWlcEnabled(true));
+        assertTrue(adapter.isWlcEnabled());
     }
 
     @Test
     @RequiresFlagsEnabled(Flags.FLAG_NFC_VENDOR_CMD)
     public void testSendVendorCmd() throws InterruptedException, RemoteException {
-        assumeTrue(getVsrApiLevel() > Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
+        assumeVsrApiGreaterThanUdc();
         CountDownLatch rspCountDownLatch = new CountDownLatch(1);
         CountDownLatch ntfCountDownLatch = new CountDownLatch(1);
         NfcAdapter nfcAdapter = getDefaultAdapter();
-        Assert.assertNotNull(nfcAdapter);
+        assertNotNull(nfcAdapter);
         NfcVendorNciCallback cb =
                 new NfcVendorNciCallback(rspCountDownLatch, ntfCountDownLatch);
         try {
@@ -587,7 +589,7 @@
                 .thenReturn(mDevicePolicyManager);
         NfcAdapter adapter = getDefaultAdapter();
         boolean result = adapter.enable();
-        Assert.assertTrue(result);
+        assertTrue(result);
     }
 
     @Test
@@ -602,32 +604,32 @@
                 .thenReturn(mDevicePolicyManager);
         NfcAdapter adapter = getDefaultAdapter();
         boolean result = adapter.disable();
-        Assert.assertTrue(result);
+        assertTrue(result);
         result = adapter.enable();
-        Assert.assertTrue(result);
+        assertTrue(result);
     }
 
     @Test
     public void testShouldDefaultToObserveModeAfterNfcOffOn() throws InterruptedException {
         NfcAdapter adapter = getDefaultAdapter();
         adapter.notifyHceDeactivated();
-        assumeTrue(adapter.isObserveModeSupported());
+        assumeObserveModeSupported(adapter);
         adapter.notifyHceDeactivated();
         Activity activity = createAndResumeActivity();
         final CardEmulation cardEmulation = CardEmulation.getInstance(adapter);
         ComponentName ctsService = new ComponentName(mContext, CtsMyHostApduService.class);
 
         try {
-            Assert.assertTrue(cardEmulation.setShouldDefaultToObserveModeForService(ctsService,
+            assertTrue(cardEmulation.setShouldDefaultToObserveModeForService(ctsService,
                     true));
 
-            Assert.assertTrue(cardEmulation.setPreferredService(activity, ctsService));
+            assertTrue(cardEmulation.setPreferredService(activity, ctsService));
             CardEmulationTest.ensurePreferredService(CtsMyHostApduService.class, mContext);
 
-            Assert.assertTrue(adapter.isObserveModeEnabled());
-            Assert.assertTrue(NfcUtils.disableNfc(adapter, mContext));
-            Assert.assertTrue(NfcUtils.enableNfc(adapter, mContext));
-            Assert.assertTrue(adapter.isObserveModeEnabled());
+            assertTrue(adapter.isObserveModeEnabled());
+            assertTrue(NfcUtils.disableNfc(adapter, mContext));
+            assertTrue(NfcUtils.enableNfc(adapter, mContext));
+            assertTrue(adapter.isObserveModeEnabled());
         } finally {
             cardEmulation.setShouldDefaultToObserveModeForService(ctsService,
                     false);
@@ -640,20 +642,20 @@
     public void testShouldDefaultToObserveModeWithNfcOff() throws InterruptedException {
         NfcAdapter adapter = getDefaultAdapter();
         adapter.notifyHceDeactivated();
-        assumeTrue(adapter.isObserveModeSupported());
+        assumeObserveModeSupported(adapter);
         Activity activity = createAndResumeActivity();
         final CardEmulation cardEmulation = CardEmulation.getInstance(adapter);
         ComponentName ctsService = new ComponentName(mContext, CtsMyHostApduService.class);
         try {
-            Assert.assertTrue(NfcUtils.disableNfc(adapter, mContext));
-            Assert.assertTrue(cardEmulation.setShouldDefaultToObserveModeForService(ctsService,
+            assertTrue(NfcUtils.disableNfc(adapter, mContext));
+            assertTrue(cardEmulation.setShouldDefaultToObserveModeForService(ctsService,
                     true));
 
-            Assert.assertTrue(cardEmulation.setPreferredService(activity, ctsService));
+            assertTrue(cardEmulation.setPreferredService(activity, ctsService));
             CardEmulationTest.ensurePreferredService(CtsMyHostApduService.class, mContext);
 
-            Assert.assertTrue(NfcUtils.enableNfc(adapter, mContext));
-            Assert.assertTrue(adapter.isObserveModeEnabled());
+            assertTrue(NfcUtils.enableNfc(adapter, mContext));
+            assertTrue(adapter.isObserveModeEnabled());
         } finally {
             cardEmulation.setShouldDefaultToObserveModeForService(ctsService,
                     false);
@@ -667,9 +669,9 @@
     public void testOemExtension() throws InterruptedException {
         CountDownLatch tagDetectedCountDownLatch = new CountDownLatch(3);
         NfcAdapter nfcAdapter = getDefaultAdapter();
-        Assert.assertNotNull(nfcAdapter);
+        assertNotNull(nfcAdapter);
         NfcOemExtension nfcOemExtension = nfcAdapter.getNfcOemExtension();
-        Assert.assertNotNull(nfcOemExtension);
+        assertNotNull(nfcOemExtension);
         NfcOemExtensionCallback cb =
                 new NfcOemExtensionCallback(tagDetectedCountDownLatch);
         try {
@@ -748,28 +750,30 @@
 
     @Test
     @RequiresDevice
+    @Ignore("b/404565741")
     @RequiresFlagsEnabled(Flags.FLAG_NFC_OEM_EXTENSION)
     public void testOemExtensionMaybeTriggerFirmwareUpdateWhenEnabled()
             throws InterruptedException, RemoteException {
         NfcAdapter nfcAdapter = getDefaultAdapter();
-        Assert.assertNotNull(nfcAdapter);
+        assertNotNull(nfcAdapter);
         NfcOemExtension nfcOemExtension = nfcAdapter.getNfcOemExtension();
-        Assert.assertNotNull(nfcOemExtension);
+        assertNotNull(nfcOemExtension);
         nfcOemExtension.maybeTriggerFirmwareUpdate();
     }
 
     @Test
     @RequiresDevice
+    @Ignore("b/404565741")
     @RequiresFlagsEnabled(Flags.FLAG_NFC_OEM_EXTENSION)
     public void testOemExtensionMaybeTriggerFirmwareUpdateWhenDisabled()
             throws InterruptedException, RemoteException {
         NfcAdapter nfcAdapter = getDefaultAdapter();
-        Assert.assertNotNull(nfcAdapter);
+        assertNotNull(nfcAdapter);
         // Disable NFC
-        Assert.assertTrue(NfcUtils.disableNfc(nfcAdapter, mContext));
-        Assert.assertFalse(nfcAdapter.isEnabled());
+        assertTrue(NfcUtils.disableNfc(nfcAdapter, mContext));
+        assertFalse(nfcAdapter.isEnabled());
         NfcOemExtension nfcOemExtension = nfcAdapter.getNfcOemExtension();
-        Assert.assertNotNull(nfcOemExtension);
+        assertNotNull(nfcOemExtension);
         nfcOemExtension.maybeTriggerFirmwareUpdate();
     }
 
@@ -778,9 +782,9 @@
     public void testOemExtensionTriggerInitialization()
             throws InterruptedException, RemoteException {
         NfcAdapter nfcAdapter = getDefaultAdapter();
-        Assert.assertNotNull(nfcAdapter);
+        assertNotNull(nfcAdapter);
         NfcOemExtension nfcOemExtension = nfcAdapter.getNfcOemExtension();
-        Assert.assertNotNull(nfcOemExtension);
+        assertNotNull(nfcOemExtension);
         nfcOemExtension.triggerInitialization();
     }
 
@@ -790,10 +794,10 @@
             throws RemoteException, InterruptedException {
         CountDownLatch tagDetectedCountDownLatch = new CountDownLatch(5);
         NfcAdapter nfcAdapter = getDefaultAdapter();
-        Assert.assertNotNull(nfcAdapter);
+        assertNotNull(nfcAdapter);
         NfcOemExtension nfcOemExtension = nfcAdapter.getNfcOemExtension();
 
-        Assert.assertNotNull(nfcOemExtension);
+        assertNotNull(nfcOemExtension);
         NfcOemExtension.Callback cb = new NfcOemExtensionCallback(tagDetectedCountDownLatch);
         try {
             nfcOemExtension.registerCallback(
@@ -914,12 +918,13 @@
     @RequiresFlagsEnabled(Flags.FLAG_NFC_OEM_EXTENSION)
     public void testOemExtensionSetControllerAlwaysOn() throws InterruptedException {
         NfcAdapter nfcAdapter = getDefaultAdapter();
-        Assert.assertNotNull(nfcAdapter);
+        assertNotNull(nfcAdapter);
         NfcOemExtension nfcOemExtension = nfcAdapter.getNfcOemExtension();
-        Assert.assertNotNull(nfcOemExtension);
+        assertNotNull(nfcOemExtension);
         androidx.test.platform.app.InstrumentationRegistry.getInstrumentation()
                 .getUiAutomation().adoptShellPermissionIdentity(NFC_SET_CONTROLLER_ALWAYS_ON);
-        assumeTrue(nfcAdapter.isControllerAlwaysOnSupported());
+        assumeTrue("Device must support controller always on",
+            nfcAdapter.isControllerAlwaysOnSupported());
         NfcControllerAlwaysOnListener cb = null;
         CountDownLatch countDownLatch;
         try {
@@ -1193,6 +1198,10 @@
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         Activity activity = InstrumentationRegistry.getInstrumentation().startActivitySync(intent);
         InstrumentationRegistry.getInstrumentation().callActivityOnResume(activity);
+        ComponentName topComponentName = mContext.getSystemService(ActivityManager.class)
+                .getRunningTasks(1).get(0).topActivity;
+        Assert.assertEquals("Foreground activity not in the foreground",
+                NfcFCardEmulationActivity.class.getName(), topComponentName.getClassName());
         return activity;
     }
 
@@ -1236,28 +1245,29 @@
     @RequiresFlagsEnabled(Flags.FLAG_NFC_CHECK_TAG_INTENT_PREFERENCE)
     public void testSetTagIntentAppPreference() throws NoSuchFieldException, RemoteException {
         NfcAdapter adapter = getDefaultAdapter();
-        assumeTrue(adapter.isTagIntentAppPreferenceSupported());
+        assumeTrue("Device must support tag intent app preference",
+            adapter.isTagIntentAppPreferenceSupported());
         int user = mContext.getUser().getIdentifier();
 
         // Disallow package
-        Assert.assertEquals(NfcAdapter.TAG_INTENT_APP_PREF_RESULT_SUCCESS,
+        assertEquals(NfcAdapter.TAG_INTENT_APP_PREF_RESULT_SUCCESS,
             adapter.setTagIntentAppPreferenceForUser(
             user, "android.nfc.cts", /* allow = */ false));
         Map<String, Boolean> disallowMap = adapter.getTagIntentAppPreferenceForUser(user);
-        Assert.assertNotNull(disallowMap);
-        Assert.assertFalse(disallowMap.isEmpty());
-        Assert.assertEquals(false, disallowMap.get("android.nfc.cts"));
-        Assert.assertFalse(adapter.isTagIntentAllowed());
+        assertNotNull(disallowMap);
+        assertFalse(disallowMap.isEmpty());
+        assertEquals(false, disallowMap.get("android.nfc.cts"));
+        assertFalse(adapter.isTagIntentAllowed());
 
         // Allow package
-        Assert.assertEquals(NfcAdapter.TAG_INTENT_APP_PREF_RESULT_SUCCESS,
+        assertEquals(NfcAdapter.TAG_INTENT_APP_PREF_RESULT_SUCCESS,
             adapter.setTagIntentAppPreferenceForUser(
                 user, "android.nfc.cts", /* allow = */ true));
         Map<String, Boolean> allowMap = adapter.getTagIntentAppPreferenceForUser(user);
-        Assert.assertNotNull(allowMap);
-        Assert.assertFalse(allowMap.isEmpty());
-        Assert.assertEquals(true, allowMap.get("android.nfc.cts"));
-        Assert.assertTrue(adapter.isTagIntentAllowed());
+        assertNotNull(allowMap);
+        assertFalse(allowMap.isEmpty());
+        assertEquals(true, allowMap.get("android.nfc.cts"));
+        assertTrue(adapter.isTagIntentAllowed());
     }
 
     @Test
diff --git a/tests/cts/tests/src/android/nfc/cts/NfcFCardEmulationTest.java b/tests/cts/tests/src/android/nfc/cts/NfcFCardEmulationTest.java
index 43a8c3c..5711c79 100644
--- a/tests/cts/tests/src/android/nfc/cts/NfcFCardEmulationTest.java
+++ b/tests/cts/tests/src/android/nfc/cts/NfcFCardEmulationTest.java
@@ -1,8 +1,13 @@
 package android.nfc.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
 import android.app.Activity;
+import android.app.ActivityManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -36,13 +41,13 @@
         assumeTrue("Device must support NFC type F HCE", supportsHardware());
         Context mContext = InstrumentationRegistry.getContext();
         mAdapter = NfcAdapter.getDefaultAdapter(mContext);
-        Assert.assertNotNull("NFC Adapter is null", mAdapter);
+        assertNotNull("NFC Adapter is null", mAdapter);
     }
 
     @Test
     public void getNonNullInstance() {
         NfcFCardEmulation instance = NfcFCardEmulation.getInstance(mAdapter);
-        Assert.assertNotNull(instance);
+        assertNotNull(instance);
     }
 
     @Test
@@ -51,23 +56,23 @@
         String code = "4000";
 
         // Register system code
-        Assert.assertTrue(instance.registerSystemCodeForService(mService, code));
-        Assert.assertEquals(instance.getSystemCodeForService(mService), code);
+        assertTrue(instance.registerSystemCodeForService(mService, code));
+        assertEquals(instance.getSystemCodeForService(mService), code);
 
         // Unregister system code
-        Assert.assertTrue(instance.unregisterSystemCodeForService(mService));
-        Assert.assertNotEquals(instance.getSystemCodeForService(mService), code);
+        assertTrue(instance.unregisterSystemCodeForService(mService));
+        assertNotEquals(instance.getSystemCodeForService(mService), code);
 
         // Re-register system code future tests
-        Assert.assertTrue(instance.registerSystemCodeForService(mService, code));
+        assertTrue(instance.registerSystemCodeForService(mService, code));
     }
 
     @Test
     public void testSetAndGetNfcid2ForService() throws RemoteException {
         NfcFCardEmulation instance = getInstance();
         String testNfcid2 = "02FE000000000000";
-        Assert.assertTrue(instance.setNfcid2ForService(mService, testNfcid2));
-        Assert.assertEquals(instance.getNfcid2ForService(mService), testNfcid2);
+        assertTrue(instance.setNfcid2ForService(mService, testNfcid2));
+        assertEquals(instance.getNfcid2ForService(mService), testNfcid2);
     }
 
     @Test
@@ -75,18 +80,21 @@
         NfcFCardEmulation instance = getInstance();
         Activity activity = createAndResumeActivity();
 
-        Assert.assertTrue(instance.enableService(activity, mService));
-        Assert.assertTrue(instance.disableService(activity));
+        assertTrue(instance.enableService(activity, mService));
+        assertTrue(instance.disableService(activity));
     }
 
     private Activity createAndResumeActivity() {
         CardEmulationTest.ensureUnlocked();
-        Intent intent
-            = new Intent(ApplicationProvider.getApplicationContext(),
-            NfcFCardEmulationActivity.class);
+        Context context = ApplicationProvider.getApplicationContext();
+        Intent intent = new Intent(context, NfcFCardEmulationActivity.class);
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         Activity activity = InstrumentationRegistry.getInstrumentation().startActivitySync(intent);
         InstrumentationRegistry.getInstrumentation().callActivityOnResume(activity);
+        ComponentName topComponentName = context.getSystemService(ActivityManager.class)
+                .getRunningTasks(1).get(0).topActivity;
+        Assert.assertEquals("Foreground activity not in the foreground",
+                NfcFCardEmulationActivity.class.getName(), topComponentName.getClassName());
         return activity;
     }
 
diff --git a/tests/cts/tests/src/android/nfc/cts/NfcPreferredPaymentTest.java b/tests/cts/tests/src/android/nfc/cts/NfcPreferredPaymentTest.java
index 863d141..f0887b8 100644
--- a/tests/cts/tests/src/android/nfc/cts/NfcPreferredPaymentTest.java
+++ b/tests/cts/tests/src/android/nfc/cts/NfcPreferredPaymentTest.java
@@ -73,7 +73,7 @@
 
     @Before
     public void setUp() throws Exception {
-        assumeTrue(supportsHardware());
+        assumeTrue("Device must support NFC HCE", supportsHardware());
         mContext = InstrumentationRegistry.getContext();
         mAdapter = NfcAdapter.getDefaultAdapter(mContext);
         assertNotNull(mAdapter);
diff --git a/tests/cts/tests/src/android/nfc/cts/NfcUtils.java b/tests/cts/tests/src/android/nfc/cts/NfcUtils.java
index f99b012..f773b5e 100644
--- a/tests/cts/tests/src/android/nfc/cts/NfcUtils.java
+++ b/tests/cts/tests/src/android/nfc/cts/NfcUtils.java
@@ -18,14 +18,21 @@
 
 import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
 
+import static com.android.compatibility.common.util.PropertyUtil.getVsrApiLevel;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.nfc.NfcAdapter;
+import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.util.Log;
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -34,97 +41,113 @@
 public final class NfcUtils {
     private NfcUtils() {}
 
-    static boolean enableNfc(NfcAdapter nfcAdapter, Context context) {
-        try {
-            if (nfcAdapter.isEnabled()) {
-                return true;
-            }
-            CountDownLatch countDownLatch = new CountDownLatch(1);
-            AtomicInteger state = new AtomicInteger(NfcAdapter.STATE_OFF);
-            BroadcastReceiver nfcChangeListener = new BroadcastReceiver() {
-                @Override
-                public void onReceive(Context context, Intent intent) {
-                    int s = intent.getIntExtra(NfcAdapter.EXTRA_ADAPTER_STATE,
-                            NfcAdapter.STATE_OFF);
-                    if (s == NfcAdapter.STATE_TURNING_ON) {
-                        return;
-                    }
-                    context.unregisterReceiver(this);
-                    state.set(s);
-                    countDownLatch.countDown();
-                }
-            };
-            HandlerThread handlerThread = new HandlerThread("nfc_cts_listener");
-            handlerThread.start();
-            Handler handler = new Handler(handlerThread.getLooper());
-            IntentFilter intentFilter = new IntentFilter();
-            intentFilter.addAction(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
-            context.registerReceiver(nfcChangeListener, intentFilter, null,
-                    handler);
-            androidx.test.platform.app.InstrumentationRegistry.getInstrumentation()
-                    .getUiAutomation().adoptShellPermissionIdentity(WRITE_SECURE_SETTINGS);
-            if (!nfcAdapter.enable()) {
-                return false;
-            }
-            countDownLatch.await(2000, TimeUnit.MILLISECONDS);
-            return state.get() == NfcAdapter.STATE_ON;
-        } catch (Exception e) {
-            e.printStackTrace();
-            return false;
-        } finally {
-            androidx.test.platform.app.InstrumentationRegistry.getInstrumentation()
-                    .getUiAutomation().dropShellPermissionIdentity();
-        }
+    private static final String TAG = "NfcUtils";
+
+    static boolean enableNfc(@NonNull NfcAdapter nfcAdapter, @NonNull Context context) {
+        return setNfcState(nfcAdapter, context, /* setEnabled= */ true, null);
     }
 
-    static boolean disableNfc(NfcAdapter nfcAdapter, Context context) {
+    static boolean disableNfc(@NonNull NfcAdapter nfcAdapter, @NonNull Context context) {
         return disableNfc(nfcAdapter, context, null);
     }
 
-    static boolean disableNfc(NfcAdapter nfcAdapter, Context context, @Nullable Boolean persist) {
+    static boolean disableNfc(@NonNull NfcAdapter nfcAdapter, @NonNull Context context,
+        @Nullable Boolean persist) {
+        return setNfcState(nfcAdapter, context, /* setEnabled= */ false, persist);
+    }
+
+    private static boolean setNfcState(
+            @NonNull NfcAdapter nfcAdapter,
+            @NonNull Context context,
+            boolean setEnabled,
+            @Nullable Boolean disablePersist) {
+        if (setEnabled == nfcAdapter.isEnabled()) {
+            return true;
+        }
+        HandlerThread handlerThread = new HandlerThread("nfc_cts_listener");
+        handlerThread.start();
+        Handler handler = new Handler(handlerThread.getLooper());
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
+
+        NfcStateChangeListener nfcChangeListener = new NfcStateChangeListener(setEnabled);
         try {
-            if (!nfcAdapter.isEnabled()) {
-                return true;
-            }
-            CountDownLatch countDownLatch = new CountDownLatch(1);
-            AtomicInteger state = new AtomicInteger(NfcAdapter.STATE_ON);
-            BroadcastReceiver nfcChangeListener = new BroadcastReceiver() {
-                @Override
-                public void onReceive(Context context, Intent intent) {
-                    int s =  intent.getIntExtra(NfcAdapter.EXTRA_ADAPTER_STATE,
-                            NfcAdapter.STATE_ON);
-                    if (s == NfcAdapter.STATE_TURNING_OFF) {
-                        return;
-                    }
-                    context.unregisterReceiver(this);
-                    state.set(s);
-                    countDownLatch.countDown();
+            context.registerReceiver(nfcChangeListener, intentFilter, null, handler);
+            androidx.test.platform.app.InstrumentationRegistry.getInstrumentation()
+                    .getUiAutomation()
+                    .adoptShellPermissionIdentity(WRITE_SECURE_SETTINGS);
+
+            if (setEnabled) {
+                if (!nfcAdapter.enable()) {
+                    Log.e(TAG, "Failed to enable NFC");
+                    return false;
                 }
-            };
-            HandlerThread handlerThread = new HandlerThread("nfc_cts_listener");
-            handlerThread.start();
-            Handler handler = new Handler(handlerThread.getLooper());
-            IntentFilter intentFilter = new IntentFilter();
-            intentFilter.addAction(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
-            context.registerReceiver(nfcChangeListener, intentFilter, null,
-                    handler);
-            androidx.test.platform.app.InstrumentationRegistry.getInstrumentation()
-                    .getUiAutomation().adoptShellPermissionIdentity(WRITE_SECURE_SETTINGS);
-            boolean result = false;
-            if (persist != null) {
-                result = nfcAdapter.disable(persist);
             } else {
-                result = nfcAdapter.disable();
+                if (disablePersist != null) {
+                    if (!nfcAdapter.disable(disablePersist)) {
+                        Log.e(TAG, "Failed to disable NFC");
+                        return false;
+                    }
+                } else {
+                    if (!nfcAdapter.disable()) {
+                        Log.e(TAG, "Failed to disable NFC");
+                        return false;
+                    }
+                }
             }
-            if (!result) return false;
-            countDownLatch.await(2000, TimeUnit.MILLISECONDS);
-            return state.get() == NfcAdapter.STATE_OFF;
-        } catch (Exception e) {
-            return false;
+
+            return nfcChangeListener.awaitStateChange();
         } finally {
+            context.unregisterReceiver(nfcChangeListener);
             androidx.test.platform.app.InstrumentationRegistry.getInstrumentation()
-                    .getUiAutomation().dropShellPermissionIdentity();
+                    .getUiAutomation()
+                    .dropShellPermissionIdentity();
         }
     }
 
+    private static class NfcStateChangeListener extends BroadcastReceiver {
+        private final CountDownLatch mCountDownLatch;
+        private final boolean mExpectingEnabled;
+
+        NfcStateChangeListener(boolean expectingEnabled) {
+            mCountDownLatch = new CountDownLatch(1);
+            mExpectingEnabled = expectingEnabled;
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            int s = intent.getIntExtra(NfcAdapter.EXTRA_ADAPTER_STATE, 0);
+
+            if ((mExpectingEnabled && s == NfcAdapter.STATE_ON)
+                    || (!mExpectingEnabled && s == NfcAdapter.STATE_OFF)) {
+                mCountDownLatch.countDown();
+            }
+        }
+
+        public boolean awaitStateChange() {
+            try {
+                boolean success = mCountDownLatch.await(20, TimeUnit.SECONDS);
+
+                if (!success) {
+                    Log.e( TAG, "Timeout waiting for NFC to be "
+                                    + (mExpectingEnabled ? "enabled" : "disabled"));
+                }
+
+                return success;
+            } catch (InterruptedException e) {
+                Log.e( TAG, "Interrupted while waiting for NFC to be "
+                                + (mExpectingEnabled ? "enabled" : "disabled"));
+                return false;
+            }
+        }
+    }
+
+    public static void assumeObserveModeSupported(@NonNull NfcAdapter adapter) {
+        assumeTrue("Observe mode must be supported", adapter.isObserveModeSupported());
+    }
+
+    public static void assumeVsrApiGreaterThanUdc() {
+        assumeTrue("Device VSR API level must be greater than UDC",
+            getVsrApiLevel() > Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
+    }
 }
diff --git a/tests/cts/tests/src/android/nfc/cts/OffHostApduServiceTest.java b/tests/cts/tests/src/android/nfc/cts/OffHostApduServiceTest.java
index b3b45cb..bb6d230 100644
--- a/tests/cts/tests/src/android/nfc/cts/OffHostApduServiceTest.java
+++ b/tests/cts/tests/src/android/nfc/cts/OffHostApduServiceTest.java
@@ -1,5 +1,7 @@
 package android.nfc.cts;
 
+import static org.junit.Assert.assertNull;
+
 import android.content.Intent;
 import android.os.Looper;
 import org.junit.Assert;
@@ -24,6 +26,6 @@
     public void testOnBind() {
         Intent serviceIntent
             = new Intent(CtsMyOffHostApduService.SERVICE_INTERFACE);
-        Assert.assertNull(service.onBind(serviceIntent));
+        assertNull(service.onBind(serviceIntent));
     }
 }
diff --git a/tests/cts/tests/src/android/nfc/cts/TagLostExceptionTest.java b/tests/cts/tests/src/android/nfc/cts/TagLostExceptionTest.java
index 47c71c5..d4bd0d0 100644
--- a/tests/cts/tests/src/android/nfc/cts/TagLostExceptionTest.java
+++ b/tests/cts/tests/src/android/nfc/cts/TagLostExceptionTest.java
@@ -1,5 +1,7 @@
 package android.nfc.cts;
 
+import static org.junit.Assert.assertTrue;
+
 import android.nfc.TagLostException;
 import org.junit.Assert;
 import org.junit.Test;
@@ -11,13 +13,13 @@
     try {
       throw new TagLostException();
     } catch (TagLostException e) {
-      Assert.assertTrue("TagLostException message is null", e.getMessage() == null);
+      assertTrue("TagLostException message is null", e.getMessage() == null);
     }
     String s = new String("testTagLostException");
     try {
       throw new TagLostException(s);
     } catch (TagLostException e) {
-      Assert.assertTrue("TagLostException message is not correct", e.getMessage().equals(s));
+      assertTrue("TagLostException message is not correct", e.getMessage().equals(s));
     }
   }
 }
diff --git a/tests/cts/tests/src/android/nfc/cts/WalletRoleTest.java b/tests/cts/tests/src/android/nfc/cts/WalletRoleTest.java
index b285bf6..0bedf36 100644
--- a/tests/cts/tests/src/android/nfc/cts/WalletRoleTest.java
+++ b/tests/cts/tests/src/android/nfc/cts/WalletRoleTest.java
@@ -23,6 +23,9 @@
 import static android.nfc.cts.WalletRoleTestUtils.clearRoleHolders;
 import static android.nfc.cts.WalletRoleTestUtils.getDefaultWalletRoleHolder;
 import static android.nfc.cts.WalletRoleTestUtils.getOverLayDefaultHolder;
+import static org.junit.Assume.assumeNotNull;
+import static org.junit.Assume.assumeTrue;
+import static org.testng.Assert.assertEquals;
 
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -53,7 +56,7 @@
     @Before
     public void setUp() {
         mContext = InstrumentationRegistry.getContext();
-        Assume.assumeTrue(supportsHardware());
+        assumeTrue(supportsHardware());
     }
 
     private boolean supportsHardware() {
@@ -64,15 +67,15 @@
     @Test
     public void testMigrationFromOverlay() {
         String overlayConfig = getOverLayDefaultHolder(mContext);
-        Assume.assumeNotNull(overlayConfig);
-        Assume.assumeTrue(canAssignRoleToPackage(mContext, overlayConfig));
+        assumeNotNull(overlayConfig);
+        assumeTrue(canAssignRoleToPackage(mContext, overlayConfig));
         runWithDefaultPaymentSetting(mContext,
                 null,
                 () -> {
                     clearRoleHolders(mContext);
                     String currentHolder = getDefaultWalletRoleHolder(mContext);
 
-                    Assert.assertEquals(currentHolder, overlayConfig);
+                    assertEquals(currentHolder, overlayConfig);
                 });
     }
 
@@ -84,7 +87,7 @@
                     clearRoleHolders(mContext);
                     String currentHolder = getDefaultWalletRoleHolder(mContext);
 
-                    Assert.assertEquals(currentHolder, CTS_PACKAGE_NAME);
+                    assertEquals(currentHolder, CTS_PACKAGE_NAME);
                 });
     }
 
diff --git a/tests/cts/tests/src/android/nfc/cts/WalletRoleTestUtils.java b/tests/cts/tests/src/android/nfc/cts/WalletRoleTestUtils.java
index 9081d7b..7990503 100644
--- a/tests/cts/tests/src/android/nfc/cts/WalletRoleTestUtils.java
+++ b/tests/cts/tests/src/android/nfc/cts/WalletRoleTestUtils.java
@@ -21,6 +21,7 @@
 import static android.Manifest.permission.MANAGE_ROLE_HOLDERS;
 import static android.Manifest.permission.OBSERVE_ROLE_HOLDERS;
 
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeFalse;
 
 import android.app.role.OnRoleHoldersChangedListener;
@@ -146,7 +147,7 @@
 
     static void runWithRole(Context context, String roleHolder, Runnable runnable) {
         final UserManager userManager = context.getSystemService(UserManager.class);
-        assumeFalse(userManager.isHeadlessSystemUserMode());
+        assumeFalse("Device must not be headless", userManager.isHeadlessSystemUserMode());
         try {
             runWithRoleNone(context, () -> {}); //Remove the role holder first to trigger callbacks
             RoleManager roleManager = context.getSystemService(RoleManager.class);
@@ -171,7 +172,7 @@
                     .getUiAutomation()
                     .adoptShellPermissionIdentity(
                             MANAGE_DEFAULT_APPLICATIONS, INTERACT_ACROSS_USERS_FULL);
-            Assert.assertTrue(setDefaultWalletRoleHolder(context, roleHolder));
+            assertTrue(setDefaultWalletRoleHolder(context, roleHolder));
             countDownLatch.await(4000, TimeUnit.MILLISECONDS);
             androidx.test.platform.app.InstrumentationRegistry.getInstrumentation()
                     .getUiAutomation().adoptShellPermissionIdentity(OBSERVE_ROLE_HOLDERS);
@@ -229,7 +230,7 @@
                     .getUiAutomation().adoptShellPermissionIdentity(MANAGE_ROLE_HOLDERS);
             if (currentHolder != null) {
                 roleManager.setRoleFallbackEnabled(RoleManager.ROLE_WALLET, false);
-                Assert.assertTrue(removeRoleHolder(context, currentHolder));
+                assertTrue(removeRoleHolder(context, currentHolder));
                 countDownLatch.await(4000, TimeUnit.MILLISECONDS);
                 roleManager.setRoleFallbackEnabled(RoleManager.ROLE_WALLET, true);
             }