Patch to manage TARGET_LOST status in case of Multiple protocol tag

Plumb status codes up through the stack.

Change-Id: Id30e69fff3bb56082ab29d42f166cb12c3061857
diff --git a/jni/com_android_nfc_NativeNfcTag.cpp b/jni/com_android_nfc_NativeNfcTag.cpp
index ade5307..e724309 100644
--- a/jni/com_android_nfc_NativeNfcTag.cpp
+++ b/jni/com_android_nfc_NativeNfcTag.cpp
@@ -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;
     }
 }
 
@@ -940,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);
@@ -955,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;
@@ -976,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) {
@@ -1008,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)
@@ -1221,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/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 17615fb..acbfc5e 100755
--- a/src/com/android/nfc/NfcService.java
+++ b/src/com/android/nfc/NfcService.java
@@ -225,6 +225,8 @@
     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
     static final int ROUTE_OFF = 1;
@@ -1305,7 +1307,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;
@@ -1326,7 +1328,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;
@@ -1392,20 +1394,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
@@ -2360,15 +2361,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()) {
@@ -2383,7 +2388,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;
 
@@ -2417,10 +2423,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];
@@ -2461,13 +2474,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;