summaryrefslogtreecommitdiffstats
path: root/nxp/jni/com_android_nfc_NativeNfcTag.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'nxp/jni/com_android_nfc_NativeNfcTag.cpp')
-rwxr-xr-xnxp/jni/com_android_nfc_NativeNfcTag.cpp1401
1 files changed, 1401 insertions, 0 deletions
diff --git a/nxp/jni/com_android_nfc_NativeNfcTag.cpp b/nxp/jni/com_android_nfc_NativeNfcTag.cpp
new file mode 100755
index 0000000..94e56c2
--- /dev/null
+++ b/nxp/jni/com_android_nfc_NativeNfcTag.cpp
@@ -0,0 +1,1401 @@
+/*
+ * 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 <errno.h>
+
+#include "com_android_nfc.h"
+#include "phNfcHalTypes.h"
+
+static phLibNfc_Data_t nfc_jni_ndef_rw;
+static phLibNfc_Handle handle;
+uint8_t *nfc_jni_ndef_buf = NULL;
+uint32_t nfc_jni_ndef_buf_len = 0;
+
+extern uint8_t device_connected_flag;
+
+namespace android {
+
+extern phLibNfc_Handle storedHandle;
+
+extern void nfc_jni_restart_discovery_locked(struct nfc_jni_native_data *nat);
+extern void nfc_jni_reset_timeout_values();
+
+/*
+ * Callbacks
+ */
+ static void nfc_jni_tag_rw_callback(void *pContext, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_tag_rw_callback", status);
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+static void nfc_jni_connect_callback(void *pContext,
+ phLibNfc_Handle hRemoteDev,
+ phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_connect_callback", status);
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ if (pCallbackData->pContext != NULL) {
+ // Store the remote dev info ptr in the callback context
+ // Note that this ptr will remain valid, it is tied to a statically
+ // allocated buffer in libnfc.
+ phLibNfc_sRemoteDevInformation_t** ppRemoteDevInfo =
+ (phLibNfc_sRemoteDevInformation_t**)pCallbackData->pContext;
+ *ppRemoteDevInfo = psRemoteDevInfo;
+ }
+
+ sem_post(&pCallbackData->sem);
+}
+
+static void nfc_jni_checkndef_callback(void *pContext,
+ phLibNfc_ChkNdef_Info_t info, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_checkndef_callback", status);
+ phLibNfc_ChkNdef_Info_t* pNdefInfo = (phLibNfc_ChkNdef_Info_t*) (pCallbackData->pContext);
+ if(status == NFCSTATUS_OK)
+ {
+ if(nfc_jni_ndef_buf)
+ {
+ free(nfc_jni_ndef_buf);
+ }
+ nfc_jni_ndef_buf_len = info.MaxNdefMsgLength;
+ nfc_jni_ndef_buf = (uint8_t*)malloc(nfc_jni_ndef_buf_len);
+ if (pNdefInfo != NULL) *pNdefInfo = info;
+ }
+ else {
+ if (pNdefInfo != NULL) {
+ memset(pNdefInfo, 0, sizeof(*pNdefInfo));
+ }
+ }
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+static void nfc_jni_disconnect_callback(void *pContext,
+ phLibNfc_Handle hRemoteDev, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_disconnect_callback", status);
+
+ if(nfc_jni_ndef_buf)
+ {
+ free(nfc_jni_ndef_buf);
+ }
+ nfc_jni_ndef_buf = NULL;
+ nfc_jni_ndef_buf_len = 0;
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+static void nfc_jni_async_disconnect_callback(void *pContext,
+ phLibNfc_Handle hRemoteDev, NFCSTATUS status)
+{
+ LOG_CALLBACK("nfc_jni_async_disconnect_callback", status);
+
+ if(nfc_jni_ndef_buf)
+ {
+ free(nfc_jni_ndef_buf);
+ }
+ nfc_jni_ndef_buf = NULL;
+ nfc_jni_ndef_buf_len = 0;
+}
+
+static phNfc_sData_t *nfc_jni_transceive_buffer;
+
+static void nfc_jni_transceive_callback(void *pContext,
+ phLibNfc_Handle handle, phNfc_sData_t *pResBuffer, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_transceive_callback", status);
+
+ nfc_jni_transceive_buffer = pResBuffer;
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+static void nfc_jni_presencecheck_callback(void *pContext, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_presencecheck_callback", status);
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+static void nfc_jni_formatndef_callback(void *pContext, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_formatndef_callback", status);
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+static void nfc_jni_readonly_callback(void *pContext, NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_readonly_callback", status);
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+/* Functions */
+static jbyteArray com_android_nfc_NativeNfcTag_doRead(JNIEnv *e,
+ jobject o)
+{
+ NFCSTATUS status;
+ phLibNfc_Handle handle = 0;
+ jbyteArray buf = NULL;
+ struct nfc_jni_callback_data cb_data;
+
+ CONCURRENCY_LOCK();
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ handle = nfc_jni_get_connected_handle(e, o);
+
+ nfc_jni_ndef_rw.length = nfc_jni_ndef_buf_len;
+ nfc_jni_ndef_rw.buffer = nfc_jni_ndef_buf;
+
+ TRACE("phLibNfc_Ndef_Read()");
+ REENTRANCE_LOCK();
+ status = phLibNfc_Ndef_Read(handle, &nfc_jni_ndef_rw,
+ phLibNfc_Ndef_EBegin,
+ nfc_jni_tag_rw_callback,
+ (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_Ndef_Read() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ if(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ goto clean_and_return;
+ }
+
+ buf = e->NewByteArray(nfc_jni_ndef_rw.length);
+ e->SetByteArrayRegion(buf, 0, nfc_jni_ndef_rw.length,
+ (jbyte *)nfc_jni_ndef_rw.buffer);
+
+clean_and_return:
+ nfc_cb_data_deinit(&cb_data);
+ CONCURRENCY_UNLOCK();
+
+ return buf;
+}
+
+
+static jboolean com_android_nfc_NativeNfcTag_doWrite(JNIEnv *e,
+ jobject o, jbyteArray buf)
+{
+ NFCSTATUS status;
+ jboolean result = JNI_FALSE;
+ struct nfc_jni_callback_data cb_data;
+
+ phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o);
+
+ CONCURRENCY_LOCK();
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ nfc_jni_ndef_rw.length = (uint32_t)e->GetArrayLength(buf);
+ nfc_jni_ndef_rw.buffer = (uint8_t *)e->GetByteArrayElements(buf, NULL);
+
+ TRACE("phLibNfc_Ndef_Write()");
+ TRACE("Ndef Handle :0x%x\n",handle);
+ TRACE("Ndef buffer length : %d", nfc_jni_ndef_rw.length);
+ REENTRANCE_LOCK();
+ status = phLibNfc_Ndef_Write(handle, &nfc_jni_ndef_rw,nfc_jni_tag_rw_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_Ndef_Write() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ if(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ goto clean_and_return;
+ }
+
+ result = JNI_TRUE;
+
+clean_and_return:
+ e->ReleaseByteArrayElements(buf, (jbyte *)nfc_jni_ndef_rw.buffer, JNI_ABORT);
+
+ nfc_cb_data_deinit(&cb_data);
+ CONCURRENCY_UNLOCK();
+ return result;
+}
+
+/*
+ * Utility to recover poll bytes from target infos
+ */
+static void set_target_pollBytes(JNIEnv *e, jobject tag,
+ phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo)
+{
+ jclass tag_cls = e->GetObjectClass(tag);
+ jfieldID f = e->GetFieldID(tag_cls, "mTechPollBytes", "[[B");
+
+ jobjectArray existingPollBytes = (jobjectArray) e->GetObjectField(tag, f);
+
+ if (existingPollBytes != NULL) {
+ return;
+ }
+
+ jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I");
+ jintArray techList = (jintArray) e->GetObjectField(tag, techListField);
+ jint *techId = e->GetIntArrayElements(techList, 0);
+ int techListLength = e->GetArrayLength(techList);
+
+ jbyteArray pollBytes = e->NewByteArray(0);
+ jobjectArray techPollBytes = e->NewObjectArray(techListLength,
+ e->GetObjectClass(pollBytes), 0);
+
+ for (int tech = 0; tech < techListLength; tech++) {
+ switch(techId[tech])
+ {
+ /* ISO14443-3A: ATQA/SENS_RES */
+ case TARGET_TYPE_ISO14443_3A:
+ if (psRemoteDevInfo->RemDevType == phNfc_eJewel_PICC) {
+ // Jewel ATQA is not read and stored by the PN544, but it is fixed
+ // at {0x00, 0x0C} in the spec. So eJewel can safely be
+ // translated to {0x00, 0x0C}.
+ const static jbyte JewelAtqA[2] = {0x00, 0x0C};
+ pollBytes = e->NewByteArray(2);
+ e->SetByteArrayRegion(pollBytes, 0, 2, (jbyte*) JewelAtqA);
+ }
+ else {
+ pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA));
+ e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA),
+ (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AtqA);
+ }
+ break;
+ /* ISO14443-3B: Application data (4 bytes) and Protocol Info (3 bytes) from ATQB/SENSB_RES */
+ case TARGET_TYPE_ISO14443_3B:
+ pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData)
+ + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo));
+ e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData),
+ (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData);
+ e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.AppData),
+ sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo),
+ (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.AtqB.AtqResInfo.ProtInfo);
+ break;
+ /* JIS_X_6319_4: PAD0 (2 byte), PAD1 (2 byte), MRTI(2 byte), PAD2 (1 byte), RC (2 byte) */
+ case TARGET_TYPE_FELICA:
+ pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm)
+ + sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode));
+ e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm),
+ (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm);
+ e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm),
+ sizeof(psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode),
+ (jbyte *)psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode);
+ break;
+ /* ISO15693: response flags (1 byte), DSFID (1 byte) */
+ case TARGET_TYPE_ISO15693:
+ pollBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags)
+ + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid));
+ e->SetByteArrayRegion(pollBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags),
+ (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags);
+ e->SetByteArrayRegion(pollBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags),
+ sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid),
+ (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid);
+ break;
+ default:
+ pollBytes = e->NewByteArray(0);
+ break;
+ }
+ e->SetObjectArrayElement(techPollBytes, tech, pollBytes);
+ }
+
+ e->SetObjectField(tag, f, techPollBytes);
+
+ e->ReleaseIntArrayElements(techList, techId, 0);
+
+}
+
+/*
+ * Utility to recover activation bytes from target infos
+ */
+static void set_target_activationBytes(JNIEnv *e, jobject tag,
+ phLibNfc_sRemoteDevInformation_t *psRemoteDevInfo)
+{
+ jclass tag_cls = e->GetObjectClass(tag);
+
+ jfieldID f = e->GetFieldID(tag_cls, "mTechActBytes", "[[B");
+ jobjectArray existingActBytes = (jobjectArray) e->GetObjectField(tag, f);
+
+ if (existingActBytes != NULL) {
+ return;
+ }
+
+ jfieldID techListField = e->GetFieldID(tag_cls, "mTechList", "[I");
+ jintArray techList = (jintArray) e->GetObjectField(tag, techListField);
+ int techListLength = e->GetArrayLength(techList);
+ jint *techId = e->GetIntArrayElements(techList, 0);
+
+ jbyteArray actBytes = e->NewByteArray(0);
+ jobjectArray techActBytes = e->NewObjectArray(techListLength,
+ e->GetObjectClass(actBytes), 0);
+
+ for (int tech = 0; tech < techListLength; tech++) {
+ switch(techId[tech]) {
+
+ /* ISO14443-3A: SAK/SEL_RES */
+ case TARGET_TYPE_ISO14443_3A:
+ actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak));
+ e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak),
+ (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.Sak);
+ break;
+ /* ISO14443-3A & ISO14443-4: SAK/SEL_RES, historical bytes from ATS */
+ /* ISO14443-3B & ISO14443-4: HiLayerResp */
+ case TARGET_TYPE_ISO14443_4:
+ // Determine whether -A or -B
+ if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_B_PICC ||
+ psRemoteDevInfo->RemDevType == phNfc_eISO14443_4B_PICC) {
+ actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength);
+ e->SetByteArrayRegion(actBytes, 0, psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerRespLength,
+ (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443B_Info.HiLayerResp);
+ }
+ else if (psRemoteDevInfo->RemDevType == phNfc_eISO14443_A_PICC ||
+ psRemoteDevInfo->RemDevType == phNfc_eISO14443_4A_PICC) {
+ actBytes = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength);
+ e->SetByteArrayRegion(actBytes, 0,
+ psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppDataLength,
+ (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443A_Info.AppData);
+ }
+ break;
+ /* ISO15693: response flags (1 byte), DSFID (1 byte) */
+ case TARGET_TYPE_ISO15693:
+ actBytes = e->NewByteArray(sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags)
+ + sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid));
+ e->SetByteArrayRegion(actBytes, 0, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags),
+ (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags);
+ e->SetByteArrayRegion(actBytes, sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Flags),
+ sizeof(psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid),
+ (jbyte *)&psRemoteDevInfo->RemoteDevInfo.Iso15693_Info.Dsfid);
+ break;
+ default:
+ actBytes = e->NewByteArray(0);
+ break;
+ }
+ e->SetObjectArrayElement(techActBytes, tech, actBytes);
+ }
+ e->SetObjectField(tag, f, techActBytes);
+
+ e->ReleaseIntArrayElements(techList, techId, 0);
+}
+
+static jint com_android_nfc_NativeNfcTag_doConnect(JNIEnv *e,
+ jobject o, phLibNfc_Handle handle)
+{
+ jclass cls;
+ jfieldID f;
+ jint status;
+ struct nfc_jni_callback_data cb_data;
+ phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL;
+ phLibNfc_sRemoteDevInformation_t* pRemDevInfoPCD = (phLibNfc_sRemoteDevInformation_t *) handle;
+ if(pRemDevInfoPCD!=NULL &&
+ (pRemDevInfoPCD->RemDevType == phNfc_eISO14443_A_PCD ||
+ pRemDevInfoPCD->RemDevType == phNfc_eISO14443_B_PCD)
+ )
+ {
+ if(pRemDevInfoPCD->SessionOpened==TRUE)
+ {
+ storedHandle = handle;
+ pRemDevInfo = pRemDevInfoPCD;
+ // Success, set poll & act bytes
+ set_target_pollBytes(e, o, pRemDevInfo);
+ set_target_activationBytes(e, o, pRemDevInfo);
+ status = NFCSTATUS_SUCCESS;
+ }
+ else
+ {
+ status = NFCSTATUS_FAILED;
+ }
+ }
+ else
+ {
+ CONCURRENCY_LOCK();
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, &pRemDevInfo))
+ {
+ status = NFCSTATUS_NOT_ENOUGH_MEMORY;
+ goto clean_and_return;
+ }
+
+ TRACE("phLibNfc_RemoteDev_Connect(RW)");
+ REENTRANCE_LOCK();
+ storedHandle = handle;
+ status = phLibNfc_RemoteDev_Connect(handle, nfc_jni_connect_callback,(void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_RemoteDev_Connect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_RemoteDev_Connect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("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);
+
+ nfc_cb_data_deinit(&cb_data);
+ /* Connect Status */
+ if(status != NFCSTATUS_SUCCESS)
+ {
+ goto clean_and_return;
+ }
+
+ // Success, set poll & act bytes
+ set_target_pollBytes(e, o, pRemDevInfo);
+ set_target_activationBytes(e, o, pRemDevInfo);
+
+clean_and_return:
+
+ CONCURRENCY_UNLOCK();
+ }
+
+ return status;
+}
+
+static jint com_android_nfc_NativeNfcTag_doHandleReconnect(JNIEnv *e,
+ jobject o, phLibNfc_Handle handle)
+{
+ jclass cls;
+ jfieldID f;
+ jint status;
+ struct nfc_jni_callback_data cb_data;
+ phLibNfc_sRemoteDevInformation_t* pRemDevInfo = NULL;
+ phLibNfc_sRemoteDevInformation_t* pRemDevInfoPCD = (phLibNfc_sRemoteDevInformation_t *) handle;
+
+ if(pRemDevInfoPCD!=NULL &&
+ (pRemDevInfoPCD->RemDevType == phNfc_eISO14443_A_PCD ||
+ pRemDevInfoPCD->RemDevType == phNfc_eISO14443_B_PCD)
+ )
+ {
+ if(pRemDevInfoPCD->SessionOpened==TRUE)
+ {
+ storedHandle = handle;
+ pRemDevInfo = pRemDevInfoPCD;
+ status = NFCSTATUS_SUCCESS;
+ }
+ else
+ status = NFCSTATUS_FAILED;
+ }
+ else
+ {
+ CONCURRENCY_LOCK();
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, &pRemDevInfo))
+ {
+ status = NFCSTATUS_NOT_ENOUGH_MEMORY;
+ goto clean_and_return;
+ }
+
+ TRACE("phLibNfc_RemoteDev_ReConnect(RW)");
+ REENTRANCE_LOCK();
+ storedHandle = handle;
+ status = phLibNfc_RemoteDev_ReConnect(handle, nfc_jni_connect_callback,(void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_RemoteDev_ReConnect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_RemoteDev_ReConnect(RW) returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ status = NFCSTATUS_ABORTED;
+ goto clean_and_return;
+ }
+
+ status = cb_data.status;
+
+ /* Connect Status */
+ if(status != NFCSTATUS_SUCCESS)
+ {
+ goto clean_and_return;
+ }
+
+clean_and_return:
+ nfc_cb_data_deinit(&cb_data);
+ CONCURRENCY_UNLOCK();
+ }
+ return status;
+}
+
+static jint com_android_nfc_NativeNfcTag_doReconnect(JNIEnv *e,
+ jobject o)
+{
+ // Reconnect is provided by libnfc by just calling connect again
+ // on the same handle.
+ int libNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o);
+ if (libNfcType != -1) {
+ // Note that some tag types are stateless, hence we do not reconnect
+ // those. Currently those are the Jewel and Iso15693 technologies.
+ if ((libNfcType != phNfc_eJewel_PICC) && (libNfcType != phNfc_eISO15693_PICC)) {
+ phLibNfc_Handle handle = nfc_jni_get_connected_handle(e,o);
+ return com_android_nfc_NativeNfcTag_doConnect(e, o, handle);
+ }
+ else {
+ return NFCSTATUS_SUCCESS;
+ }
+ }
+ else {
+ return NFCSTATUS_REJECTED;
+ }
+}
+
+
+static jboolean com_android_nfc_NativeNfcTag_doDisconnect(JNIEnv *e, jobject o)
+{
+ phLibNfc_Handle handle = 0;
+ jclass cls;
+ jfieldID f;
+ NFCSTATUS status;
+ jboolean result = JNI_FALSE;
+ struct nfc_jni_callback_data cb_data;
+
+ CONCURRENCY_LOCK();
+
+ handle = nfc_jni_get_connected_handle(e, o);
+ phLibNfc_sRemoteDevInformation_t* pRemDevInfo = (phLibNfc_sRemoteDevInformation_t *) storedHandle;
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ /* Reset the stored handle */
+ storedHandle = 0;
+
+ nfc_jni_reset_timeout_values();
+
+ /* Disconnect */
+ TRACE("Disconnecting from tag (%x)", handle);
+
+ if(pRemDevInfo!=NULL &&
+ (pRemDevInfo->RemDevType == phNfc_eISO14443_A_PCD ||
+ pRemDevInfo->RemDevType == phNfc_eISO14443_B_PCD))
+ {
+ if(pRemDevInfo->RemoteDevInfo.Iso14443_4_PCD_Info.buffer!=NULL &&
+ pRemDevInfo->RemoteDevInfo.Iso14443_4_PCD_Info.length>0)
+ {
+ free(pRemDevInfo->RemoteDevInfo.Iso14443_4_PCD_Info.buffer);
+ pRemDevInfo->RemoteDevInfo.Iso14443_4_PCD_Info.buffer = NULL;
+ pRemDevInfo->RemoteDevInfo.Iso14443_4_PCD_Info.length = 0;
+ }
+ phOsalNfc_FreeMemory(pRemDevInfo);
+ }
+ else if(handle==-1)
+ {
+ // Was never connected to any tag, exit
+ result = JNI_TRUE;
+ ALOGE("doDisconnect() - Target already disconnected");
+ nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e));
+ goto clean_and_return;
+ }
+ else
+ {
+ TRACE("phLibNfc_RemoteDev_Disconnect(%x)", handle);
+ REENTRANCE_LOCK();
+ status = phLibNfc_RemoteDev_Disconnect(handle, NFC_DISCOVERY_CONTINUE,
+ nfc_jni_disconnect_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+
+ if(status == NFCSTATUS_TARGET_NOT_CONNECTED)
+ {
+ result = JNI_TRUE;
+ TRACE("phLibNfc_RemoteDev_Disconnect() - Target already disconnected");
+ goto clean_and_return;
+ }
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, status, nfc_jni_get_status_name(status));
+ nfc_jni_restart_discovery_locked(nfc_jni_get_nat_ext(e));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_RemoteDev_Disconnect(%x) returned 0x%04x[%s]", handle, status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ /* Disconnect Status */
+ if(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ 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;
+}
+
+static uint16_t
+crc_16_ccitt1( uint8_t* msg, size_t len, uint16_t init )
+{
+ uint16_t b, crc = init;
+
+ do {
+ b = *msg++ ^ (crc & 0xFF);
+ b ^= (b << 4) & 0xFF;
+ crc = (crc >> 8) ^ (b << 8) ^ (b << 3) ^ (b >> 4);
+ } while( --len );
+
+ return crc;
+}
+
+static void
+nfc_insert_crc_a( uint8_t* msg, size_t len )
+{
+ uint16_t crc;
+
+ crc = crc_16_ccitt1( msg, len, 0x6363 );
+ msg[len] = crc & 0xFF;
+ msg[len + 1] = (crc >> 8) & 0xFF;
+}
+
+static void
+nfc_get_crc_a( uint8_t* msg, size_t len, uint8_t* byte1, uint8_t* byte2)
+{
+ uint16_t crc;
+
+ crc = crc_16_ccitt1( msg, len, 0x6363 );
+ *byte1 = crc & 0xFF;
+ *byte2 = (crc >> 8) & 0xFF;
+}
+
+static bool
+crc_valid( uint8_t* msg, size_t len)
+{
+ uint8_t crcByte1, crcByte2;
+
+ nfc_get_crc_a(nfc_jni_transceive_buffer->buffer,
+ len - 2, &crcByte1, &crcByte2);
+
+ if (msg[len - 2] == crcByte1 &&
+ msg[len - 1] == crcByte2) {
+ return true;
+ }
+ else {
+ return false;
+ }
+
+}
+
+static jbyteArray com_android_nfc_NativeNfcTag_doTransceive(JNIEnv *e,
+ jobject o, jbyteArray data, jboolean raw, jintArray statusTargetLost)
+{
+ uint8_t offset = 0;
+ // buf is the pointer to the JNI array and never overwritten,
+ // outbuf is passed into the transceive - it may be pointed to new memory
+ // to be extended with CRC.
+ uint8_t *buf = NULL;
+ uint32_t buflen;
+
+ uint8_t *outbuf = NULL;
+ uint32_t outlen;
+ phLibNfc_sTransceiveInfo_t transceive_info;
+ jbyteArray result = NULL;
+ int res;
+ phLibNfc_Handle handle = nfc_jni_get_connected_handle(e, o);
+ phLibNfc_sRemoteDevInformation_t* psRemoteDevInfo = (phLibNfc_sRemoteDevInformation_t *) handle;
+ NFCSTATUS status;
+ struct nfc_jni_callback_data cb_data;
+ int selectedTech = 0;
+ int selectedLibNfcType = 0;
+ jint* technologies = NULL;
+ bool checkResponseCrc = false;
+
+ jint *targetLost;
+ if (statusTargetLost != NULL) {
+ targetLost = e->GetIntArrayElements(statusTargetLost, 0);
+ if (targetLost != NULL) {
+ *targetLost = 0;
+ }
+ } else {
+ targetLost = NULL;
+ }
+
+ memset(&transceive_info, 0, sizeof(transceive_info));
+ selectedTech = nfc_jni_get_connected_technology(e, o);
+ buf = (uint8_t *)e->GetByteArrayElements(data, NULL);
+ if((selectedTech == TARGET_TYPE_ISO14443_4A_PCD ||
+ selectedTech == TARGET_TYPE_ISO14443_4B_PCD) &&
+ psRemoteDevInfo->RemoteDevInfo.Iso14443_4_PCD_Info.buffer!=NULL &&
+ psRemoteDevInfo->RemoteDevInfo.Iso14443_4_PCD_Info.length>0
+ )
+ {
+ if(psRemoteDevInfo->SessionOpened==TRUE)
+ {
+ result = e->NewByteArray(psRemoteDevInfo->RemoteDevInfo.Iso14443_4_PCD_Info.length);
+ if (result != NULL) {
+ e->SetByteArrayRegion(result, 0,
+ psRemoteDevInfo->RemoteDevInfo.Iso14443_4_PCD_Info.length,
+ (jbyte *)psRemoteDevInfo->RemoteDevInfo.Iso14443_4_PCD_Info.buffer);
+ free(psRemoteDevInfo->RemoteDevInfo.Iso14443_4_PCD_Info.buffer);
+ psRemoteDevInfo->RemoteDevInfo.Iso14443_4_PCD_Info.buffer = NULL;
+ psRemoteDevInfo->RemoteDevInfo.Iso14443_4_PCD_Info.length = 0;
+ status = NFCSTATUS_SUCCESS;
+ }
+ else
+ status = NFCSTATUS_FAILED;
+ }
+ else
+ status = NFCSTATUS_FAILED;
+ }
+ else
+ {
+
+ CONCURRENCY_LOCK();
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ outbuf = buf;
+
+ buflen = outlen = (uint32_t)e->GetArrayLength(data);
+
+ selectedLibNfcType = nfc_jni_get_connected_technology_libnfc_type(e, o);
+
+ switch (selectedTech) {
+ case TARGET_TYPE_FELICA:
+ transceive_info.cmd.FelCmd = phNfc_eFelica_Raw;
+ transceive_info.addr = 0;
+ break;
+ case TARGET_TYPE_MIFARE_CLASSIC:
+ case TARGET_TYPE_MIFARE_UL:
+ if (raw) {
+ // Use Mifare Raw to implement a standard
+ // ISO14443-3A transceive, with CRC added
+ transceive_info.cmd.MfCmd = phHal_eMifareRaw;
+ transceive_info.addr = 0;
+ // Need to add in the crc here
+ outbuf = (uint8_t*)malloc(buflen + 2);
+ outlen += 2;
+ memcpy(outbuf, buf, buflen);
+ nfc_insert_crc_a(outbuf, buflen);
+
+ checkResponseCrc = true;
+ } else {
+ // Use the mifare pipe
+ offset = 2;
+ transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0];
+ transceive_info.addr = (uint8_t)buf[1];
+ }
+ break;
+ case TARGET_TYPE_ISO14443_3A:
+ // Check which libnfc type
+ if (selectedLibNfcType == phNfc_eJewel_PICC) {
+ // For the Jewel pipe, CRC is automatically computed
+ transceive_info.cmd.JewelCmd = phNfc_eJewel_Raw;
+ transceive_info.addr = 0;
+ } else {
+ if (raw) {
+ // Use Mifare Raw to implement a standard
+ // ISO14443-3A transceive, with CRC added
+ transceive_info.cmd.MfCmd = phHal_eMifareRaw;
+ transceive_info.addr = 0;
+ // Need to add in the crc here
+ outbuf = (uint8_t*)malloc(buflen + 2);
+ outlen += 2;
+ memcpy(outbuf, buf, buflen);
+ nfc_insert_crc_a(outbuf, buflen);
+
+ checkResponseCrc = true;
+ } else {
+ // Use the mifare pipe
+ offset = 2;
+ transceive_info.cmd.MfCmd = (phNfc_eMifareCmdList_t)buf[0];
+ transceive_info.addr = (uint8_t)buf[1];
+ }
+
+ }
+ break;
+ case TARGET_TYPE_ISO14443_4A_PCD:
+ case TARGET_TYPE_ISO14443_4B_PCD:
+ case TARGET_TYPE_ISO14443_4:
+ transceive_info.cmd.Iso144434Cmd = phNfc_eIso14443_4_Raw;
+ transceive_info.addr = 0;
+ break;
+ case TARGET_TYPE_ISO15693:
+ transceive_info.cmd.Iso15693Cmd = phNfc_eIso15693_Cmd;
+ transceive_info.addr = 0;
+ break;
+ case TARGET_TYPE_UNKNOWN:
+ case TARGET_TYPE_ISO14443_3B:
+ // Not supported
+ goto clean_and_return;
+ default:
+ break;
+ }
+
+ transceive_info.sSendData.buffer = outbuf + offset;
+ transceive_info.sSendData.length = outlen - offset;
+ transceive_info.sRecvData.buffer = (uint8_t*)malloc(1024);
+ transceive_info.sRecvData.length = 1024;
+ if(transceive_info.sRecvData.buffer == NULL)
+ {
+ goto clean_and_return;
+ }
+
+ TRACE("phLibNfc_RemoteDev_Transceive()");
+ REENTRANCE_LOCK();
+ status = phLibNfc_RemoteDev_Transceive(handle, &transceive_info,
+ nfc_jni_transceive_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_RemoteDev_Transceive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ if ((targetLost != NULL) &&
+ (status == NFCSTATUS_TARGET_LOST || selectedTech == TARGET_TYPE_ISO14443_4A_PCD || selectedTech == TARGET_TYPE_ISO14443_4B_PCD)
+ ) {
+ *targetLost = 1;
+ }
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_RemoteDev_Transceive() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ if(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ if ((targetLost != NULL) && (cb_data.status == NFCSTATUS_TARGET_LOST)) {
+ *targetLost = 1;
+ }
+ goto clean_and_return;
+ }
+
+ /* Copy results back to Java *
+ * In case of NfcA and raw, also check the CRC in the response
+ * and cut it off in the returned data.
+ */
+ if ((nfc_jni_transceive_buffer->length > 2) && checkResponseCrc) {
+ if (crc_valid(nfc_jni_transceive_buffer->buffer, nfc_jni_transceive_buffer->length)) {
+ result = e->NewByteArray(nfc_jni_transceive_buffer->length - 2);
+ if (result != NULL) {
+ e->SetByteArrayRegion(result, 0,
+ nfc_jni_transceive_buffer->length - 2,
+ (jbyte *)nfc_jni_transceive_buffer->buffer);
+ }
+ }
+ } else {
+ result = e->NewByteArray(nfc_jni_transceive_buffer->length);
+ if (result != NULL) {
+ e->SetByteArrayRegion(result, 0,
+ nfc_jni_transceive_buffer->length,
+ (jbyte *)nfc_jni_transceive_buffer->buffer);
+ }
+ }
+clean_and_return:
+ nfc_cb_data_deinit(&cb_data);
+
+ CONCURRENCY_UNLOCK();
+
+ if(transceive_info.sRecvData.buffer != NULL)
+ {
+ free(transceive_info.sRecvData.buffer);
+ }
+
+ if ((outbuf != buf) && (outbuf != NULL)) {
+ // Buf was extended and re-alloced with crc bytes, free separately
+ free(outbuf);
+ }
+ }
+
+ e->ReleaseByteArrayElements(data,
+ (jbyte *)buf, JNI_ABORT);
+
+ if (targetLost != NULL) {
+ e->ReleaseIntArrayElements(statusTargetLost, targetLost, 0);
+ }
+
+ return result;
+}
+
+static jint com_android_nfc_NativeNfcTag_doGetNdefType(JNIEnv *e, jobject o,
+ jint libnfcType, jint javaType)
+{
+ jint ndefType = NDEF_UNKNOWN_TYPE;
+
+ switch (libnfcType) {
+ case phNfc_eJewel_PICC:
+ ndefType = NDEF_TYPE1_TAG;
+ break;
+ case phNfc_eISO14443_3A_PICC:
+ ndefType = NDEF_TYPE2_TAG;;
+ break;
+ case phNfc_eFelica_PICC:
+ ndefType = NDEF_TYPE3_TAG;
+ break;
+ case phNfc_eISO14443_A_PICC:
+ case phNfc_eISO14443_4A_PICC:
+ case phNfc_eISO14443_B_PICC:
+ case phNfc_eISO14443_4B_PICC:
+ ndefType = NDEF_TYPE4_TAG;
+ break;
+ case phNfc_eMifare_PICC:
+ if (javaType == TARGET_TYPE_MIFARE_UL) {
+ ndefType = NDEF_TYPE2_TAG;
+ } else {
+ ndefType = NDEF_MIFARE_CLASSIC_TAG;
+ }
+ break;
+ case phNfc_eISO15693_PICC:
+ ndefType = NDEF_ICODE_SLI_TAG;
+ break;
+ default:
+ ndefType = NDEF_UNKNOWN_TYPE;
+ break;
+ }
+ return ndefType;
+}
+
+static jint com_android_nfc_NativeNfcTag_doCheckNdef(JNIEnv *e, jobject o, jintArray ndefinfo)
+{
+ phLibNfc_Handle handle = 0;
+ jint status;
+ phLibNfc_ChkNdef_Info_t sNdefInfo;
+ struct nfc_jni_callback_data cb_data;
+ jint *ndef = e->GetIntArrayElements(ndefinfo, 0);
+ int apiCardState = NDEF_MODE_UNKNOWN;
+ handle = nfc_jni_get_connected_handle(e, o);
+ phLibNfc_sRemoteDevInformation_t* pRemDevInfoPCD = (phLibNfc_sRemoteDevInformation_t *) handle;
+
+ if(pRemDevInfoPCD!=NULL &&
+ (pRemDevInfoPCD->RemDevType == phNfc_eISO14443_A_PCD ||
+ pRemDevInfoPCD->RemDevType == phNfc_eISO14443_B_PCD)
+ )
+ {
+ status = NFCSTATUS_FAILED;
+ }
+ else
+ {
+ CONCURRENCY_LOCK();
+
+ /* 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;
+
+ TRACE("phLibNfc_Ndef_CheckNdef()");
+ REENTRANCE_LOCK();
+ status = phLibNfc_Ndef_CheckNdef(handle, nfc_jni_checkndef_callback,(void *)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_Ndef_CheckNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_Ndef_CheckNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ status = NFCSTATUS_ABORTED;
+ goto clean_and_return;
+ }
+
+ status = cb_data.status;
+ TRACE("phLibNfc_Ndef_CheckNdef() - Status code = %d", status);
+
+ if (status != NFCSTATUS_SUCCESS)
+ {
+ goto clean_and_return;
+ }
+
+ ndef[0] = sNdefInfo.MaxNdefMsgLength;
+ // Translate the card state to know values for the NFC API
+ switch (sNdefInfo.NdefCardState) {
+ case PHLIBNFC_NDEF_CARD_INITIALISED:
+ apiCardState = NDEF_MODE_READ_WRITE;
+ break;
+ case PHLIBNFC_NDEF_CARD_READ_ONLY:
+ apiCardState = NDEF_MODE_READ_ONLY;
+ break;
+ case PHLIBNFC_NDEF_CARD_READ_WRITE:
+ apiCardState = NDEF_MODE_READ_WRITE;
+ break;
+ case PHLIBNFC_NDEF_CARD_INVALID:
+ apiCardState = NDEF_MODE_UNKNOWN;
+ break;
+ }
+ ndef[1] = apiCardState;
+
+clean_and_return:
+ nfc_cb_data_deinit(&cb_data);
+ CONCURRENCY_UNLOCK();
+ }
+
+ e->ReleaseIntArrayElements(ndefinfo, ndef, 0);
+ return status;
+}
+
+static jboolean com_android_nfc_NativeNfcTag_doPresenceCheck(JNIEnv *e, jobject o)
+{
+ phLibNfc_Handle handle = 0;
+ NFCSTATUS status;
+ jboolean result = JNI_FALSE;
+ struct nfc_jni_callback_data cb_data;
+ handle = nfc_jni_get_connected_handle(e, o);
+ phLibNfc_sRemoteDevInformation_t* pRemDevInfoPCD = (phLibNfc_sRemoteDevInformation_t *) handle;
+
+ if(pRemDevInfoPCD!=NULL &&
+ (pRemDevInfoPCD->RemDevType == phNfc_eISO14443_A_PCD ||
+ pRemDevInfoPCD->RemDevType == phNfc_eISO14443_B_PCD)
+ )
+ {
+ if(pRemDevInfoPCD->SessionOpened==TRUE)
+ {
+ result = JNI_TRUE;
+ }
+ else
+ {
+ result = JNI_FALSE;
+ }
+ }
+ else
+ {
+ CONCURRENCY_LOCK();
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ TRACE("phLibNfc_RemoteDev_CheckPresence()");
+ REENTRANCE_LOCK();
+ status = phLibNfc_RemoteDev_CheckPresence(handle, nfc_jni_presencecheck_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_RemoteDev_CheckPresence() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_RemoteDev_CheckPresence() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ if (cb_data.status == NFCSTATUS_SUCCESS)
+ {
+ result = JNI_TRUE;
+ }
+
+clean_and_return:
+ nfc_cb_data_deinit(&cb_data);
+
+ CONCURRENCY_UNLOCK();
+ }
+
+ return result;
+}
+
+static jboolean com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable(JNIEnv *e,
+ jobject o, jbyteArray pollBytes, jbyteArray actBytes)
+{
+ // Determines whether this is a formatable IsoDep tag - currently only NXP DESFire
+ // is supported.
+ jboolean result = JNI_FALSE;
+
+ // DESfire has one sak byte and 2 ATQA bytes
+ if (pollBytes != NULL && (e->GetArrayLength(pollBytes) >= 2) &&
+ actBytes != NULL && (e->GetArrayLength(actBytes) >= 1)) {
+ jbyte* poll = e->GetByteArrayElements(pollBytes, NULL);
+ jbyte* act = e->GetByteArrayElements(actBytes, NULL);
+ if (act[0] == 0x20 && poll[1] == 0x03) {
+ uint8_t cmd[] = {0x90, 0x60, 0x00, 0x00, 0x00};
+ // Identifies as DESfire, use get version cmd to be sure
+ jbyteArray versionCmd = e->NewByteArray(5);
+ e->SetByteArrayRegion(versionCmd, 0, 5, (jbyte*)cmd);
+ jbyteArray respBytes = com_android_nfc_NativeNfcTag_doTransceive(e, o,
+ versionCmd, JNI_TRUE, NULL);
+ if (respBytes != NULL) {
+ // Check whether the response matches a typical DESfire
+ // response.
+ // libNFC even does more advanced checking than we do
+ // here, and will only format DESfire's with a certain
+ // major/minor sw version and NXP as a manufacturer.
+ // We don't want to do such checking here, to avoid
+ // having to change code in multiple places.
+ // A succesful (wrapped) DESFire getVersion command returns
+ // 9 bytes, with byte 7 0x91 and byte 8 having status
+ // code 0xAF (these values are fixed and well-known).
+ int respLength = e->GetArrayLength(respBytes);
+ jbyte* resp = e->GetByteArrayElements(respBytes, NULL);
+ if (respLength == 9 && resp[7] == (jbyte)0x91 &&
+ resp[8] == (jbyte)0xAF) {
+ result = JNI_TRUE;
+ }
+ e->ReleaseByteArrayElements(respBytes, (jbyte *)resp, JNI_ABORT);
+ }
+ }
+ e->ReleaseByteArrayElements(pollBytes, (jbyte *)poll, JNI_ABORT);
+ e->ReleaseByteArrayElements(actBytes, (jbyte *)act, JNI_ABORT);
+ }
+
+ return result;
+}
+
+static jboolean com_android_nfc_NativeNfcTag_doNdefFormat(JNIEnv *e, jobject o, jbyteArray key)
+{
+ phLibNfc_Handle handle = 0;
+ NFCSTATUS status;
+ phNfc_sData_t keyBuffer;
+ jboolean result = JNI_FALSE;
+ struct nfc_jni_callback_data cb_data;
+ handle = nfc_jni_get_connected_handle(e, o);
+ phLibNfc_sRemoteDevInformation_t* pRemDevInfoPCD = (phLibNfc_sRemoteDevInformation_t *) handle;
+
+ if(pRemDevInfoPCD!=NULL &&
+ (pRemDevInfoPCD->RemDevType == phNfc_eISO14443_A_PCD ||
+ pRemDevInfoPCD->RemDevType == phNfc_eISO14443_B_PCD)
+ )
+ {
+ result = JNI_FALSE;
+ }
+ else
+ {
+ CONCURRENCY_LOCK();
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL);
+ keyBuffer.length = e->GetArrayLength(key);
+ TRACE("phLibNfc_RemoteDev_FormatNdef()");
+ REENTRANCE_LOCK();
+ status = phLibNfc_RemoteDev_FormatNdef(handle, &keyBuffer, nfc_jni_formatndef_callback, (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("phLibNfc_RemoteDev_FormatNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_RemoteDev_FormatNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ if (cb_data.status == NFCSTATUS_SUCCESS)
+ {
+ result = JNI_TRUE;
+ }
+clean_and_return:
+ nfc_cb_data_deinit(&cb_data);
+ CONCURRENCY_UNLOCK();
+ }
+
+ e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT);
+ return result;
+}
+
+static jboolean com_android_nfc_NativeNfcTag_doMakeReadonly(JNIEnv *e, jobject o, jbyteArray key)
+{
+ phLibNfc_Handle handle = 0;
+ NFCSTATUS status;
+ jboolean result = JNI_FALSE;
+ struct nfc_jni_callback_data cb_data;
+ phNfc_sData_t keyBuffer;
+ handle = nfc_jni_get_connected_handle(e, o);
+ phLibNfc_sRemoteDevInformation_t* pRemDevInfoPCD = (phLibNfc_sRemoteDevInformation_t *) handle;
+
+ if(pRemDevInfoPCD!=NULL &&
+ (pRemDevInfoPCD->RemDevType == phNfc_eISO14443_A_PCD ||
+ pRemDevInfoPCD->RemDevType == phNfc_eISO14443_B_PCD)
+ )
+ {
+ result = JNI_FALSE;
+ }
+ else
+ {
+ CONCURRENCY_LOCK();
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ keyBuffer.buffer = (uint8_t *)e->GetByteArrayElements(key, NULL);
+ keyBuffer.length = e->GetArrayLength(key);
+ TRACE("phLibNfc_ConvertToReadOnlyNdef()");
+ REENTRANCE_LOCK();
+ status = phLibNfc_ConvertToReadOnlyNdef(handle, &keyBuffer, nfc_jni_readonly_callback,
+ (void *)&cb_data);
+ REENTRANCE_UNLOCK();
+
+ if(status != NFCSTATUS_PENDING)
+ {
+ ALOGE("pphLibNfc_ConvertToReadOnlyNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+ goto clean_and_return;
+ }
+ TRACE("phLibNfc_ConvertToReadOnlyNdef() returned 0x%04x[%s]", status, nfc_jni_get_status_name(status));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ if (cb_data.status == NFCSTATUS_SUCCESS)
+ {
+ result = JNI_TRUE;
+ }
+
+clean_and_return:
+ e->ReleaseByteArrayElements(key, (jbyte *)keyBuffer.buffer, JNI_ABORT);
+ nfc_cb_data_deinit(&cb_data);
+ CONCURRENCY_UNLOCK();
+ }
+
+ return result;
+}
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gMethods[] =
+{
+ {"doConnect", "(I)I",
+ (void *)com_android_nfc_NativeNfcTag_doConnect},
+ {"doDisconnect", "()Z",
+ (void *)com_android_nfc_NativeNfcTag_doDisconnect},
+ {"doReconnect", "()I",
+ (void *)com_android_nfc_NativeNfcTag_doReconnect},
+ {"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)I",
+ (void *)com_android_nfc_NativeNfcTag_doCheckNdef},
+ {"doRead", "()[B",
+ (void *)com_android_nfc_NativeNfcTag_doRead},
+ {"doWrite", "([B)Z",
+ (void *)com_android_nfc_NativeNfcTag_doWrite},
+ {"doPresenceCheck", "()Z",
+ (void *)com_android_nfc_NativeNfcTag_doPresenceCheck},
+ {"doIsIsoDepNdefFormatable", "([B[B)Z",
+ (void *)com_android_nfc_NativeNfcTag_doIsIsoDepNdefFormatable},
+ {"doNdefFormat", "([B)Z",
+ (void *)com_android_nfc_NativeNfcTag_doNdefFormat},
+ {"doMakeReadonly", "([B)Z",
+ (void *)com_android_nfc_NativeNfcTag_doMakeReadonly},
+};
+
+int register_com_android_nfc_NativeNfcTag(JNIEnv *e)
+{
+ return jniRegisterNativeMethods(e,
+ "com/android/nfc/dhimpl/NativeNfcTag",
+ gMethods, NELEM(gMethods));
+}
+
+} // namespace android