Return more accurate errors for NfcEe.open.

There are a number of different conditions under
which access to the SE is not possible. Since some
of these require user intervention to resolve (ie
external field present), return a more accurate
reason for NfcEe.open failure.

Bug: 4304698
Change-Id: Ie947c29be12d554a02d9246264a9f0e026a37af8
diff --git a/nci/jni/NativeSecureElement.cpp b/nci/jni/NativeSecureElement.cpp
index d1438bc..fea2e15 100755
--- a/nci/jni/NativeSecureElement.cpp
+++ b/nci/jni/NativeSecureElement.cpp
@@ -27,6 +27,13 @@
 extern void com_android_nfc_NfcManager_enableDiscovery (JNIEnv* e, jobject o, jint mode);
 extern int gGeneralTransceiveTimeout;
 
+// These must match the EE_ERROR_ types in NfcService.java
+static const int EE_ERROR_IO = -1;
+static const int EE_ERROR_ALREADY_OPEN = -2;
+static const int EE_ERROR_INIT = -3;
+static const int EE_ERROR_LISTEN_MODE = -4;
+static const int EE_ERROR_EXT_FIELD = -5;
+static const int EE_ERROR_NFC_DISABLED = -6;
 
 /*******************************************************************************
 **
@@ -36,23 +43,25 @@
 **                  e: JVM environment.
 **                  o: Java object.
 **
-** Returns:         Handle of secure element.  0 is failure.
+** Returns:         Handle of secure element.  values < 0 represent failure.
 **
 *******************************************************************************/
 static jint nativeNfcSecureElement_doOpenSecureElementConnection (JNIEnv*, jobject)
 {
     ALOGD("%s: enter", __FUNCTION__);
     bool stat = true;
-    jint secElemHandle = 0;
+    jint secElemHandle = EE_ERROR_INIT;
     SecureElement &se = SecureElement::getInstance();
 
     if (se.isActivatedInListenMode()) {
         ALOGD("Denying SE open due to SE listen mode active");
+        secElemHandle = EE_ERROR_LISTEN_MODE;
         goto TheEnd;
     }
 
     if (se.isRfFieldOn()) {
         ALOGD("Denying SE open due to SE in active RF field");
+        secElemHandle = EE_ERROR_EXT_FIELD;
         goto TheEnd;
     }
     //tell the controller to power up to get ready for sec elem operations
@@ -69,9 +78,13 @@
         //establish a pipe to sec elem
         stat = se.connectEE();
         if (stat)
+        {
             secElemHandle = se.mActiveEeHandle;
+        }
         else
+        {
             se.deactivate (0);
+        }
     }
 
     //if code fails to connect to the secure element, and nothing is active, then
diff --git a/nxp/jni/com_android_nfc.h b/nxp/jni/com_android_nfc.h
index 56c229f..1eed204 100644
--- a/nxp/jni/com_android_nfc.h
+++ b/nxp/jni/com_android_nfc.h
@@ -105,6 +105,15 @@
 
 #define SMX_SECURE_ELEMENT_ID   11259375
 
+
+/* These must match the EE_ERROR_ types in NfcService.java */
+#define EE_ERROR_IO                 -1
+#define EE_ERROR_ALREADY_OPEN       -2
+#define EE_ERROR_INIT               -3
+#define EE_ERROR_LISTEN_MODE        -4
+#define EE_ERROR_EXT_FIELD          -5
+#define EE_ERROR_NFC_DISABLED       -6
+
 /* Maximum byte length of an AID. */
 #define AID_MAXLEN                        16
 
diff --git a/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp b/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp
index 79887a0..9e0a6e2 100755
--- a/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp
+++ b/nxp/jni/com_android_nfc_NativeNfcSecureElement.cpp
@@ -179,6 +179,7 @@
 {
    NFCSTATUS ret;
    int semResult;
+   jint errorCode = EE_ERROR_INIT;
    
    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;
@@ -224,7 +225,8 @@
    /* Check if NFC device is already connected to a tag or P2P peer */
    if (device_connected_flag == 1)
    {
-       ALOGD("Unable to open SE connection, device already connected to a P2P peer or a Tag");
+       ALOGE("Unable to open SE connection, device already connected to a P2P peer or a Tag");
+       errorCode = EE_ERROR_LISTEN_MODE;
        goto clean_and_return;
    }
 
@@ -263,6 +265,7 @@
    {
       // There is an external RF field present, fail the open request
       ALOGD("Unable to open SE connection, external RF Field detected");
+      errorCode = EE_ERROR_EXT_FIELD;
       goto clean_and_return;   
    }   
 
@@ -464,7 +467,7 @@
    nfc_cb_data_deinit(&cb_data_SE_Notification);
 
    CONCURRENCY_UNLOCK();
-   return 0;
+   return errorCode;
 }
 
 
diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java
index 2791307..4436927 100755
--- a/src/com/android/nfc/NfcService.java
+++ b/src/com/android/nfc/NfcService.java
@@ -132,6 +132,15 @@
     static final int ROUTE_OFF = 1;
     static final int ROUTE_ON_WHEN_SCREEN_ON = 2;
 
+    // Return values from NfcEe.open() - these are 1:1 mapped
+    // to the thrown EE_EXCEPTION_ exceptions in nfc-extras.
+    static final int EE_ERROR_IO = -1;
+    static final int EE_ERROR_ALREADY_OPEN = -2;
+    static final int EE_ERROR_INIT = -3;
+    static final int EE_ERROR_LISTEN_MODE = -4;
+    static final int EE_ERROR_EXT_FIELD = -5;
+    static final int EE_ERROR_NFC_DISABLED = -6;
+
     /** minimum screen state that enables NFC polling (discovery) */
     static final int POLLING_MODE = SCREEN_STATE_ON_UNLOCKED;
 
@@ -1297,10 +1306,11 @@
             p.putInt("e", 0);
             return p;
         }
-        private Bundle writeIoException(IOException e) {
+
+        private Bundle writeEeException(int exceptionType, String message) {
             Bundle p = new Bundle();
-            p.putInt("e", -1);
-            p.putString("m", e.getMessage());
+            p.putInt("e", exceptionType);
+            p.putString("m", message);
             return p;
         }
 
@@ -1309,27 +1319,33 @@
             NfcService.this.enforceNfceeAdminPerm(pkg);
 
             Bundle result;
-            try {
-                _open(b);
+            int handle = _open(b);
+            if (handle < 0) {
+                result = writeEeException(handle, "NFCEE open exception.");
+            } else {
                 result = writeNoException();
-            } catch (IOException e) {
-                result = writeIoException(e);
             }
             return result;
         }
 
-        private void _open(IBinder b) throws IOException {
+        /**
+         * Opens a connection to the secure element.
+         *
+         * @return A handle with a value >= 0 in case of success, or a
+         *         negative value in case of failure.
+         */
+        private int _open(IBinder b) {
             synchronized(NfcService.this) {
                 if (!isNfcEnabled()) {
-                    throw new IOException("NFC adapter is disabled");
+                    return EE_ERROR_NFC_DISABLED;
                 }
                 if (mOpenEe != null) {
-                    throw new IOException("NFC EE already open");
+                    return EE_ERROR_ALREADY_OPEN;
                 }
 
                 int handle = doOpenSecureElementConnection();
-                if (handle == 0) {
-                    throw new IOException("NFC EE failed to open");
+                if (handle < 0) {
+                    return handle;
                 }
                 mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 30000);
 
@@ -1345,6 +1361,8 @@
                 for (String packageName : mContext.getPackageManager().getPackagesForUid(getCallingUid())) {
                     mSePackages.add(packageName);
                 }
+
+                return handle;
            }
         }
 
@@ -1357,7 +1375,7 @@
                 _nfcEeClose(getCallingPid(), binder);
                 result = writeNoException();
             } catch (IOException e) {
-                result = writeIoException(e);
+                result = writeEeException(EE_ERROR_IO, e.getMessage());
             }
             return result;
         }
@@ -1373,7 +1391,7 @@
                 result = writeNoException();
                 result.putByteArray("out", out);
             } catch (IOException e) {
-                result = writeIoException(e);
+                result = writeEeException(EE_ERROR_IO, e.getMessage());
             }
             return result;
         }