Secure Element Access implementation

Change-Id: Ia1c006c52aaf312408ef2fba96715b1b6c382ea9
diff --git a/jni/Android.mk b/jni/Android.mk
index fb092e5..7119695 100644
--- a/jni/Android.mk
+++ b/jni/Android.mk
@@ -11,6 +11,7 @@
     com_android_nfc_NativeNfcManager.cpp \
     com_android_nfc_NativeNfcTag.cpp \
     com_android_nfc_NativeP2pDevice.cpp \
+    com_android_nfc_NativeNfcSecureElement.cpp \
     com_android_nfc.cpp
 
 LOCAL_C_INCLUDES += \
diff --git a/jni/com_android_nfc.cpp b/jni/com_android_nfc.cpp
index 848a678..fa65625 100644
--- a/jni/com_android_nfc.cpp
+++ b/jni/com_android_nfc.cpp
@@ -43,6 +43,8 @@
       return JNI_ERR;
    if (android::register_com_android_nfc_NativeLlcpServiceSocket(e) == -1)
       return JNI_ERR;
+   if (android::register_com_android_nfc_NativeNfcSecureElement(e) == -1)
+      return JNI_ERR;
 
    return JNI_VERSION_1_6;
 }
@@ -277,4 +279,81 @@
    return "UNKNOWN";
 }
 
+/*
+ *  Utility to get target type name from its specs
+ */
+int get_technology_type(phNfc_eRemDevType_t type, uint8_t sak)
+{
+   switch (type)
+   {
+      case phNfc_eISO14443_A_PICC:
+      case phNfc_eISO14443_4A_PICC:
+      case phNfc_eISO14443_4B_PICC:
+        {
+          return TARGET_TYPE_ISO14443_4;
+        }break;
+        
+      case phNfc_eISO14443_3A_PICC:
+        {
+          return TARGET_TYPE_ISO14443_3A;
+        }break;
+
+      case phNfc_eISO14443_B_PICC:
+        {
+          /* Actually this can be -3B or -4B
+           * FRI doesn't allow us to tell the diff yet
+           * and the API doesn't know type 4B
+           * so return 3B for now.
+           */
+          return TARGET_TYPE_ISO14443_3B;
+        }break;
+        
+      case phNfc_eISO15693_PICC:
+        {
+          return TARGET_TYPE_ISO15693;
+        }break;
+
+      case phNfc_eMifare_PICC:
+        {
+          switch(sak)
+          {
+            case 0x00:
+              // could be UL or UL-C
+              return TARGET_TYPE_MIFARE_UL;
+            case 0x08:
+            case 0x09:
+            case 0x10:
+            case 0x11:
+            case 0x18:
+            case 0x28:
+            case 0x38:
+            case 0x88:
+            case 0x98:
+            case 0xB8:
+              return TARGET_TYPE_MIFARE_CLASSIC;
+            case 0x20:
+              return TARGET_TYPE_MIFARE_DESFIRE;
+            default:
+              {
+                return TARGET_TYPE_UNKNOWN;
+              }break;
+          }
+        }break;
+      case phNfc_eFelica_PICC:
+        {
+          return TARGET_TYPE_FELICA;
+        }break; 
+      case phNfc_eJewel_PICC:
+        {
+          return TARGET_TYPE_JEWEL;
+        }break; 
+      default:
+        {
+          return TARGET_TYPE_UNKNOWN;
+        }
+   }
+
+   return TARGET_TYPE_UNKNOWN;
+}
+
 } // namespace android
diff --git a/jni/com_android_nfc.h b/jni/com_android_nfc.h
index 881c48c..7b27186 100644
--- a/jni/com_android_nfc.h
+++ b/jni/com_android_nfc.h
@@ -152,6 +152,8 @@
 nfc_jni_native_monitor_t* nfc_jni_init_monitor(void);
 nfc_jni_native_monitor_t* nfc_jni_get_monitor(void);
 
+int get_technology_type(phNfc_eRemDevType_t type, uint8_t sak);
+
 /* P2P */
 phLibNfc_Handle nfc_jni_get_p2p_device_handle(JNIEnv *e, jobject o);
 jshort nfc_jni_get_p2p_device_mode(JNIEnv *e, jobject o);
@@ -169,6 +171,7 @@
 int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv *e);
 int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e);
 int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e);
+int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e);
 
 } // namespace android
 
diff --git a/jni/com_android_nfc_NativeNfcManager.cpp b/jni/com_android_nfc_NativeNfcManager.cpp
index cd32ede..17a24ab 100644
--- a/jni/com_android_nfc_NativeNfcManager.cpp
+++ b/jni/com_android_nfc_NativeNfcManager.cpp
@@ -26,7 +26,7 @@
 #define EEDATA_SETTINGS_NUMBER       22
 
 static phLibNfc_sConfig_t   gDrvCfg;
-static void                 *gHWRef;
+void   *gHWRef;
 static phNfc_sData_t gInputParam;
 static phNfc_sData_t gOutputParam;
 
@@ -414,83 +414,6 @@
    }     
 }
 
-/*
- *  Utility to get target type name from its specs
- */
-static int get_technology_type(phNfc_eRemDevType_t type, uint8_t sak)
-{
-   switch (type)
-   {
-      case phNfc_eISO14443_A_PICC:
-      case phNfc_eISO14443_4A_PICC:
-      case phNfc_eISO14443_4B_PICC:
-        {
-          return TARGET_TYPE_ISO14443_4;
-        }break;
-        
-      case phNfc_eISO14443_3A_PICC:
-        {
-          return TARGET_TYPE_ISO14443_3A;
-        }break;
-
-      case phNfc_eISO14443_B_PICC:
-        {
-          /* Actually this can be -3B or -4B
-           * FRI doesn't allow us to tell the diff yet
-           * and the API doesn't know type 4B
-           * so return 3B for now.
-           */
-          return TARGET_TYPE_ISO14443_3B;
-        }break;
-        
-      case phNfc_eISO15693_PICC:
-        {
-          return TARGET_TYPE_ISO15693;
-        }break;
-
-      case phNfc_eMifare_PICC:
-        {
-          switch(sak)
-          {
-            case 0x00:
-              // could be UL or UL-C
-              return TARGET_TYPE_MIFARE_UL;
-            case 0x08:
-            case 0x09:
-            case 0x10:
-            case 0x11:
-            case 0x18:
-            case 0x28:
-            case 0x38:
-            case 0x88:
-            case 0x98:
-            case 0xB8:
-              return TARGET_TYPE_MIFARE_CLASSIC;
-            case 0x20:
-              return TARGET_TYPE_MIFARE_DESFIRE;
-            default:
-              {
-                return TARGET_TYPE_UNKNOWN;
-              }break;
-          }
-        }break;
-      case phNfc_eFelica_PICC:
-        {
-          return TARGET_TYPE_FELICA;
-        }break; 
-      case phNfc_eJewel_PICC:
-        {
-          return TARGET_TYPE_JEWEL;
-        }break; 
-      default:
-        {
-          return TARGET_TYPE_UNKNOWN;
-        }
-   }
-
-   return TARGET_TYPE_UNKNOWN;
-}
-
  /*
 + *  Utility to recover UID from target infos
 + */
diff --git a/jni/com_android_nfc_NativeNfcSecureElement.cpp b/jni/com_android_nfc_NativeNfcSecureElement.cpp
new file mode 100755
index 0000000..ca000c2
--- /dev/null
+++ b/jni/com_android_nfc_NativeNfcSecureElement.cpp
@@ -0,0 +1,533 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#include <semaphore.h>
+
+#include "com_android_nfc.h"
+
+static sem_t com_android_nfc_jni_secure_element_sem;
+static NFCSTATUS com_android_nfc_jni_cb_status = NFCSTATUS_FAILED;
+static phNfc_sData_t *com_android_nfc_jni_transceive_buffer;
+static phNfc_sData_t *com_android_nfc_jni_ioctl_buffer;
+static phNfc_sRemoteDevInformation_t* SecureElementInfo;
+static int secureElementHandle;
+extern void                 *gHWRef;
+static int SecureElementTech;
+
+namespace android {
+
+static void com_android_nfc_jni_ioctl_callback ( void*            context,
+                                            phNfc_sData_t*   Outparam_Cb,
+                                            NFCSTATUS        status)
+{
+	if (status == NFCSTATUS_SUCCESS )
+	{
+		LOGD("> IOCTL successful");
+	}
+	else
+	{
+		LOGD("> IOCTL error");
+	}
+   com_android_nfc_jni_cb_status = status;
+   com_android_nfc_jni_ioctl_buffer = Outparam_Cb;
+
+   sem_post(&com_android_nfc_jni_secure_element_sem);
+}
+
+static void com_android_nfc_jni_transceive_callback(void *pContext,
+   phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status)
+{
+   LOG_CALLBACK("com_android_nfc_jni_transceive_callback", status);
+  
+   com_android_nfc_jni_cb_status = status;
+   com_android_nfc_jni_transceive_buffer = pResBuffer;
+
+   sem_post(&com_android_nfc_jni_secure_element_sem);
+}
+
+
+static void com_android_nfc_jni_connect_callback(void *pContext,
+                                            phLibNfc_Handle hRemoteDev,
+                                            phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status)
+{
+   LOG_CALLBACK("com_android_nfc_jni_connect_callback", status);
+
+   com_android_nfc_jni_cb_status = status;
+
+   sem_post(&com_android_nfc_jni_secure_element_sem);
+}
+
+static void com_android_nfc_jni_disconnect_callback(void *pContext,
+                                               phLibNfc_Handle hRemoteDev, 
+                                               NFCSTATUS status)
+{
+   LOG_CALLBACK("com_android_nfc_jni_disconnect_callback", status);
+   
+   com_android_nfc_jni_cb_status = status;
+
+   sem_post(&com_android_nfc_jni_secure_element_sem);
+}
+
+/* Set Secure Element mode callback*/
+static void com_android_nfc_jni_smartMX_setModeCb (void*            pContext,
+							                                phLibNfc_Handle  hSecureElement,
+                                              NFCSTATUS        status)
+{      
+	if(status==NFCSTATUS_SUCCESS)
+	{
+		LOGD("SE Set Mode is Successful");
+		LOGD("SE Handle: %lu", hSecureElement);		
+	}
+	else
+	{
+    LOGD("SE Set Mode is failed\n ");
+  }
+	
+	com_android_nfc_jni_cb_status = status;
+
+   sem_post(&com_android_nfc_jni_secure_element_sem);
+}
+
+static void com_android_nfc_jni_open_secure_element_notification_callback(void *pContext,
+                                                                     phLibNfc_RemoteDevList_t *psRemoteDevList,
+                                                                     uint8_t uNofRemoteDev, 
+                                                                     NFCSTATUS status)
+{
+   JNIEnv *e;
+   NFCSTATUS ret;
+   int i;
+   
+   if(status == NFCSTATUS_DESELECTED)
+   {
+      LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback: Target deselected", status);
+   }
+   else
+   {   
+      LOG_CALLBACK("com_android_nfc_jni_open_secure_element_notification_callback", status);
+      LOGI("Discovered %d tags", uNofRemoteDev);
+      
+      if(status == NFCSTATUS_MULTIPLE_PROTOCOLS)
+      {	
+         LOGD("Multiple Protocol supported\n");
+                                 
+         LOGD("Secure Element Handle: 0x%08x",psRemoteDevList[1].hTargetDev);
+         secureElementHandle = psRemoteDevList[1].hTargetDev;
+         
+         /* Set type name */
+         SecureElementTech = get_technology_type(psRemoteDevList[1].psRemoteDevInfo->RemDevType,
+                                        psRemoteDevList[1].psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak);                         
+    
+         LOGD("Store Secure Element Info\n");         
+         SecureElementInfo = psRemoteDevList->psRemoteDevInfo;
+         
+         LOGD("Discovered secure element: tech=%d", SecureElementTech);
+      }
+      else
+      {
+         LOGD("Secure Element Handle: 0x%08x",psRemoteDevList->hTargetDev);
+         secureElementHandle = psRemoteDevList->hTargetDev;
+         
+         /* Set type name */      
+         SecureElementTech = get_technology_type(psRemoteDevList->psRemoteDevInfo->RemDevType,
+                                         psRemoteDevList->psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak);                                                     
+         
+         LOGD("Store Secure Element Info\n");         
+         SecureElementInfo = psRemoteDevList->psRemoteDevInfo;
+            
+         LOGD("Discovered secure element: tech=%d", SecureElementTech);
+      }     
+   }
+         
+   com_android_nfc_jni_cb_status = status;
+   sem_post(&com_android_nfc_jni_secure_element_sem);
+}
+
+
+static jint com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection(JNIEnv *e, jobject o)
+{
+   NFCSTATUS ret;
+   int semResult;
+   
+   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_sADD_Cfg_t discovery_cfg;
+   phLibNfc_Registry_Info_t registry_info;
+   phNfc_sData_t			InParam;
+   phNfc_sData_t			OutParam;
+   uint8_t              ExternalRFDetected[3] = {0x00, 0xFC, 0x01};
+   uint8_t					Output_Buff[50];
+   uint8_t              reg_value;
+   uint8_t              mask_value;
+   
+   /* Registery */   
+   registry_info.MifareUL = TRUE;
+   registry_info.MifareStd = TRUE;
+   registry_info.ISO14443_4A = TRUE;
+   registry_info.ISO14443_4B = TRUE;
+   registry_info.Jewel = TRUE;
+   registry_info.Felica = TRUE;  
+   registry_info.NFC = FALSE;  
+     
+   CONCURRENCY_LOCK();
+   
+   LOGD("Open Secure Element");
+   
+   /* Test if External RF field is detected */
+	InParam.buffer = ExternalRFDetected;
+	InParam.length = 3;
+	OutParam.buffer = Output_Buff;
+	LOGD("phLibNfc_Mgt_IoCtl()");
+   ret = phLibNfc_Mgt_IoCtl(gHWRef,NFC_MEM_READ,&InParam, &OutParam,com_android_nfc_jni_ioctl_callback, (void *)e);
+   if(ret!=NFCSTATUS_PENDING)
+	{
+      LOGE("IOCTL status error");
+	}
+   semResult = sem_wait(&com_android_nfc_jni_secure_element_sem);
+   if (semResult)
+   {
+      LOGE("IOCTL semaphore error");
+      goto clean_and_return;
+   }
+      
+   if(com_android_nfc_jni_cb_status != NFCSTATUS_SUCCESS)
+   {
+      LOGE("READ MEM ERROR");
+      goto clean_and_return;
+   }
+   
+   /* Check the value */   
+   reg_value = com_android_nfc_jni_ioctl_buffer->buffer[0];
+   mask_value = reg_value & 0x40;
+
+   if(mask_value == 0x40)
+   {
+      LOGD("External RF Field detected");
+      goto clean_and_return;   
+   }   
+   
+   /* Get Secure Element List */
+   LOGD("phLibNfc_SE_GetSecureElementList()");
+   ret = phLibNfc_SE_GetSecureElementList( SE_List, &No_SE);
+   if (ret == NFCSTATUS_SUCCESS)
+   {
+      LOGD("\n> Number of Secure Element(s) : %d\n", No_SE);
+      /* Display Secure Element information */
+      for (i = 0; i<No_SE; i++)
+      {
+         if (SE_List[i].eSE_Type == phLibNfc_SE_Type_SmartMX)
+         {
+           LOGD("> SMX detected");
+           LOGD("> Secure Element Handle : %d\n", SE_List[i].hSecureElement);
+           /* save SMARTMX index */
+           SmartMX_detected = 1;
+           SmartMX_index = i;
+         }
+      }
+       
+      if(SmartMX_detected)
+      {
+         REENTRANCE_LOCK();
+         LOGD("phLibNfc_RemoteDev_NtfRegister()");
+         ret = phLibNfc_RemoteDev_NtfRegister(&registry_info, com_android_nfc_jni_open_secure_element_notification_callback, (void *)e);
+         REENTRANCE_UNLOCK();
+         if(ret != NFCSTATUS_SUCCESS)
+         {
+            LOGW("Register Notification error");
+            goto clean_and_return;
+         }
+      
+         /* Set wired mode */
+         REENTRANCE_LOCK();
+         LOGD("phLibNfc_SE_SetMode: Wired mode");
+         ret = phLibNfc_SE_SetMode( SE_List[SmartMX_index].hSecureElement, 
+									         phLibNfc_SE_ActModeWired, 
+									         com_android_nfc_jni_smartMX_setModeCb,
+									         (void*)e);
+         REENTRANCE_UNLOCK();
+         if (ret != NFCSTATUS_PENDING )
+         {
+            LOGD("\n> SE Set SmartMX mode ERROR \n" );
+            goto clean_and_return;
+         }
+			
+         semResult = sem_wait(&com_android_nfc_jni_secure_element_sem);
+         if (semResult)
+         {
+            LOGW("Secure Element opening error");
+            goto clean_and_return;
+         }
+      
+         if(com_android_nfc_jni_cb_status != NFCSTATUS_SUCCESS)
+         {
+            LOGE("SE set mode failed");
+            goto clean_and_return;
+         }
+      
+         LOGD("Waiting for notification");
+         semResult = sem_wait(&com_android_nfc_jni_secure_element_sem);
+         if (semResult)
+         {
+            LOGW("Secure Element opening error");
+            goto clean_and_return;
+         }
+      
+         if(com_android_nfc_jni_cb_status != NFCSTATUS_SUCCESS && com_android_nfc_jni_cb_status != NFCSTATUS_MULTIPLE_PROTOCOLS)
+         {
+            LOGE("SE detection failed");
+            goto clean_and_return;
+         }  
+         CONCURRENCY_UNLOCK();
+         
+         /* Connect Tag */
+         CONCURRENCY_LOCK();
+         LOGD("phLibNfc_RemoteDev_Connect(SMX)");
+         REENTRANCE_LOCK();
+         ret = phLibNfc_RemoteDev_Connect(secureElementHandle, com_android_nfc_jni_connect_callback,(void *)e);
+         REENTRANCE_UNLOCK();
+         if(ret != NFCSTATUS_PENDING)
+         {
+            LOGE("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+            goto clean_and_return;
+         }
+         LOGD("phLibNfc_RemoteDev_Connect(SMX) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+      
+         /* Wait for callback response */
+         sem_wait(&com_android_nfc_jni_secure_element_sem);
+         
+         /* Connect Status */
+         if(com_android_nfc_jni_cb_status != NFCSTATUS_SUCCESS)
+         {
+            goto clean_and_return;
+         }
+         
+         CONCURRENCY_UNLOCK();
+         /* Return the Handle of the SecureElement */         
+         return secureElementHandle;
+      }
+      else
+      {
+         LOGD("phLibNfc_SE_GetSecureElementList(): No SMX detected");   
+         goto clean_and_return; 
+      } 
+  }
+  else
+  {
+      LOGD("phLibNfc_SE_GetSecureElementList(): Error");
+      goto clean_and_return;
+  }
+  
+clean_and_return:
+   CONCURRENCY_UNLOCK();
+   return 0;
+}
+
+
+static jboolean com_android_nfc_NativeNfcSecureElement_doDisconnect(JNIEnv *e, jobject o, jint handle)
+{
+   jclass cls;
+   jfieldID f;
+   NFCSTATUS status;
+   jboolean result = JNI_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;
+   uint32_t SmartMX_Handle;
+
+   LOGD("Close Secure element function ");
+   
+   CONCURRENCY_LOCK();
+   /* Disconnect */
+   LOGI("Disconnecting from SMX (handle = 0x%x)", handle);
+   REENTRANCE_LOCK();
+   status = phLibNfc_RemoteDev_Disconnect(handle, 
+                                          NFC_SMARTMX_RELEASE,
+                                          com_android_nfc_jni_disconnect_callback,
+                                          (void *)e);
+   REENTRANCE_UNLOCK();
+   if(status != NFCSTATUS_PENDING)
+   {
+      LOGE("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+      goto clean_and_return;
+   }
+   LOGD("phLibNfc_RemoteDev_Disconnect(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+   /* Wait for callback response */
+   sem_wait(&com_android_nfc_jni_secure_element_sem);
+   
+   /* Disconnect Status */
+   if(com_android_nfc_jni_cb_status != NFCSTATUS_SUCCESS)
+   {
+     LOGE("\n> Disconnect SE ERROR \n" );
+      goto clean_and_return;
+   }
+   
+   result = JNI_TRUE;
+
+clean_and_return:
+   CONCURRENCY_UNLOCK();
+   return result;
+}
+
+static jbyteArray com_android_nfc_NativeNfcSecureElement_doTransceive(JNIEnv *e,
+   jobject o,jint handle, jbyteArray data)
+{
+   uint8_t offset = 0;
+   uint8_t *buf;
+   uint32_t buflen;
+   phLibNfc_sTransceiveInfo_t transceive_info;
+   jbyteArray result = NULL;
+   int res; 
+   
+   int tech = SecureElementTech;
+   NFCSTATUS status;
+
+   LOGD("Exchange APDU function ");
+   
+   CONCURRENCY_LOCK();
+   
+   LOGD("Secure Element tech: %d\n", tech);
+
+   buf = (uint8_t *)e->GetByteArrayElements(data, NULL);
+   buflen = (uint32_t)e->GetArrayLength(data);
+ 
+   /* Prepare transceive info structure */
+   if(tech == TARGET_TYPE_MIFARE_CLASSIC || tech == TARGET_TYPE_MIFARE_UL)
+   {
+      offset = 2;
+      transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0];
+      transceive_info.addr = (uint8_t)buf[1];
+   }
+   else if(tech == TARGET_TYPE_ISO14443_4)
+   {
+      transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw;
+      transceive_info.addr = 0;
+   }
+      
+   transceive_info.sSendData.buffer = buf + offset;
+   transceive_info.sSendData.length = buflen - offset;
+   transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024);
+   transceive_info.sRecvData.length = 1024;
+
+   if(transceive_info.sRecvData.buffer == NULL)
+   {
+      goto clean_and_return;
+   }
+
+   LOGD("phLibNfc_RemoteDev_Transceive(SMX)");
+   REENTRANCE_LOCK();
+   status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info,
+		   com_android_nfc_jni_transceive_callback, (void *)e);
+   REENTRANCE_UNLOCK();
+   if(status != NFCSTATUS_PENDING)
+   {
+      LOGE("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+      goto clean_and_return;
+   }
+   LOGD("phLibNfc_RemoteDev_Transceive(SMX) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+   /* Wait for callback response */
+   sem_wait(&com_android_nfc_jni_secure_element_sem);
+
+   if(com_android_nfc_jni_cb_status != NFCSTATUS_SUCCESS)
+   {
+      goto clean_and_return;
+   }
+
+   /* Copy results back to Java */
+   result = e->NewByteArray(com_android_nfc_jni_transceive_buffer->length);
+   if(result != NULL)
+   {
+      e->SetByteArrayRegion(result, 0,
+    		  com_android_nfc_jni_transceive_buffer->length,
+         (jbyte *)com_android_nfc_jni_transceive_buffer->buffer);
+   }
+
+clean_and_return:
+   if(transceive_info.sRecvData.buffer != NULL)
+   {
+      free(transceive_info.sRecvData.buffer);
+   }
+
+   e->ReleaseByteArrayElements(data,
+      (jbyte *)transceive_info.sSendData.buffer, JNI_ABORT);
+
+   CONCURRENCY_UNLOCK();
+
+   return result;
+}
+
+static jbyteArray com_android_nfc_NativeNfcSecureElement_doGetUid(JNIEnv *e, jobject o, jint handle)
+{
+   LOGD("Get Secure element UID function ");
+   jbyteArray SecureElementUid;
+      
+   if(handle == secureElementHandle)
+   {
+      SecureElementUid = e->NewByteArray(SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength);
+      e->SetByteArrayRegion(SecureElementUid, 0, SecureElementInfo->RemoteDevInfo.Iso14443A_Info.UidLength,(jbyte *)SecureElementInfo->RemoteDevInfo.Iso14443A_Info.Uid);
+      return SecureElementUid;
+   }
+   else
+   {
+      return NULL;
+   }   
+}
+
+static jintArray com_android_nfc_NativeNfcSecureElement_doGetTechList(JNIEnv *e, jobject o, jint handle)
+{
+   jintArray techList;
+   LOGD("Get Secure element Type function ");
+      
+   if(handle == secureElementHandle)
+   {
+      techList = e->NewIntArray(1);
+      e->SetIntArrayRegion(techList, 0, 1, &SecureElementTech);
+      return techList;
+   }
+   else
+   {
+      return NULL;
+   }
+}
+
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gMethods[] =
+{
+   {"doOpenSecureElementConnection", "()I",
+      (void *)com_android_nfc_NativeNfcSecureElement_doOpenSecureElementConnection},
+   {"doDisconnect", "(I)Z",
+      (void *)com_android_nfc_NativeNfcSecureElement_doDisconnect},
+   {"doTransceive", "(I[B)[B",
+      (void *)com_android_nfc_NativeNfcSecureElement_doTransceive},
+   {"doGetUid", "(I)[B",
+      (void *)com_android_nfc_NativeNfcSecureElement_doGetUid},
+   {"doGetTechList", "(I)[I",
+      (void *)com_android_nfc_NativeNfcSecureElement_doGetTechList},
+};
+
+int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e)
+{
+   if(sem_init(&com_android_nfc_jni_secure_element_sem, 0, 0) == -1)
+      return -1;
+      
+   return jniRegisterNativeMethods(e,
+      "com/android/nfc/NativeNfcSecureElement",
+      gMethods, NELEM(gMethods));
+}
+
+} // namespace android
diff --git a/src/com/android/nfc/NativeNfcSecureElement.java b/src/com/android/nfc/NativeNfcSecureElement.java
new file mode 100755
index 0000000..b666064
--- /dev/null
+++ b/src/com/android/nfc/NativeNfcSecureElement.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2010 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;
+
+
+
+/**
+ * Native interface to the NFC Secure Element functions
+ * 
+ * {@hide}
+ */
+public class NativeNfcSecureElement {
+    
+        
+    public NativeNfcSecureElement() {
+    }
+    
+    public native int doOpenSecureElementConnection();
+        
+    public native boolean doDisconnect(int handle);
+    
+    public native byte[] doTransceive(int handle, byte[] data);
+    
+    public native int[] doGetTechList(int handle);
+    
+    public native byte [] doGetUid(int handle);
+    
+}
diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java
index ce67581..f863176 100755
--- a/src/com/android/nfc/NfcService.java
+++ b/src/com/android/nfc/NfcService.java
@@ -42,6 +42,7 @@
 import android.nfc.NdefMessage;
 import android.nfc.NfcAdapter;
 import android.nfc.Tag;
+import android.nfc.INfcSecureElement;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
@@ -59,6 +60,8 @@
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.ListIterator;
+import java.util.Timer;
+import java.util.TimerTask;
 
 public class NfcService extends Application {
     static final boolean DBG = false;
@@ -172,6 +175,14 @@
     private int mSelectedSeId = 0;
     private boolean mNfcSecureElementState;
 
+    // Secure element
+    private Timer mTimerOpenSmx;
+    private boolean isClosed = false;
+    private boolean isOpened = false;
+    private boolean mOpenSmxPending = false;
+    private NativeNfcSecureElement mSecureElement;
+    private int mSecureElementHandle;
+
     // fields below are used in multiple threads and protected by synchronized(this)
     private final HashMap<Integer, Object> mObjectMap = new HashMap<Integer, Object>();
     private final HashMap<Integer, Object> mSocketMap = new HashMap<Integer, Object>();
@@ -207,6 +218,8 @@
         mMyTagServer = new MyTagServer();
         mMyTagClient = new MyTagClient(this);
 
+        mSecureElement = new NativeNfcSecureElement();
+
         mPrefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
         mPrefsEditor = mPrefs.edit();
 
@@ -597,6 +610,11 @@
             return mP2pTargetService;
         }
 
+        public INfcSecureElement getNfcSecureElementInterface() {
+            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
+            return mSecureElementService;
+        }
+
         @Override
         public String getProperties(String param) throws RemoteException {
             mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
@@ -1744,6 +1762,195 @@
         }
     };
 
+    private INfcSecureElement mSecureElementService = new INfcSecureElement.Stub() {
+
+        public int openSecureElementConnection() throws RemoteException {
+            Log.d(TAG, "openSecureElementConnection");
+            int handle;
+
+            // Check if NFC is enabled
+            if (!mIsNfcEnabled) {
+                return 0;
+            }
+
+            // Check in an open is already pending
+            if (mOpenSmxPending) {
+                return 0;
+            }
+
+            handle = mSecureElement.doOpenSecureElementConnection();
+
+            if (handle == 0) {
+                mOpenSmxPending = false;
+            } else {
+                mSecureElementHandle = handle;
+
+                /* Start timer */
+                mTimerOpenSmx = new Timer();
+                mTimerOpenSmx.schedule(new TimerOpenSecureElement(), 30000);
+
+                /* Update state */
+                isOpened = true;
+                isClosed = false;
+                mOpenSmxPending = true;
+            }
+
+            return handle;
+        }
+
+        public int closeSecureElementConnection(int nativeHandle)
+                throws RemoteException {
+
+            // Check if NFC is enabled
+            if (!mIsNfcEnabled) {
+                return ErrorCodes.ERROR_NOT_INITIALIZED;
+            }
+
+            // Check if the SE connection is closed
+            if (isClosed) {
+                return -1;
+            }
+
+            // Check if the SE connection is opened
+            if (!isOpened) {
+                return -1;
+            }
+
+            if (mSecureElement.doDisconnect(nativeHandle)) {
+
+                /* Stop timer */
+                mTimerOpenSmx.cancel();
+
+                /* Restart polling loop for notification */
+                mManager.enableDiscovery(DISCOVERY_MODE_READER);
+
+                /* Update state */
+                isOpened = false;
+                isClosed = true;
+                mOpenSmxPending = false;
+
+                return ErrorCodes.SUCCESS;
+            } else {
+
+                /* Stop timer */
+                mTimerOpenSmx.cancel();
+
+                /* Restart polling loop for notification */
+                mManager.enableDiscovery(DISCOVERY_MODE_READER);
+
+                /* Update state */
+                isOpened = false;
+                isClosed = true;
+                mOpenSmxPending = false;
+
+                return ErrorCodes.ERROR_DISCONNECT;
+            }
+        }
+
+        public int[] getSecureElementTechList(int nativeHandle)
+                throws RemoteException {
+            // Check if NFC is enabled
+            if (!mIsNfcEnabled) {
+                return null;
+            }
+
+            // Check if the SE connection is closed
+            if (isClosed) {
+                return null;
+            }
+
+            // Check if the SE connection is opened
+            if (!isOpened) {
+                return null;
+            }
+
+            int[] techList = mSecureElement.doGetTechList(nativeHandle);
+
+            /* Stop and Restart timer */
+            mTimerOpenSmx.cancel();
+            mTimerOpenSmx = new Timer();
+            mTimerOpenSmx.schedule(new TimerOpenSecureElement(), 30000);
+
+            return techList;
+        }
+
+        public byte[] getSecureElementUid(int nativeHandle)
+                throws RemoteException {
+            byte[] uid;
+
+            // Check if NFC is enabled
+            if (!mIsNfcEnabled) {
+                return null;
+            }
+
+            // Check if the SE connection is closed
+            if (isClosed) {
+                return null;
+            }
+
+            // Check if the SE connection is opened
+            if (!isOpened) {
+                return null;
+            }
+
+            uid = mSecureElement.doGetUid(nativeHandle);
+
+            /* Stop and Restart timer */
+            mTimerOpenSmx.cancel();
+            mTimerOpenSmx = new Timer();
+            mTimerOpenSmx.schedule(new TimerOpenSecureElement(), 30000);
+
+            return uid;
+        }
+
+        public byte[] exchangeAPDU(int nativeHandle, byte[] data)
+                throws RemoteException {
+            byte[] response;
+
+            // Check if NFC is enabled
+            if (!mIsNfcEnabled) {
+                return null;
+            }
+
+            // Check if the SE connection is closed
+            if (isClosed) {
+                return null;
+            }
+
+            // Check if the SE connection is opened
+            if (!isOpened) {
+                return null;
+            }
+
+            response = mSecureElement.doTransceive(nativeHandle, data);
+
+            /* Stop and Restart timer */
+            mTimerOpenSmx.cancel();
+            mTimerOpenSmx = new Timer();
+            mTimerOpenSmx.schedule(new TimerOpenSecureElement(), 30000);
+
+            return response;
+
+        }
+    };
+
+    class TimerOpenSecureElement extends TimerTask {
+
+        @Override
+        public void run() {
+            if (mSecureElementHandle != 0) {
+                Log.d(TAG, "Open SMX timer expired");
+                try {
+                    mSecureElementService
+                            .closeSecureElementConnection(mSecureElementHandle);
+                } catch (RemoteException e) {
+                }
+            }
+
+        }
+
+    }
+
     private boolean _enable(boolean oldEnabledState) {
         boolean isSuccess = mManager.initialize();
         if (isSuccess) {