1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <semaphore.h>
18#include <errno.h>
19#include <time.h>
20#include <signal.h>
21#include "OverrideLog.h"
22#include "NfcJniUtil.h"
23#include "NfcTag.h"
24#include "config.h"
25#include "Mutex.h"
26#include "IntervalTimer.h"
27#include "JavaClassConstants.h"
28#include "Pn544Interop.h"
29#include <ScopedLocalRef.h>
30#include <ScopedPrimitiveArray.h>
31
32extern "C"
33{
34    #include "nfa_api.h"
35    #include "nfa_rw_api.h"
36    #include "ndef_utils.h"
37    #include "rw_api.h"
38}
39namespace android
40{
41    extern nfc_jni_native_data* getNative(JNIEnv *e, jobject o);
42    extern bool nfcManager_isNfcActive();
43}
44
45extern bool         gActivated;
46extern SyncEvent    gDeactivatedEvent;
47
48/*****************************************************************************
49**
50** public variables and functions
51**
52*****************************************************************************/
53namespace android
54{
55    bool    gIsTagDeactivating = false;    // flag for nfa callback indicating we are deactivating for RF interface switch
56    bool    gIsSelectingRfInterface = false; // flag for nfa callback indicating we are selecting for RF interface switch
57}
58
59
60/*****************************************************************************
61**
62** private variables and functions
63**
64*****************************************************************************/
65namespace android
66{
67
68
69// Pre-defined tag type values. These must match the values in
70// framework Ndef.java for Google public NFC API.
71#define NDEF_UNKNOWN_TYPE          -1
72#define NDEF_TYPE1_TAG             1
73#define NDEF_TYPE2_TAG             2
74#define NDEF_TYPE3_TAG             3
75#define NDEF_TYPE4_TAG             4
76#define NDEF_MIFARE_CLASSIC_TAG    101
77
78#define STATUS_CODE_TARGET_LOST    146	// this error code comes from the service
79
80static uint32_t     sCheckNdefCurrentSize = 0;
81static tNFA_STATUS  sCheckNdefStatus = 0; //whether tag already contains a NDEF message
82static bool         sCheckNdefCapable = false; //whether tag has NDEF capability
83static tNFA_HANDLE  sNdefTypeHandlerHandle = NFA_HANDLE_INVALID;
84static tNFA_INTF_TYPE   sCurrentRfInterface = NFA_INTERFACE_ISO_DEP;
85static uint8_t*     sTransceiveData = NULL;
86static uint32_t     sTransceiveDataLen = 0;
87static bool         sWaitingForTransceive = false;
88static bool         sTransceiveRfTimeout = false;
89static bool         sNeedToSwitchRf = false;
90static Mutex        sRfInterfaceMutex;
91static uint32_t     sReadDataLen = 0;
92static uint8_t*     sReadData = NULL;
93static bool         sIsReadingNdefMessage = false;
94static SyncEvent    sReadEvent;
95static sem_t        sWriteSem;
96static sem_t        sFormatSem;
97static SyncEvent    sTransceiveEvent;
98static SyncEvent    sReconnectEvent;
99static sem_t        sCheckNdefSem;
100static sem_t        sPresenceCheckSem;
101static sem_t        sMakeReadonlySem;
102static IntervalTimer sSwitchBackTimer; // timer used to tell us to switch back to ISO_DEP frame interface
103static jboolean     sWriteOk = JNI_FALSE;
104static jboolean     sWriteWaitingForComplete = JNI_FALSE;
105static bool         sFormatOk = false;
106static jboolean     sConnectOk = JNI_FALSE;
107static jboolean     sConnectWaitingForComplete = JNI_FALSE;
108static bool         sGotDeactivate = false;
109static uint32_t     sCheckNdefMaxSize = 0;
110static bool         sCheckNdefCardReadOnly = false;
111static jboolean     sCheckNdefWaitingForComplete = JNI_FALSE;
112static bool         sIsTagPresent = true;
113static tNFA_STATUS  sMakeReadonlyStatus = NFA_STATUS_FAILED;
114static jboolean     sMakeReadonlyWaitingForComplete = JNI_FALSE;
115static int          sCurrentConnectedTargetType = TARGET_TYPE_UNKNOWN;
116
117static int reSelect (tNFA_INTF_TYPE rfInterface, bool fSwitchIfNeeded);
118static bool switchRfInterface(tNFA_INTF_TYPE rfInterface);
119
120
121/*******************************************************************************
122**
123** Function:        nativeNfcTag_abortWaits
124**
125** Description:     Unblock all thread synchronization objects.
126**
127** Returns:         None
128**
129*******************************************************************************/
130void nativeNfcTag_abortWaits ()
131{
132    ALOGD ("%s", __FUNCTION__);
133    {
134        SyncEventGuard g (sReadEvent);
135        sReadEvent.notifyOne ();
136    }
137    sem_post (&sWriteSem);
138    sem_post (&sFormatSem);
139    {
140        SyncEventGuard g (sTransceiveEvent);
141        sTransceiveEvent.notifyOne ();
142    }
143    {
144        SyncEventGuard g (sReconnectEvent);
145        sReconnectEvent.notifyOne ();
146    }
147
148    sem_post (&sCheckNdefSem);
149    sem_post (&sPresenceCheckSem);
150    sem_post (&sMakeReadonlySem);
151    sCurrentConnectedTargetType = TARGET_TYPE_UNKNOWN;
152}
153
154
155/*******************************************************************************
156**
157** Function:        switchBackTimerProc
158**
159** Description:     Callback function for interval timer.
160**
161** Returns:         None
162**
163*******************************************************************************/
164static void switchBackTimerProc (union sigval)
165{
166    ALOGD ("%s", __FUNCTION__);
167    switchRfInterface(NFA_INTERFACE_ISO_DEP);
168}
169
170
171/*******************************************************************************
172**
173** Function:        nativeNfcTag_doReadCompleted
174**
175** Description:     Receive the completion status of read operation.  Called by
176**                  NFA_READ_CPLT_EVT.
177**                  status: Status of operation.
178**
179** Returns:         None
180**
181*******************************************************************************/
182void nativeNfcTag_doReadCompleted (tNFA_STATUS status)
183{
184    ALOGD ("%s: status=0x%X; is reading=%u", __FUNCTION__, status, sIsReadingNdefMessage);
185
186    if (sIsReadingNdefMessage == false)
187        return; //not reading NDEF message right now, so just return
188
189    if (status != NFA_STATUS_OK)
190    {
191        sReadDataLen = 0;
192        if (sReadData)
193            free (sReadData);
194        sReadData = NULL;
195    }
196    SyncEventGuard g (sReadEvent);
197    sReadEvent.notifyOne ();
198}
199
200
201/*******************************************************************************
202**
203** Function:        ndefHandlerCallback
204**
205** Description:     Receive NDEF-message related events from stack.
206**                  event: Event code.
207**                  p_data: Event data.
208**
209** Returns:         None
210**
211*******************************************************************************/
212static void ndefHandlerCallback (tNFA_NDEF_EVT event, tNFA_NDEF_EVT_DATA *eventData)
213{
214    ALOGD ("%s: event=%u, eventData=%p", __FUNCTION__, event, eventData);
215
216    switch (event)
217    {
218    case NFA_NDEF_REGISTER_EVT:
219        {
220            tNFA_NDEF_REGISTER& ndef_reg = eventData->ndef_reg;
221            ALOGD ("%s: NFA_NDEF_REGISTER_EVT; status=0x%X; h=0x%X", __FUNCTION__, ndef_reg.status, ndef_reg.ndef_type_handle);
222            sNdefTypeHandlerHandle = ndef_reg.ndef_type_handle;
223        }
224        break;
225
226    case NFA_NDEF_DATA_EVT:
227        {
228            ALOGD ("%s: NFA_NDEF_DATA_EVT; data_len = %lu", __FUNCTION__, eventData->ndef_data.len);
229            sReadDataLen = eventData->ndef_data.len;
230            sReadData = (uint8_t*) malloc (sReadDataLen);
231            memcpy (sReadData, eventData->ndef_data.p_data, eventData->ndef_data.len);
232        }
233        break;
234
235    default:
236        ALOGE ("%s: Unknown event %u ????", __FUNCTION__, event);
237        break;
238    }
239}
240
241
242/*******************************************************************************
243**
244** Function:        nativeNfcTag_doRead
245**
246** Description:     Read the NDEF message on the tag.
247**                  e: JVM environment.
248**                  o: Java object.
249**
250** Returns:         NDEF message.
251**
252*******************************************************************************/
253static jbyteArray nativeNfcTag_doRead (JNIEnv* e, jobject)
254{
255    ALOGD ("%s: enter", __FUNCTION__);
256    tNFA_STATUS status = NFA_STATUS_FAILED;
257    jbyteArray buf = NULL;
258
259    sReadDataLen = 0;
260    if (sReadData != NULL)
261    {
262        free (sReadData);
263        sReadData = NULL;
264    }
265
266    if (sCheckNdefCurrentSize > 0)
267    {
268        {
269            SyncEventGuard g (sReadEvent);
270            sIsReadingNdefMessage = true;
271            status = NFA_RwReadNDef ();
272            sReadEvent.wait (); //wait for NFA_READ_CPLT_EVT
273        }
274        sIsReadingNdefMessage = false;
275
276        if (sReadDataLen > 0) //if stack actually read data from the tag
277        {
278            ALOGD ("%s: read %u bytes", __FUNCTION__, sReadDataLen);
279            buf = e->NewByteArray (sReadDataLen);
280            e->SetByteArrayRegion (buf, 0, sReadDataLen, (jbyte*) sReadData);
281        }
282    }
283    else
284    {
285        ALOGD ("%s: create emtpy buffer", __FUNCTION__);
286        sReadDataLen = 0;
287        sReadData = (uint8_t*) malloc (1);
288        buf = e->NewByteArray (sReadDataLen);
289        e->SetByteArrayRegion (buf, 0, sReadDataLen, (jbyte*) sReadData);
290    }
291
292    if (sReadData)
293    {
294        free (sReadData);
295        sReadData = NULL;
296    }
297    sReadDataLen = 0;
298
299    ALOGD ("%s: exit", __FUNCTION__);
300    return buf;
301}
302
303
304/*******************************************************************************
305**
306** Function:        nativeNfcTag_doWriteStatus
307**
308** Description:     Receive the completion status of write operation.  Called
309**                  by NFA_WRITE_CPLT_EVT.
310**                  isWriteOk: Status of operation.
311**
312** Returns:         None
313**
314*******************************************************************************/
315void nativeNfcTag_doWriteStatus (jboolean isWriteOk)
316{
317    if (sWriteWaitingForComplete != JNI_FALSE)
318    {
319        sWriteWaitingForComplete = JNI_FALSE;
320        sWriteOk = isWriteOk;
321        sem_post (&sWriteSem);
322    }
323}
324
325
326/*******************************************************************************
327**
328** Function:        nativeNfcTag_formatStatus
329**
330** Description:     Receive the completion status of format operation.  Called
331**                  by NFA_FORMAT_CPLT_EVT.
332**                  isOk: Status of operation.
333**
334** Returns:         None
335**
336*******************************************************************************/
337void nativeNfcTag_formatStatus (bool isOk)
338{
339    sFormatOk = isOk;
340    sem_post (&sFormatSem);
341}
342
343
344/*******************************************************************************
345**
346** Function:        nativeNfcTag_doWrite
347**
348** Description:     Write a NDEF message to the tag.
349**                  e: JVM environment.
350**                  o: Java object.
351**                  buf: Contains a NDEF message.
352**
353** Returns:         True if ok.
354**
355*******************************************************************************/
356static jboolean nativeNfcTag_doWrite (JNIEnv* e, jobject, jbyteArray buf)
357{
358    jboolean result = JNI_FALSE;
359    tNFA_STATUS status = 0;
360    const int maxBufferSize = 1024;
361    UINT8 buffer[maxBufferSize] = { 0 };
362    UINT32 curDataSize = 0;
363
364    ScopedByteArrayRO bytes(e, buf);
365    UINT8* p_data = const_cast<UINT8*>(reinterpret_cast<const UINT8*>(&bytes[0])); // TODO: const-ness API bug in NFA_RwWriteNDef!
366
367    ALOGD ("%s: enter; len = %zu", __FUNCTION__, bytes.size());
368
369    /* Create the write semaphore */
370    if (sem_init (&sWriteSem, 0, 0) == -1)
371    {
372        ALOGE ("%s: semaphore creation failed (errno=0x%08x)", __FUNCTION__, errno);
373        return JNI_FALSE;
374    }
375
376    sWriteWaitingForComplete = JNI_TRUE;
377    if (sCheckNdefStatus == NFA_STATUS_FAILED)
378    {
379        //if tag does not contain a NDEF message
380        //and tag is capable of storing NDEF message
381        if (sCheckNdefCapable)
382        {
383            ALOGD ("%s: try format", __FUNCTION__);
384            sem_init (&sFormatSem, 0, 0);
385            sFormatOk = false;
386            status = NFA_RwFormatTag ();
387            sem_wait (&sFormatSem);
388            sem_destroy (&sFormatSem);
389            if (sFormatOk == false) //if format operation failed
390                goto TheEnd;
391        }
392        ALOGD ("%s: try write", __FUNCTION__);
393        status = NFA_RwWriteNDef (p_data, bytes.size());
394    }
395    else if (bytes.size() == 0)
396    {
397        //if (NXP TagWriter wants to erase tag) then create and write an empty ndef message
398        NDEF_MsgInit (buffer, maxBufferSize, &curDataSize);
399        status = NDEF_MsgAddRec (buffer, maxBufferSize, &curDataSize, NDEF_TNF_EMPTY, NULL, 0, NULL, 0, NULL, 0);
400        ALOGD ("%s: create empty ndef msg; status=%u; size=%lu", __FUNCTION__, status, curDataSize);
401        status = NFA_RwWriteNDef (buffer, curDataSize);
402    }
403    else
404    {
405        ALOGD ("%s: NFA_RwWriteNDef", __FUNCTION__);
406        status = NFA_RwWriteNDef (p_data, bytes.size());
407    }
408
409    if (status != NFA_STATUS_OK)
410    {
411        ALOGE ("%s: write/format error=%d", __FUNCTION__, status);
412        goto TheEnd;
413    }
414
415    /* Wait for write completion status */
416    sWriteOk = false;
417    if (sem_wait (&sWriteSem))
418    {
419        ALOGE ("%s: wait semaphore (errno=0x%08x)", __FUNCTION__, errno);
420        goto TheEnd;
421    }
422
423    result = sWriteOk;
424
425TheEnd:
426    /* Destroy semaphore */
427    if (sem_destroy (&sWriteSem))
428    {
429        ALOGE ("%s: failed destroy semaphore (errno=0x%08x)", __FUNCTION__, errno);
430    }
431    sWriteWaitingForComplete = JNI_FALSE;
432    ALOGD ("%s: exit; result=%d", __FUNCTION__, result);
433    return result;
434}
435
436
437/*******************************************************************************
438**
439** Function:        nativeNfcTag_doConnectStatus
440**
441** Description:     Receive the completion status of connect operation.
442**                  isConnectOk: Status of the operation.
443**
444** Returns:         None
445**
446*******************************************************************************/
447void nativeNfcTag_doConnectStatus (jboolean isConnectOk)
448{
449    if (sConnectWaitingForComplete != JNI_FALSE)
450    {
451        sConnectWaitingForComplete = JNI_FALSE;
452        sConnectOk = isConnectOk;
453        SyncEventGuard g (sReconnectEvent);
454        sReconnectEvent.notifyOne ();
455    }
456}
457
458
459/*******************************************************************************
460**
461** Function:        nativeNfcTag_doDeactivateStatus
462**
463** Description:     Receive the completion status of deactivate operation.
464**
465** Returns:         None
466**
467*******************************************************************************/
468void nativeNfcTag_doDeactivateStatus (int status)
469{
470    sGotDeactivate = (status == 0);
471
472    SyncEventGuard g (sReconnectEvent);
473    sReconnectEvent.notifyOne ();
474}
475
476
477/*******************************************************************************
478**
479** Function:        nativeNfcTag_doConnect
480**
481** Description:     Connect to the tag in RF field.
482**                  e: JVM environment.
483**                  o: Java object.
484**                  targetHandle: Handle of the tag.
485**
486** Returns:         Must return NXP status code, which NFC service expects.
487**
488*******************************************************************************/
489static jint nativeNfcTag_doConnect (JNIEnv*, jobject, jint targetHandle)
490{
491    ALOGD ("%s: targetHandle = %d", __FUNCTION__, targetHandle);
492    int i = targetHandle;
493    NfcTag& natTag = NfcTag::getInstance ();
494    int retCode = NFCSTATUS_SUCCESS;
495
496    sNeedToSwitchRf = false;
497    if (i >= NfcTag::MAX_NUM_TECHNOLOGY)
498    {
499        ALOGE ("%s: Handle not found", __FUNCTION__);
500        retCode = NFCSTATUS_FAILED;
501        goto TheEnd;
502    }
503
504    if (natTag.getActivationState() != NfcTag::Active)
505    {
506        ALOGE ("%s: tag already deactivated", __FUNCTION__);
507        retCode = NFCSTATUS_FAILED;
508        goto TheEnd;
509    }
510
511    sCurrentConnectedTargetType = natTag.mTechList[i];
512    if (natTag.mTechLibNfcTypes[i] != NFC_PROTOCOL_ISO_DEP)
513    {
514        ALOGD ("%s() Nfc type = %d, do nothing for non ISO_DEP", __FUNCTION__, natTag.mTechLibNfcTypes[i]);
515        retCode = NFCSTATUS_SUCCESS;
516        goto TheEnd;
517    }
518
519    if (natTag.mTechList[i] == TARGET_TYPE_ISO14443_3A || natTag.mTechList[i] == TARGET_TYPE_ISO14443_3B)
520    {
521        ALOGD ("%s: switching to tech: %d need to switch rf intf to frame", __FUNCTION__, natTag.mTechList[i]);
522        // connecting to NfcA or NfcB don't actually switch until/unless we get a transceive
523        sNeedToSwitchRf = true;
524    }
525    else
526    {
527        // connecting back to IsoDep or NDEF
528        return (switchRfInterface (NFA_INTERFACE_ISO_DEP) ? NFCSTATUS_SUCCESS : NFCSTATUS_FAILED);
529    }
530
531TheEnd:
532    ALOGD ("%s: exit 0x%X", __FUNCTION__, retCode);
533    return retCode;
534}
535
536/*******************************************************************************
537**
538** Function:        reSelect
539**
540** Description:     Deactivates the tag and re-selects it with the specified
541**                  rf interface.
542**
543** Returns:         status code, 0 on success, 1 on failure,
544**                  146 (defined in service) on tag lost
545**
546*******************************************************************************/
547static int reSelect (tNFA_INTF_TYPE rfInterface, bool fSwitchIfNeeded)
548{
549    ALOGD ("%s: enter; rf intf = %d, current intf = %d", __FUNCTION__, rfInterface, sCurrentRfInterface);
550
551    sRfInterfaceMutex.lock ();
552
553    if (fSwitchIfNeeded && (rfInterface == sCurrentRfInterface))
554    {
555        // already in the requested interface
556        sRfInterfaceMutex.unlock ();
557        return 0;   // success
558    }
559
560    NfcTag& natTag = NfcTag::getInstance ();
561
562    tNFA_STATUS status;
563    int rVal = 1;
564
565    do
566    {
567        //if tag has shutdown, abort this method
568        if (NfcTag::getInstance ().isNdefDetectionTimedOut())
569        {
570            ALOGD ("%s: ndef detection timeout; break", __FUNCTION__);
571            rVal = STATUS_CODE_TARGET_LOST;
572            break;
573        }
574
575        {
576            SyncEventGuard g (sReconnectEvent);
577            gIsTagDeactivating = true;
578            sGotDeactivate = false;
579            ALOGD ("%s: deactivate to sleep", __FUNCTION__);
580            if (NFA_STATUS_OK != (status = NFA_Deactivate (TRUE))) //deactivate to sleep state
581            {
582                ALOGE ("%s: deactivate failed, status = %d", __FUNCTION__, status);
583                break;
584            }
585
586            if (sReconnectEvent.wait (1000) == false) //if timeout occurred
587            {
588                ALOGE ("%s: timeout waiting for deactivate", __FUNCTION__);
589            }
590        }
591
592        if (!sGotDeactivate)
593        {
594            rVal = STATUS_CODE_TARGET_LOST;
595            break;
596        }
597
598        if (NfcTag::getInstance ().getActivationState () != NfcTag::Sleep)
599        {
600            ALOGD ("%s: tag is not in sleep", __FUNCTION__);
601            rVal = STATUS_CODE_TARGET_LOST;
602            break;
603        }
604
605        gIsTagDeactivating = false;
606
607        {
608            SyncEventGuard g2 (sReconnectEvent);
609
610            sConnectWaitingForComplete = JNI_TRUE;
611            ALOGD ("%s: select interface %u", __FUNCTION__, rfInterface);
612            gIsSelectingRfInterface = true;
613            if (NFA_STATUS_OK != (status = NFA_Select (natTag.mTechHandles[0], natTag.mTechLibNfcTypes[0], rfInterface)))
614            {
615                ALOGE ("%s: NFA_Select failed, status = %d", __FUNCTION__, status);
616                break;
617            }
618
619            sConnectOk = false;
620            if (sReconnectEvent.wait (1000) == false) //if timeout occured
621            {
622                ALOGE ("%s: timeout waiting for select", __FUNCTION__);
623                break;
624            }
625        }
626
627        ALOGD("%s: select completed; sConnectOk=%d", __FUNCTION__, sConnectOk);
628        if (NfcTag::getInstance ().getActivationState () != NfcTag::Active)
629        {
630            ALOGD("%s: tag is not active", __FUNCTION__);
631            rVal = STATUS_CODE_TARGET_LOST;
632            break;
633        }
634        if (sConnectOk)
635        {
636            rVal = 0;   // success
637            sCurrentRfInterface = rfInterface;
638        }
639        else
640        {
641            rVal = 1;
642        }
643    } while (0);
644
645    sConnectWaitingForComplete = JNI_FALSE;
646    gIsTagDeactivating = false;
647    gIsSelectingRfInterface = false;
648    sRfInterfaceMutex.unlock ();
649    ALOGD ("%s: exit; status=%d", __FUNCTION__, rVal);
650    return rVal;
651}
652
653/*******************************************************************************
654**
655** Function:        switchRfInterface
656**
657** Description:     Switch controller's RF interface to frame, ISO-DEP, or NFC-DEP.
658**                  rfInterface: Type of RF interface.
659**
660** Returns:         True if ok.
661**
662*******************************************************************************/
663static bool switchRfInterface (tNFA_INTF_TYPE rfInterface)
664{
665    ALOGD ("%s: rf intf = %d", __FUNCTION__, rfInterface);
666    NfcTag& natTag = NfcTag::getInstance ();
667
668    if (natTag.mTechLibNfcTypes[0] != NFC_PROTOCOL_ISO_DEP)
669    {
670        ALOGD ("%s: protocol: %d not ISO_DEP, do nothing", __FUNCTION__, natTag.mTechLibNfcTypes[0]);
671        return true;
672    }
673
674    ALOGD ("%s: new rf intf = %d, cur rf intf = %d", __FUNCTION__, rfInterface, sCurrentRfInterface);
675
676    return (0 == reSelect(rfInterface, true));
677}
678
679
680/*******************************************************************************
681**
682** Function:        nativeNfcTag_doReconnect
683**
684** Description:     Re-connect to the tag in RF field.
685**                  e: JVM environment.
686**                  o: Java object.
687**
688** Returns:         Status code.
689**
690*******************************************************************************/
691static jint nativeNfcTag_doReconnect (JNIEnv*, jobject)
692{
693    ALOGD ("%s: enter", __FUNCTION__);
694    int retCode = NFCSTATUS_SUCCESS;
695    NfcTag& natTag = NfcTag::getInstance ();
696
697    if (natTag.getActivationState() != NfcTag::Active)
698    {
699        ALOGE ("%s: tag already deactivated", __FUNCTION__);
700        retCode = NFCSTATUS_FAILED;
701        goto TheEnd;
702    }
703
704    // special case for Kovio
705    if (NfcTag::getInstance ().mTechList [0] == TARGET_TYPE_KOVIO_BARCODE)
706    {
707        ALOGD ("%s: fake out reconnect for Kovio", __FUNCTION__);
708        goto TheEnd;
709    }
710
711    // this is only supported for type 2 or 4 (ISO_DEP) tags
712    if (natTag.mTechLibNfcTypes[0] == NFA_PROTOCOL_ISO_DEP)
713        retCode = reSelect(NFA_INTERFACE_ISO_DEP, false);
714    else if (natTag.mTechLibNfcTypes[0] == NFA_PROTOCOL_T2T)
715        retCode = reSelect(NFA_INTERFACE_FRAME, false);
716
717TheEnd:
718    ALOGD ("%s: exit 0x%X", __FUNCTION__, retCode);
719    return retCode;
720}
721
722
723/*******************************************************************************
724**
725** Function:        nativeNfcTag_doHandleReconnect
726**
727** Description:     Re-connect to the tag in RF field.
728**                  e: JVM environment.
729**                  o: Java object.
730**                  targetHandle: Handle of the tag.
731**
732** Returns:         Status code.
733**
734*******************************************************************************/
735static jint nativeNfcTag_doHandleReconnect (JNIEnv *e, jobject o, jint targetHandle)
736{
737    ALOGD ("%s: targetHandle = %d", __FUNCTION__, targetHandle);
738    return nativeNfcTag_doConnect (e, o, targetHandle);
739}
740
741
742/*******************************************************************************
743**
744** Function:        nativeNfcTag_doDisconnect
745**
746** Description:     Deactivate the RF field.
747**                  e: JVM environment.
748**                  o: Java object.
749**
750** Returns:         True if ok.
751**
752*******************************************************************************/
753static jboolean nativeNfcTag_doDisconnect (JNIEnv*, jobject)
754{
755    ALOGD ("%s: enter", __FUNCTION__);
756    tNFA_STATUS nfaStat = NFA_STATUS_OK;
757
758    NfcTag::getInstance().resetAllTransceiveTimeouts ();
759
760    if (NfcTag::getInstance ().getActivationState () != NfcTag::Active)
761    {
762        ALOGE ("%s: tag already deactivated", __FUNCTION__);
763        goto TheEnd;
764    }
765
766    nfaStat = NFA_Deactivate (FALSE);
767    if (nfaStat != NFA_STATUS_OK)
768        ALOGE ("%s: deactivate failed; error=0x%X", __FUNCTION__, nfaStat);
769
770TheEnd:
771    ALOGD ("%s: exit", __FUNCTION__);
772    return (nfaStat == NFA_STATUS_OK) ? JNI_TRUE : JNI_FALSE;
773}
774
775
776/*******************************************************************************
777**
778** Function:        nativeNfcTag_doTransceiveStatus
779**
780** Description:     Receive the completion status of transceive operation.
781**                  buf: Contains tag's response.
782**                  bufLen: Length of buffer.
783**
784** Returns:         None
785**
786*******************************************************************************/
787void nativeNfcTag_doTransceiveStatus (uint8_t* buf, uint32_t bufLen)
788{
789    SyncEventGuard g (sTransceiveEvent);
790    ALOGD ("%s: data len=%d, waiting for transceive: %d", __FUNCTION__, bufLen, sWaitingForTransceive);
791    if (!sWaitingForTransceive)
792        return;
793
794    sTransceiveDataLen = 0;
795    if (bufLen)
796    {
797        if (NULL == (sTransceiveData = (uint8_t *) malloc (bufLen)))
798        {
799            ALOGD ("%s: memory allocation error", __FUNCTION__);
800        }
801        else
802        {
803            memcpy (sTransceiveData, buf, sTransceiveDataLen = bufLen);
804        }
805    }
806
807    sTransceiveEvent.notifyOne ();
808}
809
810
811void nativeNfcTag_notifyRfTimeout ()
812{
813    SyncEventGuard g (sTransceiveEvent);
814    ALOGD ("%s: waiting for transceive: %d", __FUNCTION__, sWaitingForTransceive);
815    if (!sWaitingForTransceive)
816        return;
817
818    sTransceiveRfTimeout = true;
819
820    sTransceiveEvent.notifyOne ();
821}
822/*******************************************************************************
823**
824** Function:        nativeNfcTag_doTransceive
825**
826** Description:     Send raw data to the tag; receive tag's response.
827**                  e: JVM environment.
828**                  o: Java object.
829**                  raw: Not used.
830**                  statusTargetLost: Whether tag responds or times out.
831**
832** Returns:         Response from tag.
833**
834*******************************************************************************/
835static jbyteArray nativeNfcTag_doTransceive (JNIEnv* e, jobject, jbyteArray data, jboolean raw, jintArray statusTargetLost)
836{
837    int timeout = NfcTag::getInstance ().getTransceiveTimeout(sCurrentConnectedTargetType);
838    ALOGD ("%s: enter; raw=%u; timeout = %d", __FUNCTION__, raw, timeout);
839    bool fNeedToSwitchBack = false;
840    bool waitOk = false;
841    bool isNack = false;
842    jint *targetLost = NULL;
843
844    if (NfcTag::getInstance ().getActivationState () != NfcTag::Active)
845    {
846        if (statusTargetLost)
847        {
848            targetLost = e->GetIntArrayElements (statusTargetLost, 0);
849            if (targetLost)
850                *targetLost = 1; //causes NFC service to throw TagLostException
851            e->ReleaseIntArrayElements (statusTargetLost, targetLost, 0);
852        }
853        ALOGD ("%s: tag not active", __FUNCTION__);
854        return NULL;
855    }
856
857    NfcTag& natTag = NfcTag::getInstance ();
858
859    // get input buffer and length from java call
860    ScopedByteArrayRO bytes(e, data);
861    uint8_t* buf = const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(&bytes[0])); // TODO: API bug; NFA_SendRawFrame should take const*!
862    size_t bufLen = bytes.size();
863
864    if (statusTargetLost)
865    {
866        targetLost = e->GetIntArrayElements (statusTargetLost, 0);
867        if (targetLost)
868            *targetLost = 0; //success, tag is still present
869    }
870
871    sSwitchBackTimer.kill ();
872    ScopedLocalRef<jbyteArray> result(e, NULL);
873    do
874    {
875        if (sNeedToSwitchRf)
876        {
877            // for ISO_DEP tags connected to NfcA or NfcB we need to be in FRAME interface
878            if (!switchRfInterface (NFA_INTERFACE_FRAME)) //NFA_INTERFACE_ISO_DEP
879            {
880                break;
881            }
882            fNeedToSwitchBack = true;
883        }
884
885        {
886            SyncEventGuard g (sTransceiveEvent);
887            sTransceiveRfTimeout = false;
888            sWaitingForTransceive = true;
889            sTransceiveDataLen = 0;
890            tNFA_STATUS status = NFA_SendRawFrame (buf, bufLen,
891                    NFA_DM_DEFAULT_PRESENCE_CHECK_START_DELAY);
892            if (status != NFA_STATUS_OK)
893            {
894                ALOGE ("%s: fail send; error=%d", __FUNCTION__, status);
895                break;
896            }
897
898            waitOk = sTransceiveEvent.wait (timeout);
899        }
900
901        if (waitOk == false || sTransceiveRfTimeout) //if timeout occurred
902        {
903            ALOGE ("%s: wait response timeout", __FUNCTION__);
904            if (targetLost)
905                *targetLost = 1; //causes NFC service to throw TagLostException
906            break;
907        }
908
909        if (NfcTag::getInstance ().getActivationState () != NfcTag::Active)
910        {
911            ALOGE ("%s: already deactivated", __FUNCTION__);
912            if (targetLost)
913                *targetLost = 1; //causes NFC service to throw TagLostException
914            break;
915        }
916
917        ALOGD ("%s: response %d bytes", __FUNCTION__, sTransceiveDataLen);
918
919        if ((natTag.getProtocol () == NFA_PROTOCOL_T2T) &&
920            natTag.isT2tNackResponse (sTransceiveData, sTransceiveDataLen))
921        {
922            isNack = true;
923        }
924
925        if (sTransceiveDataLen)
926        {
927            if (!isNack) {
928                // marshall data to java for return
929                result.reset(e->NewByteArray(sTransceiveDataLen));
930                if (result.get() != NULL) {
931                    e->SetByteArrayRegion(result.get(), 0, sTransceiveDataLen, (jbyte *) sTransceiveData);
932                }
933                else
934                    ALOGE ("%s: Failed to allocate java byte array", __FUNCTION__);
935            } // else a nack is treated as a transceive failure to the upper layers
936
937            free (sTransceiveData);
938            sTransceiveData = NULL;
939            sTransceiveDataLen = 0;
940        }
941    } while (0);
942
943    sWaitingForTransceive = false;
944    if (targetLost)
945        e->ReleaseIntArrayElements (statusTargetLost, targetLost, 0);
946
947    if (fNeedToSwitchBack)
948    {
949        // this timer proc will switch us back to ISO_DEP frame interface
950        sSwitchBackTimer.set (1500, switchBackTimerProc);
951    }
952
953    ALOGD ("%s: exit", __FUNCTION__);
954    return result.release();
955}
956
957
958/*******************************************************************************
959**
960** Function:        nativeNfcTag_doGetNdefType
961**
962** Description:     Retrieve the type of tag.
963**                  e: JVM environment.
964**                  o: Java object.
965**                  libnfcType: Type of tag represented by JNI.
966**                  javaType: Not used.
967**
968** Returns:         Type of tag represented by NFC Service.
969**
970*******************************************************************************/
971static jint nativeNfcTag_doGetNdefType (JNIEnv*, jobject, jint libnfcType, jint javaType)
972{
973    ALOGD ("%s: enter; libnfc type=%d; java type=%d", __FUNCTION__, libnfcType, javaType);
974    jint ndefType = NDEF_UNKNOWN_TYPE;
975
976    // For NFA, libnfcType is mapped to the protocol value received
977    // in the NFA_ACTIVATED_EVT and NFA_DISC_RESULT_EVT event.
978    switch (libnfcType) {
979    case NFA_PROTOCOL_T1T:
980        ndefType = NDEF_TYPE1_TAG;
981        break;
982    case NFA_PROTOCOL_T2T:
983        ndefType = NDEF_TYPE2_TAG;;
984        break;
985    case NFA_PROTOCOL_T3T:
986        ndefType = NDEF_TYPE3_TAG;
987        break;
988    case NFA_PROTOCOL_ISO_DEP:
989        ndefType = NDEF_TYPE4_TAG;
990        break;
991    case NFA_PROTOCOL_ISO15693:
992        ndefType = NDEF_UNKNOWN_TYPE;
993        break;
994    case NFA_PROTOCOL_INVALID:
995        ndefType = NDEF_UNKNOWN_TYPE;
996        break;
997    default:
998        ndefType = NDEF_UNKNOWN_TYPE;
999        break;
1000    }
1001    ALOGD ("%s: exit; ndef type=%d", __FUNCTION__, ndefType);
1002    return ndefType;
1003}
1004
1005
1006/*******************************************************************************
1007**
1008** Function:        nativeNfcTag_doCheckNdefResult
1009**
1010** Description:     Receive the result of checking whether the tag contains a NDEF
1011**                  message.  Called by the NFA_NDEF_DETECT_EVT.
1012**                  status: Status of the operation.
1013**                  maxSize: Maximum size of NDEF message.
1014**                  currentSize: Current size of NDEF message.
1015**                  flags: Indicate various states.
1016**
1017** Returns:         None
1018**
1019*******************************************************************************/
1020void nativeNfcTag_doCheckNdefResult (tNFA_STATUS status, uint32_t maxSize, uint32_t currentSize, uint8_t flags)
1021{
1022    //this function's flags parameter is defined using the following macros
1023    //in nfc/include/rw_api.h;
1024    //#define RW_NDEF_FL_READ_ONLY  0x01    /* Tag is read only              */
1025    //#define RW_NDEF_FL_FORMATED   0x02    /* Tag formated for NDEF         */
1026    //#define RW_NDEF_FL_SUPPORTED  0x04    /* NDEF supported by the tag     */
1027    //#define RW_NDEF_FL_UNKNOWN    0x08    /* Unable to find if tag is ndef capable/formated/read only */
1028    //#define RW_NDEF_FL_FORMATABLE 0x10    /* Tag supports format operation */
1029
1030    if (status == NFC_STATUS_BUSY)
1031    {
1032        ALOGE ("%s: stack is busy", __FUNCTION__);
1033        return;
1034    }
1035
1036    if (!sCheckNdefWaitingForComplete)
1037    {
1038        ALOGE ("%s: not waiting", __FUNCTION__);
1039        return;
1040    }
1041
1042    if (flags & RW_NDEF_FL_READ_ONLY)
1043        ALOGD ("%s: flag read-only", __FUNCTION__);
1044    if (flags & RW_NDEF_FL_FORMATED)
1045        ALOGD ("%s: flag formatted for ndef", __FUNCTION__);
1046    if (flags & RW_NDEF_FL_SUPPORTED)
1047        ALOGD ("%s: flag ndef supported", __FUNCTION__);
1048    if (flags & RW_NDEF_FL_UNKNOWN)
1049        ALOGD ("%s: flag all unknown", __FUNCTION__);
1050    if (flags & RW_NDEF_FL_FORMATABLE)
1051        ALOGD ("%s: flag formattable", __FUNCTION__);
1052
1053    sCheckNdefWaitingForComplete = JNI_FALSE;
1054    sCheckNdefStatus = status;
1055    sCheckNdefCapable = false; //assume tag is NOT ndef capable
1056    if (sCheckNdefStatus == NFA_STATUS_OK)
1057    {
1058        //NDEF content is on the tag
1059        sCheckNdefMaxSize = maxSize;
1060        sCheckNdefCurrentSize = currentSize;
1061        sCheckNdefCardReadOnly = flags & RW_NDEF_FL_READ_ONLY;
1062        sCheckNdefCapable = true;
1063    }
1064    else if (sCheckNdefStatus == NFA_STATUS_FAILED)
1065    {
1066        //no NDEF content on the tag
1067        sCheckNdefMaxSize = 0;
1068        sCheckNdefCurrentSize = 0;
1069        sCheckNdefCardReadOnly = flags & RW_NDEF_FL_READ_ONLY;
1070        if ((flags & RW_NDEF_FL_UNKNOWN) == 0) //if stack understands the tag
1071        {
1072            if (flags & RW_NDEF_FL_SUPPORTED) //if tag is ndef capable
1073                sCheckNdefCapable = true;
1074        }
1075    }
1076    else
1077    {
1078        ALOGE ("%s: unknown status=0x%X", __FUNCTION__, status);
1079        sCheckNdefMaxSize = 0;
1080        sCheckNdefCurrentSize = 0;
1081        sCheckNdefCardReadOnly = false;
1082    }
1083    sem_post (&sCheckNdefSem);
1084}
1085
1086
1087/*******************************************************************************
1088**
1089** Function:        nativeNfcTag_doCheckNdef
1090**
1091** Description:     Does the tag contain a NDEF message?
1092**                  e: JVM environment.
1093**                  o: Java object.
1094**                  ndefInfo: NDEF info.
1095**
1096** Returns:         Status code; 0 is success.
1097**
1098*******************************************************************************/
1099static jint nativeNfcTag_doCheckNdef (JNIEnv* e, jobject, jintArray ndefInfo)
1100{
1101    tNFA_STATUS status = NFA_STATUS_FAILED;
1102    jint* ndef = NULL;
1103
1104    ALOGD ("%s: enter", __FUNCTION__);
1105
1106    // special case for Kovio
1107    if (NfcTag::getInstance ().mTechList [0] == TARGET_TYPE_KOVIO_BARCODE)
1108    {
1109        ALOGD ("%s: Kovio tag, no NDEF", __FUNCTION__);
1110        ndef = e->GetIntArrayElements (ndefInfo, 0);
1111        ndef[0] = 0;
1112        ndef[1] = NDEF_MODE_READ_ONLY;
1113        e->ReleaseIntArrayElements (ndefInfo, ndef, 0);
1114        return NFA_STATUS_FAILED;
1115    }
1116
1117    // special case for Kovio
1118    if (NfcTag::getInstance ().mTechList [0] == TARGET_TYPE_KOVIO_BARCODE)
1119    {
1120        ALOGD ("%s: Kovio tag, no NDEF", __FUNCTION__);
1121        ndef = e->GetIntArrayElements (ndefInfo, 0);
1122        ndef[0] = 0;
1123        ndef[1] = NDEF_MODE_READ_ONLY;
1124        e->ReleaseIntArrayElements (ndefInfo, ndef, 0);
1125        return NFA_STATUS_FAILED;
1126    }
1127
1128    /* Create the write semaphore */
1129    if (sem_init (&sCheckNdefSem, 0, 0) == -1)
1130    {
1131        ALOGE ("%s: Check NDEF semaphore creation failed (errno=0x%08x)", __FUNCTION__, errno);
1132        return JNI_FALSE;
1133    }
1134
1135    if (NfcTag::getInstance ().getActivationState () != NfcTag::Active)
1136    {
1137        ALOGE ("%s: tag already deactivated", __FUNCTION__);
1138        goto TheEnd;
1139    }
1140
1141    ALOGD ("%s: try NFA_RwDetectNDef", __FUNCTION__);
1142    sCheckNdefWaitingForComplete = JNI_TRUE;
1143    status = NFA_RwDetectNDef ();
1144
1145    if (status != NFA_STATUS_OK)
1146    {
1147        ALOGE ("%s: NFA_RwDetectNDef failed, status = 0x%X", __FUNCTION__, status);
1148        goto TheEnd;
1149    }
1150
1151    /* Wait for check NDEF completion status */
1152    if (sem_wait (&sCheckNdefSem))
1153    {
1154        ALOGE ("%s: Failed to wait for check NDEF semaphore (errno=0x%08x)", __FUNCTION__, errno);
1155        goto TheEnd;
1156    }
1157
1158    if (sCheckNdefStatus == NFA_STATUS_OK)
1159    {
1160        //stack found a NDEF message on the tag
1161        ndef = e->GetIntArrayElements (ndefInfo, 0);
1162        if (NfcTag::getInstance ().getProtocol () == NFA_PROTOCOL_T1T)
1163            ndef[0] = NfcTag::getInstance ().getT1tMaxMessageSize ();
1164        else
1165            ndef[0] = sCheckNdefMaxSize;
1166        if (sCheckNdefCardReadOnly)
1167            ndef[1] = NDEF_MODE_READ_ONLY;
1168        else
1169            ndef[1] = NDEF_MODE_READ_WRITE;
1170        e->ReleaseIntArrayElements (ndefInfo, ndef, 0);
1171        status = NFA_STATUS_OK;
1172    }
1173    else if (sCheckNdefStatus == NFA_STATUS_FAILED)
1174    {
1175        //stack did not find a NDEF message on the tag;
1176        ndef = e->GetIntArrayElements (ndefInfo, 0);
1177        if (NfcTag::getInstance ().getProtocol () == NFA_PROTOCOL_T1T)
1178            ndef[0] = NfcTag::getInstance ().getT1tMaxMessageSize ();
1179        else
1180            ndef[0] = sCheckNdefMaxSize;
1181        if (sCheckNdefCardReadOnly)
1182            ndef[1] = NDEF_MODE_READ_ONLY;
1183        else
1184            ndef[1] = NDEF_MODE_READ_WRITE;
1185        e->ReleaseIntArrayElements (ndefInfo, ndef, 0);
1186        status = NFA_STATUS_FAILED;
1187    }
1188    else if (sCheckNdefStatus == NFA_STATUS_TIMEOUT)
1189    {
1190        pn544InteropStopPolling ();
1191        status = sCheckNdefStatus;
1192    }
1193    else
1194    {
1195        ALOGD ("%s: unknown status 0x%X", __FUNCTION__, sCheckNdefStatus);
1196        status = sCheckNdefStatus;
1197    }
1198
1199TheEnd:
1200    /* Destroy semaphore */
1201    if (sem_destroy (&sCheckNdefSem))
1202    {
1203        ALOGE ("%s: Failed to destroy check NDEF semaphore (errno=0x%08x)", __FUNCTION__, errno);
1204    }
1205    sCheckNdefWaitingForComplete = JNI_FALSE;
1206    ALOGD ("%s: exit; status=0x%X", __FUNCTION__, status);
1207    return status;
1208}
1209
1210
1211/*******************************************************************************
1212**
1213** Function:        nativeNfcTag_resetPresenceCheck
1214**
1215** Description:     Reset variables related to presence-check.
1216**
1217** Returns:         None
1218**
1219*******************************************************************************/
1220void nativeNfcTag_resetPresenceCheck ()
1221{
1222    sIsTagPresent = true;
1223}
1224
1225
1226/*******************************************************************************
1227**
1228** Function:        nativeNfcTag_doPresenceCheckResult
1229**
1230** Description:     Receive the result of presence-check.
1231**                  status: Result of presence-check.
1232**
1233** Returns:         None
1234**
1235*******************************************************************************/
1236void nativeNfcTag_doPresenceCheckResult (tNFA_STATUS status)
1237{
1238    sIsTagPresent = status == NFA_STATUS_OK;
1239    sem_post (&sPresenceCheckSem);
1240}
1241
1242
1243/*******************************************************************************
1244**
1245** Function:        nativeNfcTag_doPresenceCheck
1246**
1247** Description:     Check if the tag is in the RF field.
1248**                  e: JVM environment.
1249**                  o: Java object.
1250**
1251** Returns:         True if tag is in RF field.
1252**
1253*******************************************************************************/
1254static jboolean nativeNfcTag_doPresenceCheck (JNIEnv*, jobject)
1255{
1256    ALOGD ("%s", __FUNCTION__);
1257    tNFA_STATUS status = NFA_STATUS_OK;
1258    jboolean isPresent = JNI_FALSE;
1259
1260    // Special case for Kovio.  The deactivation would have already occurred
1261    // but was ignored so that normal tag opertions could complete.  Now we
1262    // want to process as if the deactivate just happened.
1263    if (NfcTag::getInstance ().mTechList [0] == TARGET_TYPE_KOVIO_BARCODE)
1264    {
1265        ALOGD ("%s: Kovio, force deactivate handling", __FUNCTION__);
1266        tNFA_DEACTIVATED deactivated = {NFA_DEACTIVATE_TYPE_IDLE};
1267        {
1268            SyncEventGuard g (gDeactivatedEvent);
1269            gActivated = false; //guard this variable from multi-threaded access
1270            gDeactivatedEvent.notifyOne ();
1271        }
1272
1273        NfcTag::getInstance().setDeactivationState (deactivated);
1274        nativeNfcTag_resetPresenceCheck();
1275        NfcTag::getInstance().connectionEventHandler (NFA_DEACTIVATED_EVT, NULL);
1276        nativeNfcTag_abortWaits();
1277        NfcTag::getInstance().abort ();
1278
1279        return JNI_FALSE;
1280    }
1281
1282    if (nfcManager_isNfcActive() == false)
1283    {
1284        ALOGD ("%s: NFC is no longer active.", __FUNCTION__);
1285        return JNI_FALSE;
1286    }
1287
1288    if (!sRfInterfaceMutex.tryLock())
1289    {
1290        ALOGD ("%s: tag is being reSelected assume it is present", __FUNCTION__);
1291        return JNI_TRUE;
1292    }
1293
1294    sRfInterfaceMutex.unlock();
1295
1296    if (NfcTag::getInstance ().isActivated () == false)
1297    {
1298        ALOGD ("%s: tag already deactivated", __FUNCTION__);
1299        return JNI_FALSE;
1300    }
1301
1302    if (sem_init (&sPresenceCheckSem, 0, 0) == -1)
1303    {
1304        ALOGE ("%s: semaphore creation failed (errno=0x%08x)", __FUNCTION__, errno);
1305        return JNI_FALSE;
1306    }
1307
1308    status = NFA_RwPresenceCheck ();
1309    if (status == NFA_STATUS_OK)
1310    {
1311        if (sem_wait (&sPresenceCheckSem))
1312        {
1313            ALOGE ("%s: failed to wait (errno=0x%08x)", __FUNCTION__, errno);
1314        }
1315        else
1316        {
1317            isPresent = sIsTagPresent ? JNI_TRUE : JNI_FALSE;
1318        }
1319    }
1320
1321    if (sem_destroy (&sPresenceCheckSem))
1322    {
1323        ALOGE ("Failed to destroy check NDEF semaphore (errno=0x%08x)", errno);
1324    }
1325
1326    if (isPresent == JNI_FALSE)
1327        ALOGD ("%s: tag absent", __FUNCTION__);
1328    return isPresent;
1329}
1330
1331
1332/*******************************************************************************
1333**
1334** Function:        nativeNfcTag_doIsNdefFormatable
1335**
1336** Description:     Can tag be formatted to store NDEF message?
1337**                  e: JVM environment.
1338**                  o: Java object.
1339**                  libNfcType: Type of tag.
1340**                  uidBytes: Tag's unique ID.
1341**                  pollBytes: Data from activation.
1342**                  actBytes: Data from activation.
1343**
1344** Returns:         True if formattable.
1345**
1346*******************************************************************************/
1347static jboolean nativeNfcTag_doIsNdefFormatable (JNIEnv*,
1348        jobject, jint /*libNfcType*/, jbyteArray, jbyteArray,
1349        jbyteArray)
1350{
1351    jboolean isFormattable = JNI_FALSE;
1352
1353    switch (NfcTag::getInstance().getProtocol())
1354    {
1355    case NFA_PROTOCOL_T1T:
1356    case NFA_PROTOCOL_ISO15693:
1357        isFormattable = JNI_TRUE;
1358        break;
1359
1360    case NFA_PROTOCOL_T2T:
1361        isFormattable = NfcTag::getInstance().isMifareUltralight() ? JNI_TRUE : JNI_FALSE;
1362    }
1363    ALOGD("%s: is formattable=%u", __FUNCTION__, isFormattable);
1364    return isFormattable;
1365}
1366
1367
1368/*******************************************************************************
1369**
1370** Function:        nativeNfcTag_doIsIsoDepNdefFormatable
1371**
1372** Description:     Is ISO-DEP tag formattable?
1373**                  e: JVM environment.
1374**                  o: Java object.
1375**                  pollBytes: Data from activation.
1376**                  actBytes: Data from activation.
1377**
1378** Returns:         True if formattable.
1379**
1380*******************************************************************************/
1381static jboolean nativeNfcTag_doIsIsoDepNdefFormatable (JNIEnv *e, jobject o, jbyteArray pollBytes, jbyteArray actBytes)
1382{
1383    uint8_t uidFake[] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
1384    ALOGD ("%s", __FUNCTION__);
1385    jbyteArray uidArray = e->NewByteArray (8);
1386    e->SetByteArrayRegion (uidArray, 0, 8, (jbyte*) uidFake);
1387    return nativeNfcTag_doIsNdefFormatable (e, o, 0, uidArray, pollBytes, actBytes);
1388}
1389
1390
1391/*******************************************************************************
1392**
1393** Function:        nativeNfcTag_doNdefFormat
1394**
1395** Description:     Format a tag so it can store NDEF message.
1396**                  e: JVM environment.
1397**                  o: Java object.
1398**                  key: Not used.
1399**
1400** Returns:         True if ok.
1401**
1402*******************************************************************************/
1403static jboolean nativeNfcTag_doNdefFormat (JNIEnv*, jobject, jbyteArray)
1404{
1405    ALOGD ("%s: enter", __FUNCTION__);
1406    tNFA_STATUS status = NFA_STATUS_OK;
1407
1408    // Do not try to format if tag is already deactivated.
1409    if (NfcTag::getInstance ().isActivated () == false)
1410    {
1411        ALOGD ("%s: tag already deactivated(no need to format)", __FUNCTION__);
1412        return JNI_FALSE;
1413    }
1414
1415    sem_init (&sFormatSem, 0, 0);
1416    sFormatOk = false;
1417    status = NFA_RwFormatTag ();
1418    if (status == NFA_STATUS_OK)
1419    {
1420        ALOGD ("%s: wait for completion", __FUNCTION__);
1421        sem_wait (&sFormatSem);
1422        status = sFormatOk ? NFA_STATUS_OK : NFA_STATUS_FAILED;
1423    }
1424    else
1425        ALOGE ("%s: error status=%u", __FUNCTION__, status);
1426    sem_destroy (&sFormatSem);
1427
1428    ALOGD ("%s: exit", __FUNCTION__);
1429    return (status == NFA_STATUS_OK) ? JNI_TRUE : JNI_FALSE;
1430}
1431
1432
1433/*******************************************************************************
1434**
1435** Function:        nativeNfcTag_doMakeReadonlyResult
1436**
1437** Description:     Receive the result of making a tag read-only. Called by the
1438**                  NFA_SET_TAG_RO_EVT.
1439**                  status: Status of the operation.
1440**
1441** Returns:         None
1442**
1443*******************************************************************************/
1444void nativeNfcTag_doMakeReadonlyResult (tNFA_STATUS status)
1445{
1446    if (sMakeReadonlyWaitingForComplete != JNI_FALSE)
1447    {
1448        sMakeReadonlyWaitingForComplete = JNI_FALSE;
1449        sMakeReadonlyStatus = status;
1450
1451        sem_post (&sMakeReadonlySem);
1452    }
1453}
1454
1455
1456/*******************************************************************************
1457**
1458** Function:        nativeNfcTag_doMakeReadonly
1459**
1460** Description:     Make the tag read-only.
1461**                  e: JVM environment.
1462**                  o: Java object.
1463**                  key: Key to access the tag.
1464**
1465** Returns:         True if ok.
1466**
1467*******************************************************************************/
1468static jboolean nativeNfcTag_doMakeReadonly (JNIEnv*, jobject, jbyteArray)
1469{
1470    jboolean result = JNI_FALSE;
1471    tNFA_STATUS status;
1472
1473    ALOGD ("%s", __FUNCTION__);
1474
1475    /* Create the make_readonly semaphore */
1476    if (sem_init (&sMakeReadonlySem, 0, 0) == -1)
1477    {
1478        ALOGE ("%s: Make readonly semaphore creation failed (errno=0x%08x)", __FUNCTION__, errno);
1479        return JNI_FALSE;
1480    }
1481
1482    sMakeReadonlyWaitingForComplete = JNI_TRUE;
1483
1484    // Hard-lock the tag (cannot be reverted)
1485    status = NFA_RwSetTagReadOnly(TRUE);
1486    if (status == NFA_STATUS_REJECTED)
1487    {
1488        status = NFA_RwSetTagReadOnly (FALSE); //try soft lock
1489        if (status != NFA_STATUS_OK)
1490        {
1491            ALOGE ("%s: fail soft lock, status=%d", __FUNCTION__, status);
1492            goto TheEnd;
1493        }
1494    }
1495    else if (status != NFA_STATUS_OK)
1496    {
1497        ALOGE ("%s: fail hard lock, status=%d", __FUNCTION__, status);
1498        goto TheEnd;
1499    }
1500
1501    /* Wait for check NDEF completion status */
1502    if (sem_wait (&sMakeReadonlySem))
1503    {
1504        ALOGE ("%s: Failed to wait for make_readonly semaphore (errno=0x%08x)", __FUNCTION__, errno);
1505        goto TheEnd;
1506    }
1507
1508    if (sMakeReadonlyStatus == NFA_STATUS_OK)
1509    {
1510        result = JNI_TRUE;
1511    }
1512
1513TheEnd:
1514    /* Destroy semaphore */
1515    if (sem_destroy (&sMakeReadonlySem))
1516    {
1517        ALOGE ("%s: Failed to destroy read_only semaphore (errno=0x%08x)", __FUNCTION__, errno);
1518    }
1519    sMakeReadonlyWaitingForComplete = JNI_FALSE;
1520    return result;
1521}
1522
1523
1524/*******************************************************************************
1525**
1526** Function:        nativeNfcTag_registerNdefTypeHandler
1527**
1528** Description:     Register a callback to receive NDEF message from the tag
1529**                  from the NFA_NDEF_DATA_EVT.
1530**
1531** Returns:         None
1532**
1533*******************************************************************************/
1534//register a callback to receive NDEF message from the tag
1535//from the NFA_NDEF_DATA_EVT;
1536void nativeNfcTag_registerNdefTypeHandler ()
1537{
1538    ALOGD ("%s", __FUNCTION__);
1539    sNdefTypeHandlerHandle = NFA_HANDLE_INVALID;
1540    NFA_RegisterNDefTypeHandler (TRUE, NFA_TNF_DEFAULT, (UINT8 *) "", 0, ndefHandlerCallback);
1541}
1542
1543
1544/*******************************************************************************
1545**
1546** Function:        nativeNfcTag_deregisterNdefTypeHandler
1547**
1548** Description:     No longer need to receive NDEF message from the tag.
1549**
1550** Returns:         None
1551**
1552*******************************************************************************/
1553void nativeNfcTag_deregisterNdefTypeHandler ()
1554{
1555    ALOGD ("%s", __FUNCTION__);
1556    NFA_DeregisterNDefTypeHandler (sNdefTypeHandlerHandle);
1557    sNdefTypeHandlerHandle = NFA_HANDLE_INVALID;
1558}
1559
1560
1561/*****************************************************************************
1562**
1563** JNI functions for Android 4.0.3
1564**
1565*****************************************************************************/
1566static JNINativeMethod gMethods[] =
1567{
1568   {"doConnect", "(I)I", (void *)nativeNfcTag_doConnect},
1569   {"doDisconnect", "()Z", (void *)nativeNfcTag_doDisconnect},
1570   {"doReconnect", "()I", (void *)nativeNfcTag_doReconnect},
1571   {"doHandleReconnect", "(I)I", (void *)nativeNfcTag_doHandleReconnect},
1572   {"doTransceive", "([BZ[I)[B", (void *)nativeNfcTag_doTransceive},
1573   {"doGetNdefType", "(II)I", (void *)nativeNfcTag_doGetNdefType},
1574   {"doCheckNdef", "([I)I", (void *)nativeNfcTag_doCheckNdef},
1575   {"doRead", "()[B", (void *)nativeNfcTag_doRead},
1576   {"doWrite", "([B)Z", (void *)nativeNfcTag_doWrite},
1577   {"doPresenceCheck", "()Z", (void *)nativeNfcTag_doPresenceCheck},
1578   {"doIsIsoDepNdefFormatable", "([B[B)Z", (void *)nativeNfcTag_doIsIsoDepNdefFormatable},
1579   {"doNdefFormat", "([B)Z", (void *)nativeNfcTag_doNdefFormat},
1580   {"doMakeReadonly", "([B)Z", (void *)nativeNfcTag_doMakeReadonly},
1581};
1582
1583
1584/*******************************************************************************
1585**
1586** Function:        register_com_android_nfc_NativeNfcTag
1587**
1588** Description:     Regisgter JNI functions with Java Virtual Machine.
1589**                  e: Environment of JVM.
1590**
1591** Returns:         Status of registration.
1592**
1593*******************************************************************************/
1594int register_com_android_nfc_NativeNfcTag (JNIEnv *e)
1595{
1596    ALOGD ("%s", __FUNCTION__);
1597    return jniRegisterNativeMethods (e, gNativeNfcTagClassName, gMethods, NELEM (gMethods));
1598}
1599
1600
1601} /* namespace android */
1602