keep history
diff --git a/jni/com_android_nfc_NativeNfcManager.cpp b/jni/com_android_nfc_NativeNfcManager.cpp
index cba4691..e724524 100644
--- a/jni/com_android_nfc_NativeNfcManager.cpp
+++ b/jni/com_android_nfc_NativeNfcManager.cpp
@@ -26,13 +26,16 @@
 
 #define ERROR_BUFFER_TOO_SMALL       -12
 #define ERROR_INSUFFICIENT_RESOURCES -9
-#define EEDATA_SETTINGS_NUMBER       28
+#define EEDATA_SETTINGS_NUMBER       29
 
 static phLibNfc_sConfig_t   gDrvCfg;
 void   *gHWRef;
 static phNfc_sData_t gInputParam;
 static phNfc_sData_t gOutputParam;
 
+uint8_t device_connected_flag;
+static bool driverConfigured = FALSE;
+
 static phLibNfc_Handle              hLlcpHandle;
 static NFCSTATUS                    lastErrorStatus = NFCSTATUS_FAILED;
 static phLibNfc_Llcp_eLinkStatus_t  g_eLinkStatus = phFriNfc_LlcpMac_eLinkDefault;
@@ -46,6 +49,10 @@
 static jmethodID cached_NfcManager_notifySeFieldActivated;
 static jmethodID cached_NfcManager_notifySeFieldDeactivated;
 
+static jmethodID cached_NfcManager_notifySeApduReceived;
+static jmethodID cached_NfcManager_notifySeMifareAccess;
+static jmethodID cached_NfcManager_notifySeEmvCardRemoval;
+
 namespace android {
 
 phLibNfc_Handle     storedHandle = 0;
@@ -102,6 +109,9 @@
 	// Set NFCT ATQA
 	,{0x00, 0x98, 0x7D, 0x02}
 	,{0x00, 0x98, 0x7E, 0x00}
+
+     // Enable CEA detection mechanism
+    ,{0x00, 0x9F, 0xC8, 0x01}
 };
 
 /* Internal functions declaration */
@@ -210,7 +220,7 @@
     uint8_t OutputBuffer[1];
     uint8_t InputBuffer[1];
     struct timespec ts;
-    NFCSTATUS status;
+    NFCSTATUS status = NFCSTATUS_FAILED;
     phLibNfc_StackCapabilities_t caps;
     struct nfc_jni_callback_data cb_data;
 
@@ -277,13 +287,21 @@
        goto clean_and_return;
     }
 
-    /* Download Status */
-    if(cb_data.status != NFCSTATUS_SUCCESS)
+    /* NOTE: we will get NFCSTATUS_FEATURE_NOT_SUPPORTED when we
+       try to download an old-style firmware on top of a new-style
+       firmware.  Hence, this is expected behavior, and not an
+       error condition. */
+    if(cb_data.status != NFCSTATUS_SUCCESS && cb_data.status != NFCSTATUS_FEATURE_NOT_SUPPORTED)
     {
         status = cb_data.status;
         goto clean_and_return;
     }
 
+    if(cb_data.status == NFCSTATUS_FEATURE_NOT_SUPPORTED)
+    {
+        LOGW("Old-style firmware not installed on top of new-style firmware. Using existing firmware in the chip.");
+    }
+
 reinit:
     TRACE("phLibNfc_HW_Reset()");
     phLibNfc_HW_Reset();
@@ -323,13 +341,14 @@
     }
     else
     {
-        LOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, FW Update Info = %d",
+        LOGD("NFC capabilities: HAL = %x, FW = %x, HW = %x, Model = %x, HCI = %x, Full_FW = %d, Rev = %d, FW Update Info = %d",
               caps.psDevCapabilities.hal_version,
               caps.psDevCapabilities.fw_version,
               caps.psDevCapabilities.hw_version,
               caps.psDevCapabilities.model_id,
               caps.psDevCapabilities.hci_version,
               caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-1],
+              caps.psDevCapabilities.full_version[NXP_FULL_VERSION_LEN-2],
               caps.psDevCapabilities.firmware_update_info);
     }
 
@@ -341,20 +360,83 @@
    return status;
 }
 
+static int nfc_jni_configure_driver(struct nfc_jni_native_data *nat)
+{
+    char value[PROPERTY_VALUE_MAX];
+    int result = FALSE;
+    NFCSTATUS status;
+
+    /* ====== CONFIGURE DRIVER ======= */
+    /* Configure hardware link */
+    gDrvCfg.nClientId = phDal4Nfc_msgget(0, 0600);
+
+    property_get("ro.nfc.port", value, "unknown");
+    gDrvCfg.nLinkType = parseLinkType(value);
+
+    TRACE("phLibNfc_Mgt_ConfigureDriver(0x%08x, 0x%08x)", gDrvCfg.nClientId, gDrvCfg.nLinkType);
+    REENTRANCE_LOCK();
+    status = phLibNfc_Mgt_ConfigureDriver(&gDrvCfg, &gHWRef);
+    REENTRANCE_UNLOCK();
+    if(status == NFCSTATUS_ALREADY_INITIALISED) {
+           LOGW("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+    }
+    else if(status != NFCSTATUS_SUCCESS)
+    {
+        LOGE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+        goto clean_and_return;
+    }
+    TRACE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+    if(pthread_create(&(nat->thread), NULL, nfc_jni_client_thread, nat) != 0)
+    {
+        LOGE("pthread_create failed");
+        goto clean_and_return;
+    }
+
+    driverConfigured = TRUE;
+
+clean_and_return:
+    return result;
+}
+
+static int nfc_jni_unconfigure_driver(struct nfc_jni_native_data *nat)
+{
+    int result = FALSE;
+    NFCSTATUS status;
+
+    /* Unconfigure driver */
+    TRACE("phLibNfc_Mgt_UnConfigureDriver()");
+    REENTRANCE_LOCK();
+    status = phLibNfc_Mgt_UnConfigureDriver(gHWRef);
+    REENTRANCE_UNLOCK();
+    if(status != NFCSTATUS_SUCCESS)
+    {
+        LOGE("phLibNfc_Mgt_UnConfigureDriver() returned error 0x%04x[%s] -- this should never happen", status, nfc_jni_get_status_name( status));
+    }
+    else
+    {
+       LOGD("phLibNfc_Mgt_UnConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+       result = TRUE;
+    }
+
+    driverConfigured = FALSE;
+
+    return result;
+}
+
 /* Initialization function */
 static int nfc_jni_initialize(struct nfc_jni_native_data *nat) {
    struct timespec ts;
    uint8_t resp[16];
    NFCSTATUS status;
    phLibNfc_StackCapabilities_t caps;
-   char value[PROPERTY_VALUE_MAX];
-   int result = FALSE;
    phLibNfc_SE_List_t SE_List[PHLIBNFC_MAXNO_OF_SE];
    uint8_t i, No_SE = PHLIBNFC_MAXNO_OF_SE, SmartMX_index = 0, SmartMX_detected = 0;
    phLibNfc_Llcp_sLinkParameters_t LlcpConfigInfo;
    struct nfc_jni_callback_data cb_data;
    uint8_t firmware_status;
    uint8_t update = TRUE;
+   int result = JNI_FALSE;
 
    LOGD("Start Initialization\n");
 
@@ -364,36 +446,16 @@
       goto clean_and_return;
    }
 
+   /* Reset device connected handle */
+   device_connected_flag = 0;
+
    /* Reset stored handle */
    storedHandle = 0;
 
-   /* Configure hardware link */
-   gDrvCfg.nClientId = phDal4Nfc_msgget(0, 0600);
-
-   property_get("ro.nfc.port", value, "unknown");
-   gDrvCfg.nLinkType = parseLinkType(value);
-
-   /* ====== CONFIGURE DRIVER ======= */
-
-   TRACE("phLibNfc_Mgt_ConfigureDriver(0x%08x, 0x%08x)", gDrvCfg.nClientId, gDrvCfg.nLinkType);
-   REENTRANCE_LOCK();
-   status = phLibNfc_Mgt_ConfigureDriver(&gDrvCfg, &gHWRef);
-   REENTRANCE_UNLOCK();
-   if(status == NFCSTATUS_ALREADY_INITIALISED) {
-      LOGW("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
-   }
-   else if(status != NFCSTATUS_SUCCESS)
+   /* Initialize Driver */
+   if(!driverConfigured)
    {
-      LOGE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
-      goto clean_and_return;
-   }
-   TRACE("phLibNfc_Mgt_ConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
-
-   if(pthread_create(&(nat->thread), NULL, nfc_jni_client_thread,
-         nat) != 0)
-   {
-      LOGE("pthread_create failed");
-      goto clean_and_return;
+       nfc_jni_configure_driver(nat);
    }
 
    /* ====== INITIALIZE ======= */
@@ -460,6 +522,7 @@
                break;
            }
            LOGW("Firmware update FAILED");
+           update = FALSE;
        }
        if(i>=3)
        {
@@ -655,6 +718,9 @@
    /* Reset the PN544 ISO XCHG / sw watchdog timeouts */
    nfc_jni_reset_timeout_values();
 
+   /* Reset device connected flag */
+   device_connected_flag = 0;
+
    /* Restart Polling loop */
    TRACE("******  Start NFC Discovery ******");
    REENTRANCE_LOCK();
@@ -839,12 +905,15 @@
                                                                                   sLinkParams.miu,
                                                                                   sLinkParams.option,
                                                                                   sLinkParams.wks);
+           device_connected_flag = 1;
       }
    }
    else if(eLinkStatus == phFriNfc_LlcpMac_eLinkDeactivated)
    {
       LOGI("LLCP Link deactivated");
       free(pContextData);
+      /* Reset device connected flag */
+      device_connected_flag = 0;
 
       /* Reset incoming socket list */
       while (!LIST_EMPTY(&pMonitor->incoming_socket_head))
@@ -982,7 +1051,10 @@
    {
       LOG_CALLBACK("nfc_jni_Discovery_notification_callback", status);
       TRACE("Discovered %d tags", uNofRemoteDev);
-      
+
+      /* Reset device connected flag */
+      device_connected_flag = 1;
+
       if((psRemoteDevList->psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Initiator)
           || (psRemoteDevList->psRemoteDevInfo->RemDevType == phNfc_eNfcIP1_Target))
       {
@@ -1176,9 +1248,11 @@
    phLibNfc_uSeEvtInfo_t *evt_info, NFCSTATUS status)
 {
     JNIEnv *e;
-    jobject aid_array = NULL;
+    jobject tmp_array = NULL;
+    jobject mifare_block = NULL;
     struct nfc_jni_native_data *nat;
     phNfc_sData_t *aid;
+    phNfc_sData_t *mifare_command;
     struct nfc_jni_callback_data *pCallbackData;
     int i=0;
 
@@ -1205,18 +1279,18 @@
                     {
                         char aid_str[AID_MAXLEN * 2 + 1];
                         aid_str[0] = '\0';
-                        for (i = 0; i < (aid->length) && i < AID_MAXLEN; i++) {
+                        for (i = 0; i < (int) (aid->length) && i < AID_MAXLEN; i++) {
                           snprintf(&aid_str[i*2], 3, "%02x", aid->buffer[i]);
                         }
                         LOGD("> AID: %s", aid_str);
 
-                        aid_array = e->NewByteArray(aid->length);
-                        if(aid_array == NULL)
+                        tmp_array = e->NewByteArray(aid->length);
+                        if (tmp_array == NULL)
                         {
                             goto error;
                         }
 
-                        e->SetByteArrayRegion((jbyteArray)aid_array, 0, aid->length, (jbyte *)aid->buffer);
+                        e->SetByteArrayRegion((jbyteArray)tmp_array, 0, aid->length, (jbyte *)aid->buffer);
                         if(e->ExceptionCheck())
                         {
                             goto error;
@@ -1229,7 +1303,7 @@
 
                     TRACE("Notify Nfc Service");
                     /* Notify manager that a new event occurred on a SE */
-                    e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTransactionListeners, aid_array);
+                    e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTransactionListeners, tmp_array);
                     if(e->ExceptionCheck())
                     {
                         goto error;
@@ -1241,6 +1315,56 @@
                 }
             }break;
 
+            case phLibNfc_eSE_EvtApduReceived:
+            {
+                phNfc_sData_t *apdu = &(evt_info->UiccEvtInfo.aid);
+                TRACE("> SE EVT_APDU_RECEIVED");
+
+                if (apdu != NULL) {
+                        TRACE("  APDU length=%d", apdu->length);
+                        tmp_array = e->NewByteArray(apdu->length);
+                        if (tmp_array == NULL) {
+                            goto error;
+                        }
+                        e->SetByteArrayRegion((jbyteArray)tmp_array, 0, apdu->length, (jbyte *)apdu->buffer);
+                        if (e->ExceptionCheck()) {
+                            goto error;
+                        }
+                } else {
+                        TRACE("  APDU EMPTY");
+                }
+
+                TRACE("Notify Nfc Service");
+                e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeApduReceived, tmp_array);
+            }break;
+
+            case phLibNfc_eSE_EvtCardRemoval:
+            {
+                TRACE("> SE EVT_EMV_CARD_REMOVAL");
+                TRACE("Notify Nfc Service");
+                e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeEmvCardRemoval);
+            }break;
+
+            case phLibNfc_eSE_EvtMifareAccess:
+            {
+                TRACE("> SE EVT_MIFARE_ACCESS");
+                mifare_command = &(evt_info->UiccEvtInfo.aid);
+                TRACE("> MIFARE Block: %d",mifare_command->buffer[1]);
+                tmp_array = e->NewByteArray(2);
+                if (tmp_array == NULL)
+                {
+                    goto error;
+                }
+
+                e->SetByteArrayRegion((jbyteArray)tmp_array, 0, 2, (jbyte *)mifare_command->buffer);
+                if(e->ExceptionCheck())
+                {
+                    goto error;
+                }
+                TRACE("Notify Nfc Service");
+                e->CallVoidMethod(nat->manager, cached_NfcManager_notifySeMifareAccess, mifare_block);
+            }break;
+
             case phLibNfc_eSE_EvtFieldOn:
             {
                 TRACE("> SE EVT_FIELD_ON");
@@ -1276,9 +1400,9 @@
     e->ExceptionClear();
 
  clean_and_return:
-    if(aid_array != NULL)
+    if(tmp_array != NULL)
     {
-       e->DeleteLocalRef(aid_array);
+       e->DeleteLocalRef(tmp_array);
     }
 }
 
@@ -1354,6 +1478,9 @@
    /* Reset the PN544 ISO XCHG / sw watchdog timeouts */
    nfc_jni_reset_timeout_values();
 
+   /* Reset device connected flag */
+   device_connected_flag = 0;
+
 #if 0
    nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443A = TRUE;
    nat->discovery_cfg.PollDevInfo.PollCfgInfo.EnableIso14443B = TRUE;
@@ -1454,7 +1581,7 @@
    }
 
    discovery_cfg.PollDevInfo.PollEnabled = 0;
-   discovery_cfg.Duration = 0xffffffff;
+   discovery_cfg.Duration = 300000; /* in ms */
    /*discovery_cfg.NfcIP_Mode = phNfc_eInvalidP2PMode;*/
    discovery_cfg.NfcIP_Mode = phNfc_eDefaultP2PMode;
    discovery_cfg.NfcIP_Tgt_Disable = TRUE;
@@ -1631,7 +1758,16 @@
       "notifySeFieldActivated", "()V");
 
    cached_NfcManager_notifySeFieldDeactivated = e->GetMethodID(cls,
-       "notifySeFieldDeactivated", "()V");
+      "notifySeFieldDeactivated", "()V");
+
+   cached_NfcManager_notifySeApduReceived= e->GetMethodID(cls,
+      "notifySeApduReceived", "([B)V");
+
+   cached_NfcManager_notifySeMifareAccess = e->GetMethodID(cls,
+      "notifySeMifareAccess", "([B)V");
+
+   cached_NfcManager_notifySeEmvCardRemoval =  e->GetMethodID(cls,
+      "notifySeEmvCardRemoval", "()V");
 
    if(nfc_jni_cache_object(e,"com/android/nfc/NativeNfcTag",&(nat->cached_NfcTag)) == -1)
    {
@@ -1644,11 +1780,11 @@
       LOGD("Native Structure initialization failed");
       return FALSE;   
    }
-
-   TRACE("****** Init Native Structure OK ******"); 
+   TRACE("****** Init Native Structure OK ******");
    return TRUE;
+
 }
- 
+
 /* Init/Deinit method */
 static jboolean com_android_nfc_NfcManager_initialize(JNIEnv *e, jobject o)
 {
@@ -1687,17 +1823,20 @@
 {
    struct timespec ts;
    NFCSTATUS status;
+   int result = JNI_FALSE;
    struct nfc_jni_native_data *nat;
    int bStackReset = FALSE;
    struct nfc_jni_callback_data cb_data;
 
+   CONCURRENCY_LOCK();
+
    /* Retrieve native structure address */
-   nat = nfc_jni_get_nat(e, o); 
+   nat = nfc_jni_get_nat(e, o);
 
    /* Clear previous configuration */
    memset(&nat->discovery_cfg, 0, sizeof(phLibNfc_sADD_Cfg_t));
    memset(&nat->registry_info, 0, sizeof(phLibNfc_Registry_Info_t));
-   
+
    /* Create the local semaphore */
    if (nfc_cb_data_init(&cb_data, NULL))
    {
@@ -1747,22 +1886,12 @@
       emergency_recovery(nat);
    }
 
-   /* Unconfigure driver */
-   TRACE("phLibNfc_Mgt_UnConfigureDriver()");
-   REENTRANCE_LOCK();
-   status = phLibNfc_Mgt_UnConfigureDriver(gHWRef);
-   REENTRANCE_UNLOCK();
-   if(status != NFCSTATUS_SUCCESS)
-   {
-      LOGE("phLibNfc_Mgt_UnConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
-   }
-   else
-   {
-      LOGD("phLibNfc_Mgt_UnConfigureDriver() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
-   }
+   result = nfc_jni_unconfigure_driver(nat);
 
    TRACE("NFC Deinitialized");
 
+   CONCURRENCY_UNLOCK();
+
    return TRUE;
 }
 
@@ -2384,14 +2513,123 @@
     emergency_recovery(NULL);
 }
 
+static jboolean com_android_nfc_NfcManager_doDownload(JNIEnv *e, jobject o)
+{
+    char* firmware_version;
+    jboolean result = FALSE;
+    int load_result;
+    int unconfigure_status;
+    bool drive_state = FALSE;
+    uint8_t OutputBuffer[1];
+    uint8_t InputBuffer[1];
+    struct timespec ts;
+    NFCSTATUS status = NFCSTATUS_FAILED;
+    struct nfc_jni_callback_data cb_data;
+    struct nfc_jni_native_data *nat = NULL;
+    char value[PROPERTY_VALUE_MAX];
+
+    /* Create the local semaphore */
+    if (!nfc_cb_data_init(&cb_data, NULL))
+    {
+       result = FALSE;
+       goto clean_and_return;
+    }
+
+    /* Retrieve native structure address */
+    nat = nfc_jni_get_nat(e, o);
+
+    CONCURRENCY_LOCK();
+
+    /* Initialize Driver */
+    if(!driverConfigured)
+    {
+        result = nfc_jni_configure_driver(nat);
+        drive_state = TRUE;
+    }
+
+    TRACE("com_android_nfc_NfcManager_doDownload()");
+
+    TRACE("Go in Download Mode");
+    phLibNfc_Download_Mode();
+
+    TRACE("Load new Firmware Image");
+    load_result = phLibNfc_Load_Firmware_Image();
+    if(load_result != 0)
+    {
+        TRACE("Load new Firmware Image - status = %d",load_result);
+        result = FALSE;
+        goto clean_and_return;
+    }
+
+    // Download
+    gInputParam.buffer  = InputBuffer;
+    gInputParam.length  = 0x01;
+    gOutputParam.buffer = OutputBuffer;
+    gOutputParam.length = 0x01;
+
+    LOGD("Download new Firmware");
+    REENTRANCE_LOCK();
+    status = phLibNfc_Mgt_IoCtl(gHWRef,NFC_FW_DOWNLOAD, &gInputParam, &gOutputParam, nfc_jni_ioctl_callback, (void *)&cb_data);
+    REENTRANCE_UNLOCK();
+    if(status != NFCSTATUS_PENDING)
+    {
+        LOGE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+        result = FALSE;
+        goto clean_and_return;
+    }
+    TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+    /* Wait for callback response */
+    if(sem_wait(&cb_data.sem))
+    {
+       LOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+       result = FALSE;
+       goto clean_and_return;
+    }
+
+    /* NOTE: we will get NFCSTATUS_FEATURE_NOT_SUPPORTED when we
+       try to download an old-style firmware on top of a new-style
+       firmware.  Hence, this is expected behavior, and not an
+       error condition. */
+    if(cb_data.status != NFCSTATUS_SUCCESS && cb_data.status != NFCSTATUS_FEATURE_NOT_SUPPORTED)
+    {
+        TRACE("phLibNfc_Mgt_IoCtl() (download) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+        result = FALSE;
+        goto clean_and_return;
+    }
+
+    if(cb_data.status == NFCSTATUS_FEATURE_NOT_SUPPORTED)
+    {
+        LOGW("Old-style firmware not installed on top of new-style firmware. Using existing firmware in the chip.");
+    }
+
+    /*Download is successful*/
+    result = TRUE;
+
+clean_and_return:
+    TRACE("phLibNfc_HW_Reset()");
+    phLibNfc_HW_Reset();
+    /* Deinitialize Driver */
+    if(drive_state)
+    {
+        result = nfc_jni_unconfigure_driver(nat);
+    }
+    CONCURRENCY_UNLOCK();
+    nfc_cb_data_deinit(&cb_data);
+    return result;
+}
+
 /*
  * JNI registration.
  */
 static JNINativeMethod gMethods[] =
 {
+   {"doDownload", "()Z",
+        (void *)com_android_nfc_NfcManager_doDownload},
+
    {"initializeNativeStructure", "()Z",
       (void *)com_android_nfc_NfcManager_init_native_struc},
-      
+
    {"initialize", "()Z",
       (void *)com_android_nfc_NfcManager_initialize},
  
diff --git a/jni/com_android_nfc_NativeNfcSecureElement.cpp b/jni/com_android_nfc_NativeNfcSecureElement.cpp
index f309122..f4a402b 100755
--- a/jni/com_android_nfc_NativeNfcSecureElement.cpp
+++ b/jni/com_android_nfc_NativeNfcSecureElement.cpp
@@ -24,6 +24,7 @@
 static int secureElementHandle;
 extern void                 *gHWRef;
 static int SecureElementTech;
+extern uint8_t device_connected_flag;
 
 namespace android {
 
@@ -204,6 +205,13 @@
    
    TRACE("Open Secure Element");
    
+   /* Check if NFC device is already connected to a tag or P2P peer */
+   if (device_connected_flag == 1)
+   {
+       LOGD("Unable to open SE connection, device already connected to a P2P peer or a Tag");
+       goto clean_and_return;
+   }
+
    /* Test if External RF field is detected */
    InParam.buffer = ExternalRFDetected;
    InParam.length = 3;
@@ -215,6 +223,7 @@
    if(ret!=NFCSTATUS_PENDING)
    {
       LOGE("IOCTL status error");
+      goto clean_and_return;
    }
 
    /* Wait for callback response */
diff --git a/jni/com_android_nfc_NativeNfcTag.cpp b/jni/com_android_nfc_NativeNfcTag.cpp
index 566b28e..e724309 100644
--- a/jni/com_android_nfc_NativeNfcTag.cpp
+++ b/jni/com_android_nfc_NativeNfcTag.cpp
@@ -25,7 +25,7 @@
 uint8_t *nfc_jni_ndef_buf = NULL;
 uint32_t nfc_jni_ndef_buf_len = 0;
 
-
+extern uint8_t device_connected_flag;
 
 namespace android {
 
@@ -444,13 +444,12 @@
     e->ReleaseIntArrayElements(techList, techId, 0);
 }
 
-static jboolean com_android_nfc_NativeNfcTag_doConnect(JNIEnv *e,
+static jint com_android_nfc_NativeNfcTag_doConnect(JNIEnv *e,
    jobject o, phLibNfc_Handle handle)
 {
    jclass cls;
    jfieldID f;
-   NFCSTATUS status;
-   jboolean result = JNI_FALSE;
+   jint status;
    struct nfc_jni_callback_data cb_data;
    phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL;
 
@@ -459,6 +458,7 @@
    /* Create the local semaphore */
    if (!nfc_cb_data_init(&cb_data, &pRemDevInfo))
    {
+      status = NFCSTATUS_NOT_ENOUGH_MEMORY;
       goto clean_and_return;
    }
 
@@ -478,11 +478,15 @@
    if(sem_wait(&cb_data.sem))
    {
       LOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+      status = NFCSTATUS_ABORTED;
       goto clean_and_return;
    }
-   
+
+   status = cb_data.status;
+   TRACE("phLibNfc_RemoteDev_Connect() - Status code = %d", status);
+
    /* Connect Status */
-   if(cb_data.status != NFCSTATUS_SUCCESS)
+   if(status != NFCSTATUS_SUCCESS)
    {
       goto clean_and_return;
    }
@@ -491,21 +495,18 @@
    set_target_pollBytes(e, o, pRemDevInfo);
    set_target_activationBytes(e, o, pRemDevInfo);
 
-   result = JNI_TRUE;
-
 clean_and_return:
    nfc_cb_data_deinit(&cb_data);
    CONCURRENCY_UNLOCK();
-   return result;
+   return status;
 }
 
-static jboolean com_android_nfc_NativeNfcTag_doHandleReconnect(JNIEnv *e,
+static jint com_android_nfc_NativeNfcTag_doHandleReconnect(JNIEnv *e,
    jobject o, phLibNfc_Handle handle)
 {
    jclass cls;
    jfieldID f;
-   NFCSTATUS status;
-   jboolean result = JNI_FALSE;
+   jint status;
    struct nfc_jni_callback_data cb_data;
    phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL;
    CONCURRENCY_LOCK();
@@ -513,6 +514,7 @@
    /* Create the local semaphore */
    if (!nfc_cb_data_init(&cb_data, &pRemDevInfo))
    {
+      status = NFCSTATUS_NOT_ENOUGH_MEMORY;
       goto clean_and_return;
    }
 
@@ -532,24 +534,25 @@
    if(sem_wait(&cb_data.sem))
    {
       LOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+      status = NFCSTATUS_ABORTED;
       goto clean_and_return;
    }
 
+   status = cb_data.status;
+
    /* Connect Status */
-   if(cb_data.status != NFCSTATUS_SUCCESS)
+   if(status != NFCSTATUS_SUCCESS)
    {
       goto clean_and_return;
    }
 
-   result = JNI_TRUE;
-
 clean_and_return:
    nfc_cb_data_deinit(&cb_data);
    CONCURRENCY_UNLOCK();
-   return result;
+   return status;
 }
 
-static jboolean com_android_nfc_NativeNfcTag_doReconnect(JNIEnv *e,
+static jint com_android_nfc_NativeNfcTag_doReconnect(JNIEnv *e,
    jobject o)
 {
     // Reconnect is provided by libnfc by just calling connect again
@@ -563,11 +566,11 @@
             return com_android_nfc_NativeNfcTag_doConnect(e, o, handle);
         }
         else {
-            return JNI_TRUE;
+            return NFCSTATUS_SUCCESS;
         }
     }
     else {
-        return JNI_FALSE;
+        return NFCSTATUS_REJECTED;
     }
 }
 
@@ -639,9 +642,12 @@
     {
         goto clean_and_return;
     }
+
     result = JNI_TRUE;
 
 clean_and_return:
+    /* Reset device connected flag */
+    device_connected_flag = 0;
    nfc_cb_data_deinit(&cb_data);
    CONCURRENCY_UNLOCK();
    return result;
@@ -937,11 +943,10 @@
     return ndefType;
 }
 
-static bool com_android_nfc_NativeNfcTag_doCheckNdef(JNIEnv *e, jobject o, jintArray ndefinfo)
+static jint com_android_nfc_NativeNfcTag_doCheckNdef(JNIEnv *e, jobject o, jintArray ndefinfo)
 {
    phLibNfc_Handle handle = 0;
-   NFCSTATUS status;
-   bool result = JNI_FALSE;
+   jint status;
    phLibNfc_ChkNdef_Info_t sNdefInfo;
    struct nfc_jni_callback_data cb_data;
    jint *ndef = e->GetIntArrayElements(ndefinfo, 0);
@@ -952,6 +957,7 @@
    /* Create the local semaphore */
    if (!nfc_cb_data_init(&cb_data, NULL))
    {
+      status = NFCSTATUS_NOT_ENOUGH_MEMORY;
       goto clean_and_return;
    }
    cb_data.pContext = &sNdefInfo;
@@ -973,16 +979,18 @@
    if(sem_wait(&cb_data.sem))
    {
       LOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+      status = NFCSTATUS_ABORTED;
       goto clean_and_return;
    }
 
-   if (cb_data.status != NFCSTATUS_SUCCESS)
+   status = cb_data.status;
+   TRACE("phLibNfc_Ndef_CheckNdef() - Status code = %d", status);
+
+   if (status != NFCSTATUS_SUCCESS)
    {
       goto clean_and_return;
    }
 
-   result = JNI_TRUE;
-
    ndef[0] = sNdefInfo.MaxNdefMsgLength;
    // Translate the card state to know values for the NFC API
    switch (sNdefInfo.NdefCardState) {
@@ -1005,7 +1013,7 @@
    e->ReleaseIntArrayElements(ndefinfo, ndef, 0);
    nfc_cb_data_deinit(&cb_data);
    CONCURRENCY_UNLOCK();
-   return result;
+   return status;
 }
 
 static jboolean com_android_nfc_NativeNfcTag_doPresenceCheck(JNIEnv *e, jobject o)
@@ -1051,6 +1059,7 @@
 
 clean_and_return:
    nfc_cb_data_deinit(&cb_data);
+
    CONCURRENCY_UNLOCK();
 
    return result;
@@ -1217,19 +1226,19 @@
  */
 static JNINativeMethod gMethods[] =
 {
-   {"doConnect", "(I)Z",
+   {"doConnect", "(I)I",
       (void *)com_android_nfc_NativeNfcTag_doConnect},
    {"doDisconnect", "()Z",
       (void *)com_android_nfc_NativeNfcTag_doDisconnect},
-   {"doReconnect", "()Z",
+   {"doReconnect", "()I",
       (void *)com_android_nfc_NativeNfcTag_doReconnect},
-   {"doHandleReconnect", "(I)Z",
+   {"doHandleReconnect", "(I)I",
       (void *)com_android_nfc_NativeNfcTag_doHandleReconnect},
    {"doTransceive", "([BZ[I)[B",
       (void *)com_android_nfc_NativeNfcTag_doTransceive},
    {"doGetNdefType", "(II)I",
       (void *)com_android_nfc_NativeNfcTag_doGetNdefType},
-   {"doCheckNdef", "([I)Z",
+   {"doCheckNdef", "([I)I",
       (void *)com_android_nfc_NativeNfcTag_doCheckNdef},
    {"doRead", "()[B",
       (void *)com_android_nfc_NativeNfcTag_doRead},
diff --git a/jni/com_android_nfc_NativeP2pDevice.cpp b/jni/com_android_nfc_NativeP2pDevice.cpp
index fd9af3e..ed85620 100644
--- a/jni/com_android_nfc_NativeP2pDevice.cpp
+++ b/jni/com_android_nfc_NativeP2pDevice.cpp
@@ -20,6 +20,8 @@
 
 #include "com_android_nfc.h"
 
+extern uint8_t device_connected_flag;
+
 namespace android {
 
 extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat);
@@ -252,9 +254,12 @@
     {
         goto clean_and_return;
     }
+
     result = JNI_TRUE;
 
 clean_and_return:
+    /* Reset device connected flag */
+    device_connected_flag = 0;
     nfc_cb_data_deinit(&cb_data);
     CONCURRENCY_UNLOCK();
     return result;
diff --git a/src/com/android/nfc/NativeNfcManager.java b/src/com/android/nfc/NativeNfcManager.java
index 3f0f532..5938613 100755
--- a/src/com/android/nfc/NativeNfcManager.java
+++ b/src/com/android/nfc/NativeNfcManager.java
@@ -104,6 +104,8 @@
         doSetIsoDepTimeout(timeout);
     }
 
+    public native boolean doDownload();
+
     /**
      * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered)
      */
@@ -146,4 +148,16 @@
     private void notifySeFieldDeactivated() {
         mNfcService.sendMessage(NfcService.MSG_SE_FIELD_DEACTIVATED, null);
     }
+
+    private void notifySeApduReceived(byte[] apdu) {
+        mNfcService.sendMessage(NfcService.MSG_SE_APDU_RECEIVED, apdu);
+    }
+
+    private void notifySeEmvCardRemoval() {
+        mNfcService.sendMessage(NfcService.MSG_SE_EMV_CARD_REMOVAL, null);
+    }
+
+    private void notifySeMifareAccess(byte[] block) {
+        mNfcService.sendMessage(NfcService.MSG_SE_MIFARE_ACCESS, block);
+    }
 }
diff --git a/src/com/android/nfc/NativeNfcTag.java b/src/com/android/nfc/NativeNfcTag.java
index 94df1d2..1937744 100755
--- a/src/com/android/nfc/NativeNfcTag.java
+++ b/src/com/android/nfc/NativeNfcTag.java
@@ -43,6 +43,8 @@
 
     private int mConnectedTechnology; // Index in mTechList
 
+    private int mLastStatusCode;
+
     private final String TAG = "NativeNfcTag";
 
     private boolean mIsPresent; // Whether the tag is known to be still present
@@ -115,12 +117,12 @@
         }
     }
 
-    private native boolean doConnect(int handle);
-    public synchronized boolean connect(int technology) {
+    private native int doConnect(int handle);
+    public synchronized int connect(int technology) {
         if (mWatchdog != null) {
             mWatchdog.pause();
         }
-        boolean isSuccess = false;
+        int status = -1;
         for (int i = 0; i < mTechList.length; i++) {
             if (mTechList[i] == technology) {
                 // Get the handle and connect, if not already connected
@@ -139,12 +141,12 @@
                     //    allowed.
                     if (mConnectedTechnology == -1) {
                         // Not connected yet
-                        isSuccess = doConnect(mTechHandles[i]);
+                        status = doConnect(mTechHandles[i]);
                     }
                     else if ((mConnectedTechnology != -1) &&
                             (mTechHandles[mConnectedTechnology] != mTechHandles[i])) {
                         // Connect to a tech with a different handle
-                        isSuccess = reconnect(mTechHandles[i]);
+                        status = reconnect(mTechHandles[i]);
                     }
                     else {
                         // Already connected to a tech with the same handle
@@ -152,24 +154,23 @@
                         // success
                         if ((technology == TagTechnology.NDEF) ||
                                 (technology == TagTechnology.NDEF_FORMATABLE)) {
-                            isSuccess = true;
+                            status = 0;
                         } else {
                             if ((technology != TagTechnology.ISO_DEP) &&
                                 (hasTechOnHandle(TagTechnology.ISO_DEP, mTechHandles[i]))) {
                                 // Don't allow to connect a -4 tag at a different level
                                 // than IsoDep, as this is not supported by
                                 // libNFC.
-                                isSuccess = false;
                             } else {
-                                isSuccess = true;
+                                status = 0;
                             }
                         }
                     }
-                    if (isSuccess) {
+                    if (status == 0) {
                         mConnectedTechnology = i;
                     }
                 } else {
-                    isSuccess = true; // Already connect to this tech
+                    status = 0; // Already connect to this tech
                 }
                 break;
             }
@@ -177,7 +178,8 @@
         if (mWatchdog != null) {
             mWatchdog.doResume();
         }
-        return isSuccess;
+        mLastStatusCode = status;
+        return status;
     }
 
     public synchronized void startPresenceChecking() {
@@ -219,28 +221,28 @@
         return result;
     }
 
-    native boolean doReconnect();
-    public synchronized boolean reconnect() {
+    native int doReconnect();
+    public synchronized int reconnect() {
         if (mWatchdog != null) {
             mWatchdog.pause();
         }
-        boolean result = doReconnect();
+        int status = doReconnect();
         if (mWatchdog != null) {
             mWatchdog.doResume();
         }
-        return result;
+        return status;
     }
 
-    native boolean doHandleReconnect(int handle);
-    public synchronized boolean reconnect(int handle) {
+    native int doHandleReconnect(int handle);
+    public synchronized int reconnect(int handle) {
         if (mWatchdog != null) {
             mWatchdog.pause();
         }
-        boolean result = doHandleReconnect(handle);
+        int status = doHandleReconnect(handle);
         if (mWatchdog != null) {
             mWatchdog.doResume();
         }
-        return result;
+        return status;
     }
 
     private native byte[] doTransceive(byte[] data, boolean raw, int[] returnCode);
@@ -255,16 +257,17 @@
         return result;
     }
 
-    private native boolean doCheckNdef(int[] ndefinfo);
-    public synchronized boolean checkNdef(int[] ndefinfo) {
+    private native int doCheckNdef(int[] ndefinfo);
+    public synchronized int checkNdef(int[] ndefinfo) {
         if (mWatchdog != null) {
             mWatchdog.pause();
         }
-        boolean result = doCheckNdef(ndefinfo);
+        int status = doCheckNdef(ndefinfo);
         if (mWatchdog != null) {
             mWatchdog.doResume();
         }
-        return result;
+        mLastStatusCode = status;
+        return status;
     }
 
     private native byte[] doRead();
@@ -348,6 +351,10 @@
     private NativeNfcTag() {
     }
 
+    public int getLastStatusCode() {
+        return mLastStatusCode;
+    }
+
     public int getHandle() {
         // This is just a handle for the clients; it can simply use the first
         // technology handle we have.
diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java
index 283d72d..51cbfa4 100755
--- a/src/com/android/nfc/NfcService.java
+++ b/src/com/android/nfc/NfcService.java
@@ -70,7 +70,7 @@
 
 import java.io.ByteArrayOutputStream;
 import java.io.DataInputStream;
-import java.io.DataOutputStream;
+import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
@@ -79,6 +79,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 
@@ -89,6 +90,7 @@
 
     private static final String MY_TAG_FILE_NAME = "mytag";
     private static final String SE_RESET_SCRIPT_FILE_NAME = "/system/etc/se-reset-script";
+    private static final String NFC_CONTROLLER_FIRMWARE_FILE_NAME = "/system/lib/libpn544_fw.so";
 
     static {
         System.loadLibrary("nfc_jni");
@@ -189,6 +191,9 @@
     private static final String PREF_DISCOVERY_NFCIP = "discovery_nfcip";
     private static final boolean DISCOVERY_NFCIP_DEFAULT = true;
 
+    private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime";
+    private static final long FIRMWARE_MODTIME_DEFAULT = -1;
+
     /** NFC Reader Discovery mode for enableDiscovery() */
     private static final int DISCOVERY_MODE_READER = 0;
 
@@ -221,6 +226,11 @@
     static final int MSG_MOCK_NDEF = 7;
     static final int MSG_SE_FIELD_ACTIVATED = 8;
     static final int MSG_SE_FIELD_DEACTIVATED = 9;
+    static final int MSG_SE_APDU_RECEIVED = 10;
+    static final int MSG_SE_EMV_CARD_REMOVAL = 11;
+    static final int MSG_SE_MIFARE_ACCESS = 12;
+
+    static final int STATUS_CODE_TARGET_LOST = 146;
 
     // Copied from com.android.nfc_extras to avoid library dependency
     // Must keep in sync with com.android.nfc_extras
@@ -234,6 +244,19 @@
         "com.android.nfc_extras.action.AID_SELECTED";
     public static final String EXTRA_AID = "com.android.nfc_extras.extra.AID";
 
+    public static final String ACTION_APDU_RECEIVED =
+        "com.android.nfc_extras.action.APDU_RECEIVED";
+    public static final String EXTRA_APDU_BYTES =
+        "com.android.nfc_extras.extra.APDU_BYTES";
+
+    public static final String ACTION_EMV_CARD_REMOVAL =
+        "com.android.nfc_extras.action.EMV_CARD_REMOVAL";
+
+    public static final String ACTION_MIFARE_ACCESS_DETECTED =
+        "com.android.nfc_extras.action.MIFARE_ACCESS_DETECTED";
+    public static final String EXTRA_MIFARE_BLOCK =
+        "com.android.nfc_extras.extra.MIFARE_BLOCK";
+
     // Locked on mNfcAdapter
     PendingIntent mDispatchOverrideIntent;
     IntentFilter[] mDispatchOverrideFilters;
@@ -256,7 +279,7 @@
     private final HashMap<Integer, Object> mObjectMap = new HashMap<Integer, Object>();
     private final HashMap<Integer, Object> mSocketMap = new HashMap<Integer, Object>();
     private boolean mScreenOn;
-    private String mSePackageName;
+    private HashSet<String> mSePackages = new HashSet<String>();
 
     // fields below are final after onCreate()
     Context mContext;
@@ -307,6 +330,7 @@
                 NfcAdapter.ACTION_TECH_DISCOVERED, NfcAdapter.ACTION_TECH_DISCOVERED);
 
         mSecureElement = new NativeNfcSecureElement();
+        mEeRoutingState = ROUTE_OFF;
 
         mPrefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
         mPrefsEditor = mPrefs.edit();
@@ -336,9 +360,14 @@
         Thread t = new Thread() {
             @Override
             public void run() {
+                Log.d(TAG,"checking on firmware download");
                 boolean nfc_on = mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT);
                 if (nfc_on) {
+                    Log.d(TAG,"NFC is on. Doing normal stuff");
                     _enable(false, true);
+                } else {
+                    Log.d(TAG,"NFC is off.  Checking firmware version");
+                    _maybeUpdateFirmware();
                 }
                 resetSeOnFirstBoot();
             }
@@ -1288,7 +1317,7 @@
             // Note that on most tags, all technologies are behind a single
             // handle. This means that the connect at the lower levels
             // will do nothing, as the tag is already connected to that handle.
-            if (tag.connect(technology)) {
+            if (tag.connect(technology) == 0) {
                 return ErrorCodes.SUCCESS;
             } else {
                 return ErrorCodes.ERROR_DISCONNECT;
@@ -1309,7 +1338,7 @@
             /* find the tag in the hmap */
             tag = (NativeNfcTag) findObject(nativeHandle);
             if (tag != null) {
-                if (tag.reconnect()) {
+                if (tag.reconnect() == 0) {
                     return ErrorCodes.SUCCESS;
                 } else {
                     return ErrorCodes.ERROR_DISCONNECT;
@@ -1375,20 +1404,19 @@
         @Override
         public boolean isNdef(int nativeHandle) throws RemoteException {
             NativeNfcTag tag = null;
-            boolean isSuccess = false;
 
             // Check if NFC is enabled
             if (!mIsNfcEnabled) {
-                return isSuccess;
+                return false;
             }
 
             /* find the tag in the hmap */
             tag = (NativeNfcTag) findObject(nativeHandle);
             int[] ndefInfo = new int[2];
-            if (tag != null) {
-                isSuccess = tag.checkNdef(ndefInfo);
+            if (tag == null) {
+                return false;
             }
-            return isSuccess;
+            return tag.checkNdef(ndefInfo) == 0;
         }
 
         @Override
@@ -1821,6 +1849,12 @@
                 } catch (RemoteException e) {
                     mOpenEe.binderDied();
                 }
+
+                // Add the calling package to the list of packages that have accessed
+                // the secure element.
+                for (String packageName : getPackageManager().getPackagesForUid(getCallingUid())) {
+                    mSePackages.add(packageName);
+                }
            }
         }
 
@@ -1884,17 +1918,8 @@
         }
 
         @Override
-        public void registerTearDownApdus(String packageName, ApduList apdu) throws RemoteException {
+        public void authenticate(byte[] token) throws RemoteException {
             NfcService.enforceNfceeAdminPerm(mContext);
-            Log.w(TAG, "NOP");
-            //TODO: Remove this API
-        }
-
-        @Override
-        public void unregisterTearDownApdus(String packageName) throws RemoteException {
-            NfcService.enforceNfceeAdminPerm(mContext);
-            Log.w(TAG, "NOP");
-            //TODO: Remove this API
         }
     };
 
@@ -1982,6 +2007,48 @@
         return isSuccess;
     }
 
+    // Check that the NFC controller firmware is up to date.  This
+    // ensures that firmware updates are applied in a timely fashion,
+    // and makes it much less likely that the user will have to wait
+    // for a firmware download when they enable NFC in the settings
+    // app.  Firmware download can take some time, so this should be
+    // run in a separate thread.
+    private void _maybeUpdateFirmware() {
+        // check the timestamp of the firmware file
+        File firmwareFile;
+        int nbRetry = 0;
+        try {
+            firmwareFile = new File(NFC_CONTROLLER_FIRMWARE_FILE_NAME);
+        } catch(NullPointerException npe) {
+            Log.e(TAG,"path to firmware file was null");
+            return;
+        }
+
+        long modtime = firmwareFile.lastModified();
+
+        long prev_fw_modtime = mPrefs.getLong(PREF_FIRMWARE_MODTIME, FIRMWARE_MODTIME_DEFAULT);
+        Log.d(TAG,"prev modtime: " + prev_fw_modtime);
+        Log.d(TAG,"new modtime: " + modtime);
+        if (prev_fw_modtime == modtime) {
+            return;
+        }
+
+        // FW download.
+        while(nbRetry < 5) {
+            Log.d(TAG,"Perform Download");
+            if(mManager.doDownload()) {
+                Log.d(TAG,"Download Success");
+                // Now that we've finished updating the firmware, save the new modtime.
+                mPrefsEditor.putLong(PREF_FIRMWARE_MODTIME, modtime);
+                mPrefsEditor.apply();
+                break;
+            } else {
+                Log.d(TAG,"Download Failed");
+                nbRetry++;
+            }
+        }
+    }
+
     private class WatchDogThread extends Thread {
         boolean mWatchDogCanceled = false;
         @Override
@@ -2346,15 +2413,19 @@
             int techIndex = 0;
             int lastHandleScanned = 0;
             boolean ndefFoundAndConnected = false;
+            boolean isTargetLost = false;
             NdefMessage[] ndefMsgs = null;
             boolean foundFormattable = false;
             int formattableHandle = 0;
             int formattableTechnology = 0;
+            int status;
 
-            while ((!ndefFoundAndConnected) && (techIndex < technologies.length)) {
+            while ((!ndefFoundAndConnected) && (techIndex < technologies.length) && (!isTargetLost))
+            {
                 if (handles[techIndex] != lastHandleScanned) {
                     // We haven't seen this handle yet, connect and checkndef
-                    if (nativeTag.connect(technologies[techIndex])) {
+                    status = nativeTag.connect(technologies[techIndex]);
+                    if (status == 0) {
                         // Check if this type is NDEF formatable
                         if (!foundFormattable) {
                             if (nativeTag.isNdefFormatable()) {
@@ -2369,7 +2440,8 @@
                         } // else, already found formattable technology
 
                         int[] ndefinfo = new int[2];
-                        if (nativeTag.checkNdef(ndefinfo)) {
+                        status = nativeTag.checkNdef(ndefinfo);
+                        if (status == 0) {
                             ndefFoundAndConnected = true;
                             boolean generateEmptyNdef = false;
 
@@ -2403,10 +2475,17 @@
                                        supportedNdefLength, cardState);
                                nativeTag.reconnect();
                            }
-                        } // else, no NDEF on this tech, continue loop
+                        } else { // else, no NDEF on this tech, continue loop
+                            Log.d(TAG, "Check NDEF Failed - status = "+ status);
+                            if (status == STATUS_CODE_TARGET_LOST) {
+                                isTargetLost = true;
+                            }
+                        }
                     } else {
-                        // Connect failed, tag maybe lost. Try next handle
-                        // anyway.
+                        Log.d(TAG, "Connect Failed - status = "+ status);
+                        if (status == STATUS_CODE_TARGET_LOST) {
+                            isTargetLost = true;
+                        }
                     }
                 }
                 lastHandleScanned = handles[techIndex];
@@ -2447,13 +2526,14 @@
                    dispatchNativeTag(nativeTag, ndefMsgs);
                } else {
                    // No ndef found or connect failed, just try to reconnect and dispatch
-                   if (nativeTag.reconnect()) {
-                       nativeTag.startPresenceChecking();
-                       dispatchNativeTag(nativeTag, null);
-                   } else {
-                       Log.w(TAG, "Failed to connect to tag");
-                       nativeTag.disconnect();
-                   }
+                   if (nativeTag.getLastStatusCode() != STATUS_CODE_TARGET_LOST) {
+                       if (nativeTag.reconnect() == 0) {
+                            nativeTag.startPresenceChecking();
+                            dispatchNativeTag(nativeTag, null);
+                       }
+                    } else {
+                        nativeTag.disconnect();
+                    }
                }
                break;
 
@@ -2464,10 +2544,47 @@
                Intent aidIntent = new Intent();
                aidIntent.setAction(ACTION_AID_SELECTED);
                aidIntent.putExtra(EXTRA_AID, aid);
-               if (DBG) Log.d(TAG, "Broadcasting ACTION_AID_SELECTED");
+               if (DBG) Log.d(TAG, "Broadcasting " + ACTION_AID_SELECTED);
                mContext.sendBroadcast(aidIntent, NFCEE_ADMIN_PERM);
                break;
 
+           case MSG_SE_EMV_CARD_REMOVAL:
+               if (DBG) Log.d(TAG, "Card Removal message");
+               /* Send broadcast */
+               Intent cardRemovalIntent = new Intent();
+               cardRemovalIntent.setAction(ACTION_EMV_CARD_REMOVAL);
+               if (DBG) Log.d(TAG, "Broadcasting " + ACTION_EMV_CARD_REMOVAL);
+               mContext.sendBroadcast(cardRemovalIntent, NFCEE_ADMIN_PERM);
+               break;
+
+           case MSG_SE_APDU_RECEIVED:
+               if (DBG) Log.d(TAG, "APDU Received message");
+               byte[] apduBytes = (byte[]) msg.obj;
+               /* Send broadcast */
+               Intent apduReceivedIntent = new Intent();
+               apduReceivedIntent.setAction(ACTION_APDU_RECEIVED);
+               if (apduBytes != null && apduBytes.length > 0) {
+                 apduReceivedIntent.putExtra(EXTRA_APDU_BYTES, apduBytes);
+               }
+               if (DBG) Log.d(TAG, "Broadcasting " + ACTION_APDU_RECEIVED);
+               mContext.sendBroadcast(apduReceivedIntent, NFCEE_ADMIN_PERM);
+               break;
+
+           case MSG_SE_MIFARE_ACCESS:
+               if (DBG) Log.d(TAG, "MIFARE access message");
+               /* Send broadcast */
+               byte[] mifareCmd = (byte[]) msg.obj;
+               Intent mifareAccessIntent = new Intent();
+               mifareAccessIntent.setAction(ACTION_MIFARE_ACCESS_DETECTED);
+               if (mifareCmd != null && mifareCmd.length > 1) {
+                 int mifareBlock = mifareCmd[1] & 0xff;
+                 if (DBG) Log.d(TAG, "Mifare Block=" + mifareBlock);
+                 mifareAccessIntent.putExtra(EXTRA_MIFARE_BLOCK, mifareBlock);
+               }
+               if (DBG) Log.d(TAG, "Broadcasting " + ACTION_MIFARE_ACCESS_DETECTED);
+               mContext.sendBroadcast(mifareAccessIntent, NFCEE_ADMIN_PERM);
+               break;
+
            case MSG_LLCP_LINK_ACTIVATION:
                NativeP2pDevice device = (NativeP2pDevice) msg.obj;
 
@@ -2972,8 +3089,9 @@
                     String packageName = data.getSchemeSpecificPart();
 
                     synchronized (NfcService.this) {
-                        if (packageName.equals(mSePackageName)) {
+                        if (mSePackages.contains(packageName)) {
                             executeSeReset();
+                            mSePackages.remove(packageName);
                         }
                     }
                 }