blob: b1199f94079876f48f66bfde1afbc8a6f0c0b781 [file] [log] [blame]
/*
* Copyright (C) 2012 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 "OverrideLog.h"
#include "NfcJniUtil.h"
#include "NfcAdaptation.h"
#include "SyncEvent.h"
#include "PeerToPeer.h"
#include "SecureElement.h"
#include "NfcTag.h"
#include "config.h"
#include "PowerSwitch.h"
#include "JavaClassConstants.h"
#include "Pn544Interop.h"
#include <ScopedLocalRef.h>
#include <ScopedUtfChars.h>
extern "C"
{
#include "nfa_api.h"
#include "nfa_p2p_api.h"
#include "rw_api.h"
#include "nfa_ee_api.h"
#include "nfc_brcm_defs.h"
#include "ce_api.h"
}
extern UINT8 *p_nfa_dm_lptd_cfg;
extern UINT8 *p_nfa_dm_start_up_cfg;
extern const UINT8 nfca_version_string [];
namespace android
{
extern bool gIsTagDeactivating;
extern bool gIsSelectingRfInterface;
extern void nativeNfcTag_doTransceiveStatus (uint8_t * buf, uint32_t buflen);
extern void nativeNfcTag_doConnectStatus (jboolean is_connect_ok);
extern void nativeNfcTag_doDeactivateStatus (int status);
extern void nativeNfcTag_doWriteStatus (jboolean is_write_ok);
extern void nativeNfcTag_doCheckNdefResult (tNFA_STATUS status, uint32_t max_size, uint32_t current_size, uint8_t flags);
extern void nativeNfcTag_doMakeReadonlyResult (tNFA_STATUS status);
extern void nativeNfcTag_doPresenceCheckResult (tNFA_STATUS status);
extern void nativeNfcTag_formatStatus (bool is_ok);
extern void nativeNfcTag_resetPresenceCheck ();
extern void nativeNfcTag_doReadCompleted (tNFA_STATUS status);
extern void nativeNfcTag_abortWaits ();
extern void nativeLlcpConnectionlessSocket_abortWait ();
extern void nativeNfcTag_registerNdefTypeHandler ();
extern void nativeLlcpConnectionlessSocket_receiveData (uint8_t* data, uint32_t len, uint32_t remote_sap);
}
/*****************************************************************************
**
** public variables and functions
**
*****************************************************************************/
namespace android
{
int gGeneralTransceiveTimeout = 1000;
jmethodID gCachedNfcManagerNotifyNdefMessageListeners;
jmethodID gCachedNfcManagerNotifyTransactionListeners;
jmethodID gCachedNfcManagerNotifyLlcpLinkActivation;
jmethodID gCachedNfcManagerNotifyLlcpLinkDeactivated;
jmethodID gCachedNfcManagerNotifyLlcpFirstPacketReceived;
jmethodID gCachedNfcManagerNotifySeFieldActivated;
jmethodID gCachedNfcManagerNotifySeFieldDeactivated;
jmethodID gCachedNfcManagerNotifySeListenActivated;
jmethodID gCachedNfcManagerNotifySeListenDeactivated;
const char* gNativeP2pDeviceClassName = "com/android/nfc/dhimpl/NativeP2pDevice";
const char* gNativeLlcpServiceSocketClassName = "com/android/nfc/dhimpl/NativeLlcpServiceSocket";
const char* gNativeLlcpConnectionlessSocketClassName = "com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket";
const char* gNativeLlcpSocketClassName = "com/android/nfc/dhimpl/NativeLlcpSocket";
const char* gNativeNfcTagClassName = "com/android/nfc/dhimpl/NativeNfcTag";
const char* gNativeNfcManagerClassName = "com/android/nfc/dhimpl/NativeNfcManager";
const char* gNativeNfcSecureElementClassName = "com/android/nfc/dhimpl/NativeNfcSecureElement";
void doStartupConfig ();
void startStopPolling (bool isStartPolling);
void startRfDiscovery (bool isStart);
void setUiccIdleTimeout (bool enable);
}
/*****************************************************************************
**
** private variables and functions
**
*****************************************************************************/
namespace android
{
static jint sLastError = ERROR_BUFFER_TOO_SMALL;
static jmethodID sCachedNfcManagerNotifySeApduReceived;
static jmethodID sCachedNfcManagerNotifySeMifareAccess;
static jmethodID sCachedNfcManagerNotifySeEmvCardRemoval;
static jmethodID sCachedNfcManagerNotifyTargetDeselected;
static SyncEvent sNfaEnableEvent; //event for NFA_Enable()
static SyncEvent sNfaDisableEvent; //event for NFA_Disable()
static SyncEvent sNfaEnableDisablePollingEvent; //event for NFA_EnablePolling(), NFA_DisablePolling()
static SyncEvent sNfaSetConfigEvent; // event for Set_Config....
static bool sIsNfaEnabled = false;
static bool sDiscoveryEnabled = false; //is polling for tag?
static bool sIsDisabling = false;
static bool sRfEnabled = false; // whether RF discovery is enabled
static bool sSeRfActive = false; // whether RF with SE is likely active
static bool sP2pActive = false; // whether p2p was last active
static bool sAbortConnlessWait = false;
static bool sIsSecElemSelected = false; //has NFC service selected a sec elem
static UINT8 * sOriginalLptdCfg = NULL;
#define CONFIG_UPDATE_LPTD (1 << 0)
#define CONFIG_UPDATE_TECH_MASK (1 << 1)
#define DEFAULT_TECH_MASK (NFA_TECHNOLOGY_MASK_A \
| NFA_TECHNOLOGY_MASK_B \
| NFA_TECHNOLOGY_MASK_F \
| NFA_TECHNOLOGY_MASK_ISO15693 \
| NFA_TECHNOLOGY_MASK_B_PRIME \
| NFA_TECHNOLOGY_MASK_A_ACTIVE \
| NFA_TECHNOLOGY_MASK_F_ACTIVE \
| NFA_TECHNOLOGY_MASK_KOVIO)
static void nfaConnectionCallback (UINT8 event, tNFA_CONN_EVT_DATA *eventData);
static void nfaDeviceManagementCallback (UINT8 event, tNFA_DM_CBACK_DATA *eventData);
static bool isPeerToPeer (tNFA_ACTIVATED& activated);
static bool isListenMode(tNFA_ACTIVATED& activated);
/////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////
/*******************************************************************************
**
** Function: getNative
**
** Description: Get native data
**
** Returns: Native data structure.
**
*******************************************************************************/
nfc_jni_native_data *getNative (JNIEnv* e, jobject o)
{
static struct nfc_jni_native_data *sCachedNat = NULL;
if (e)
{
sCachedNat = nfc_jni_get_nat(e, o);
}
return sCachedNat;
}
/*******************************************************************************
**
** Function: handleRfDiscoveryEvent
**
** Description: Handle RF-discovery events from the stack.
** discoveredDevice: Discovered device.
**
** Returns: None
**
*******************************************************************************/
static void handleRfDiscoveryEvent (tNFC_RESULT_DEVT* discoveredDevice)
{
if (discoveredDevice->more)
{
//there is more discovery notification coming
return;
}
bool isP2p = NfcTag::getInstance ().isP2pDiscovered ();
if (isP2p)
{
//select the peer that supports P2P
NfcTag::getInstance ().selectP2p();
}
else
{
//select the first of multiple tags that is discovered
NfcTag::getInstance ().selectFirstTag();
}
}
/*******************************************************************************
**
** Function: nfaConnectionCallback
**
** Description: Receive connection-related events from stack.
** connEvent: Event code.
** eventData: Event data.
**
** Returns: None
**
*******************************************************************************/
static void nfaConnectionCallback (UINT8 connEvent, tNFA_CONN_EVT_DATA* eventData)
{
tNFA_STATUS status = NFA_STATUS_FAILED;
ALOGD("%s: event= %u", __FUNCTION__, connEvent);
if (gIsTagDeactivating && connEvent != NFA_DEACTIVATED_EVT && connEvent != NFA_PRESENCE_CHECK_EVT && connEvent != NFA_DATA_EVT)
{
// special case to switching frame interface for ISO_DEP tags
gIsTagDeactivating = false;
ALOGD("%s: deactivating, should get NFA_DEACTIVATED_EVT", __FUNCTION__);
nativeNfcTag_doDeactivateStatus(1);
}
switch (connEvent)
{
case NFA_POLL_ENABLED_EVT: // whether polling successfully started
{
ALOGD("%s: NFA_POLL_ENABLED_EVT: status = %u", __FUNCTION__, eventData->status);
SyncEventGuard guard (sNfaEnableDisablePollingEvent);
sNfaEnableDisablePollingEvent.notifyOne ();
}
break;
case NFA_POLL_DISABLED_EVT: // Listening/Polling stopped
{
ALOGD("%s: NFA_POLL_DISABLED_EVT: status = %u", __FUNCTION__, eventData->status);
SyncEventGuard guard (sNfaEnableDisablePollingEvent);
sNfaEnableDisablePollingEvent.notifyOne ();
}
break;
case NFA_RF_DISCOVERY_STARTED_EVT: // RF Discovery started
{
ALOGD("%s: NFA_RF_DISCOVERY_STARTED_EVT: status = %u", __FUNCTION__, eventData->status);
SyncEventGuard guard (sNfaEnableDisablePollingEvent);
sNfaEnableDisablePollingEvent.notifyOne ();
}
break;
case NFA_RF_DISCOVERY_STOPPED_EVT: // RF Discovery stopped event
{
ALOGD("%s: NFA_RF_DISCOVERY_STOPPED_EVT: status = %u", __FUNCTION__, eventData->status);
SyncEventGuard guard (sNfaEnableDisablePollingEvent);
sNfaEnableDisablePollingEvent.notifyOne ();
}
break;
case NFA_DISC_RESULT_EVT: // NFC link/protocol discovery notificaiton
status = eventData->disc_result.status;
ALOGD("%s: NFA_DISC_RESULT_EVT: status = %d", __FUNCTION__, status);
if (status != NFA_STATUS_OK)
{
ALOGE("%s: NFA_DISC_RESULT_EVT error: status = %d", __FUNCTION__, status);
}
else
{
NfcTag::getInstance().connectionEventHandler(connEvent, eventData);
handleRfDiscoveryEvent(&eventData->disc_result.discovery_ntf);
}
break;
case NFA_SELECT_RESULT_EVT: // NFC link/protocol discovery select response
ALOGD("%s: NFA_SELECT_RESULT_EVT: status = %d, gIsSelectingRfInterface = %d, sIsDisabling=%d", __FUNCTION__, eventData->status, gIsSelectingRfInterface, sIsDisabling);
if (sIsDisabling)
break;
if (eventData->status != NFA_STATUS_OK)
{
if (gIsSelectingRfInterface)
{
nativeNfcTag_doConnectStatus(false);
}
ALOGE("%s: NFA_SELECT_RESULT_EVT error: status = %d", __FUNCTION__, eventData->status);
NFA_Deactivate (FALSE);
}
break;
case NFA_DEACTIVATE_FAIL_EVT:
ALOGD("%s: NFA_DEACTIVATE_FAIL_EVT: status = %d", __FUNCTION__, eventData->status);
break;
case NFA_ACTIVATED_EVT: // NFC link/protocol activated
ALOGD("%s: NFA_ACTIVATED_EVT: gIsSelectingRfInterface=%d, sIsDisabling=%d", __FUNCTION__, gIsSelectingRfInterface, sIsDisabling);
if (sIsDisabling || !sIsNfaEnabled)
break;
NfcTag::getInstance().setActivationState ();
if (gIsSelectingRfInterface)
{
nativeNfcTag_doConnectStatus(true);
break;
}
nativeNfcTag_resetPresenceCheck();
if (isPeerToPeer(eventData->activated))
{
sP2pActive = true;
ALOGD("%s: NFA_ACTIVATED_EVT; is p2p", __FUNCTION__);
// Disable RF field events in case of p2p
UINT8 nfa_disable_rf_events[] = { 0x00 };
ALOGD ("%s: Disabling RF field events", __FUNCTION__);
status = NFA_SetConfig(NCI_PARAM_ID_RF_FIELD_INFO, sizeof(nfa_disable_rf_events),
&nfa_disable_rf_events[0]);
if (status == NFA_STATUS_OK) {
ALOGD ("%s: Disabled RF field events", __FUNCTION__);
} else {
ALOGE ("%s: Failed to disable RF field events", __FUNCTION__);
}
// For the SE, consider the field to be on while p2p is active.
SecureElement::getInstance().notifyRfFieldEvent (true);
}
else if (pn544InteropIsBusy() == false)
{
NfcTag::getInstance().connectionEventHandler (connEvent, eventData);
// We know it is not activating for P2P. If it activated in
// listen mode then it is likely for an SE transaction.
// Send the RF Event.
if (isListenMode(eventData->activated))
{
sSeRfActive = true;
SecureElement::getInstance().notifyListenModeState (true);
}
}
break;
case NFA_DEACTIVATED_EVT: // NFC link/protocol deactivated
ALOGD("%s: NFA_DEACTIVATED_EVT Type: %u, gIsTagDeactivating: %d", __FUNCTION__, eventData->deactivated.type,gIsTagDeactivating);
NfcTag::getInstance().setDeactivationState (eventData->deactivated);
if (eventData->deactivated.type != NFA_DEACTIVATE_TYPE_SLEEP)
{
nativeNfcTag_resetPresenceCheck();
NfcTag::getInstance().connectionEventHandler (connEvent, eventData);
nativeNfcTag_abortWaits();
NfcTag::getInstance().abort ();
}
else if (gIsTagDeactivating)
{
nativeNfcTag_doDeactivateStatus(0);
}
// If RF is activated for what we think is a Secure Element transaction
// and it is deactivated to either IDLE or DISCOVERY mode, notify w/event.
if ((eventData->deactivated.type == NFA_DEACTIVATE_TYPE_IDLE)
|| (eventData->deactivated.type == NFA_DEACTIVATE_TYPE_DISCOVERY))
{
if (sSeRfActive) {
sSeRfActive = false;
if (!sIsDisabling && sIsNfaEnabled)
SecureElement::getInstance().notifyListenModeState (false);
} else if (sP2pActive) {
sP2pActive = false;
// Make sure RF field events are re-enabled
ALOGD("%s: NFA_DEACTIVATED_EVT; is p2p", __FUNCTION__);
// Disable RF field events in case of p2p
UINT8 nfa_enable_rf_events[] = { 0x01 };
if (!sIsDisabling && sIsNfaEnabled)
{
ALOGD ("%s: Enabling RF field events", __FUNCTION__);
status = NFA_SetConfig(NCI_PARAM_ID_RF_FIELD_INFO, sizeof(nfa_enable_rf_events),
&nfa_enable_rf_events[0]);
if (status == NFA_STATUS_OK) {
ALOGD ("%s: Enabled RF field events", __FUNCTION__);
} else {
ALOGE ("%s: Failed to enable RF field events", __FUNCTION__);
}
// Consider the field to be off at this point
SecureElement::getInstance().notifyRfFieldEvent (false);
}
}
}
break;
case NFA_TLV_DETECT_EVT: // TLV Detection complete
status = eventData->tlv_detect.status;
ALOGD("%s: NFA_TLV_DETECT_EVT: status = %d, protocol = %d, num_tlvs = %d, num_bytes = %d",
__FUNCTION__, status, eventData->tlv_detect.protocol,
eventData->tlv_detect.num_tlvs, eventData->tlv_detect.num_bytes);
if (status != NFA_STATUS_OK)
{
ALOGE("%s: NFA_TLV_DETECT_EVT error: status = %d", __FUNCTION__, status);
}
break;
case NFA_NDEF_DETECT_EVT: // NDEF Detection complete;
//if status is failure, it means the tag does not contain any or valid NDEF data;
//pass the failure status to the NFC Service;
status = eventData->ndef_detect.status;
ALOGD("%s: NFA_NDEF_DETECT_EVT: status = 0x%X, protocol = %u, "
"max_size = %lu, cur_size = %lu, flags = 0x%X", __FUNCTION__,
status,
eventData->ndef_detect.protocol, eventData->ndef_detect.max_size,
eventData->ndef_detect.cur_size, eventData->ndef_detect.flags);
NfcTag::getInstance().connectionEventHandler (connEvent, eventData);
nativeNfcTag_doCheckNdefResult(status,
eventData->ndef_detect.max_size, eventData->ndef_detect.cur_size,
eventData->ndef_detect.flags);
break;
case NFA_DATA_EVT: // Data message received (for non-NDEF reads)
ALOGD("%s: NFA_DATA_EVT: len = %d", __FUNCTION__, eventData->data.len);
nativeNfcTag_doTransceiveStatus(eventData->data.p_data,eventData->data.len);
break;
case NFA_SELECT_CPLT_EVT: // Select completed
status = eventData->status;
ALOGD("%s: NFA_SELECT_CPLT_EVT: status = %d", __FUNCTION__, status);
if (status != NFA_STATUS_OK)
{
ALOGE("%s: NFA_SELECT_CPLT_EVT error: status = %d", __FUNCTION__, status);
}
break;
case NFA_READ_CPLT_EVT: // NDEF-read or tag-specific-read completed
ALOGD("%s: NFA_READ_CPLT_EVT: status = 0x%X", __FUNCTION__, eventData->status);
nativeNfcTag_doReadCompleted (eventData->status);
NfcTag::getInstance().connectionEventHandler (connEvent, eventData);
break;
case NFA_WRITE_CPLT_EVT: // Write completed
ALOGD("%s: NFA_WRITE_CPLT_EVT: status = %d", __FUNCTION__, eventData->status);
nativeNfcTag_doWriteStatus (eventData->status == NFA_STATUS_OK);
break;
case NFA_SET_TAG_RO_EVT: // Tag set as Read only
ALOGD("%s: NFA_SET_TAG_RO_EVT: status = %d", __FUNCTION__, eventData->status);
nativeNfcTag_doMakeReadonlyResult(eventData->status);
break;
case NFA_CE_NDEF_WRITE_START_EVT: // NDEF write started
ALOGD("%s: NFA_CE_NDEF_WRITE_START_EVT: status: %d", __FUNCTION__, eventData->status);
if (eventData->status != NFA_STATUS_OK)
ALOGE("%s: NFA_CE_NDEF_WRITE_START_EVT error: status = %d", __FUNCTION__, eventData->status);
break;
case NFA_CE_NDEF_WRITE_CPLT_EVT: // NDEF write completed
ALOGD("%s: FA_CE_NDEF_WRITE_CPLT_EVT: len = %lu", __FUNCTION__, eventData->ndef_write_cplt.len);
break;
case NFA_LLCP_ACTIVATED_EVT: // LLCP link is activated
ALOGD("%s: NFA_LLCP_ACTIVATED_EVT: is_initiator: %d remote_wks: %d, remote_lsc: %d, remote_link_miu: %d, local_link_miu: %d",
__FUNCTION__,
eventData->llcp_activated.is_initiator,
eventData->llcp_activated.remote_wks,
eventData->llcp_activated.remote_lsc,
eventData->llcp_activated.remote_link_miu,
eventData->llcp_activated.local_link_miu);
PeerToPeer::getInstance().llcpActivatedHandler (getNative(0, 0), eventData->llcp_activated);
break;
case NFA_LLCP_DEACTIVATED_EVT: // LLCP link is deactivated
ALOGD("%s: NFA_LLCP_DEACTIVATED_EVT", __FUNCTION__);
PeerToPeer::getInstance().llcpDeactivatedHandler (getNative(0, 0), eventData->llcp_deactivated);
break;
case NFA_LLCP_FIRST_PACKET_RECEIVED_EVT: // Received first packet over llcp
ALOGD("%s: NFA_LLCP_FIRST_PACKET_RECEIVED_EVT", __FUNCTION__);
PeerToPeer::getInstance().llcpFirstPacketHandler (getNative(0, 0));
break;
case NFA_PRESENCE_CHECK_EVT:
ALOGD("%s: NFA_PRESENCE_CHECK_EVT", __FUNCTION__);
nativeNfcTag_doPresenceCheckResult (eventData->status);
break;
case NFA_FORMAT_CPLT_EVT:
ALOGD("%s: NFA_FORMAT_CPLT_EVT: status=0x%X", __FUNCTION__, eventData->status);
nativeNfcTag_formatStatus (eventData->status == NFA_STATUS_OK);
break;
case NFA_I93_CMD_CPLT_EVT:
ALOGD("%s: NFA_I93_CMD_CPLT_EVT: status=0x%X", __FUNCTION__, eventData->status);
break;
case NFA_CE_UICC_LISTEN_CONFIGURED_EVT :
ALOGD("%s: NFA_CE_UICC_LISTEN_CONFIGURED_EVT : status=0x%X", __FUNCTION__, eventData->status);
SecureElement::getInstance().connectionEventHandler (connEvent, eventData);
break;
case NFA_SET_P2P_LISTEN_TECH_EVT:
ALOGD("%s: NFA_SET_P2P_LISTEN_TECH_EVT", __FUNCTION__);
PeerToPeer::getInstance().connectionEventHandler (connEvent, eventData);
break;
default:
ALOGE("%s: unknown event ????", __FUNCTION__);
break;
}
}
/*******************************************************************************
**
** Function: nfcManager_initNativeStruc
**
** Description: Initialize variables.
** e: JVM environment.
** o: Java object.
**
** Returns: True if ok.
**
*******************************************************************************/
static jboolean nfcManager_initNativeStruc (JNIEnv* e, jobject o)
{
ALOGD ("%s: enter", __FUNCTION__);
nfc_jni_native_data* nat = (nfc_jni_native_data*)malloc(sizeof(struct nfc_jni_native_data));
if (nat == NULL)
{
ALOGE ("%s: fail allocate native data", __FUNCTION__);
return JNI_FALSE;
}
memset (nat, 0, sizeof(*nat));
e->GetJavaVM(&(nat->vm));
nat->env_version = e->GetVersion();
nat->manager = e->NewGlobalRef(o);
ScopedLocalRef<jclass> cls(e, e->GetObjectClass(o));
jfieldID f = e->GetFieldID(cls.get(), "mNative", "I");
e->SetIntField(o, f, (jint)nat);
/* Initialize native cached references */
gCachedNfcManagerNotifyNdefMessageListeners = e->GetMethodID(cls.get(),
"notifyNdefMessageListeners", "(Lcom/android/nfc/dhimpl/NativeNfcTag;)V");
gCachedNfcManagerNotifyTransactionListeners = e->GetMethodID(cls.get(),
"notifyTransactionListeners", "([B)V");
gCachedNfcManagerNotifyLlcpLinkActivation = e->GetMethodID(cls.get(),
"notifyLlcpLinkActivation", "(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V");
gCachedNfcManagerNotifyLlcpLinkDeactivated = e->GetMethodID(cls.get(),
"notifyLlcpLinkDeactivated", "(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V");
gCachedNfcManagerNotifyLlcpFirstPacketReceived = e->GetMethodID(cls.get(),
"notifyLlcpLinkFirstPacketReceived", "(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V");
sCachedNfcManagerNotifyTargetDeselected = e->GetMethodID(cls.get(),
"notifyTargetDeselected","()V");
gCachedNfcManagerNotifySeFieldActivated = e->GetMethodID(cls.get(),
"notifySeFieldActivated", "()V");
gCachedNfcManagerNotifySeFieldDeactivated = e->GetMethodID(cls.get(),
"notifySeFieldDeactivated", "()V");
gCachedNfcManagerNotifySeListenActivated = e->GetMethodID(cls.get(),
"notifySeListenActivated", "()V");
gCachedNfcManagerNotifySeListenDeactivated = e->GetMethodID(cls.get(),
"notifySeListenDeactivated", "()V");
sCachedNfcManagerNotifySeApduReceived = e->GetMethodID(cls.get(),
"notifySeApduReceived", "([B)V");
sCachedNfcManagerNotifySeMifareAccess = e->GetMethodID(cls.get(),
"notifySeMifareAccess", "([B)V");
sCachedNfcManagerNotifySeEmvCardRemoval = e->GetMethodID(cls.get(),
"notifySeEmvCardRemoval", "()V");
if (nfc_jni_cache_object(e, gNativeNfcTagClassName, &(nat->cached_NfcTag)) == -1)
{
ALOGE ("%s: fail cache NativeNfcTag", __FUNCTION__);
return JNI_FALSE;
}
if (nfc_jni_cache_object(e, gNativeP2pDeviceClassName, &(nat->cached_P2pDevice)) == -1)
{
ALOGE ("%s: fail cache NativeP2pDevice", __FUNCTION__);
return JNI_FALSE;
}
ALOGD ("%s: exit", __FUNCTION__);
return JNI_TRUE;
}
/*******************************************************************************
**
** Function: nfaDeviceManagementCallback
**
** Description: Receive device management events from stack.
** dmEvent: Device-management event ID.
** eventData: Data associated with event ID.
**
** Returns: None
**
*******************************************************************************/
void nfaDeviceManagementCallback (UINT8 dmEvent, tNFA_DM_CBACK_DATA* eventData)
{
ALOGD ("%s: enter; event=0x%X", __FUNCTION__, dmEvent);
switch (dmEvent)
{
case NFA_DM_ENABLE_EVT: /* Result of NFA_Enable */
{
SyncEventGuard guard (sNfaEnableEvent);
ALOGD ("%s: NFA_DM_ENABLE_EVT; status=0x%X",
__FUNCTION__, eventData->status);
sIsNfaEnabled = eventData->status == NFA_STATUS_OK;
sIsDisabling = false;
sNfaEnableEvent.notifyOne ();
}
break;
case NFA_DM_DISABLE_EVT: /* Result of NFA_Disable */
{
SyncEventGuard guard (sNfaDisableEvent);
ALOGD ("%s: NFA_DM_DISABLE_EVT", __FUNCTION__);
sIsNfaEnabled = false;
sIsDisabling = false;
sNfaDisableEvent.notifyOne ();
}
break;
case NFA_DM_SET_CONFIG_EVT: //result of NFA_SetConfig
ALOGD ("%s: NFA_DM_SET_CONFIG_EVT", __FUNCTION__);
{
SyncEventGuard guard (sNfaSetConfigEvent);
sNfaSetConfigEvent.notifyOne();
}
break;
case NFA_DM_GET_CONFIG_EVT: /* Result of NFA_GetConfig */
ALOGD ("%s: NFA_DM_GET_CONFIG_EVT", __FUNCTION__);
break;
case NFA_DM_RF_FIELD_EVT:
ALOGD ("%s: NFA_DM_RF_FIELD_EVT; status=0x%X; field status=%u", __FUNCTION__,
eventData->rf_field.status, eventData->rf_field.rf_field_status);
if (sIsDisabling || !sIsNfaEnabled)
break;
if (!sP2pActive && eventData->rf_field.status == NFA_STATUS_OK)
SecureElement::getInstance().notifyRfFieldEvent (
eventData->rf_field.rf_field_status == NFA_DM_RF_FIELD_ON);
break;
case NFA_DM_NFCC_TRANSPORT_ERR_EVT:
case NFA_DM_NFCC_TIMEOUT_EVT:
{
if (dmEvent == NFA_DM_NFCC_TIMEOUT_EVT)
ALOGD ("%s: NFA_DM_NFCC_TIMEOUT_EVT; abort all outstanding operations", __FUNCTION__);
else
ALOGD ("%s: NFA_DM_NFCC_TRANSPORT_ERR_EVT; abort all outstanding operations", __FUNCTION__);
nativeNfcTag_abortWaits();
NfcTag::getInstance().abort ();
sAbortConnlessWait = true;
nativeLlcpConnectionlessSocket_abortWait();
{
ALOGD ("%s: aborting sNfaEnableDisablePollingEvent", __FUNCTION__);
SyncEventGuard guard (sNfaEnableDisablePollingEvent);
sNfaEnableDisablePollingEvent.notifyOne();
}
{
ALOGD ("%s: aborting sNfaEnableEvent", __FUNCTION__);
SyncEventGuard guard (sNfaEnableEvent);
sNfaEnableEvent.notifyOne();
}
{
ALOGD ("%s: aborting sNfaDisableEvent", __FUNCTION__);
SyncEventGuard guard (sNfaDisableEvent);
sNfaDisableEvent.notifyOne();
}
sDiscoveryEnabled = false;
PowerSwitch::getInstance ().abort ();
if (!sIsDisabling && sIsNfaEnabled)
{
NFA_Disable(FALSE);
sIsDisabling = true;
}
else
{
sIsNfaEnabled = false;
sIsDisabling = false;
}
PowerSwitch::getInstance ().initialize (PowerSwitch::UNKNOWN_LEVEL);
ALOGD ("%s: aborted all waiting events", __FUNCTION__);
}
break;
case NFA_DM_PWR_MODE_CHANGE_EVT:
PowerSwitch::getInstance ().deviceManagementCallback (dmEvent, eventData);
break;
default:
ALOGD ("%s: unhandled event", __FUNCTION__);
break;
}
}
/*******************************************************************************
**
** Function: nfcManager_doInitialize
**
** Description: Turn on NFC.
** e: JVM environment.
** o: Java object.
**
** Returns: True if ok.
**
*******************************************************************************/
static jboolean nfcManager_doInitialize (JNIEnv* e, jobject o)
{
ALOGD ("%s: enter; NCI_VERSION=0x%02X", __FUNCTION__, NCI_VERSION);
tNFA_STATUS stat = NFA_STATUS_OK;
if (sIsNfaEnabled)
{
ALOGD ("%s: already enabled", __FUNCTION__);
goto TheEnd;
}
PowerSwitch::getInstance ().initialize (PowerSwitch::FULL_POWER);
{
unsigned long num = 0;
NfcAdaptation& theInstance = NfcAdaptation::GetInstance();
theInstance.Initialize(); //start GKI, NCI task, NFC task
{
SyncEventGuard guard (sNfaEnableEvent);
tHAL_NFC_ENTRY* halFuncEntries = theInstance.GetHalEntryFuncs ();
NFA_Init (halFuncEntries);
stat = NFA_Enable (nfaDeviceManagementCallback, nfaConnectionCallback);
if (stat == NFA_STATUS_OK)
{
num = initializeGlobalAppLogLevel ();
CE_SetTraceLevel (num);
LLCP_SetTraceLevel (num);
NFC_SetTraceLevel (num);
RW_SetTraceLevel (num);
NFA_SetTraceLevel (num);
NFA_P2pSetTraceLevel (num);
sNfaEnableEvent.wait(); //wait for NFA command to finish
}
}
if (stat == NFA_STATUS_OK)
{
//sIsNfaEnabled indicates whether stack started successfully
if (sIsNfaEnabled)
{
SecureElement::getInstance().initialize (getNative(e, o));
nativeNfcTag_registerNdefTypeHandler ();
NfcTag::getInstance().initialize (getNative(e, o));
PeerToPeer::getInstance().initialize ();
PeerToPeer::getInstance().handleNfcOnOff (true);
/////////////////////////////////////////////////////////////////////////////////
// Add extra configuration here (work-arounds, etc.)
struct nfc_jni_native_data *nat = getNative(e, o);
if ( nat )
{
if (GetNumValue(NAME_POLLING_TECH_MASK, &num, sizeof(num)))
nat->tech_mask = num;
else
nat->tech_mask = DEFAULT_TECH_MASK;
ALOGD ("%s: tag polling tech mask=0x%X", __FUNCTION__, nat->tech_mask);
}
// Always restore LPTD Configuration to the stack default.
if (sOriginalLptdCfg != NULL)
p_nfa_dm_lptd_cfg = sOriginalLptdCfg;
// if this value exists, set polling interval.
if (GetNumValue(NAME_NFA_DM_DISC_DURATION_POLL, &num, sizeof(num)))
NFA_SetRfDiscoveryDuration(num);
// Do custom NFCA startup configuration.
doStartupConfig();
goto TheEnd;
}
}
ALOGE ("%s: fail nfa enable; error=0x%X", __FUNCTION__, stat);
if (sIsNfaEnabled)
stat = NFA_Disable (FALSE /* ungraceful */);
theInstance.Finalize();
}
TheEnd:
if (sIsNfaEnabled)
PowerSwitch::getInstance ().setLevel (PowerSwitch::LOW_POWER);
ALOGD ("%s: exit", __FUNCTION__);
return sIsNfaEnabled ? JNI_TRUE : JNI_FALSE;
}
/*******************************************************************************
**
** Function: nfcManager_enableDiscovery
**
** Description: Start polling and listening for devices.
** e: JVM environment.
** o: Java object.
** mode: Not used.
**
** Returns: None
**
*******************************************************************************/
static void nfcManager_enableDiscovery (JNIEnv* e, jobject o)
{
tNFA_TECHNOLOGY_MASK tech_mask = DEFAULT_TECH_MASK;
struct nfc_jni_native_data *nat = getNative(e, o);
if (nat)
tech_mask = (tNFA_TECHNOLOGY_MASK)nat->tech_mask;
ALOGD ("%s: enter; tech_mask = %02x", __FUNCTION__, tech_mask);
if (sDiscoveryEnabled)
{
ALOGE ("%s: already polling", __FUNCTION__);
return;
}
tNFA_STATUS stat = NFA_STATUS_OK;
ALOGD ("%s: sIsSecElemSelected=%u", __FUNCTION__, sIsSecElemSelected);
PowerSwitch::getInstance ().setLevel (PowerSwitch::FULL_POWER);
if (sRfEnabled) {
// Stop RF discovery to reconfigure
startRfDiscovery(false);
}
{
SyncEventGuard guard (sNfaEnableDisablePollingEvent);
stat = NFA_EnablePolling (tech_mask);
if (stat == NFA_STATUS_OK)
{
ALOGD ("%s: wait for enable event", __FUNCTION__);
sDiscoveryEnabled = true;
sNfaEnableDisablePollingEvent.wait (); //wait for NFA_POLL_ENABLED_EVT
ALOGD ("%s: got enabled event", __FUNCTION__);
}
else
{
ALOGE ("%s: fail enable discovery; error=0x%X", __FUNCTION__, stat);
}
}
// Start P2P listening if tag polling was enabled or the mask was 0.
if (sDiscoveryEnabled || (tech_mask == 0))
{
ALOGD ("%s: Enable p2pListening", __FUNCTION__);
PeerToPeer::getInstance().enableP2pListening (true);
//if NFC service has deselected the sec elem, then apply default routes
if (!sIsSecElemSelected)
stat = SecureElement::getInstance().routeToDefault ();
}
// Actually start discovery.
startRfDiscovery (true);
PowerSwitch::getInstance ().setModeOn (PowerSwitch::DISCOVERY);
ALOGD ("%s: exit", __FUNCTION__);
}
/*******************************************************************************
**
** Function: nfcManager_disableDiscovery
**
** Description: Stop polling and listening for devices.
** e: JVM environment.
** o: Java object.
**
** Returns: None
**
*******************************************************************************/
void nfcManager_disableDiscovery (JNIEnv*, jobject)
{
tNFA_STATUS status = NFA_STATUS_OK;
ALOGD ("%s: enter;", __FUNCTION__);
pn544InteropAbortNow ();
if (sDiscoveryEnabled == false)
{
ALOGD ("%s: already disabled", __FUNCTION__);
goto TheEnd;
}
// Stop RF Discovery.
startRfDiscovery (false);
if (sDiscoveryEnabled)
{
SyncEventGuard guard (sNfaEnableDisablePollingEvent);
status = NFA_DisablePolling ();
if (status == NFA_STATUS_OK)
{
sDiscoveryEnabled = false;
sNfaEnableDisablePollingEvent.wait (); //wait for NFA_POLL_DISABLED_EVT
}
else
ALOGE ("%s: Failed to disable polling; error=0x%X", __FUNCTION__, status);
}
PeerToPeer::getInstance().enableP2pListening (false);
//if nothing is active after this, then tell the controller to power down
if (! PowerSwitch::getInstance ().setModeOff (PowerSwitch::DISCOVERY))
PowerSwitch::getInstance ().setLevel (PowerSwitch::LOW_POWER);
// We may have had RF field notifications that did not cause
// any activate/deactive events. For example, caused by wireless
// charging orbs. Those may cause us to go to sleep while the last
// field event was indicating a field. To prevent sticking in that
// state, always reset the rf field status when we disable discovery.
SecureElement::getInstance().resetRfFieldStatus();
TheEnd:
ALOGD ("%s: exit", __FUNCTION__);
}
void setUiccIdleTimeout (bool enable)
{
tNFA_STATUS stat = NFA_STATUS_OK;
SyncEventGuard guard(sNfaSetConfigEvent);
if (enable)
{
UINT8 enable_uicc_idle[] = { 0x61,0x00,0x82,0x04,0x40,0x4B,0x4C,0x00 };
stat = NFA_SetConfig(0xC2, sizeof(enable_uicc_idle), &enable_uicc_idle[0]);
if (stat == NFA_STATUS_OK)
sNfaSetConfigEvent.wait ();
else
ALOGE("%s: Could not enable UICC idle timeout feature", __FUNCTION__);
}
else
{
UINT8 disable_uicc_idle[] = { 0x60,0x00,0x82,0x04,0x40,0x4B,0x4C,0x00 };
stat = NFA_SetConfig(0xC2, sizeof(disable_uicc_idle), &disable_uicc_idle[0]);
if (stat == NFA_STATUS_OK)
sNfaSetConfigEvent.wait ();
else
ALOGE("%s: Could not disable UICC idle timeout feature", __FUNCTION__);
}
}
/*******************************************************************************
**
** Function nfc_jni_cache_object_local
**
** Description Allocates a java object and calls it's constructor
**
** Returns -1 on failure, 0 on success
**
*******************************************************************************/
static int nfc_jni_cache_object_local (JNIEnv *e, const char *className, jobject *cachedObj)
{
ScopedLocalRef<jclass> cls(e, e->FindClass(className));
if(cls.get() == NULL) {
ALOGE ("%s: find class error", __FUNCTION__);
return -1;
}
jmethodID ctor = e->GetMethodID(cls.get(), "<init>", "()V");
jobject obj = e->NewObject(cls.get(), ctor);
if (obj == NULL) {
ALOGE ("%s: create object error", __FUNCTION__);
return -1;
}
*cachedObj = obj;
if (*cachedObj == NULL) {
ALOGE ("%s: global ref error", __FUNCTION__);
return -1;
}
return 0;
}
/*******************************************************************************
**
** Function: nfcManager_doCreateLlcpServiceSocket
**
** Description: Create a new LLCP server socket.
** e: JVM environment.
** o: Java object.
** nSap: Service access point.
** sn: Service name
** miu: Maximum information unit.
** rw: Receive window size.
** linearBufferLength: Max buffer size.
**
** Returns: NativeLlcpServiceSocket Java object.
**
*******************************************************************************/
static jobject nfcManager_doCreateLlcpServiceSocket (JNIEnv* e, jobject, jint nSap, jstring sn, jint miu, jint rw, jint linearBufferLength)
{
PeerToPeer::tJNI_HANDLE jniHandle = PeerToPeer::getInstance().getNewJniHandle ();
ScopedUtfChars serviceName(e, sn);
ALOGD ("%s: enter: sap=%i; name=%s; miu=%i; rw=%i; buffLen=%i", __FUNCTION__, nSap, serviceName.c_str(), miu, rw, linearBufferLength);
/* Create new NativeLlcpServiceSocket object */
jobject serviceSocket = NULL;
if (nfc_jni_cache_object(e, gNativeLlcpServiceSocketClassName, &(serviceSocket)) == -1)
{
ALOGE ("%s: Llcp socket object creation error", __FUNCTION__);
return NULL;
}
/* Get NativeLlcpServiceSocket class object */
ScopedLocalRef<jclass> clsNativeLlcpServiceSocket(e, e->GetObjectClass(serviceSocket));
if (e->ExceptionCheck())
{
e->ExceptionClear();
ALOGE("%s: Llcp Socket get object class error", __FUNCTION__);
return NULL;
}
if (!PeerToPeer::getInstance().registerServer (jniHandle, serviceName.c_str()))
{
ALOGE("%s: RegisterServer error", __FUNCTION__);
return NULL;
}
jfieldID f;
/* Set socket handle to be the same as the NfaHandle*/
f = e->GetFieldID(clsNativeLlcpServiceSocket.get(), "mHandle", "I");
e->SetIntField(serviceSocket, f, (jint) jniHandle);
ALOGD ("%s: socket Handle = 0x%X", __FUNCTION__, jniHandle);
/* Set socket linear buffer length */
f = e->GetFieldID(clsNativeLlcpServiceSocket.get(), "mLocalLinearBufferLength", "I");
e->SetIntField(serviceSocket, f,(jint)linearBufferLength);
ALOGD ("%s: buffer length = %d", __FUNCTION__, linearBufferLength);
/* Set socket MIU */
f = e->GetFieldID(clsNativeLlcpServiceSocket.get(), "mLocalMiu", "I");
e->SetIntField(serviceSocket, f,(jint)miu);
ALOGD ("%s: MIU = %d", __FUNCTION__, miu);
/* Set socket RW */
f = e->GetFieldID(clsNativeLlcpServiceSocket.get(), "mLocalRw", "I");
e->SetIntField(serviceSocket, f,(jint)rw);
ALOGD ("%s: RW = %d", __FUNCTION__, rw);
sLastError = 0;
ALOGD ("%s: exit", __FUNCTION__);
return serviceSocket;
}
/*******************************************************************************
**
** Function: nfcManager_doGetLastError
**
** Description: Get the last error code.
** e: JVM environment.
** o: Java object.
**
** Returns: Last error code.
**
*******************************************************************************/
static jint nfcManager_doGetLastError(JNIEnv*, jobject)
{
ALOGD ("%s: last error=%i", __FUNCTION__, sLastError);
return sLastError;
}
/*******************************************************************************
**
** Function: nfcManager_doDeinitialize
**
** Description: Turn off NFC.
** e: JVM environment.
** o: Java object.
**
** Returns: True if ok.
**
*******************************************************************************/
static jboolean nfcManager_doDeinitialize (JNIEnv*, jobject)
{
ALOGD ("%s: enter", __FUNCTION__);
sIsDisabling = true;
pn544InteropAbortNow ();
SecureElement::getInstance().finalize ();
if (sIsNfaEnabled)
{
SyncEventGuard guard (sNfaDisableEvent);
tNFA_STATUS stat = NFA_Disable (TRUE /* graceful */);
if (stat == NFA_STATUS_OK)
{
ALOGD ("%s: wait for completion", __FUNCTION__);
sNfaDisableEvent.wait (); //wait for NFA command to finish
PeerToPeer::getInstance ().handleNfcOnOff (false);
}
else
{
ALOGE ("%s: fail disable; error=0x%X", __FUNCTION__, stat);
}
}
nativeNfcTag_abortWaits();
NfcTag::getInstance().abort ();
sAbortConnlessWait = true;
nativeLlcpConnectionlessSocket_abortWait();
sIsNfaEnabled = false;
sDiscoveryEnabled = false;
sIsDisabling = false;
sIsSecElemSelected = false;
{
//unblock NFA_EnablePolling() and NFA_DisablePolling()
SyncEventGuard guard (sNfaEnableDisablePollingEvent);
sNfaEnableDisablePollingEvent.notifyOne ();
}
NfcAdaptation& theInstance = NfcAdaptation::GetInstance();
theInstance.Finalize();
ALOGD ("%s: exit", __FUNCTION__);
return JNI_TRUE;
}
/*******************************************************************************
**
** Function: nfcManager_doCreateLlcpSocket
**
** Description: Create a LLCP connection-oriented socket.
** e: JVM environment.
** o: Java object.
** nSap: Service access point.
** miu: Maximum information unit.
** rw: Receive window size.
** linearBufferLength: Max buffer size.
**
** Returns: NativeLlcpSocket Java object.
**
*******************************************************************************/
static jobject nfcManager_doCreateLlcpSocket (JNIEnv* e, jobject, jint nSap, jint miu, jint rw, jint linearBufferLength)
{
ALOGD ("%s: enter; sap=%d; miu=%d; rw=%d; buffer len=%d", __FUNCTION__, nSap, miu, rw, linearBufferLength);
PeerToPeer::tJNI_HANDLE jniHandle = PeerToPeer::getInstance().getNewJniHandle ();
bool stat = PeerToPeer::getInstance().createClient (jniHandle, miu, rw);
/* Create new NativeLlcpSocket object */
jobject clientSocket = NULL;
if (nfc_jni_cache_object_local(e, gNativeLlcpSocketClassName, &(clientSocket)) == -1)
{
ALOGE ("%s: fail Llcp socket creation", __FUNCTION__);
return clientSocket;
}
/* Get NativeConnectionless class object */
ScopedLocalRef<jclass> clsNativeLlcpSocket(e, e->GetObjectClass(clientSocket));
if (e->ExceptionCheck())
{
e->ExceptionClear();
ALOGE ("%s: fail get class object", __FUNCTION__);
return clientSocket;
}
jfieldID f;
/* Set socket SAP */
f = e->GetFieldID (clsNativeLlcpSocket.get(), "mSap", "I");
e->SetIntField (clientSocket, f, (jint) nSap);
/* Set socket handle */
f = e->GetFieldID (clsNativeLlcpSocket.get(), "mHandle", "I");
e->SetIntField (clientSocket, f, (jint) jniHandle);
/* Set socket MIU */
f = e->GetFieldID (clsNativeLlcpSocket.get(), "mLocalMiu", "I");
e->SetIntField (clientSocket, f, (jint) miu);
/* Set socket RW */
f = e->GetFieldID (clsNativeLlcpSocket.get(), "mLocalRw", "I");
e->SetIntField (clientSocket, f, (jint) rw);
ALOGD ("%s: exit", __FUNCTION__);
return clientSocket;
}
/*******************************************************************************
**
** Function: nfcManager_doCreateLlcpConnectionlessSocket
**
** Description: Create a connection-less socket.
** e: JVM environment.
** o: Java object.
** nSap: Service access point.
** sn: Service name.
**
** Returns: NativeLlcpConnectionlessSocket Java object.
**
*******************************************************************************/
static jobject nfcManager_doCreateLlcpConnectionlessSocket (JNIEnv *, jobject, jint nSap, jstring /*sn*/)
{
ALOGD ("%s: nSap=0x%X", __FUNCTION__, nSap);
return NULL;
}
/*******************************************************************************
**
** Function: nfcManager_doGetSecureElementList
**
** Description: Get a list of secure element handles.
** e: JVM environment.
** o: Java object.
**
** Returns: List of secure element handles.
**
*******************************************************************************/
static jintArray nfcManager_doGetSecureElementList(JNIEnv* e, jobject)
{
ALOGD ("%s", __FUNCTION__);
return SecureElement::getInstance().getListOfEeHandles (e);
}
/*******************************************************************************
**
** Function: nfcManager_doSelectSecureElement
**
** Description: NFC controller starts routing data in listen mode.
** e: JVM environment.
** o: Java object.
**
** Returns: None
**
*******************************************************************************/
static void nfcManager_doSelectSecureElement(JNIEnv*, jobject)
{
ALOGD ("%s: enter", __FUNCTION__);
bool stat = true;
if (sIsSecElemSelected)
{
ALOGD ("%s: already selected", __FUNCTION__);
goto TheEnd;
}
PowerSwitch::getInstance ().setLevel (PowerSwitch::FULL_POWER);
if (sRfEnabled) {
// Stop RF Discovery if we were polling
startRfDiscovery (false);
}
stat = SecureElement::getInstance().activate (0xABCDEF);
if (stat)
SecureElement::getInstance().routeToSecureElement ();
sIsSecElemSelected = true;
startRfDiscovery (true);
PowerSwitch::getInstance ().setModeOn (PowerSwitch::SE_ROUTING);
TheEnd:
ALOGD ("%s: exit", __FUNCTION__);
}
/*******************************************************************************
**
** Function: nfcManager_doDeselectSecureElement
**
** Description: NFC controller stops routing data in listen mode.
** e: JVM environment.
** o: Java object.
**
** Returns: None
**
*******************************************************************************/
static void nfcManager_doDeselectSecureElement(JNIEnv*, jobject)
{
ALOGD ("%s: enter", __FUNCTION__);
bool stat = false;
bool bRestartDiscovery = false;
if (! sIsSecElemSelected)
{
ALOGE ("%s: already deselected", __FUNCTION__);
goto TheEnd;
}
if (PowerSwitch::getInstance ().getLevel() == PowerSwitch::LOW_POWER)
{
ALOGD ("%s: do not deselect while power is OFF", __FUNCTION__);
sIsSecElemSelected = false;
goto TheEnd;
}
if (sRfEnabled) {
// Stop RF Discovery if we were polling
startRfDiscovery (false);
bRestartDiscovery = true;
}
stat = SecureElement::getInstance().routeToDefault ();
sIsSecElemSelected = false;
//if controller is not routing to sec elems AND there is no pipe connected,
//then turn off the sec elems
if (SecureElement::getInstance().isBusy() == false)
SecureElement::getInstance().deactivate (0xABCDEF);
TheEnd:
if (bRestartDiscovery)
startRfDiscovery (true);
//if nothing is active after this, then tell the controller to power down
if (! PowerSwitch::getInstance ().setModeOff (PowerSwitch::SE_ROUTING))
PowerSwitch::getInstance ().setLevel (PowerSwitch::LOW_POWER);
ALOGD ("%s: exit", __FUNCTION__);
}
/*******************************************************************************
**
** Function: isPeerToPeer
**
** Description: Whether the activation data indicates the peer supports NFC-DEP.
** activated: Activation data.
**
** Returns: True if the peer supports NFC-DEP.
**
*******************************************************************************/
static bool isPeerToPeer (tNFA_ACTIVATED& activated)
{
return activated.activate_ntf.protocol == NFA_PROTOCOL_NFC_DEP;
}
/*******************************************************************************
**
** Function: isListenMode
**
** Description: Indicates whether the activation data indicates it is
** listen mode.
**
** Returns: True if this listen mode.
**
*******************************************************************************/
static bool isListenMode(tNFA_ACTIVATED& activated)
{
return ((NFC_DISCOVERY_TYPE_LISTEN_A == activated.activate_ntf.rf_tech_param.mode)
|| (NFC_DISCOVERY_TYPE_LISTEN_B == activated.activate_ntf.rf_tech_param.mode)
|| (NFC_DISCOVERY_TYPE_LISTEN_F == activated.activate_ntf.rf_tech_param.mode)
|| (NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE == activated.activate_ntf.rf_tech_param.mode)
|| (NFC_DISCOVERY_TYPE_LISTEN_F_ACTIVE == activated.activate_ntf.rf_tech_param.mode)
|| (NFC_DISCOVERY_TYPE_LISTEN_ISO15693 == activated.activate_ntf.rf_tech_param.mode)
|| (NFC_DISCOVERY_TYPE_LISTEN_B_PRIME == activated.activate_ntf.rf_tech_param.mode));
}
/*******************************************************************************
**
** Function: nfcManager_doCheckLlcp
**
** Description: Not used.
**
** Returns: True
**
*******************************************************************************/
static jboolean nfcManager_doCheckLlcp(JNIEnv*, jobject)
{
ALOGD("%s", __FUNCTION__);
return JNI_TRUE;
}
/*******************************************************************************
**
** Function: nfcManager_doActivateLlcp
**
** Description: Not used.
**
** Returns: True
**
*******************************************************************************/
static jboolean nfcManager_doActivateLlcp(JNIEnv*, jobject)
{
ALOGD("%s", __FUNCTION__);
return JNI_TRUE;
}
/*******************************************************************************
**
** Function: nfcManager_doAbort
**
** Description: Not used.
**
** Returns: None
**
*******************************************************************************/
static void nfcManager_doAbort(JNIEnv*, jobject)
{
ALOGE("%s: abort()", __FUNCTION__);
abort();
}
/*******************************************************************************
**
** Function: nfcManager_doDownload
**
** Description: Not used.
**
** Returns: True
**
*******************************************************************************/
static jboolean nfcManager_doDownload(JNIEnv*, jobject)
{
ALOGD("%s", __FUNCTION__);
return JNI_TRUE;
}
/*******************************************************************************
**
** Function: nfcManager_doResetTimeouts
**
** Description: Not used.
**
** Returns: None
**
*******************************************************************************/
static void nfcManager_doResetTimeouts(JNIEnv*, jobject)
{
ALOGD ("%s: %d millisec", __FUNCTION__, DEFAULT_GENERAL_TRANS_TIMEOUT);
gGeneralTransceiveTimeout = DEFAULT_GENERAL_TRANS_TIMEOUT;
}
/*******************************************************************************
**
** Function: nfcManager_doSetTimeout
**
** Description: Set timeout value.
** e: JVM environment.
** o: Java object.
** timeout: Timeout value.
**
** Returns: True if ok.
**
*******************************************************************************/
static bool nfcManager_doSetTimeout(JNIEnv*, jobject, jint /*tech*/, jint timeout)
{
if (timeout <= 0)
{
ALOGE("%s: Timeout must be positive.",__FUNCTION__);
return false;
}
ALOGD ("%s: timeout=%d", __FUNCTION__, timeout);
gGeneralTransceiveTimeout = timeout;
return true;
}
/*******************************************************************************
**
** Function: nfcManager_doGetTimeout
**
** Description: Get timeout value.
** e: JVM environment.
** o: Java object.
** tech: Not used.
**
** Returns: Timeout value.
**
*******************************************************************************/
static jint nfcManager_doGetTimeout(JNIEnv*, jobject, jint /*tech*/)
{
ALOGD ("%s: timeout=%d", __FUNCTION__, gGeneralTransceiveTimeout);
return gGeneralTransceiveTimeout;
}
/*******************************************************************************
**
** Function: nfcManager_doDump
**
** Description: Not used.
** e: JVM environment.
** o: Java object.
**
** Returns: Text dump.
**
*******************************************************************************/
static jstring nfcManager_doDump(JNIEnv* e, jobject)
{
char buffer[100];
snprintf(buffer, sizeof(buffer), "libnfc llc error_count=%u", /*libnfc_llc_error_count*/ 0);
return e->NewStringUTF(buffer);
}
/*******************************************************************************
**
** Function: nfcManager_doSetP2pInitiatorModes
**
** Description: Set P2P initiator's activation modes.
** e: JVM environment.
** o: Java object.
** modes: Active and/or passive modes. The values are specified
** in external/libnfc-nxp/inc/phNfcTypes.h. See
** enum phNfc_eP2PMode_t.
**
** Returns: None.
**
*******************************************************************************/
static void nfcManager_doSetP2pInitiatorModes (JNIEnv *e, jobject o, jint modes)
{
ALOGD ("%s: modes=0x%X", __FUNCTION__, modes);
struct nfc_jni_native_data *nat = getNative(e, o);
tNFA_TECHNOLOGY_MASK mask = 0;
if (modes & 0x01) mask |= NFA_TECHNOLOGY_MASK_A;
if (modes & 0x02) mask |= NFA_TECHNOLOGY_MASK_F;
if (modes & 0x04) mask |= NFA_TECHNOLOGY_MASK_F;
if (modes & 0x08) mask |= NFA_TECHNOLOGY_MASK_A_ACTIVE;
if (modes & 0x10) mask |= NFA_TECHNOLOGY_MASK_F_ACTIVE;
if (modes & 0x20) mask |= NFA_TECHNOLOGY_MASK_F_ACTIVE;
nat->tech_mask = mask;
//this function is not called by the NFC service nor exposed by public API.
}
/*******************************************************************************
**
** Function: nfcManager_doSetP2pTargetModes
**
** Description: Set P2P target's activation modes.
** e: JVM environment.
** o: Java object.
** modes: Active and/or passive modes.
**
** Returns: None.
**
*******************************************************************************/
static void nfcManager_doSetP2pTargetModes (JNIEnv*, jobject, jint modes)
{
ALOGD ("%s: modes=0x%X", __FUNCTION__, modes);
// Map in the right modes
tNFA_TECHNOLOGY_MASK mask = 0;
if (modes & 0x01) mask |= NFA_TECHNOLOGY_MASK_A;
if (modes & 0x02) mask |= NFA_TECHNOLOGY_MASK_F;
if (modes & 0x04) mask |= NFA_TECHNOLOGY_MASK_F;
if (modes & 0x08) mask |= NFA_TECHNOLOGY_MASK_A_ACTIVE | NFA_TECHNOLOGY_MASK_F_ACTIVE;
PeerToPeer::getInstance().setP2pListenMask(mask);
//this function is not called by the NFC service nor exposed by public API.
}
/*****************************************************************************
**
** JNI functions for android-4.0.1_r1
**
*****************************************************************************/
static JNINativeMethod gMethods[] =
{
{"doDownload", "()Z",
(void *)nfcManager_doDownload},
{"initializeNativeStructure", "()Z",
(void*) nfcManager_initNativeStruc},
{"doInitialize", "()Z",
(void*) nfcManager_doInitialize},
{"doDeinitialize", "()Z",
(void*) nfcManager_doDeinitialize},
{"enableDiscovery", "()V",
(void*) nfcManager_enableDiscovery},
{"doGetSecureElementList", "()[I",
(void *)nfcManager_doGetSecureElementList},
{"doSelectSecureElement", "()V",
(void *)nfcManager_doSelectSecureElement},
{"doDeselectSecureElement", "()V",
(void *)nfcManager_doDeselectSecureElement},
{"doCheckLlcp", "()Z",
(void *)nfcManager_doCheckLlcp},
{"doActivateLlcp", "()Z",
(void *)nfcManager_doActivateLlcp},
{"doCreateLlcpConnectionlessSocket", "(ILjava/lang/String;)Lcom/android/nfc/dhimpl/NativeLlcpConnectionlessSocket;",
(void *)nfcManager_doCreateLlcpConnectionlessSocket},
{"doCreateLlcpServiceSocket", "(ILjava/lang/String;III)Lcom/android/nfc/dhimpl/NativeLlcpServiceSocket;",
(void*) nfcManager_doCreateLlcpServiceSocket},
{"doCreateLlcpSocket", "(IIII)Lcom/android/nfc/dhimpl/NativeLlcpSocket;",
(void*) nfcManager_doCreateLlcpSocket},
{"doGetLastError", "()I",
(void*) nfcManager_doGetLastError},
{"disableDiscovery", "()V",
(void*) nfcManager_disableDiscovery},
{"doSetTimeout", "(II)Z",
(void *)nfcManager_doSetTimeout},
{"doGetTimeout", "(I)I",
(void *)nfcManager_doGetTimeout},
{"doResetTimeouts", "()V",
(void *)nfcManager_doResetTimeouts},
{"doAbort", "()V",
(void *)nfcManager_doAbort},
{"doSetP2pInitiatorModes", "(I)V",
(void *)nfcManager_doSetP2pInitiatorModes},
{"doSetP2pTargetModes", "(I)V",
(void *)nfcManager_doSetP2pTargetModes},
{"doDump", "()Ljava/lang/String;",
(void *)nfcManager_doDump},
};
/*******************************************************************************
**
** Function: register_com_android_nfc_NativeNfcManager
**
** Description: Regisgter JNI functions with Java Virtual Machine.
** e: Environment of JVM.
**
** Returns: Status of registration.
**
*******************************************************************************/
int register_com_android_nfc_NativeNfcManager (JNIEnv *e)
{
ALOGD ("%s: enter", __FUNCTION__);
PowerSwitch::getInstance ().initialize (PowerSwitch::UNKNOWN_LEVEL);
ALOGD ("%s: exit", __FUNCTION__);
return jniRegisterNativeMethods (e, gNativeNfcManagerClassName, gMethods, NELEM (gMethods));
}
/*******************************************************************************
**
** Function: startRfDiscovery
**
** Description: Ask stack to start polling and listening for devices.
** isStart: Whether to start.
**
** Returns: None
**
*******************************************************************************/
void startRfDiscovery(bool isStart)
{
tNFA_STATUS status = NFA_STATUS_FAILED;
ALOGD ("%s: is start=%d", __FUNCTION__, isStart);
SyncEventGuard guard (sNfaEnableDisablePollingEvent);
status = isStart ? NFA_StartRfDiscovery () : NFA_StopRfDiscovery ();
if (status == NFA_STATUS_OK)
{
sNfaEnableDisablePollingEvent.wait (); //wait for NFA_RF_DISCOVERY_xxxx_EVT
sRfEnabled = isStart;
}
else
{
ALOGE ("%s: Failed to start/stop RF discovery; error=0x%X", __FUNCTION__, status);
}
}
/*******************************************************************************
**
** Function: doStartupConfig
**
** Description: Configure the NFC controller.
**
** Returns: None
**
*******************************************************************************/
void doStartupConfig()
{
unsigned long num = 0;
struct nfc_jni_native_data *nat = getNative(0, 0);
tNFA_STATUS stat = NFA_STATUS_FAILED;
// If polling for Active mode, set the ordering so that we choose Active over Passive mode first.
if (nat && (nat->tech_mask & (NFA_TECHNOLOGY_MASK_A_ACTIVE | NFA_TECHNOLOGY_MASK_F_ACTIVE)))
{
UINT8 act_mode_order_param[] = { 0x01 };
SyncEventGuard guard (sNfaSetConfigEvent);
stat = NFA_SetConfig(NCI_PARAM_ID_ACT_ORDER, sizeof(act_mode_order_param), &act_mode_order_param[0]);
if (stat == NFA_STATUS_OK)
sNfaSetConfigEvent.wait ();
}
}
/*******************************************************************************
**
** Function: nfcManager_isNfcActive
**
** Description: Used externaly to determine if NFC is active or not.
**
** Returns: 'true' if the NFC stack is running, else 'false'.
**
*******************************************************************************/
bool nfcManager_isNfcActive()
{
return sIsNfaEnabled;
}
/*******************************************************************************
**
** Function: startStopPolling
**
** Description: Start or stop polling.
** isStartPolling: true to start polling; false to stop polling.
**
** Returns: None.
**
*******************************************************************************/
void startStopPolling (bool isStartPolling)
{
ALOGD ("%s: enter; isStart=%u", __FUNCTION__, isStartPolling);
tNFA_STATUS stat = NFA_STATUS_FAILED;
startRfDiscovery (false);
if (isStartPolling)
{
tNFA_TECHNOLOGY_MASK tech_mask = DEFAULT_TECH_MASK;
unsigned long num = 0;
if (GetNumValue(NAME_POLLING_TECH_MASK, &num, sizeof(num)))
tech_mask = num;
SyncEventGuard guard (sNfaEnableDisablePollingEvent);
ALOGD ("%s: enable polling", __FUNCTION__);
stat = NFA_EnablePolling (tech_mask);
if (stat == NFA_STATUS_OK)
{
ALOGD ("%s: wait for enable event", __FUNCTION__);
sNfaEnableDisablePollingEvent.wait (); //wait for NFA_POLL_ENABLED_EVT
}
else
ALOGE ("%s: fail enable polling; error=0x%X", __FUNCTION__, stat);
}
else
{
SyncEventGuard guard (sNfaEnableDisablePollingEvent);
ALOGD ("%s: disable polling", __FUNCTION__);
stat = NFA_DisablePolling ();
if (stat == NFA_STATUS_OK)
{
sNfaEnableDisablePollingEvent.wait (); //wait for NFA_POLL_DISABLED_EVT
}
else
ALOGE ("%s: fail disable polling; error=0x%X", __FUNCTION__, stat);
}
startRfDiscovery (true);
ALOGD ("%s: exit", __FUNCTION__);
}
} /* namespace android */