summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2012-12-13 16:24:26 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2012-12-13 16:24:26 -0800
commit525c260303268a83da4c3413b953d13c9084e834 (patch)
tree110a4a6bc2621f34fa2cf7f4c8ba2625598873aa
parent7a1d2adf875d414625853b3a5360663e420a3769 (diff)
downloadpackages_apps_nfc-525c260303268a83da4c3413b953d13c9084e834.zip
packages_apps_nfc-525c260303268a83da4c3413b953d13c9084e834.tar.gz
packages_apps_nfc-525c260303268a83da4c3413b953d13c9084e834.tar.bz2
Snapshot 1a6bcf3cca90fedfbad33c1cdd6d05af5774fc01
Change-Id: I3ccb25bf7cde2c22f52260cae0e9957517e6bb5f
-rw-r--r--Android.mk35
-rwxr-xr-xAndroidManifest.xml6
-rw-r--r--nci/Android.mk3
-rw-r--r--nci/jni/Android.mk54
-rw-r--r--nci/jni/CondVar.cpp145
-rw-r--r--nci/jni/CondVar.h91
-rw-r--r--nci/jni/DataQueue.cpp155
-rw-r--r--nci/jni/DataQueue.h106
-rw-r--r--nci/jni/HostAidRouter.cpp291
-rw-r--r--nci/jni/HostAidRouter.h156
-rw-r--r--nci/jni/IntervalTimer.cpp99
-rw-r--r--nci/jni/IntervalTimer.h38
-rw-r--r--nci/jni/JavaClassConstants.h37
-rw-r--r--nci/jni/Mutex.cpp136
-rw-r--r--nci/jni/Mutex.h113
-rw-r--r--nci/jni/NativeLlcpConnectionlessSocket.cpp311
-rw-r--r--nci/jni/NativeLlcpServiceSocket.cpp158
-rw-r--r--nci/jni/NativeLlcpSocket.cpp271
-rwxr-xr-xnci/jni/NativeNfcManager.cpp1816
-rwxr-xr-xnci/jni/NativeNfcTag.cpp1507
-rw-r--r--nci/jni/NativeP2pDevice.cpp93
-rwxr-xr-xnci/jni/NativeSecureElement.cpp245
-rwxr-xr-xnci/jni/NfcJniUtil.cpp150
-rwxr-xr-xnci/jni/NfcJniUtil.h152
-rwxr-xr-xnci/jni/NfcTag.cpp1325
-rwxr-xr-xnci/jni/NfcTag.h419
-rw-r--r--nci/jni/PeerToPeer.cpp1840
-rw-r--r--nci/jni/PeerToPeer.h779
-rw-r--r--nci/jni/Pn544Interop.cpp153
-rw-r--r--nci/jni/Pn544Interop.h64
-rwxr-xr-xnci/jni/PowerSwitch.cpp439
-rwxr-xr-xnci/jni/PowerSwitch.h258
-rw-r--r--nci/jni/RouteDataSet.cpp555
-rw-r--r--nci/jni/RouteDataSet.h308
-rwxr-xr-xnci/jni/SecureElement.cpp2189
-rwxr-xr-xnci/jni/SecureElement.h607
-rw-r--r--nci/jni/SyncEvent.h171
-rwxr-xr-xnci/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java78
-rwxr-xr-xnci/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java53
-rwxr-xr-xnci/src/com/android/nfc/dhimpl/NativeLlcpSocket.java99
-rwxr-xr-xnci/src/com/android/nfc/dhimpl/NativeNfcManager.java378
-rwxr-xr-xnci/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java67
-rwxr-xr-xnci/src/com/android/nfc/dhimpl/NativeNfcTag.java811
-rwxr-xr-xnci/src/com/android/nfc/dhimpl/NativeP2pDevice.java77
-rwxr-xr-xnxp/src/com/android/nfc/dhimpl/NativeNfcManager.java46
-rwxr-xr-xnxp/src/com/android/nfc/dhimpl/NativeNfcTag.java5
-rw-r--r--src/com/android/nfc/DeviceHost.java20
-rw-r--r--src/com/android/nfc/FireflyRenderer.java1
-rw-r--r--src/com/android/nfc/NfcApplication.java24
-rw-r--r--src/com/android/nfc/NfcDispatcher.java42
-rw-r--r--src/com/android/nfc/NfcRootActivity.java4
-rwxr-xr-xsrc/com/android/nfc/NfcService.java401
-rwxr-xr-xsrc/com/android/nfc/P2pLinkManager.java18
-rw-r--r--src/com/android/nfc/RegisteredComponentCache.java31
-rw-r--r--src/com/android/nfc/SendUi.java20
-rw-r--r--src/com/android/nfc/handover/BluetoothHeadsetHandover.java231
-rw-r--r--src/com/android/nfc/handover/HandoverManager.java55
-rwxr-xr-xsrc/com/android/nfc/ndefpush/NdefPushServer.java67
-rw-r--r--src/com/android/nfc/snep/SnepClient.java24
-rw-r--r--src/com/android/nfc/snep/SnepServer.java22
60 files changed, 17536 insertions, 313 deletions
diff --git a/Android.mk b/Android.mk
index 2cdfc68..9aa7ee2 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,4 +1,8 @@
LOCAL_PATH:= $(call my-dir)
+
+########################################
+# NXP Configuration
+########################################
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
@@ -6,13 +10,8 @@ LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := \
$(call all-java-files-under, src)
-ifeq ($(NFC_USE_NCI_STACK), true)
- LOCAL_SRC_FILES += \
- $(call all-java-files-under, nci)
-else
- LOCAL_SRC_FILES += \
+LOCAL_SRC_FILES += \
$(call all-java-files-under, nxp)
-endif
LOCAL_PACKAGE_NAME := Nfc
LOCAL_CERTIFICATE := platform
@@ -25,6 +24,30 @@ LOCAL_PROGUARD_ENABLED := disabled
include $(BUILD_PACKAGE)
+########################################
+# NCI Configuration
+########################################
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+ $(call all-java-files-under, src)
+
+LOCAL_SRC_FILES += \
+ $(call all-java-files-under, nci)
+
+LOCAL_PACKAGE_NAME := NfcNci
+LOCAL_OVERRIDES_PACKAGES := Nfc
+LOCAL_CERTIFICATE := platform
+
+LOCAL_STATIC_JAVA_LIBRARIES := NfcLogTags
+
+LOCAL_JNI_SHARED_LIBRARIES := libnfc_nci_jni
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+include $(BUILD_PACKAGE)
#####
# static lib for the log tags
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index f0c027f..710e2ee 100755
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -20,10 +20,12 @@
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+ <uses-permission android:name="android.permission.MANAGE_USERS" />
+ <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" />
<uses-permission android:name="com.android.permission.WHITELIST_BLUETOOTH_DEVICE" />
<uses-permission android:name="com.android.permission.HANDOVER_STATUS" />
-
- <application android:name=".NfcService"
+ <application android:name=".NfcApplication"
android:icon="@drawable/icon"
android:label="@string/app_name"
android:persistent="true"
diff --git a/nci/Android.mk b/nci/Android.mk
new file mode 100644
index 0000000..34f4385
--- /dev/null
+++ b/nci/Android.mk
@@ -0,0 +1,3 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/nci/jni/Android.mk b/nci/jni/Android.mk
new file mode 100644
index 0000000..39832fd
--- /dev/null
+++ b/nci/jni/Android.mk
@@ -0,0 +1,54 @@
+VOB_COMPONENTS := external/libnfc-nci/src
+NFA := $(VOB_COMPONENTS)/nfa
+NFC := $(VOB_COMPONENTS)/nfc
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_PRELINK_MODULE := false
+
+ifneq ($(NCI_VERSION),)
+LOCAL_CFLAGS += -DNCI_VERSION=$(NCI_VERSION) -O0 -g
+endif
+
+define all-cpp-files-under
+$(patsubst ./%,%, \
+ $(shell cd $(LOCAL_PATH) ; \
+ find $(1) -name "*.cpp" -and -not -name ".*") \
+ )
+endef
+
+LOCAL_SRC_FILES:= $(call all-cpp-files-under, .)
+
+LOCAL_C_INCLUDES += \
+ bionic \
+ bionic/libstdc++ \
+ external/stlport/stlport \
+ external/libxml2/include \
+ external/icu4c/common \
+ frameworks/native/include \
+ $(NFA)/include \
+ $(NFA)/brcm \
+ $(NFC)/include \
+ $(NFC)/brcm \
+ $(NFC)/int \
+ $(VOB_COMPONENTS)/hal/include \
+ $(VOB_COMPONENTS)/hal/int \
+ $(VOB_COMPONENTS)/include \
+ $(VOB_COMPONENTS)/gki/ulinux \
+ $(VOB_COMPONENTS)/gki/common
+
+LOCAL_SHARED_LIBRARIES := \
+ libicuuc \
+ libnativehelper \
+ libcutils \
+ libutils \
+ libnfc-nci \
+ libstlport
+
+LOCAL_STATIC_LIBRARIES := libxml2
+
+LOCAL_MODULE := libnfc_nci_jni
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/nci/jni/CondVar.cpp b/nci/jni/CondVar.cpp
new file mode 100644
index 0000000..e69cc46
--- /dev/null
+++ b/nci/jni/CondVar.cpp
@@ -0,0 +1,145 @@
+/*
+ * 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.
+ */
+
+/*
+ * Encapsulate a condition variable for thread synchronization.
+ */
+
+#include "CondVar.h"
+#include "NfcJniUtil.h"
+#include <errno.h>
+
+
+/*******************************************************************************
+**
+** Function: CondVar
+**
+** Description: Initialize member variables.
+**
+** Returns: None.
+**
+*******************************************************************************/
+CondVar::CondVar ()
+{
+ memset (&mCondition, 0, sizeof(mCondition));
+ int const res = pthread_cond_init (&mCondition, NULL);
+ if (res)
+ {
+ ALOGE ("CondVar::CondVar: fail init; error=0x%X", res);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: ~CondVar
+**
+** Description: Cleanup all resources.
+**
+** Returns: None.
+**
+*******************************************************************************/
+CondVar::~CondVar ()
+{
+ int const res = pthread_cond_destroy (&mCondition);
+ if (res)
+ {
+ ALOGE ("CondVar::~CondVar: fail destroy; error=0x%X", res);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: wait
+**
+** Description: Block the caller and wait for a condition.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void CondVar::wait (Mutex& mutex)
+{
+ int const res = pthread_cond_wait (&mCondition, mutex.nativeHandle());
+ if (res)
+ {
+ ALOGE ("CondVar::wait: fail wait; error=0x%X", res);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: wait
+**
+** Description: Block the caller and wait for a condition.
+** millisec: Timeout in milliseconds.
+**
+** Returns: True if wait is successful; false if timeout occurs.
+**
+*******************************************************************************/
+bool CondVar::wait (Mutex& mutex, long millisec)
+{
+ bool retVal = false;
+ struct timespec absoluteTime;
+
+ if (clock_gettime (CLOCK_MONOTONIC, &absoluteTime) == -1)
+ {
+ ALOGE ("CondVar::wait: fail get time; errno=0x%X", errno);
+ }
+ else
+ {
+ absoluteTime.tv_sec += millisec / 1000;
+ long ns = absoluteTime.tv_nsec + ((millisec % 1000) * 1000000);
+ if (ns > 1000000000)
+ {
+ absoluteTime.tv_sec++;
+ absoluteTime.tv_nsec = ns - 1000000000;
+ }
+ else
+ absoluteTime.tv_nsec = ns;
+ }
+
+ //pthread_cond_timedwait_monotonic_np() is an Android-specific function
+ //declared in /development/ndk/platforms/android-9/include/pthread.h;
+ //it uses monotonic clock.
+ //the standard pthread_cond_timedwait() uses realtime clock.
+ int waitResult = pthread_cond_timedwait_monotonic_np (&mCondition, mutex.nativeHandle(), &absoluteTime);
+ if ((waitResult != 0) && (waitResult != ETIMEDOUT))
+ ALOGE ("CondVar::wait: fail timed wait; error=0x%X", waitResult);
+ retVal = (waitResult == 0); //waited successfully
+ return retVal;
+}
+
+
+/*******************************************************************************
+**
+** Function: notifyOne
+**
+** Description: Unblock the waiting thread.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void CondVar::notifyOne ()
+{
+ int const res = pthread_cond_signal (&mCondition);
+ if (res)
+ {
+ ALOGE ("CondVar::notifyOne: fail signal; error=0x%X", res);
+ }
+}
+
diff --git a/nci/jni/CondVar.h b/nci/jni/CondVar.h
new file mode 100644
index 0000000..c286d5c
--- /dev/null
+++ b/nci/jni/CondVar.h
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+/*
+ * Encapsulate a condition variable for thread synchronization.
+ */
+
+#pragma once
+#include <pthread.h>
+#include "Mutex.h"
+
+
+class CondVar
+{
+public:
+ /*******************************************************************************
+ **
+ ** Function: CondVar
+ **
+ ** Description: Initialize member variables.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ CondVar ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: ~CondVar
+ **
+ ** Description: Cleanup all resources.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ ~CondVar ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: wait
+ **
+ ** Description: Block the caller and wait for a condition.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void wait (Mutex& mutex);
+
+
+ /*******************************************************************************
+ **
+ ** Function: wait
+ **
+ ** Description: Block the caller and wait for a condition.
+ ** millisec: Timeout in milliseconds.
+ **
+ ** Returns: True if wait is successful; false if timeout occurs.
+ **
+ *******************************************************************************/
+ bool wait (Mutex& mutex, long millisec);
+
+
+ /*******************************************************************************
+ **
+ ** Function: notifyOne
+ **
+ ** Description: Unblock the waiting thread.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void notifyOne ();
+
+private:
+ pthread_cond_t mCondition;
+};
diff --git a/nci/jni/DataQueue.cpp b/nci/jni/DataQueue.cpp
new file mode 100644
index 0000000..caa2575
--- /dev/null
+++ b/nci/jni/DataQueue.cpp
@@ -0,0 +1,155 @@
+/*
+ * 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.
+ */
+
+/*
+ * Store data bytes in a variable-size queue.
+ */
+
+#include "DataQueue.h"
+
+
+/*******************************************************************************
+**
+** Function: DataQueue
+**
+** Description: Initialize member variables.
+**
+** Returns: None.
+**
+*******************************************************************************/
+DataQueue::DataQueue ()
+{
+}
+
+
+/*******************************************************************************
+**
+** Function: ~DataQueue
+**
+** Description: Release all resources.
+**
+** Returns: None.
+**
+*******************************************************************************/
+DataQueue::~DataQueue ()
+{
+ mMutex.lock ();
+ while (mQueue.empty() == false)
+ {
+ tHeader* header = mQueue.front ();
+ mQueue.pop_front ();
+ free (header);
+ }
+ mMutex.unlock ();
+}
+
+
+bool DataQueue::isEmpty()
+{
+ mMutex.lock ();
+ bool retval = mQueue.empty();
+ mMutex.unlock ();
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: enqueue
+**
+** Description: Append data to the queue.
+** data: array of bytes
+** dataLen: length of the data.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool DataQueue::enqueue (UINT8* data, UINT16 dataLen)
+{
+ if ((data == NULL) || (dataLen==0))
+ return false;
+
+ mMutex.lock ();
+
+ bool retval = false;
+ tHeader* header = (tHeader*) malloc (sizeof(tHeader) + dataLen);
+
+ if (header)
+ {
+ memset (header, 0, sizeof(tHeader));
+ header->mDataLen = dataLen;
+ memcpy (header+1, data, dataLen);
+
+ mQueue.push_back (header);
+
+ retval = true;
+ }
+ else
+ {
+ ALOGE ("DataQueue::enqueue: out of memory ?????");
+ }
+ mMutex.unlock ();
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: dequeue
+**
+** Description: Retrieve and remove data from the front of the queue.
+** buffer: array to store the data.
+** bufferMaxLen: maximum size of the buffer.
+** actualLen: actual length of the data.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool DataQueue::dequeue (UINT8* buffer, UINT16 bufferMaxLen, UINT16& actualLen)
+{
+ mMutex.lock ();
+
+ tHeader* header = mQueue.front ();
+ bool retval = false;
+
+ if (header && buffer && (bufferMaxLen>0))
+ {
+ if (header->mDataLen <= bufferMaxLen)
+ {
+ //caller's buffer is big enough to store all data
+ actualLen = header->mDataLen;
+ char* src = (char*)(header) + sizeof(tHeader) + header->mOffset;
+ memcpy (buffer, src, actualLen);
+
+ mQueue.pop_front ();
+ free (header);
+ }
+ else
+ {
+ //caller's buffer is too small
+ actualLen = bufferMaxLen;
+ char* src = (char*)(header) + sizeof(tHeader) + header->mOffset;
+ memcpy (buffer, src, actualLen);
+ //adjust offset so the next dequeue() will get the remainder
+ header->mDataLen -= actualLen;
+ header->mOffset += actualLen;
+ }
+ retval = true;
+ }
+ mMutex.unlock ();
+ return retval;
+}
+
diff --git a/nci/jni/DataQueue.h b/nci/jni/DataQueue.h
new file mode 100644
index 0000000..bfd415c
--- /dev/null
+++ b/nci/jni/DataQueue.h
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+
+/*
+ * Store data bytes in a variable-size queue.
+ */
+
+#pragma once
+#include "NfcJniUtil.h"
+#include "gki.h"
+#include "Mutex.h"
+#include <list>
+
+
+class DataQueue
+{
+public:
+ /*******************************************************************************
+ **
+ ** Function: DataQueue
+ **
+ ** Description: Initialize member variables.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ DataQueue ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: ~DataQueue
+ **
+ ** Description: Release all resources.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ ~DataQueue ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: enqueue
+ **
+ ** Description: Append data to the queue.
+ ** data: array of bytes
+ ** dataLen: length of the data.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool enqueue (UINT8* data, UINT16 dataLen);
+
+
+ /*******************************************************************************
+ **
+ ** Function: dequeue
+ **
+ ** Description: Retrieve and remove data from the front of the queue.
+ ** buffer: array to store the data.
+ ** bufferMaxLen: maximum size of the buffer.
+ ** actualLen: actual length of the data.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool dequeue (UINT8* buffer, UINT16 bufferMaxLen, UINT16& actualLen);
+
+
+ /*******************************************************************************
+ **
+ ** Function: isEmpty
+ **
+ ** Description: Whether the queue is empty.
+ **
+ ** Returns: True if empty.
+ **
+ *******************************************************************************/
+ bool isEmpty();
+
+private:
+ struct tHeader
+ {
+ UINT16 mDataLen; //number of octets of data
+ UINT16 mOffset; //offset of the first octet of data
+ };
+ typedef std::list<tHeader*> Queue;
+
+ Queue mQueue;
+ Mutex mMutex;
+};
+
diff --git a/nci/jni/HostAidRouter.cpp b/nci/jni/HostAidRouter.cpp
new file mode 100644
index 0000000..0b511f8
--- /dev/null
+++ b/nci/jni/HostAidRouter.cpp
@@ -0,0 +1,291 @@
+/*
+ * 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.
+ */
+
+/*
+ * Manage listen-mode AID routing to the host.
+ */
+#include "OverrideLog.h"
+#include "HostAidRouter.h"
+#include "config.h"
+#include "SecureElement.h"
+
+
+HostAidRouter HostAidRouter::sHostAidRouter; //singleton HostAidRouter object
+
+
+/*******************************************************************************
+**
+** Function: HostAidRouter
+**
+** Description: Private constructor to prevent public call.
+**
+** Returns: None.
+**
+*******************************************************************************/
+HostAidRouter::HostAidRouter ()
+ : mTempHandle (NFA_HANDLE_INVALID),
+ mIsFeatureEnabled (true)
+{
+}
+
+
+/*******************************************************************************
+**
+** Function: ~HostAidRouter
+**
+** Description: Private destructor to prevent public call.
+**
+** Returns: None.
+**
+*******************************************************************************/
+HostAidRouter::~HostAidRouter ()
+{
+}
+
+
+/*******************************************************************************
+**
+** Function: getInstance
+**
+** Description: Obtain a reference to the singleton object of HostAidRouter
+**
+** Returns: Reference to HostAidRouter object.
+**
+*******************************************************************************/
+HostAidRouter& HostAidRouter::getInstance ()
+{
+ return sHostAidRouter;
+}
+
+
+/*******************************************************************************
+**
+** Function: initialize
+**
+** Description: Initialize all resources.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool HostAidRouter::initialize ()
+{
+ unsigned long num = 0;
+ mTempHandle = NFA_HANDLE_INVALID;
+ mHandleDatabase.clear ();
+
+ if (GetNumValue (NAME_REGISTER_VIRTUAL_SE, &num, sizeof (num)))
+ mIsFeatureEnabled = num != 0;
+ return true;
+}
+
+
+/*******************************************************************************
+**
+** Function: addPpseRoute
+**
+** Description: Route Proximity Payment System Environment request
+** to the host. This function is called when there is no
+** route data.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool HostAidRouter::addPpseRoute ()
+{
+ static const char fn [] = "HostAidRouter::addPpseRoute";
+ ALOGD ("%s: enter", fn);
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ bool retval = false;
+
+ if (! mIsFeatureEnabled)
+ {
+ ALOGD ("%s: feature disabled", fn);
+ goto TheEnd;
+ }
+
+ {
+ ALOGD ("%s: register PPSE AID", fn);
+ SyncEventGuard guard (mRegisterEvent);
+ mTempHandle = NFA_HANDLE_INVALID;
+ nfaStat = NFA_CeRegisterAidOnDH ((UINT8*) "2PAY.SYS.DDF01", 14, stackCallback);
+ if (nfaStat == NFA_STATUS_OK)
+ {
+ mRegisterEvent.wait (); //wait for NFA_CE_REGISTERED_EVT
+ if (mTempHandle == NFA_HANDLE_INVALID)
+ {
+ ALOGE ("%s: received invalid handle", fn);
+ goto TheEnd;
+ }
+ else
+ mHandleDatabase.push_back (mTempHandle);
+ }
+ else
+ {
+ ALOGE ("%s: fail register", fn);
+ goto TheEnd;
+ }
+ }
+ retval = true;
+
+TheEnd:
+ ALOGD ("%s: exit; ok=%u", fn, retval);
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: deleteAllRoutes
+**
+** Description: Delete all AID routes to the host.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool HostAidRouter::deleteAllRoutes ()
+{
+ static const char fn [] = "HostAidRouter::deleteAllRoutes";
+ ALOGD ("%s: enter", fn);
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ bool retval = false;
+
+ if (! mIsFeatureEnabled)
+ {
+ ALOGD ("%s: feature disabled", fn);
+ goto TheEnd;
+ }
+
+ //deregister each registered AID from the stack
+ for (AidHandleDatabase::iterator iter1 = mHandleDatabase.begin(); iter1 != mHandleDatabase.end(); iter1++)
+ {
+ tNFA_HANDLE aidHandle = *iter1;
+ ALOGD ("%s: deregister h=0x%X", fn, aidHandle);
+ SyncEventGuard guard (mDeregisterEvent);
+ nfaStat = NFA_CeDeregisterAidOnDH (aidHandle);
+ if (nfaStat == NFA_STATUS_OK)
+ mDeregisterEvent.wait (); //wait for NFA_CE_DEREGISTERED_EVT
+ else
+ ALOGE ("%s: fail deregister", fn);
+ }
+ mHandleDatabase.clear ();
+ retval = true;
+
+TheEnd:
+ ALOGD ("%s: exit; ok=%u", fn, retval);
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: startRoute
+**
+** Description: Begin to route AID request to the host.
+** aid: Buffer that contains Application ID
+** aidLen: Actual length of the buffer.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool HostAidRouter::startRoute (const UINT8* aid, UINT8 aidLen)
+{
+ static const char fn [] = "HostAidRouter::startRoute";
+ ALOGD ("%s: enter", fn);
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ bool retval = false;
+
+ if (! mIsFeatureEnabled)
+ {
+ ALOGD ("%s: feature disabled", fn);
+ goto TheEnd;
+ }
+
+ {
+ ALOGD ("%s: register AID; len=%u", fn, aidLen);
+ SyncEventGuard guard (mRegisterEvent);
+ mTempHandle = NFA_HANDLE_INVALID;
+ nfaStat = NFA_CeRegisterAidOnDH ((UINT8*) aid, aidLen, stackCallback);
+ if (nfaStat == NFA_STATUS_OK)
+ {
+ mRegisterEvent.wait (); //wait for NFA_CE_REGISTERED_EVT
+ if (mTempHandle == NFA_HANDLE_INVALID)
+ {
+ ALOGE ("%s: received invalid handle", fn);
+ goto TheEnd;
+ }
+ else
+ mHandleDatabase.push_back (mTempHandle);
+ }
+ else
+ {
+ ALOGE ("%s: fail register", fn);
+ goto TheEnd;
+ }
+ }
+
+TheEnd:
+ ALOGD ("%s: exit; ok=%u", fn, retval);
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: stackCallback
+**
+** Description: Receive events from the NFC stack.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void HostAidRouter::stackCallback (UINT8 event, tNFA_CONN_EVT_DATA* eventData)
+{
+ static const char fn [] = "HostAidRouter::stackCallback";
+ ALOGD("%s: event=0x%X", fn, event);
+
+ switch (event)
+ {
+ case NFA_CE_REGISTERED_EVT:
+ {
+ tNFA_CE_REGISTERED& ce_registered = eventData->ce_registered;
+ ALOGD("%s: NFA_CE_REGISTERED_EVT; status=0x%X; h=0x%X", fn, ce_registered.status, ce_registered.handle);
+ SyncEventGuard guard (sHostAidRouter.mRegisterEvent);
+ if (ce_registered.status == NFA_STATUS_OK)
+ sHostAidRouter.mTempHandle = ce_registered.handle;
+ else
+ sHostAidRouter.mTempHandle = NFA_HANDLE_INVALID;
+ sHostAidRouter.mRegisterEvent.notifyOne();
+ }
+ break;
+
+ case NFA_CE_DEREGISTERED_EVT:
+ {
+ tNFA_CE_DEREGISTERED& ce_deregistered = eventData->ce_deregistered;
+ ALOGD("%s: NFA_CE_DEREGISTERED_EVT; h=0x%X", fn, ce_deregistered.handle);
+ SyncEventGuard guard (sHostAidRouter.mDeregisterEvent);
+ sHostAidRouter.mDeregisterEvent.notifyOne();
+ }
+ break;
+
+ case NFA_CE_DATA_EVT:
+ {
+ tNFA_CE_DATA& ce_data = eventData->ce_data;
+ ALOGD("%s: NFA_CE_DATA_EVT; h=0x%X; data len=%u", fn, ce_data.handle, ce_data.len);
+ SecureElement::getInstance().notifyTransactionListenersOfAid ((UINT8 *)"2PAY.SYS.DDF01", 14);
+ }
+ break;
+ }
+}
diff --git a/nci/jni/HostAidRouter.h b/nci/jni/HostAidRouter.h
new file mode 100644
index 0000000..f653aa9
--- /dev/null
+++ b/nci/jni/HostAidRouter.h
@@ -0,0 +1,156 @@
+/*
+ * 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.
+ */
+
+/*
+ * Manage listen-mode AID routing to the host.
+ */
+#pragma once
+#include "SyncEvent.h"
+#include "NfcJniUtil.h"
+#include "RouteDataSet.h"
+#include <vector>
+extern "C"
+{
+ #include "nfa_api.h"
+}
+
+
+class HostAidRouter
+{
+public:
+ /*******************************************************************************
+ **
+ ** Function: getInstance
+ **
+ ** Description: Obtain a reference to the singleton object of HostAidRouter
+ **
+ ** Returns: Reference to HostAidRouter object.
+ **
+ *******************************************************************************/
+ static HostAidRouter& getInstance ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: initialize
+ **
+ ** Description: Initialize all resources.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool initialize ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: addPpseRoute
+ **
+ ** Description: Route Proximity Payment System Environment request
+ ** to the host. This function is called when there is no
+ ** route data.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool addPpseRoute ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: deleteAllRoutes
+ **
+ ** Description: Delete all AID routes to the host.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool deleteAllRoutes ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: isFeatureEnabled
+ **
+ ** Description: Is AID-routing-to-host feature enabled?
+ **
+ ** Returns: True if enabled.
+ **
+ *******************************************************************************/
+ bool isFeatureEnabled () {return mIsFeatureEnabled;};
+
+
+ /*******************************************************************************
+ **
+ ** Function: startRoute
+ **
+ ** Description: Begin to route AID request to the host.
+ ** aid: Buffer that contains Application ID
+ ** aidLen: Actual length of the buffer.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool startRoute (const UINT8* aid, UINT8 aidLen);
+
+
+private:
+ typedef std::vector<tNFA_HANDLE> AidHandleDatabase;
+
+ tNFA_HANDLE mTempHandle;
+ bool mIsFeatureEnabled;
+ static HostAidRouter sHostAidRouter; //singleton object
+ RouteDataSet mRouteDataSet; //route data from xml file
+ SyncEvent mRegisterEvent;
+ SyncEvent mDeregisterEvent;
+ AidHandleDatabase mHandleDatabase; //store all AID handles that are registered with the stack
+
+
+ /*******************************************************************************
+ **
+ ** Function: HostAidRouter
+ **
+ ** Description: Private constructor to prevent public call.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ HostAidRouter ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: ~HostAidRouter
+ **
+ ** Description: Private destructor to prevent public call.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ ~HostAidRouter ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: stackCallback
+ **
+ ** Description: Receive events from the NFC stack.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ static void stackCallback (UINT8 event, tNFA_CONN_EVT_DATA* eventdata);
+};
diff --git a/nci/jni/IntervalTimer.cpp b/nci/jni/IntervalTimer.cpp
new file mode 100644
index 0000000..f71ca8e
--- /dev/null
+++ b/nci/jni/IntervalTimer.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+/*
+ * Asynchronous interval timer.
+ */
+
+#include "IntervalTimer.h"
+#include "OverrideLog.h"
+
+
+IntervalTimer::IntervalTimer()
+{
+ mTimerId = NULL;
+ mCb = NULL;
+}
+
+
+bool IntervalTimer::set(int ms, TIMER_FUNC cb)
+{
+ if (mTimerId == NULL)
+ {
+ if (cb == NULL)
+ return false;
+
+ if (!create(cb))
+ return false;
+ }
+ if (cb != mCb)
+ {
+ kill();
+ if (!create(cb))
+ return false;
+ }
+
+ int stat = 0;
+ struct itimerspec ts;
+ ts.it_value.tv_sec = ms / 1000;
+ ts.it_value.tv_nsec = (ms % 1000) * 1000000;
+
+ ts.it_interval.tv_sec = 0;
+ ts.it_interval.tv_nsec = 0;
+
+ stat = timer_settime(mTimerId, 0, &ts, 0);
+ if (stat == -1)
+ ALOGE("IntervalTimer::set: fail set timer");
+ return stat == 0;
+}
+
+
+IntervalTimer::~IntervalTimer()
+{
+ kill();
+}
+
+
+void IntervalTimer::kill()
+{
+ if (mTimerId == NULL)
+ return;
+
+ timer_delete(mTimerId);
+ mTimerId = NULL;
+ mCb = NULL;
+}
+
+
+bool IntervalTimer::create(TIMER_FUNC cb)
+{
+ struct sigevent se;
+ int stat = 0;
+
+ /*
+ * Set the sigevent structure to cause the signal to be
+ * delivered by creating a new thread.
+ */
+ se.sigev_notify = SIGEV_THREAD;
+ se.sigev_value.sival_ptr = &mTimerId;
+ se.sigev_notify_function = cb;
+ se.sigev_notify_attributes = NULL;
+ mCb = cb;
+ stat = timer_create(CLOCK_MONOTONIC, &se, &mTimerId);
+ if (stat == -1)
+ ALOGE("IntervalTimer::create: fail create timer");
+ return stat == 0;
+}
diff --git a/nci/jni/IntervalTimer.h b/nci/jni/IntervalTimer.h
new file mode 100644
index 0000000..66e345d
--- /dev/null
+++ b/nci/jni/IntervalTimer.h
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+/*
+ * Asynchronous interval timer.
+ */
+
+#include <time.h>
+
+
+class IntervalTimer
+{
+public:
+ typedef void (*TIMER_FUNC) (union sigval);
+
+ IntervalTimer();
+ ~IntervalTimer();
+ bool set(int ms, TIMER_FUNC cb);
+ void kill();
+ bool create(TIMER_FUNC );
+
+private:
+ timer_t mTimerId;
+ TIMER_FUNC mCb;
+};
diff --git a/nci/jni/JavaClassConstants.h b/nci/jni/JavaClassConstants.h
new file mode 100644
index 0000000..30deca9
--- /dev/null
+++ b/nci/jni/JavaClassConstants.h
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+#pragma once
+
+
+namespace android
+{
+ extern jmethodID gCachedNfcManagerNotifyNdefMessageListeners;
+ extern jmethodID gCachedNfcManagerNotifyTransactionListeners;
+ extern jmethodID gCachedNfcManagerNotifyLlcpLinkActivation;
+ extern jmethodID gCachedNfcManagerNotifyLlcpLinkDeactivated;
+ extern jmethodID gCachedNfcManagerNotifySeFieldActivated;
+ extern jmethodID gCachedNfcManagerNotifySeFieldDeactivated;
+ extern jmethodID gCachedNfcManagerNotifySeListenActivated;
+ extern jmethodID gCachedNfcManagerNotifySeListenDeactivated;
+
+ extern const char* gNativeP2pDeviceClassName;
+ extern const char* gNativeLlcpServiceSocketClassName;
+ extern const char* gNativeLlcpConnectionlessSocketClassName;
+ extern const char* gNativeLlcpSocketClassName;
+ extern const char* gNativeNfcTagClassName;
+ extern const char* gNativeNfcManagerClassName;
+ extern const char* gNativeNfcSecureElementClassName;
+}
diff --git a/nci/jni/Mutex.cpp b/nci/jni/Mutex.cpp
new file mode 100644
index 0000000..c0b12c0
--- /dev/null
+++ b/nci/jni/Mutex.cpp
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+
+/*
+ * Encapsulate a mutex for thread synchronization.
+ */
+
+#include "Mutex.h"
+#include "NfcJniUtil.h"
+#include <errno.h>
+
+/*******************************************************************************
+**
+** Function: Mutex
+**
+** Description: Initialize member variables.
+**
+** Returns: None.
+**
+*******************************************************************************/
+Mutex::Mutex ()
+{
+ memset (&mMutex, 0, sizeof(mMutex));
+ int res = pthread_mutex_init (&mMutex, NULL);
+ if (res != 0)
+ {
+ ALOGE ("Mutex::Mutex: fail init; error=0x%X", res);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: ~Mutex
+**
+** Description: Cleanup all resources.
+**
+** Returns: None.
+**
+*******************************************************************************/
+Mutex::~Mutex ()
+{
+ int res = pthread_mutex_destroy (&mMutex);
+ if (res != 0)
+ {
+ ALOGE ("Mutex::~Mutex: fail destroy; error=0x%X", res);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: lock
+**
+** Description: Block the thread and try lock the mutex.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void Mutex::lock ()
+{
+ int res = pthread_mutex_lock (&mMutex);
+ if (res != 0)
+ {
+ ALOGE ("Mutex::lock: fail lock; error=0x%X", res);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: unlock
+**
+** Description: Unlock a mutex to unblock a thread.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void Mutex::unlock ()
+{
+ int res = pthread_mutex_unlock (&mMutex);
+ if (res != 0)
+ {
+ ALOGE ("Mutex::unlock: fail unlock; error=0x%X", res);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: tryLock
+**
+** Description: Try to lock the mutex.
+**
+** Returns: True if the mutex is locked.
+**
+*******************************************************************************/
+bool Mutex::tryLock ()
+{
+ int res = pthread_mutex_trylock (&mMutex);
+ if ((res != 0) && (res != EBUSY))
+ {
+ ALOGE ("Mutex::tryLock: error=0x%X", res);
+ }
+ return res == 0;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeHandle
+**
+** Description: Get the handle of the mutex.
+**
+** Returns: Handle of the mutex.
+**
+*******************************************************************************/
+pthread_mutex_t* Mutex::nativeHandle ()
+{
+ return &mMutex;
+}
+
+
diff --git a/nci/jni/Mutex.h b/nci/jni/Mutex.h
new file mode 100644
index 0000000..45f42de
--- /dev/null
+++ b/nci/jni/Mutex.h
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+/*
+ * Encapsulate a mutex for thread synchronization.
+ */
+
+#pragma once
+#include <pthread.h>
+
+
+class Mutex
+{
+public:
+ /*******************************************************************************
+ **
+ ** Function: Mutex
+ **
+ ** Description: Initialize member variables.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ Mutex ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: ~Mutex
+ **
+ ** Description: Cleanup all resources.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ ~Mutex ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: lock
+ **
+ ** Description: Block the thread and try lock the mutex.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void lock ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: unlock
+ **
+ ** Description: Unlock a mutex to unblock a thread.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void unlock ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: tryLock
+ **
+ ** Description: Try to lock the mutex.
+ **
+ ** Returns: True if the mutex is locked.
+ **
+ *******************************************************************************/
+ bool tryLock ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: nativeHandle
+ **
+ ** Description: Get the handle of the mutex.
+ **
+ ** Returns: Handle of the mutex.
+ **
+ *******************************************************************************/
+ pthread_mutex_t* nativeHandle ();
+
+ class Autolock {
+ public:
+ inline Autolock(Mutex& mutex) : mLock(mutex) { mLock.lock(); }
+ inline Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }
+ inline ~Autolock() { mLock.unlock(); }
+ private:
+ Mutex& mLock;
+ };
+
+
+private:
+ pthread_mutex_t mMutex;
+};
+
+typedef Mutex::Autolock AutoMutex;
diff --git a/nci/jni/NativeLlcpConnectionlessSocket.cpp b/nci/jni/NativeLlcpConnectionlessSocket.cpp
new file mode 100644
index 0000000..ecc57e3
--- /dev/null
+++ b/nci/jni/NativeLlcpConnectionlessSocket.cpp
@@ -0,0 +1,311 @@
+/*
+ * 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 "JavaClassConstants.h"
+extern "C"
+{
+ #include "nfa_api.h"
+ #include "nfa_p2p_api.h"
+}
+
+
+namespace android
+{
+
+
+/*****************************************************************************
+**
+** private variables and functions
+**
+*****************************************************************************/
+static sem_t sConnlessRecvSem;
+static jboolean sConnlessRecvWaitingForData = JNI_FALSE;
+static uint8_t* sConnlessRecvBuf = NULL;
+static uint32_t sConnlessRecvLen = 0;
+static uint32_t sConnlessRecvRemoteSap = 0;
+
+
+/*******************************************************************************
+**
+** Function: nativeLlcpConnectionlessSocket_doSendTo
+**
+** Description: Send data to peer.
+** e: JVM environment.
+** o: Java object.
+** nsap: service access point.
+** data: buffer for data.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+static jboolean nativeLlcpConnectionlessSocket_doSendTo (JNIEnv *e, jobject o, jint nsap, jbyteArray data)
+{
+ tNFA_STATUS status = NFA_STATUS_FAILED;
+ jint handle = 0;
+ uint8_t* buf = NULL;
+ uint32_t len = 0;
+ jclass c = NULL;
+ jfieldID f = NULL;
+
+ ALOGD ("%s: nsap = %d", __FUNCTION__, nsap);
+
+ c = e->GetObjectClass (o);
+ f = e->GetFieldID (c, "mHandle", "I");
+ handle = e->GetIntField (o, f);
+
+ buf = (uint8_t*) e->GetByteArrayElements (data, NULL);
+ len = (uint32_t) e->GetArrayLength (data);
+
+ ALOGD ("NFA_P2pSendUI: len = %d", len);
+ status = NFA_P2pSendUI ((tNFA_HANDLE) handle, nsap, len, buf);
+
+ ALOGD ("%s: NFA_P2pSendUI done, status = %d", __FUNCTION__, status);
+ if (status != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: NFA_P2pSendUI failed, status = %d", __FUNCTION__, status);
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeLlcpConnectionlessSocket_receiveData
+**
+** Description: Receive data from the stack.
+** data: buffer contains data.
+** len: length of data.
+** remoteSap: remote service access point.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nativeLlcpConnectionlessSocket_receiveData (uint8_t* data, uint32_t len, uint32_t remoteSap)
+{
+ ALOGD ("%s: waiting for data = %d, len = %d", __FUNCTION__, sConnlessRecvWaitingForData, len);
+
+ // Sanity...
+ if (sConnlessRecvLen < len)
+ {
+ len = sConnlessRecvLen;
+ }
+
+ if (sConnlessRecvWaitingForData)
+ {
+ sConnlessRecvWaitingForData = JNI_FALSE;
+ sConnlessRecvLen = len;
+ memcpy (sConnlessRecvBuf, data, len);
+ sConnlessRecvRemoteSap = remoteSap;
+
+ sem_post (&sConnlessRecvSem);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: connectionlessCleanup
+**
+** Description: Free resources.
+**
+** Returns: None
+**
+*******************************************************************************/
+static jobject connectionlessCleanup ()
+{
+ sConnlessRecvWaitingForData = JNI_FALSE;
+ sConnlessRecvLen = 0;
+ if (sConnlessRecvBuf != NULL)
+ {
+ free (sConnlessRecvBuf);
+ sConnlessRecvBuf = NULL;
+ }
+ return NULL;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeLlcpConnectionlessSocket_abortWait
+**
+** Description: Abort current operation and unblock threads.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nativeLlcpConnectionlessSocket_abortWait ()
+{
+ sem_post (&sConnlessRecvSem);
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeLlcpConnectionlessSocket_doReceiveFrom
+**
+** Description: Receive data from a peer.
+** e: JVM environment.
+** o: Java object.
+** linkMiu: max info unit
+**
+** Returns: LlcpPacket Java object.
+**
+*******************************************************************************/
+static jobject nativeLlcpConnectionlessSocket_doReceiveFrom (JNIEnv *e, jobject o, jint linkMiu)
+{
+ jbyteArray receivedData = NULL;
+ jobject llcpPacket = NULL;
+ jclass clsLlcpPacket = NULL;
+ jfieldID f = NULL;
+
+ ALOGD ("%s: linkMiu = %d", __FUNCTION__, linkMiu);
+
+ if (sConnlessRecvWaitingForData != JNI_FALSE)
+ {
+ ALOGD ("%s: Already waiting for incoming data", __FUNCTION__);
+ return NULL;
+ }
+
+ sConnlessRecvBuf = (uint8_t*) malloc (linkMiu);
+ if (sConnlessRecvBuf == NULL)
+ {
+ ALOGD ("%s: Failed to allocate %d bytes memory buffer", __FUNCTION__, linkMiu);
+ return NULL;
+ }
+ sConnlessRecvLen = linkMiu;
+
+ // Create the write semaphore
+ if (sem_init (&sConnlessRecvSem, 0, 0) == -1)
+ {
+ ALOGE ("%s: semaphore creation failed (errno=0x%08x)", __FUNCTION__, errno);
+ return connectionlessCleanup ();
+ }
+
+ sConnlessRecvWaitingForData = JNI_TRUE;
+
+ // Wait for sConnlessRecvSem completion status
+ if (sem_wait (&sConnlessRecvSem))
+ {
+ ALOGE ("%s: Failed to wait for write semaphore (errno=0x%08x)", __FUNCTION__, errno);
+ goto TheEnd;
+ }
+
+ // Create new LlcpPacket object
+ if (nfc_jni_cache_object (e, "com/android/nfc/LlcpPacket", &(llcpPacket)) == -1)
+ {
+ ALOGE ("%s: Find LlcpPacket class error", __FUNCTION__);
+ return connectionlessCleanup ();
+ }
+
+ // Get NativeConnectionless class object
+ clsLlcpPacket = e->GetObjectClass (llcpPacket);
+ if (e->ExceptionCheck ())
+ {
+ e->ExceptionClear();
+ ALOGE ("%s: Get Object class error", __FUNCTION__);
+ return connectionlessCleanup ();
+ }
+
+ // Set Llcp Packet remote SAP
+ f = e->GetFieldID (clsLlcpPacket, "mRemoteSap", "I");
+ e->SetIntField (llcpPacket, f, (jbyte) sConnlessRecvRemoteSap);
+
+ // Set Llcp Packet Buffer
+ ALOGD ("%s: Received Llcp packet buffer size = %d\n", __FUNCTION__, sConnlessRecvLen);
+ f = e->GetFieldID (clsLlcpPacket, "mDataBuffer", "[B");
+ receivedData = e->NewByteArray (sConnlessRecvLen);
+ e->SetByteArrayRegion (receivedData, 0, sConnlessRecvLen, (jbyte*) sConnlessRecvBuf);
+ e->SetObjectField (llcpPacket, f, receivedData);
+
+TheEnd:
+ connectionlessCleanup ();
+ if (sem_destroy (&sConnlessRecvSem))
+ {
+ ALOGE ("%s: Failed to destroy sConnlessRecvSem semaphore (errno=0x%08x)", __FUNCTION__, errno);
+ }
+ return llcpPacket;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeLlcpConnectionlessSocket_doClose
+**
+** Description: Close socket.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+static jboolean nativeLlcpConnectionlessSocket_doClose (JNIEnv *e, jobject o)
+{
+ tNFA_STATUS status = NFA_STATUS_FAILED;
+ jint handle = 0;
+ jclass c = NULL;
+ jfieldID f = NULL;
+
+ ALOGD ("%s", __FUNCTION__);
+
+ c = e->GetObjectClass (o);
+ f = e->GetFieldID (c, "mHandle", "I");
+ handle = e->GetIntField (o, f);
+
+ status = NFA_P2pDisconnect ((tNFA_HANDLE) handle, FALSE);
+ if (status != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: disconnect failed, status = %d", __FUNCTION__, status);
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+
+/*****************************************************************************
+**
+** Description: JNI functions
+**
+*****************************************************************************/
+static JNINativeMethod gMethods[] =
+{
+ {"doSendTo", "(I[B)Z", (void*) nativeLlcpConnectionlessSocket_doSendTo},
+ {"doReceiveFrom", "(I)Lcom/android/nfc/LlcpPacket;", (void*) nativeLlcpConnectionlessSocket_doReceiveFrom},
+ {"doClose", "()Z", (void*) nativeLlcpConnectionlessSocket_doClose},
+};
+
+
+/*******************************************************************************
+**
+** Function: register_com_android_nfc_NativeLlcpConnectionlessSocket
+**
+** Description: Regisgter JNI functions with Java Virtual Machine.
+** e: Environment of JVM.
+**
+** Returns: Status of registration.
+**
+*******************************************************************************/
+int register_com_android_nfc_NativeLlcpConnectionlessSocket (JNIEnv *e)
+{
+ return jniRegisterNativeMethods (e, gNativeLlcpConnectionlessSocketClassName, gMethods, NELEM(gMethods));
+}
+
+
+} // android namespace
diff --git a/nci/jni/NativeLlcpServiceSocket.cpp b/nci/jni/NativeLlcpServiceSocket.cpp
new file mode 100644
index 0000000..e1c2bb5
--- /dev/null
+++ b/nci/jni/NativeLlcpServiceSocket.cpp
@@ -0,0 +1,158 @@
+/*
+ * 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 "OverrideLog.h"
+#include "NfcJniUtil.h"
+#include "NfcAdaptation.h"
+#include "PeerToPeer.h"
+#include "JavaClassConstants.h"
+extern "C"
+{
+ #include "nfa_api.h"
+ #include "nfa_p2p_api.h"
+}
+
+
+namespace android
+{
+
+
+/*******************************************************************************
+**
+** Function: nativeLlcpServiceSocket_doAccept
+**
+** Description: Accept a connection request from a peer.
+** e: JVM environment.
+** o: Java object.
+** miu: Maximum information unit.
+** rw: Receive window.
+** linearBufferLength: Not used.
+**
+** Returns: LlcpSocket Java object.
+**
+*******************************************************************************/
+static jobject nativeLlcpServiceSocket_doAccept(JNIEnv *e, jobject o, jint miu, jint rw, jint linearBufferLength)
+{
+ jobject clientSocket = NULL;
+ jclass clsNativeLlcpSocket = NULL;
+ jfieldID f = 0;
+ PeerToPeer::tJNI_HANDLE serverHandle; //handle of the local server
+ bool stat = false;
+ PeerToPeer::tJNI_HANDLE connHandle = PeerToPeer::getInstance().getNewJniHandle ();
+
+ ALOGD ("%s: enter", __FUNCTION__);
+
+ serverHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle (e, o);
+
+ stat = PeerToPeer::getInstance().accept (serverHandle, connHandle, miu, rw);
+
+ if (! stat)
+ {
+ ALOGE ("%s: fail accept", __FUNCTION__);
+ goto TheEnd;
+ }
+
+ /* Create new LlcpSocket object */
+ if (nfc_jni_cache_object(e, gNativeLlcpSocketClassName, &(clientSocket)) == -1)
+ {
+ ALOGE ("%s: fail create NativeLlcpSocket", __FUNCTION__);
+ goto TheEnd;
+ }
+
+ /* Get NativeConnectionOriented class object */
+ clsNativeLlcpSocket = e->GetObjectClass (clientSocket);
+ if (e->ExceptionCheck())
+ {
+ e->ExceptionClear();
+ ALOGE ("%s: get class object error", __FUNCTION__);
+ goto TheEnd;
+ }
+
+ /* Set socket handle */
+ f = e->GetFieldID (clsNativeLlcpSocket, "mHandle", "I");
+ e->SetIntField (clientSocket, f, (jint) connHandle);
+
+ /* Set socket MIU */
+ f = e->GetFieldID (clsNativeLlcpSocket, "mLocalMiu", "I");
+ e->SetIntField (clientSocket, f, (jint)miu);
+
+ /* Set socket RW */
+ f = e->GetFieldID (clsNativeLlcpSocket, "mLocalRw", "I");
+ e->SetIntField (clientSocket, f, (jint)rw);
+
+TheEnd:
+ ALOGD ("%s: exit", __FUNCTION__);
+ return clientSocket;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeLlcpServiceSocket_doClose
+**
+** Description: Close a server socket.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+static jboolean nativeLlcpServiceSocket_doClose(JNIEnv *e, jobject o)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ PeerToPeer::tJNI_HANDLE jniServerHandle = 0;
+ bool stat = false;
+
+ jniServerHandle = nfc_jni_get_nfc_socket_handle (e, o);
+
+ stat = PeerToPeer::getInstance().deregisterServer (jniServerHandle);
+
+ ALOGD ("%s: exit", __FUNCTION__);
+ return JNI_TRUE;
+}
+
+
+/*****************************************************************************
+**
+** Description: JNI functions
+**
+*****************************************************************************/
+static JNINativeMethod gMethods[] =
+{
+ {"doAccept", "(III)Lcom/android/nfc/dhimpl/NativeLlcpSocket;", (void*) nativeLlcpServiceSocket_doAccept},
+ {"doClose", "()Z", (void*) nativeLlcpServiceSocket_doClose},
+};
+
+
+/*******************************************************************************
+**
+** Function: register_com_android_nfc_NativeLlcpServiceSocket
+**
+** Description: Regisgter JNI functions with Java Virtual Machine.
+** e: Environment of JVM.
+**
+** Returns: Status of registration.
+**
+*******************************************************************************/
+int register_com_android_nfc_NativeLlcpServiceSocket (JNIEnv* e)
+{
+ return jniRegisterNativeMethods (e, gNativeLlcpServiceSocketClassName,
+ gMethods, NELEM(gMethods));
+}
+
+
+} //namespace android
+
diff --git a/nci/jni/NativeLlcpSocket.cpp b/nci/jni/NativeLlcpSocket.cpp
new file mode 100644
index 0000000..74a59b9
--- /dev/null
+++ b/nci/jni/NativeLlcpSocket.cpp
@@ -0,0 +1,271 @@
+/*
+ * 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 "OverrideLog.h"
+#include "PeerToPeer.h"
+#include "JavaClassConstants.h"
+
+
+namespace android
+{
+
+
+/*******************************************************************************
+**
+** Function: nativeLlcpSocket_doConnect
+**
+** Description: Establish a connection to the peer.
+** e: JVM environment.
+** o: Java object.
+** nSap: Service access point.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+static jboolean nativeLlcpSocket_doConnect (JNIEnv* e, jobject o, jint nSap)
+{
+ bool stat = false;
+ jboolean retVal = JNI_FALSE;
+
+ ALOGD ("%s: enter; sap=%d", __FUNCTION__, nSap);
+
+ PeerToPeer::tJNI_HANDLE jniHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o);
+
+ stat = PeerToPeer::getInstance().connectConnOriented (jniHandle, nSap);
+
+ if (stat)
+ retVal = JNI_TRUE;
+
+ ALOGD ("%s: exit", __FUNCTION__);
+ return retVal;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeLlcpSocket_doConnectBy
+**
+** Description: Establish a connection to the peer.
+** e: JVM environment.
+** o: Java object.
+** sn: Service name.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+static jboolean nativeLlcpSocket_doConnectBy (JNIEnv* e, jobject o, jstring sn)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ bool stat = false;
+ jboolean retVal = JNI_FALSE;
+
+ PeerToPeer::tJNI_HANDLE jniHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o);
+
+ const char* serviceName = e->GetStringUTFChars (sn, JNI_FALSE); //convert jstring, which is unicode, into char*
+
+ stat = PeerToPeer::getInstance().connectConnOriented (jniHandle, serviceName);
+
+ e->ReleaseStringUTFChars (sn, serviceName); //free the string
+
+ if (stat)
+ retVal = JNI_TRUE;
+
+ ALOGD ("%s: exit", __FUNCTION__);
+ return retVal;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeLlcpSocket_doClose
+**
+** Description: Close socket.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+static jboolean nativeLlcpSocket_doClose(JNIEnv *e, jobject o)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ bool stat = false;
+ jboolean retVal = JNI_FALSE;
+
+ PeerToPeer::tJNI_HANDLE jniHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o);
+
+ stat = PeerToPeer::getInstance().disconnectConnOriented (jniHandle);
+
+ retVal = JNI_TRUE;
+ ALOGD ("%s: exit", __FUNCTION__);
+ return retVal;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeLlcpSocket_doSend
+**
+** Description: Send data to peer.
+** e: JVM environment.
+** o: Java object.
+** data: Buffer of data.
+**
+** Returns: True if sent ok.
+**
+*******************************************************************************/
+static jboolean nativeLlcpSocket_doSend (JNIEnv* e, jobject o, jbyteArray data)
+{
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: enter", __FUNCTION__);
+ uint8_t* dataBuffer = (uint8_t*) e->GetByteArrayElements (data, NULL);
+ uint32_t dataBufferLen = (uint32_t) e->GetArrayLength (data);
+ bool stat = false;
+
+ PeerToPeer::tJNI_HANDLE jniHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o);
+
+ stat = PeerToPeer::getInstance().send (jniHandle, dataBuffer, dataBufferLen);
+
+ e->ReleaseByteArrayElements (data, (jbyte*) dataBuffer, JNI_ABORT);
+
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: exit", __FUNCTION__);
+ return stat ? JNI_TRUE : JNI_FALSE;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeLlcpSocket_doReceive
+**
+** Description: Receive data from peer.
+** e: JVM environment.
+** o: Java object.
+** origBuffer: Buffer to put received data.
+**
+** Returns: Number of bytes received.
+**
+*******************************************************************************/
+static jint nativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray origBuffer)
+{
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: enter", __FUNCTION__);
+ uint8_t* dataBuffer = (uint8_t*) e->GetByteArrayElements (origBuffer, NULL);
+ uint32_t dataBufferLen = (uint32_t) e->GetArrayLength (origBuffer);
+ uint16_t actualLen = 0;
+ bool stat = false;
+ jint retval = 0;
+
+ PeerToPeer::tJNI_HANDLE jniHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o);
+
+ stat = PeerToPeer::getInstance().receive (jniHandle, dataBuffer, dataBufferLen, actualLen);
+
+ if (stat && (actualLen>0))
+ {
+ retval = actualLen;
+ }
+ else
+ retval = -1;
+
+ e->ReleaseByteArrayElements (origBuffer, (jbyte*) dataBuffer, 0);
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: exit; actual len=%d", __FUNCTION__, retval);
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeLlcpSocket_doGetRemoteSocketMIU
+**
+** Description: Get peer's maximum information unit.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: Peer's maximum information unit.
+**
+*******************************************************************************/
+static jint nativeLlcpSocket_doGetRemoteSocketMIU (JNIEnv* e, jobject o)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ bool stat = false;
+
+ PeerToPeer::tJNI_HANDLE jniHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o);
+ jint miu = 0;
+
+ miu = PeerToPeer::getInstance().getRemoteMaxInfoUnit (jniHandle);
+
+ ALOGD ("%s: exit", __FUNCTION__);
+ return miu;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeLlcpSocket_doGetRemoteSocketRW
+**
+** Description: Get peer's receive window size.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: Peer's receive window size.
+**
+*******************************************************************************/
+static jint nativeLlcpSocket_doGetRemoteSocketRW (JNIEnv* e, jobject o)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ bool stat = false;
+ jint rw = 0;
+
+ PeerToPeer::tJNI_HANDLE jniHandle = (PeerToPeer::tJNI_HANDLE) nfc_jni_get_nfc_socket_handle (e,o);
+
+ rw = PeerToPeer::getInstance().getRemoteRecvWindow (jniHandle);
+
+ ALOGD ("%s: exit", __FUNCTION__);
+ return rw;
+}
+
+
+/*****************************************************************************
+**
+** Description: JNI functions
+**
+*****************************************************************************/
+static JNINativeMethod gMethods[] =
+{
+ {"doConnect", "(I)Z", (void * ) nativeLlcpSocket_doConnect},
+ {"doConnectBy", "(Ljava/lang/String;)Z", (void*) nativeLlcpSocket_doConnectBy},
+ {"doClose", "()Z", (void *) nativeLlcpSocket_doClose},
+ {"doSend", "([B)Z", (void *) nativeLlcpSocket_doSend},
+ {"doReceive", "([B)I", (void *) nativeLlcpSocket_doReceive},
+ {"doGetRemoteSocketMiu", "()I", (void *) nativeLlcpSocket_doGetRemoteSocketMIU},
+ {"doGetRemoteSocketRw", "()I", (void *) nativeLlcpSocket_doGetRemoteSocketRW},
+};
+
+
+/*******************************************************************************
+**
+** Function: register_com_android_nfc_NativeLlcpSocket
+**
+** Description: Regisgter JNI functions with Java Virtual Machine.
+** e: Environment of JVM.
+**
+** Returns: Status of registration.
+**
+*******************************************************************************/
+int register_com_android_nfc_NativeLlcpSocket (JNIEnv* e)
+{
+ return jniRegisterNativeMethods (e, gNativeLlcpSocketClassName, gMethods, NELEM(gMethods));
+}
+
+
+} //namespace android
+
diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp
new file mode 100755
index 0000000..f15c92f
--- /dev/null
+++ b/nci/jni/NativeNfcManager.cpp
@@ -0,0 +1,1816 @@
+/*
+ * 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"
+
+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 "nfa_cho_api.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 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);
+}
+
+
+/*****************************************************************************
+**
+** 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 int sConnlessSap = 0;
+static int sConnlessLinkMiu = 0;
+static bool sAbortConnlessWait = false;
+static bool sIsSecElemSelected = false; //has NFC service selected a sec elem
+static UINT8 * sOriginalLptdCfg = NULL;
+static UINT8 sNewLptdCfg[LPTD_PARAM_LEN];
+static UINT32 sConfigUpdated = 0;
+#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)
+
+
+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)
+ 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__);
+ }
+ }
+ 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 and 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;
+ SecureElement::getInstance().notifyListenModeState (false);
+ } else if (sP2pActive) {
+ sP2pActive = false;
+ // Make sure RF field events are re-enabled
+ ALOGD("%s: NFA_ACTIVATED_EVT; is p2p", __FUNCTION__);
+ // Disable RF field events in case of p2p
+ UINT8 nfa_enable_rf_events[] = { 0x01 };
+
+ 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__);
+ }
+ }
+ }
+
+ 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_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)
+{
+ nfc_jni_native_data* nat = NULL;
+ jclass cls = NULL;
+ jobject obj = NULL;
+ jfieldID f = 0;
+
+ ALOGD ("%s: enter", __FUNCTION__);
+
+ 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);
+
+ cls = e->GetObjectClass (o);
+ f = e->GetFieldID (cls, "mNative", "I");
+ e->SetIntField (o, f, (jint)nat);
+
+ /* Initialize native cached references */
+ gCachedNfcManagerNotifyNdefMessageListeners = e->GetMethodID (cls,
+ "notifyNdefMessageListeners", "(Lcom/android/nfc/dhimpl/NativeNfcTag;)V");
+ gCachedNfcManagerNotifyTransactionListeners = e->GetMethodID (cls,
+ "notifyTransactionListeners", "([B)V");
+ gCachedNfcManagerNotifyLlcpLinkActivation = e->GetMethodID (cls,
+ "notifyLlcpLinkActivation", "(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V");
+ gCachedNfcManagerNotifyLlcpLinkDeactivated = e->GetMethodID (cls,
+ "notifyLlcpLinkDeactivated", "(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V");
+ sCachedNfcManagerNotifyTargetDeselected = e->GetMethodID (cls,
+ "notifyTargetDeselected","()V");
+ gCachedNfcManagerNotifySeFieldActivated = e->GetMethodID (cls,
+ "notifySeFieldActivated", "()V");
+ gCachedNfcManagerNotifySeFieldDeactivated = e->GetMethodID (cls,
+ "notifySeFieldDeactivated", "()V");
+ gCachedNfcManagerNotifySeListenActivated = e->GetMethodID (cls,
+ "notifySeListenActivated", "()V");
+ gCachedNfcManagerNotifySeListenDeactivated = e->GetMethodID (cls,
+ "notifySeListenDeactivated", "()V");
+
+ sCachedNfcManagerNotifySeApduReceived = e->GetMethodID(cls,
+ "notifySeApduReceived", "([B)V");
+
+ sCachedNfcManagerNotifySeMifareAccess = e->GetMethodID(cls,
+ "notifySeMifareAccess", "([B)V");
+
+ sCachedNfcManagerNotifySeEmvCardRemoval = e->GetMethodID(cls,
+ "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 && 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_ChoSetTraceLevel (num);
+ NFA_P2pSetTraceLevel (num);
+ NFA_SnepSetTraceLevel (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* e, jobject o)
+{
+ 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);
+
+TheEnd:
+ ALOGD ("%s: exit", __FUNCTION__);
+}
+
+/*******************************************************************************
+**
+** Function nfc_jni_cache_object_local
+**
+** Description Allocates a java object and calls it's constructor
+**
+** Returns -1 on failure, 0 on success
+**
+*******************************************************************************/
+int nfc_jni_cache_object_local (JNIEnv *e, const char *className, jobject *cachedObj)
+{
+ jclass cls = NULL;
+ jobject obj = NULL;
+ jmethodID ctor = 0;
+
+ cls = e->FindClass (className);
+ if(cls == NULL)
+ {
+ ALOGE ("%s: find class error", __FUNCTION__);
+ return -1;
+ }
+
+ ctor = e->GetMethodID (cls, "<init>", "()V");
+ obj = e->NewObject (cls, ctor);
+ if (obj == NULL)
+ {
+ ALOGE ("%s: create object error", __FUNCTION__);
+ return -1;
+ }
+
+ *cachedObj = e->NewLocalRef (obj);
+ if (*cachedObj == NULL)
+ {
+ e->DeleteLocalRef (obj);
+ ALOGE ("%s: global ref error", __FUNCTION__);
+ return -1;
+ }
+ e->DeleteLocalRef (obj);
+ 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 o, jint nSap, jstring sn, jint miu, jint rw, jint linearBufferLength)
+{
+ bool stat = false;
+ jobject serviceSocket = NULL;
+ jclass clsNativeLlcpServiceSocket = NULL;
+ jfieldID f = 0;
+ PeerToPeer::tJNI_HANDLE jniHandle = PeerToPeer::getInstance().getNewJniHandle ();
+ const char* serviceName = e->GetStringUTFChars (sn, JNI_FALSE); //convert jstring, which is unicode, into char*
+ std::string serviceName2 (serviceName);
+
+ e->ReleaseStringUTFChars (sn, serviceName); //free the string
+ ALOGD ("%s: enter: sap=%i; name=%s; miu=%i; rw=%i; buffLen=%i", __FUNCTION__, nSap, serviceName2.c_str(), miu, rw, linearBufferLength);
+
+ /* Create new NativeLlcpServiceSocket object */
+ if (nfc_jni_cache_object(e, gNativeLlcpServiceSocketClassName, &(serviceSocket)) == -1)
+ {
+ ALOGE ("%s: Llcp socket object creation error", __FUNCTION__);
+ return NULL;
+ }
+
+ /* Get NativeLlcpServiceSocket class object */
+ clsNativeLlcpServiceSocket = e->GetObjectClass (serviceSocket);
+ if (e->ExceptionCheck())
+ {
+ e->ExceptionClear();
+ ALOGE("%s: Llcp Socket get object class error", __FUNCTION__);
+ return NULL;
+ }
+
+ if (!PeerToPeer::getInstance().registerServer (jniHandle, serviceName2.c_str()))
+ {
+ ALOGE("%s: RegisterServer error", __FUNCTION__);
+ return NULL;
+ }
+
+ /* Set socket handle to be the same as the NfaHandle*/
+ f = e->GetFieldID (clsNativeLlcpServiceSocket, "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, "mLocalLinearBufferLength", "I");
+ e->SetIntField (serviceSocket, f,(jint)linearBufferLength);
+ ALOGD ("%s: buffer length = %d", __FUNCTION__, linearBufferLength);
+
+ /* Set socket MIU */
+ f = e->GetFieldID (clsNativeLlcpServiceSocket, "mLocalMiu", "I");
+ e->SetIntField (serviceSocket, f,(jint)miu);
+ ALOGD ("%s: MIU = %d", __FUNCTION__, miu);
+
+ /* Set socket RW */
+ f = e->GetFieldID (clsNativeLlcpServiceSocket, "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* e, jobject o)
+{
+ 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* e, jobject o)
+{
+ 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 o, 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);
+ jobject clientSocket = NULL;
+ jclass clsNativeLlcpSocket;
+ jfieldID f;
+ PeerToPeer::tJNI_HANDLE jniHandle = PeerToPeer::getInstance().getNewJniHandle ();
+ bool stat = false;
+
+ stat = PeerToPeer::getInstance().createClient (jniHandle, miu, rw);
+
+ /* Create new NativeLlcpSocket object */
+ if (nfc_jni_cache_object_local(e, gNativeLlcpSocketClassName, &(clientSocket)) == -1)
+ {
+ ALOGE ("%s: fail Llcp socket creation", __FUNCTION__);
+ goto TheEnd;
+ }
+
+ /* Get NativeConnectionless class object */
+ clsNativeLlcpSocket = e->GetObjectClass (clientSocket);
+ if (e->ExceptionCheck())
+ {
+ e->ExceptionClear();
+ ALOGE ("%s: fail get class object", __FUNCTION__);
+ goto TheEnd;
+ }
+
+ /* Set socket SAP */
+ f = e->GetFieldID (clsNativeLlcpSocket, "mSap", "I");
+ e->SetIntField (clientSocket, f, (jint) nSap);
+
+ /* Set socket handle */
+ f = e->GetFieldID (clsNativeLlcpSocket, "mHandle", "I");
+ e->SetIntField (clientSocket, f, (jint) jniHandle);
+
+ /* Set socket MIU */
+ f = e->GetFieldID (clsNativeLlcpSocket, "mLocalMiu", "I");
+ e->SetIntField (clientSocket, f, (jint) miu);
+
+ /* Set socket RW */
+ f = e->GetFieldID (clsNativeLlcpSocket, "mLocalRw", "I");
+ e->SetIntField (clientSocket, f, (jint) rw);
+
+TheEnd:
+ 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 *e, jobject o, 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 o)
+{
+ 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 *e, jobject o)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ bool stat = true;
+
+ PowerSwitch::getInstance ().setLevel (PowerSwitch::FULL_POWER);
+
+ if (sRfEnabled) {
+ // Stop RF Discovery if we were polling
+ startRfDiscovery (false);
+ }
+
+ if (sIsSecElemSelected)
+ {
+ ALOGD ("%s: already selected", __FUNCTION__);
+ goto TheEnd;
+ }
+
+ stat = SecureElement::getInstance().activate (0xABCDEF);
+ if (stat)
+ SecureElement::getInstance().routeToSecureElement ();
+ sIsSecElemSelected = true;
+
+TheEnd:
+ startRfDiscovery (true);
+
+ PowerSwitch::getInstance ().setModeOn (PowerSwitch::SE_ROUTING);
+
+ 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 *e, jobject o)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ bool stat = 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;
+ }
+
+ 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 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 *e, jobject o)
+{
+ ALOGD("%s", __FUNCTION__);
+ return JNI_TRUE;
+}
+
+
+/*******************************************************************************
+**
+** Function: nfcManager_doActivateLlcp
+**
+** Description: Not used.
+**
+** Returns: True
+**
+*******************************************************************************/
+static jboolean nfcManager_doActivateLlcp(JNIEnv *e, jobject o)
+{
+ ALOGD("%s", __FUNCTION__);
+ return JNI_TRUE;
+}
+
+
+/*******************************************************************************
+**
+** Function: nfcManager_doAbort
+**
+** Description: Not used.
+**
+** Returns: None
+**
+*******************************************************************************/
+static void nfcManager_doAbort(JNIEnv *e, jobject o)
+{
+ ALOGE("%s: abort()", __FUNCTION__);
+ abort();
+}
+
+
+/*******************************************************************************
+**
+** Function: nfcManager_doDownload
+**
+** Description: Not used.
+**
+** Returns: True
+**
+*******************************************************************************/
+static jboolean nfcManager_doDownload(JNIEnv *e, jobject o)
+{
+ ALOGD("%s", __FUNCTION__);
+ return JNI_TRUE;
+}
+
+
+/*******************************************************************************
+**
+** Function: nfcManager_doResetTimeouts
+**
+** Description: Not used.
+**
+** Returns: None
+**
+*******************************************************************************/
+static void nfcManager_doResetTimeouts(JNIEnv *e, jobject o)
+{
+ 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 *e, jobject o, 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 *e, jobject o, 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 o)
+{
+ 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 *e, jobject o, 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;
+
+ // Enable the "RC workaround" to allow our stack/firmware to work with a retail
+ // Nexus S that causes IOP issues. Only enable if value exists and set to 1.
+ if (GetNumValue(NAME_USE_NXP_P2P_RC_WORKAROUND, &num, sizeof(num)) && (num == 1))
+ {
+#if (NCI_VERSION > NCI_VERSION_20791B0)
+ UINT8 nfa_dm_rc_workaround[] = { 0x03, 0x0f, 0xab };
+#else
+ UINT8 nfa_dm_rc_workaround[] = { 0x01, 0x0f, 0xab, 0x01 };
+#endif
+
+ ALOGD ("%s: Configure RC work-around", __FUNCTION__);
+ SyncEventGuard guard (sNfaSetConfigEvent);
+ stat = NFA_SetConfig(NCI_PARAM_ID_FW_WORKAROUND, sizeof(nfa_dm_rc_workaround), &nfa_dm_rc_workaround[0]);
+ if (stat == NFA_STATUS_OK)
+ sNfaSetConfigEvent.wait ();
+ }
+
+ // 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 ();
+ }
+
+ // Set configuration to allow UICC to Power off if there is no traffic.
+ if (GetNumValue(NAME_UICC_IDLE_TIMEOUT, &num, sizeof(num)) && (num != 0))
+ {
+ // 61 => The least significant bit of this byte enables the power off when Idle mode.
+ // 00 87 93 03 == > These 4 bytes form a 4 byte value which decides the idle timeout(in us)
+ // value to trigger the uicc deactivation.
+ // e.g. in current example its value is 0x3938700 i.e. 60000000 is 60 seconds.
+ UINT8 swpcfg_param[] = { 0x61, 0x00, 0x82, 0x04, 0x20, 0xA1, 0x07, 0x00,
+ 0x90, 0xD0, 0x03, 0x00, 0x00, 0x87, 0x93, 0x03 };
+
+ ALOGD ("%s: Configure UICC idle-timeout to %lu ms", __FUNCTION__, num);
+
+ // Set the timeout from the .conf file value.
+ num *= 1000;
+ UINT8 * p = &swpcfg_param[12];
+ UINT32_TO_STREAM(p, num)
+
+ SyncEventGuard guard (sNfaSetConfigEvent);
+ stat = NFA_SetConfig(NCI_PARAM_ID_SWPCFG, sizeof(swpcfg_param), &swpcfg_param[0]);
+ if (stat == NFA_STATUS_OK)
+ sNfaSetConfigEvent.wait ();
+ }
+
+ // Set antenna tuning configuration if configured.
+#define PREINIT_DSP_CFG_SIZE 30
+ UINT8 preinit_dsp_param[PREINIT_DSP_CFG_SIZE];
+
+ if (GetStrValue(NAME_PREINIT_DSP_CFG, (char*)&preinit_dsp_param[0], sizeof(preinit_dsp_param)))
+ {
+ SyncEventGuard guard (sNfaSetConfigEvent);
+ stat = NFA_SetConfig(NCI_PARAM_ID_PREINIT_DSP_CFG, sizeof(preinit_dsp_param), &preinit_dsp_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 */
diff --git a/nci/jni/NativeNfcTag.cpp b/nci/jni/NativeNfcTag.cpp
new file mode 100755
index 0000000..0ba7b21
--- /dev/null
+++ b/nci/jni/NativeNfcTag.cpp
@@ -0,0 +1,1507 @@
+/*
+ * 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 <time.h>
+#include <signal.h>
+#include "OverrideLog.h"
+#include "NfcJniUtil.h"
+#include "NfcTag.h"
+#include "config.h"
+#include "Mutex.h"
+#include "IntervalTimer.h"
+#include "JavaClassConstants.h"
+#include "Pn544Interop.h"
+
+extern "C"
+{
+ #include "nfa_api.h"
+ #include "nfa_rw_api.h"
+ #include "ndef_utils.h"
+ #include "rw_api.h"
+}
+namespace android
+{
+ extern nfc_jni_native_data* getNative(JNIEnv *e, jobject o);
+ extern bool nfcManager_isNfcActive();
+ extern int gGeneralTransceiveTimeout;
+}
+
+
+/*****************************************************************************
+**
+** public variables and functions
+**
+*****************************************************************************/
+namespace android
+{
+ bool gIsTagDeactivating = false; // flag for nfa callback indicating we are deactivating for RF interface switch
+ bool gIsSelectingRfInterface = false; // flag for nfa callback indicating we are selecting for RF interface switch
+}
+
+
+/*****************************************************************************
+**
+** private variables and functions
+**
+*****************************************************************************/
+namespace android
+{
+
+
+// Pre-defined tag type values. These must match the values in
+// framework Ndef.java for Google public NFC API.
+#define NDEF_UNKNOWN_TYPE -1
+#define NDEF_TYPE1_TAG 1
+#define NDEF_TYPE2_TAG 2
+#define NDEF_TYPE3_TAG 3
+#define NDEF_TYPE4_TAG 4
+#define NDEF_MIFARE_CLASSIC_TAG 101
+
+#define STATUS_CODE_TARGET_LOST 146 // this error code comes from the service
+
+static uint32_t sCheckNdefCurrentSize = 0;
+static tNFA_STATUS sCheckNdefStatus = 0; //whether tag already contains a NDEF message
+static bool sCheckNdefCapable = false; //whether tag has NDEF capability
+static tNFA_HANDLE sNdefTypeHandlerHandle = NFA_HANDLE_INVALID;
+static tNFA_INTF_TYPE sCurrentRfInterface = NFA_INTERFACE_ISO_DEP;
+static uint8_t* sTransceiveData = NULL;
+static uint32_t sTransceiveDataLen = 0;
+static bool sWaitingForTransceive = false;
+static bool sNeedToSwitchRf = false;
+static Mutex sRfInterfaceMutex;
+static uint32_t sReadDataLen = 0;
+static uint8_t* sReadData = NULL;
+static bool sIsReadingNdefMessage = false;
+static SyncEvent sReadEvent;
+static sem_t sWriteSem;
+static sem_t sFormatSem;
+static SyncEvent sTransceiveEvent;
+static SyncEvent sReconnectEvent;
+static sem_t sCheckNdefSem;
+static sem_t sPresenceCheckSem;
+static sem_t sMakeReadonlySem;
+static IntervalTimer sSwitchBackTimer; // timer used to tell us to switch back to ISO_DEP frame interface
+static jboolean sWriteOk = JNI_FALSE;
+static jboolean sWriteWaitingForComplete = JNI_FALSE;
+static bool sFormatOk = false;
+static jboolean sConnectOk = JNI_FALSE;
+static jboolean sConnectWaitingForComplete = JNI_FALSE;
+static bool sGotDeactivate = false;
+static uint32_t sCheckNdefMaxSize = 0;
+static bool sCheckNdefCardReadOnly = false;
+static jboolean sCheckNdefWaitingForComplete = JNI_FALSE;
+static int sCountTagAway = 0; //count the consecutive number of presence-check failures
+static tNFA_STATUS sMakeReadonlyStatus = NFA_STATUS_FAILED;
+static jboolean sMakeReadonlyWaitingForComplete = JNI_FALSE;
+
+static int reSelect (tNFA_INTF_TYPE rfInterface);
+static bool switchRfInterface(tNFA_INTF_TYPE rfInterface);
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_abortWaits
+**
+** Description: Unblock all thread synchronization objects.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nativeNfcTag_abortWaits ()
+{
+ ALOGD ("%s", __FUNCTION__);
+ {
+ SyncEventGuard g (sReadEvent);
+ sReadEvent.notifyOne ();
+ }
+ sem_post (&sWriteSem);
+ sem_post (&sFormatSem);
+ {
+ SyncEventGuard g (sTransceiveEvent);
+ sTransceiveEvent.notifyOne ();
+ }
+ {
+ SyncEventGuard g (sReconnectEvent);
+ sReconnectEvent.notifyOne ();
+ }
+
+ sem_post (&sCheckNdefSem);
+ sem_post (&sPresenceCheckSem);
+ sem_post (&sMakeReadonlySem);
+}
+
+
+/*******************************************************************************
+**
+** Function: switchBackTimerProc
+**
+** Description: Callback function for interval timer.
+**
+** Returns: None
+**
+*******************************************************************************/
+static void switchBackTimerProc (union sigval)
+{
+ ALOGD ("%s", __FUNCTION__);
+ switchRfInterface(NFA_INTERFACE_ISO_DEP);
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doReadCompleted
+**
+** Description: Receive the completion status of read operation. Called by
+** NFA_READ_CPLT_EVT.
+** status: Status of operation.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nativeNfcTag_doReadCompleted (tNFA_STATUS status)
+{
+ ALOGD ("%s: status=0x%X; is reading=%u", __FUNCTION__, status, sIsReadingNdefMessage);
+
+ if (sIsReadingNdefMessage == false)
+ return; //not reading NDEF message right now, so just return
+
+ if (status != NFA_STATUS_OK)
+ {
+ sReadDataLen = 0;
+ if (sReadData)
+ free (sReadData);
+ sReadData = NULL;
+ }
+ SyncEventGuard g (sReadEvent);
+ sReadEvent.notifyOne ();
+}
+
+
+/*******************************************************************************
+**
+** Function: ndefHandlerCallback
+**
+** Description: Receive NDEF-message related events from stack.
+** event: Event code.
+** p_data: Event data.
+**
+** Returns: None
+**
+*******************************************************************************/
+static void ndefHandlerCallback (tNFA_NDEF_EVT event, tNFA_NDEF_EVT_DATA *eventData)
+{
+ ALOGD ("%s: event=%u, eventData=%p", __FUNCTION__, event, eventData);
+
+ switch (event)
+ {
+ case NFA_NDEF_REGISTER_EVT:
+ {
+ tNFA_NDEF_REGISTER& ndef_reg = eventData->ndef_reg;
+ ALOGD ("%s: NFA_NDEF_REGISTER_EVT; status=0x%X; h=0x%X", __FUNCTION__, ndef_reg.status, ndef_reg.ndef_type_handle);
+ sNdefTypeHandlerHandle = ndef_reg.ndef_type_handle;
+ }
+ break;
+
+ case NFA_NDEF_DATA_EVT:
+ {
+ ALOGD ("%s: NFA_NDEF_DATA_EVT; data_len = %lu", __FUNCTION__, eventData->ndef_data.len);
+ sReadDataLen = eventData->ndef_data.len;
+ sReadData = (uint8_t*) malloc (sReadDataLen);
+ memcpy (sReadData, eventData->ndef_data.p_data, eventData->ndef_data.len);
+ }
+ break;
+
+ default:
+ ALOGE ("%s: Unknown event %u ????", __FUNCTION__, event);
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doRead
+**
+** Description: Read the NDEF message on the tag.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: NDEF message.
+**
+*******************************************************************************/
+static jbyteArray nativeNfcTag_doRead (JNIEnv *e, jobject o)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ tNFA_STATUS status = NFA_STATUS_FAILED;
+ jbyteArray buf = NULL;
+
+ sReadDataLen = 0;
+ if (sReadData != NULL)
+ {
+ free (sReadData);
+ sReadData = NULL;
+ }
+
+ if (sCheckNdefCurrentSize > 0)
+ {
+ {
+ SyncEventGuard g (sReadEvent);
+ sIsReadingNdefMessage = true;
+ status = NFA_RwReadNDef ();
+ sReadEvent.wait (); //wait for NFA_READ_CPLT_EVT
+ }
+ sIsReadingNdefMessage = false;
+
+ if (sReadDataLen > 0) //if stack actually read data from the tag
+ {
+ ALOGD ("%s: read %u bytes", __FUNCTION__, sReadDataLen);
+ buf = e->NewByteArray (sReadDataLen);
+ e->SetByteArrayRegion (buf, 0, sReadDataLen, (jbyte*) sReadData);
+ }
+ }
+ else
+ {
+ ALOGD ("%s: create emtpy buffer", __FUNCTION__);
+ static uint8_t* empty = (uint8_t*) "";
+ sReadDataLen = 0;
+ sReadData = (uint8_t*) malloc (1);
+ buf = e->NewByteArray (sReadDataLen);
+ e->SetByteArrayRegion (buf, 0, sReadDataLen, (jbyte*) sReadData);
+ }
+
+ if (sReadData)
+ {
+ free (sReadData);
+ sReadData = NULL;
+ }
+ sReadDataLen = 0;
+
+ ALOGD ("%s: exit", __FUNCTION__);
+ return buf;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doWriteStatus
+**
+** Description: Receive the completion status of write operation. Called
+** by NFA_WRITE_CPLT_EVT.
+** isWriteOk: Status of operation.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nativeNfcTag_doWriteStatus (jboolean isWriteOk)
+{
+ if (sWriteWaitingForComplete != JNI_FALSE)
+ {
+ sWriteWaitingForComplete = JNI_FALSE;
+ sWriteOk = isWriteOk;
+ sem_post (&sWriteSem);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_formatStatus
+**
+** Description: Receive the completion status of format operation. Called
+** by NFA_FORMAT_CPLT_EVT.
+** isOk: Status of operation.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nativeNfcTag_formatStatus (bool isOk)
+{
+ sFormatOk = isOk;
+ sem_post (&sFormatSem);
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doWrite
+**
+** Description: Write a NDEF message to the tag.
+** e: JVM environment.
+** o: Java object.
+** buf: Contains a NDEF message.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+static jboolean nativeNfcTag_doWrite (JNIEnv *e, jobject o, jbyteArray buf)
+{
+ jboolean result = JNI_FALSE;
+ tNFA_STATUS status = 0;
+ UINT32 len = 0;
+ UINT8* p_data = NULL;
+ const int maxBufferSize = 1024;
+ UINT8 buffer[maxBufferSize] = { 0 };
+ UINT32 curDataSize = 0;
+
+ len = (UINT32) e->GetArrayLength (buf);
+ p_data = (UINT8*) e->GetByteArrayElements (buf, NULL);
+
+ ALOGD ("%s: enter; len = %lu", __FUNCTION__, len);
+
+ /* Create the write semaphore */
+ if (sem_init (&sWriteSem, 0, 0) == -1)
+ {
+ ALOGE ("%s: semaphore creation failed (errno=0x%08x)", __FUNCTION__, errno);
+ return JNI_FALSE;
+ }
+
+ sWriteWaitingForComplete = JNI_TRUE;
+ if (sCheckNdefStatus == NFA_STATUS_FAILED)
+ {
+ //if tag does not contain a NDEF message
+ //and tag is capable of storing NDEF message
+ if (sCheckNdefCapable)
+ {
+ ALOGD ("%s: try format", __FUNCTION__);
+ sem_init (&sFormatSem, 0, 0);
+ sFormatOk = false;
+ status = NFA_RwFormatTag ();
+ sem_wait (&sFormatSem);
+ sem_destroy (&sFormatSem);
+ if (sFormatOk == false) //if format operation failed
+ goto TheEnd;
+ }
+ ALOGD ("%s: try write", __FUNCTION__);
+ status = NFA_RwWriteNDef (p_data, len);
+ }
+ else if (len == 0)
+ {
+ //if (NXP TagWriter wants to erase tag) then create and write an empty ndef message
+ NDEF_MsgInit (buffer, maxBufferSize, &curDataSize);
+ status = NDEF_MsgAddRec (buffer, maxBufferSize, &curDataSize, NDEF_TNF_EMPTY, NULL, 0, NULL, 0, NULL, 0);
+ ALOGD ("%s: create empty ndef msg; status=%u; size=%lu", __FUNCTION__, status, curDataSize);
+ status = NFA_RwWriteNDef (buffer, curDataSize);
+ }
+ else
+ {
+ ALOGD ("%s: NFA_RwWriteNDef", __FUNCTION__);
+ status = NFA_RwWriteNDef (p_data, len);
+ }
+
+ if (status != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: write/format error=%d", __FUNCTION__, status);
+ goto TheEnd;
+ }
+
+ /* Wait for write completion status */
+ sWriteOk = false;
+ if (sem_wait (&sWriteSem))
+ {
+ ALOGE ("%s: wait semaphore (errno=0x%08x)", __FUNCTION__, errno);
+ goto TheEnd;
+ }
+
+ result = sWriteOk;
+
+TheEnd:
+ /* Destroy semaphore */
+ if (sem_destroy (&sWriteSem))
+ {
+ ALOGE ("%s: failed destroy semaphore (errno=0x%08x)", __FUNCTION__, errno);
+ }
+ sWriteWaitingForComplete = JNI_FALSE;
+ ALOGD ("%s: exit; result=%d", __FUNCTION__, result);
+ return result;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doConnectStatus
+**
+** Description: Receive the completion status of connect operation.
+** isConnectOk: Status of the operation.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nativeNfcTag_doConnectStatus (jboolean isConnectOk)
+{
+ if (sConnectWaitingForComplete != JNI_FALSE)
+ {
+ sConnectWaitingForComplete = JNI_FALSE;
+ sConnectOk = isConnectOk;
+ SyncEventGuard g (sReconnectEvent);
+ sReconnectEvent.notifyOne ();
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doDeactivateStatus
+**
+** Description: Receive the completion status of deactivate operation.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nativeNfcTag_doDeactivateStatus (int status)
+{
+ sGotDeactivate = (status == 0);
+
+ SyncEventGuard g (sReconnectEvent);
+ sReconnectEvent.notifyOne ();
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doConnect
+**
+** Description: Connect to the tag in RF field.
+** e: JVM environment.
+** o: Java object.
+** targetHandle: Handle of the tag.
+**
+** Returns: Must return NXP status code, which NFC service expects.
+**
+*******************************************************************************/
+static jint nativeNfcTag_doConnect (JNIEnv *e, jobject o, jint targetHandle)
+{
+ ALOGD ("%s: targetHandle = %d", __FUNCTION__, targetHandle);
+ int i = targetHandle;
+ struct nfc_jni_native_data *nat = getNative (0, 0);
+ NfcTag& natTag = NfcTag::getInstance ();
+ int retCode = NFCSTATUS_SUCCESS;
+
+ sNeedToSwitchRf = false;
+ if (i >= NfcTag::MAX_NUM_TECHNOLOGY)
+ {
+ ALOGE ("%s: Handle not found", __FUNCTION__);
+ retCode = NFCSTATUS_FAILED;
+ goto TheEnd;
+ }
+
+ if (natTag.getActivationState() != NfcTag::Active)
+ {
+ ALOGE ("%s: tag already deactivated", __FUNCTION__);
+ retCode = NFCSTATUS_FAILED;
+ goto TheEnd;
+ }
+
+ if (natTag.mTechLibNfcTypes[i] != NFC_PROTOCOL_ISO_DEP)
+ {
+ ALOGD ("%s() Nfc type = %d, do nothing for non ISO_DEP", __FUNCTION__, natTag.mTechLibNfcTypes[i]);
+ retCode = NFCSTATUS_SUCCESS;
+ goto TheEnd;
+ }
+
+ if (natTag.mTechList[i] == TARGET_TYPE_ISO14443_3A || natTag.mTechList[i] == TARGET_TYPE_ISO14443_3B)
+ {
+ ALOGD ("%s: switching to tech: %d need to switch rf intf to frame", __FUNCTION__, natTag.mTechList[i]);
+ // connecting to NfcA or NfcB don't actually switch until/unless we get a transceive
+ sNeedToSwitchRf = true;
+ }
+ else
+ {
+ // connecting back to IsoDep or NDEF
+ return (switchRfInterface (NFA_INTERFACE_ISO_DEP) ? NFCSTATUS_SUCCESS : NFCSTATUS_FAILED);
+ }
+
+TheEnd:
+ ALOGD ("%s: exit 0x%X", __FUNCTION__, retCode);
+ return retCode;
+}
+
+/*******************************************************************************
+**
+** Function: reSelect
+**
+** Description: Deactivates the tag and re-selects it with the specified
+** rf interface.
+**
+** Returns: status code, 0 on success, 1 on failure,
+** 146 (defined in service) on tag lost
+**
+*******************************************************************************/
+static int reSelect (tNFA_INTF_TYPE rfInterface)
+{
+ ALOGD ("%s: enter; rf intf = %d", __FUNCTION__, rfInterface);
+ NfcTag& natTag = NfcTag::getInstance ();
+
+ tNFA_STATUS status;
+ int rVal = 1;
+
+ do
+ {
+ //if tag has shutdown, abort this method
+ if (NfcTag::getInstance ().isNdefDetectionTimedOut())
+ {
+ ALOGD ("%s: ndef detection timeout; break", __FUNCTION__);
+ rVal = STATUS_CODE_TARGET_LOST;
+ break;
+ }
+
+ {
+ SyncEventGuard g (sReconnectEvent);
+ gIsTagDeactivating = true;
+ sGotDeactivate = false;
+ ALOGD ("%s: deactivate to sleep", __FUNCTION__);
+ if (NFA_STATUS_OK != (status = NFA_Deactivate (TRUE))) //deactivate to sleep state
+ {
+ ALOGE ("%s: deactivate failed, status = %d", __FUNCTION__, status);
+ break;
+ }
+
+ if (sReconnectEvent.wait (1000) == false) //if timeout occurred
+ {
+ ALOGE ("%s: timeout waiting for deactivate", __FUNCTION__);
+ }
+ }
+
+ if (NfcTag::getInstance ().getActivationState () != NfcTag::Sleep)
+ {
+ ALOGD ("%s: tag is not in sleep", __FUNCTION__);
+ rVal = STATUS_CODE_TARGET_LOST;
+ break;
+ }
+
+ gIsTagDeactivating = false;
+
+ {
+ SyncEventGuard g2 (sReconnectEvent);
+
+ sConnectWaitingForComplete = JNI_TRUE;
+ ALOGD ("%s: select interface %u", __FUNCTION__, rfInterface);
+ gIsSelectingRfInterface = true;
+ if (NFA_STATUS_OK != (status = NFA_Select (natTag.mTechHandles[0], natTag.mTechLibNfcTypes[0], rfInterface)))
+ {
+ ALOGE ("%s: NFA_Select failed, status = %d", __FUNCTION__, status);
+ break;
+ }
+
+ sConnectOk = false;
+ if (sReconnectEvent.wait (1000) == false) //if timeout occured
+ {
+ ALOGE ("%s: timeout waiting for select", __FUNCTION__);
+ break;
+ }
+ }
+
+ ALOGD("%s: select completed; sConnectOk=%d", __FUNCTION__, sConnectOk);
+ if (NfcTag::getInstance ().getActivationState () != NfcTag::Active)
+ {
+ ALOGD("%s: tag is not active", __FUNCTION__);
+ rVal = STATUS_CODE_TARGET_LOST;
+ break;
+ }
+ rVal = (sConnectOk) ? 0 : 1;
+ } while (0);
+
+ sConnectWaitingForComplete = JNI_FALSE;
+ gIsTagDeactivating = false;
+ gIsSelectingRfInterface = false;
+ ALOGD ("%s: exit; status=%d", __FUNCTION__, rVal);
+ return rVal;
+}
+
+/*******************************************************************************
+**
+** Function: switchRfInterface
+**
+** Description: Switch controller's RF interface to frame, ISO-DEP, or NFC-DEP.
+** rfInterface: Type of RF interface.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+static bool switchRfInterface (tNFA_INTF_TYPE rfInterface)
+{
+ ALOGD ("%s: rf intf = %d", __FUNCTION__, rfInterface);
+ NfcTag& natTag = NfcTag::getInstance ();
+
+ if (natTag.mTechLibNfcTypes[0] != NFC_PROTOCOL_ISO_DEP)
+ {
+ ALOGD ("%s: protocol: %d not ISO_DEP, do nothing", __FUNCTION__, natTag.mTechLibNfcTypes[0]);
+ return true;
+ }
+
+ sRfInterfaceMutex.lock ();
+ ALOGD ("%s: new rf intf = %d, cur rf intf = %d", __FUNCTION__, rfInterface, sCurrentRfInterface);
+
+ bool rVal = true;
+ if (rfInterface != sCurrentRfInterface)
+ {
+ if (rVal = (0 == reSelect(rfInterface)))
+ {
+ sCurrentRfInterface = rfInterface;
+ }
+ }
+
+ sRfInterfaceMutex.unlock ();
+ return rVal;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doReconnect
+**
+** Description: Re-connect to the tag in RF field.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: Status code.
+**
+*******************************************************************************/
+static jint nativeNfcTag_doReconnect (JNIEnv *e, jobject o)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ int retCode = NFCSTATUS_SUCCESS;
+ NfcTag& natTag = NfcTag::getInstance ();
+
+ if (natTag.getActivationState() != NfcTag::Active)
+ {
+ ALOGE ("%s: tag already deactivated", __FUNCTION__);
+ retCode = NFCSTATUS_FAILED;
+ goto TheEnd;
+ }
+
+ // this is only supported for type 2 or 4 (ISO_DEP) tags
+ if (natTag.mTechLibNfcTypes[0] == NFA_PROTOCOL_ISO_DEP)
+ retCode = reSelect(NFA_INTERFACE_ISO_DEP);
+ else if (natTag.mTechLibNfcTypes[0] == NFA_PROTOCOL_T2T)
+ retCode = reSelect(NFA_INTERFACE_FRAME);
+
+TheEnd:
+ ALOGD ("%s: exit 0x%X", __FUNCTION__, retCode);
+ return retCode;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doHandleReconnect
+**
+** Description: Re-connect to the tag in RF field.
+** e: JVM environment.
+** o: Java object.
+** targetHandle: Handle of the tag.
+**
+** Returns: Status code.
+**
+*******************************************************************************/
+static jint nativeNfcTag_doHandleReconnect (JNIEnv *e, jobject o, jint targetHandle)
+{
+ ALOGD ("%s: targetHandle = %d", __FUNCTION__, targetHandle);
+ return nativeNfcTag_doConnect (e, o, targetHandle);
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doDisconnect
+**
+** Description: Deactivate the RF field.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+static jboolean nativeNfcTag_doDisconnect (JNIEnv *e, jobject o)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ struct nfc_jni_native_data *nat = getNative (0, 0);
+ tNFA_STATUS nfaStat = NFA_STATUS_OK;
+
+ gGeneralTransceiveTimeout = DEFAULT_GENERAL_TRANS_TIMEOUT;
+
+ if (NfcTag::getInstance ().getActivationState () != NfcTag::Active)
+ {
+ ALOGE ("%s: tag already deactivated", __FUNCTION__);
+ goto TheEnd;
+ }
+
+ nfaStat = NFA_Deactivate (FALSE);
+ if (nfaStat != NFA_STATUS_OK)
+ ALOGE ("%s: deactivate failed; error=0x%X", __FUNCTION__, nfaStat);
+
+TheEnd:
+ ALOGD ("%s: exit", __FUNCTION__);
+ return (nfaStat == NFA_STATUS_OK) ? JNI_TRUE : JNI_FALSE;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doTransceiveStatus
+**
+** Description: Receive the completion status of transceive operation.
+** buf: Contains tag's response.
+** bufLen: Length of buffer.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nativeNfcTag_doTransceiveStatus (uint8_t* buf, uint32_t bufLen)
+{
+ ALOGD ("%s: data len=%d, waiting for transceive: %d", __FUNCTION__, bufLen, sWaitingForTransceive);
+ if (!sWaitingForTransceive)
+ return;
+
+ sTransceiveDataLen = 0;
+ if (bufLen)
+ {
+ if (NULL == (sTransceiveData = (uint8_t *) malloc (bufLen)))
+ {
+ ALOGD ("%s: memory allocation error", __FUNCTION__);
+ }
+ else
+ {
+ memcpy (sTransceiveData, buf, sTransceiveDataLen = bufLen);
+ }
+ }
+
+ {
+ SyncEventGuard g (sTransceiveEvent);
+ sTransceiveEvent.notifyOne ();
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doTransceive
+**
+** Description: Send raw data to the tag; receive tag's response.
+** e: JVM environment.
+** o: Java object.
+** raw: Not used.
+** statusTargetLost: Whether tag responds or times out.
+**
+** Returns: Response from tag.
+**
+*******************************************************************************/
+static jbyteArray nativeNfcTag_doTransceive (JNIEnv *e, jobject o, jbyteArray data, jboolean raw, jintArray statusTargetLost)
+{
+ ALOGD ("%s: enter; raw=%u; timeout = %d", __FUNCTION__, raw, gGeneralTransceiveTimeout);
+ bool fNeedToSwitchBack = false;
+ nfc_jni_native_data *nat = getNative (0, 0);
+ bool waitOk = false;
+ bool isNack = false;
+ uint8_t *buf = NULL;
+ uint32_t bufLen = 0;
+ jint *targetLost = NULL;
+
+ if (NfcTag::getInstance ().getActivationState () != NfcTag::Active)
+ {
+ if (statusTargetLost)
+ {
+ targetLost = e->GetIntArrayElements (statusTargetLost, 0);
+ if (targetLost)
+ *targetLost = 1; //causes NFC service to throw TagLostException
+ e->ReleaseIntArrayElements (statusTargetLost, targetLost, 0);
+ }
+ ALOGD ("%s: tag not active", __FUNCTION__);
+ return NULL;
+ }
+
+ NfcTag& natTag = NfcTag::getInstance ();
+
+ // get input buffer and length from java call
+ buf = (uint8_t *) e->GetByteArrayElements (data, NULL);
+ bufLen = (uint32_t) e->GetArrayLength (data);
+
+ if (statusTargetLost)
+ {
+ targetLost = e->GetIntArrayElements (statusTargetLost, 0);
+ if (targetLost)
+ *targetLost = 0; //success, tag is still present
+ }
+
+ sSwitchBackTimer.kill ();
+ jbyteArray result = NULL;
+ do
+ {
+ if (sNeedToSwitchRf)
+ {
+ // for ISO_DEP tags connected to NfcA or NfcB we need to be in FRAME interface
+ if (!switchRfInterface (NFA_INTERFACE_FRAME)) //NFA_INTERFACE_ISO_DEP
+ {
+ break;
+ }
+ fNeedToSwitchBack = true;
+ }
+
+ sWaitingForTransceive = true;
+ sTransceiveDataLen = 0;
+ {
+ SyncEventGuard g (sTransceiveEvent);
+ tNFA_STATUS status = NFA_SendRawFrame (buf, bufLen);
+ if (status != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: fail send; error=%d", __FUNCTION__, status);
+ break;
+ }
+ waitOk = sTransceiveEvent.wait (gGeneralTransceiveTimeout);
+ }
+
+ if (waitOk == false) //if timeout occurred
+ {
+ ALOGE ("%s: wait response timeout", __FUNCTION__);
+ if (targetLost)
+ *targetLost = 1; //causes NFC service to throw TagLostException
+ break;
+ }
+
+ if (NfcTag::getInstance ().getActivationState () != NfcTag::Active)
+ {
+ ALOGE ("%s: already deactivated", __FUNCTION__);
+ if (targetLost)
+ *targetLost = 1; //causes NFC service to throw TagLostException
+ break;
+ }
+
+ ALOGD ("%s: response %d bytes", __FUNCTION__, sTransceiveDataLen);
+
+ if ((natTag.getProtocol () == NFA_PROTOCOL_T2T) &&
+ natTag.isT2tNackResponse (sTransceiveData, sTransceiveDataLen))
+ {
+ isNack = true;
+ }
+
+ if (sTransceiveDataLen)
+ {
+ if (!isNack) {
+ // marshall data to java for return
+ result = e->NewByteArray (sTransceiveDataLen);
+ if (result != NULL)
+ {
+ e->SetByteArrayRegion (result, 0, sTransceiveDataLen, (jbyte *) sTransceiveData);
+ }
+ else
+ ALOGE ("%s: Failed to allocate java byte array", __FUNCTION__);
+ } // else a nack is treated as a transceive failure to the upper layers
+
+ free (sTransceiveData);
+ sTransceiveData = NULL;
+ sTransceiveDataLen = 0;
+ }
+ } while (0);
+
+ sWaitingForTransceive = false;
+ e->ReleaseByteArrayElements (data, (jbyte *) buf, JNI_ABORT);
+ if (targetLost)
+ e->ReleaseIntArrayElements (statusTargetLost, targetLost, 0);
+
+ if (fNeedToSwitchBack)
+ {
+ // this timer proc will switch us back to ISO_DEP frame interface
+ sSwitchBackTimer.set (1500, switchBackTimerProc);
+ }
+
+ ALOGD ("%s: exit", __FUNCTION__);
+ return result;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doGetNdefType
+**
+** Description: Retrieve the type of tag.
+** e: JVM environment.
+** o: Java object.
+** libnfcType: Type of tag represented by JNI.
+** javaType: Not used.
+**
+** Returns: Type of tag represented by NFC Service.
+**
+*******************************************************************************/
+static jint nativeNfcTag_doGetNdefType (JNIEnv *e, jobject o, jint libnfcType, jint javaType)
+{
+ ALOGD ("%s: enter; libnfc type=%d; java type=%d", __FUNCTION__, libnfcType, javaType);
+ jint ndefType = NDEF_UNKNOWN_TYPE;
+
+ // For NFA, libnfcType is mapped to the protocol value received
+ // in the NFA_ACTIVATED_EVT and NFA_DISC_RESULT_EVT event.
+ switch (libnfcType) {
+ case NFA_PROTOCOL_T1T:
+ ndefType = NDEF_TYPE1_TAG;
+ break;
+ case NFA_PROTOCOL_T2T:
+ ndefType = NDEF_TYPE2_TAG;;
+ break;
+ case NFA_PROTOCOL_T3T:
+ ndefType = NDEF_TYPE3_TAG;
+ break;
+ case NFA_PROTOCOL_ISO_DEP:
+ ndefType = NDEF_TYPE4_TAG;
+ break;
+ case NFA_PROTOCOL_ISO15693:
+ ndefType = NDEF_UNKNOWN_TYPE;
+ break;
+ case NFA_PROTOCOL_INVALID:
+ ndefType = NDEF_UNKNOWN_TYPE;
+ break;
+ default:
+ ndefType = NDEF_UNKNOWN_TYPE;
+ break;
+ }
+ ALOGD ("%s: exit; ndef type=%d", __FUNCTION__, ndefType);
+ return ndefType;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doCheckNdefResult
+**
+** Description: Receive the result of checking whether the tag contains a NDEF
+** message. Called by the NFA_NDEF_DETECT_EVT.
+** status: Status of the operation.
+** maxSize: Maximum size of NDEF message.
+** currentSize: Current size of NDEF message.
+** flags: Indicate various states.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nativeNfcTag_doCheckNdefResult (tNFA_STATUS status, uint32_t maxSize, uint32_t currentSize, uint8_t flags)
+{
+ //this function's flags parameter is defined using the following macros
+ //in nfc/include/rw_api.h;
+ //#define RW_NDEF_FL_READ_ONLY 0x01 /* Tag is read only */
+ //#define RW_NDEF_FL_FORMATED 0x02 /* Tag formated for NDEF */
+ //#define RW_NDEF_FL_SUPPORTED 0x04 /* NDEF supported by the tag */
+ //#define RW_NDEF_FL_UNKNOWN 0x08 /* Unable to find if tag is ndef capable/formated/read only */
+ //#define RW_NDEF_FL_FORMATABLE 0x10 /* Tag supports format operation */
+
+ if (status == NFC_STATUS_BUSY)
+ {
+ ALOGE ("%s: stack is busy", __FUNCTION__);
+ return;
+ }
+
+ if (!sCheckNdefWaitingForComplete)
+ {
+ ALOGE ("%s: not waiting", __FUNCTION__);
+ return;
+ }
+
+ if (flags & RW_NDEF_FL_READ_ONLY)
+ ALOGD ("%s: flag read-only", __FUNCTION__);
+ if (flags & RW_NDEF_FL_FORMATED)
+ ALOGD ("%s: flag formatted for ndef", __FUNCTION__);
+ if (flags & RW_NDEF_FL_SUPPORTED)
+ ALOGD ("%s: flag ndef supported", __FUNCTION__);
+ if (flags & RW_NDEF_FL_UNKNOWN)
+ ALOGD ("%s: flag all unknown", __FUNCTION__);
+ if (flags & RW_NDEF_FL_FORMATABLE)
+ ALOGD ("%s: flag formattable", __FUNCTION__);
+
+ sCheckNdefWaitingForComplete = JNI_FALSE;
+ sCheckNdefStatus = status;
+ sCheckNdefCapable = false; //assume tag is NOT ndef capable
+ if (sCheckNdefStatus == NFA_STATUS_OK)
+ {
+ //NDEF content is on the tag
+ sCheckNdefMaxSize = maxSize;
+ sCheckNdefCurrentSize = currentSize;
+ sCheckNdefCardReadOnly = flags & RW_NDEF_FL_READ_ONLY;
+ sCheckNdefCapable = true;
+ }
+ else if (sCheckNdefStatus == NFA_STATUS_FAILED)
+ {
+ //no NDEF content on the tag
+ sCheckNdefMaxSize = 0;
+ sCheckNdefCurrentSize = 0;
+ sCheckNdefCardReadOnly = flags & RW_NDEF_FL_READ_ONLY;
+ if ((flags & RW_NDEF_FL_UNKNOWN) == 0) //if stack understands the tag
+ {
+ if (flags & RW_NDEF_FL_SUPPORTED) //if tag is ndef capable
+ sCheckNdefCapable = true;
+ }
+ }
+ else
+ {
+ ALOGE ("%s: unknown status=0x%X", __FUNCTION__, status);
+ sCheckNdefMaxSize = 0;
+ sCheckNdefCurrentSize = 0;
+ sCheckNdefCardReadOnly = false;
+ }
+ sem_post (&sCheckNdefSem);
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doCheckNdef
+**
+** Description: Does the tag contain a NDEF message?
+** e: JVM environment.
+** o: Java object.
+** ndefInfo: NDEF info.
+**
+** Returns: Status code; 0 is success.
+**
+*******************************************************************************/
+static jint nativeNfcTag_doCheckNdef (JNIEnv *e, jobject o, jintArray ndefInfo)
+{
+ tNFA_STATUS status = NFA_STATUS_FAILED;
+ jint* ndef = NULL;
+
+ ALOGD ("%s: enter", __FUNCTION__);
+
+ /* Create the write semaphore */
+ if (sem_init (&sCheckNdefSem, 0, 0) == -1)
+ {
+ ALOGE ("%s: Check NDEF semaphore creation failed (errno=0x%08x)", __FUNCTION__, errno);
+ return JNI_FALSE;
+ }
+
+ if (NfcTag::getInstance ().getActivationState () != NfcTag::Active)
+ {
+ ALOGE ("%s: tag already deactivated", __FUNCTION__);
+ goto TheEnd;
+ }
+
+ ALOGD ("%s: try NFA_RwDetectNDef", __FUNCTION__);
+ sCheckNdefWaitingForComplete = JNI_TRUE;
+ status = NFA_RwDetectNDef ();
+
+ if (status != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: NFA_RwDetectNDef failed, status = 0x%X", __FUNCTION__, status);
+ goto TheEnd;
+ }
+
+ /* Wait for check NDEF completion status */
+ if (sem_wait (&sCheckNdefSem))
+ {
+ ALOGE ("%s: Failed to wait for check NDEF semaphore (errno=0x%08x)", __FUNCTION__, errno);
+ goto TheEnd;
+ }
+
+ if (sCheckNdefStatus == NFA_STATUS_OK)
+ {
+ //stack found a NDEF message on the tag
+ ndef = e->GetIntArrayElements (ndefInfo, 0);
+ if (NfcTag::getInstance ().getProtocol () == NFA_PROTOCOL_T1T)
+ ndef[0] = NfcTag::getInstance ().getT1tMaxMessageSize ();
+ else
+ ndef[0] = sCheckNdefMaxSize;
+ if (sCheckNdefCardReadOnly)
+ ndef[1] = NDEF_MODE_READ_ONLY;
+ else
+ ndef[1] = NDEF_MODE_READ_WRITE;
+ e->ReleaseIntArrayElements (ndefInfo, ndef, 0);
+ status = NFA_STATUS_OK;
+ }
+ else if (sCheckNdefStatus == NFA_STATUS_FAILED)
+ {
+ //stack did not find a NDEF message on the tag;
+ ndef = e->GetIntArrayElements (ndefInfo, 0);
+ if (NfcTag::getInstance ().getProtocol () == NFA_PROTOCOL_T1T)
+ ndef[0] = NfcTag::getInstance ().getT1tMaxMessageSize ();
+ else
+ ndef[0] = sCheckNdefMaxSize;
+ if (sCheckNdefCardReadOnly)
+ ndef[1] = NDEF_MODE_READ_ONLY;
+ else
+ ndef[1] = NDEF_MODE_READ_WRITE;
+ e->ReleaseIntArrayElements (ndefInfo, ndef, 0);
+ status = NFA_STATUS_FAILED;
+ }
+ else if (sCheckNdefStatus == NFA_STATUS_TIMEOUT)
+ {
+ pn544InteropStopPolling ();
+ status = sCheckNdefStatus;
+ }
+ else
+ {
+ ALOGD ("%s: unknown status 0x%X", __FUNCTION__, sCheckNdefStatus);
+ status = sCheckNdefStatus;
+ }
+
+TheEnd:
+ /* Destroy semaphore */
+ if (sem_destroy (&sCheckNdefSem))
+ {
+ ALOGE ("%s: Failed to destroy check NDEF semaphore (errno=0x%08x)", __FUNCTION__, errno);
+ }
+ sCheckNdefWaitingForComplete = JNI_FALSE;
+ ALOGD ("%s: exit; status=0x%X", __FUNCTION__, status);
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_resetPresenceCheck
+**
+** Description: Reset variables related to presence-check.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nativeNfcTag_resetPresenceCheck ()
+{
+ sCountTagAway = 0;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doPresenceCheckResult
+**
+** Description: Receive the result of presence-check.
+** status: Result of presence-check.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nativeNfcTag_doPresenceCheckResult (tNFA_STATUS status)
+{
+ if (status == NFA_STATUS_OK)
+ sCountTagAway = 0;
+ else
+ sCountTagAway++;
+ if (sCountTagAway > 0)
+ ALOGD ("%s: sCountTagAway=%d", __FUNCTION__, sCountTagAway);
+ sem_post (&sPresenceCheckSem);
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doPresenceCheck
+**
+** Description: Check if the tag is in the RF field.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: True if tag is in RF field.
+**
+*******************************************************************************/
+static jboolean nativeNfcTag_doPresenceCheck (JNIEnv *e, jobject o)
+{
+ ALOGD ("%s", __FUNCTION__);
+ tNFA_STATUS status = NFA_STATUS_OK;
+ jboolean isPresent = JNI_FALSE;
+
+ if (nfcManager_isNfcActive() == false)
+ {
+ ALOGD ("%s: NFC is no longer active.", __FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ if (NfcTag::getInstance ().getActivationState () != NfcTag::Active)
+ {
+ ALOGD ("%s: tag already deactivated", __FUNCTION__);
+ return JNI_FALSE;
+ }
+
+ if (sem_init (&sPresenceCheckSem, 0, 0) == -1)
+ {
+ ALOGE ("%s: semaphore creation failed (errno=0x%08x)", __FUNCTION__, errno);
+ return JNI_FALSE;
+ }
+
+ status = NFA_RwPresenceCheck ();
+ if (status == NFA_STATUS_OK)
+ {
+ if (sem_wait (&sPresenceCheckSem))
+ {
+ ALOGE ("%s: failed to wait (errno=0x%08x)", __FUNCTION__, errno);
+ }
+ else
+ {
+ isPresent = (sCountTagAway > 3) ? JNI_FALSE : JNI_TRUE;
+ }
+ }
+
+ if (sem_destroy (&sPresenceCheckSem))
+ {
+ ALOGE ("Failed to destroy check NDEF semaphore (errno=0x%08x)", errno);
+ }
+
+ if (isPresent == JNI_FALSE)
+ ALOGD ("%s: tag absent ????", __FUNCTION__);
+ return isPresent;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doIsNdefFormatable
+**
+** Description: Can tag be formatted to store NDEF message?
+** e: JVM environment.
+** o: Java object.
+** libNfcType: Type of tag.
+** uidBytes: Tag's unique ID.
+** pollBytes: Data from activation.
+** actBytes: Data from activation.
+**
+** Returns: True if formattable.
+**
+*******************************************************************************/
+static jboolean nativeNfcTag_doIsNdefFormatable (JNIEnv *e,
+ jobject o, jint libNfcType, jbyteArray uidBytes, jbyteArray pollBytes,
+ jbyteArray actBytes)
+{
+ jboolean isFormattable = JNI_FALSE;
+
+ switch (NfcTag::getInstance().getProtocol())
+ {
+ case NFA_PROTOCOL_T1T:
+ case NFA_PROTOCOL_ISO15693:
+ isFormattable = JNI_TRUE;
+ break;
+
+ case NFA_PROTOCOL_T2T:
+ isFormattable = NfcTag::getInstance().isMifareUltralight() ? JNI_TRUE : JNI_FALSE;
+ }
+ ALOGD("%s: is formattable=%u", __FUNCTION__, isFormattable);
+ return isFormattable;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doIsIsoDepNdefFormatable
+**
+** Description: Is ISO-DEP tag formattable?
+** e: JVM environment.
+** o: Java object.
+** pollBytes: Data from activation.
+** actBytes: Data from activation.
+**
+** Returns: True if formattable.
+**
+*******************************************************************************/
+static jboolean nativeNfcTag_doIsIsoDepNdefFormatable (JNIEnv *e, jobject o, jbyteArray pollBytes, jbyteArray actBytes)
+{
+ uint8_t uidFake[] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
+ ALOGD ("%s", __FUNCTION__);
+ jbyteArray uidArray = e->NewByteArray (8);
+ e->SetByteArrayRegion (uidArray, 0, 8, (jbyte*) uidFake);
+ return nativeNfcTag_doIsNdefFormatable (e, o, 0, uidArray, pollBytes, actBytes);
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doNdefFormat
+**
+** Description: Format a tag so it can store NDEF message.
+** e: JVM environment.
+** o: Java object.
+** key: Not used.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+static jboolean nativeNfcTag_doNdefFormat (JNIEnv *e, jobject o, jbyteArray key)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ tNFA_STATUS status = NFA_STATUS_OK;
+
+ sem_init (&sFormatSem, 0, 0);
+ sFormatOk = false;
+ status = NFA_RwFormatTag ();
+ if (status == NFA_STATUS_OK)
+ {
+ ALOGD ("%s: wait for completion", __FUNCTION__);
+ sem_wait (&sFormatSem);
+ status = sFormatOk ? NFA_STATUS_OK : NFA_STATUS_FAILED;
+ }
+ else
+ ALOGE ("%s: error status=%u", __FUNCTION__, status);
+ sem_destroy (&sFormatSem);
+
+ ALOGD ("%s: exit", __FUNCTION__);
+ return (status == NFA_STATUS_OK) ? JNI_TRUE : JNI_FALSE;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doMakeReadonlyResult
+**
+** Description: Receive the result of making a tag read-only. Called by the
+** NFA_SET_TAG_RO_EVT.
+** status: Status of the operation.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nativeNfcTag_doMakeReadonlyResult (tNFA_STATUS status)
+{
+ if (sMakeReadonlyWaitingForComplete != JNI_FALSE)
+ {
+ sMakeReadonlyWaitingForComplete = JNI_FALSE;
+ sMakeReadonlyStatus = status;
+
+ sem_post (&sMakeReadonlySem);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_doMakeReadonly
+**
+** Description: Make the tag read-only.
+** e: JVM environment.
+** o: Java object.
+** key: Key to access the tag.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+static jboolean nativeNfcTag_doMakeReadonly (JNIEnv *e, jobject o, jbyteArray key)
+{
+ jboolean result = JNI_FALSE;
+ tNFA_STATUS status;
+
+ ALOGD ("%s", __FUNCTION__);
+
+ /* Create the make_readonly semaphore */
+ if (sem_init (&sMakeReadonlySem, 0, 0) == -1)
+ {
+ ALOGE ("%s: Make readonly semaphore creation failed (errno=0x%08x)", __FUNCTION__, errno);
+ return JNI_FALSE;
+ }
+
+ sMakeReadonlyWaitingForComplete = JNI_TRUE;
+
+ // Hard-lock the tag (cannot be reverted)
+ status = NFA_RwSetTagReadOnly(TRUE);
+
+ if (status != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: NFA_RwSetTagReadOnly failed, status = %d", __FUNCTION__, status);
+ goto TheEnd;
+ }
+
+ /* Wait for check NDEF completion status */
+ if (sem_wait (&sMakeReadonlySem))
+ {
+ ALOGE ("%s: Failed to wait for make_readonly semaphore (errno=0x%08x)", __FUNCTION__, errno);
+ goto TheEnd;
+ }
+
+ if (sMakeReadonlyStatus == NFA_STATUS_OK)
+ {
+ result = JNI_TRUE;
+ }
+
+TheEnd:
+ /* Destroy semaphore */
+ if (sem_destroy (&sMakeReadonlySem))
+ {
+ ALOGE ("%s: Failed to destroy read_only semaphore (errno=0x%08x)", __FUNCTION__, errno);
+ }
+ sMakeReadonlyWaitingForComplete = JNI_FALSE;
+ return result;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_registerNdefTypeHandler
+**
+** Description: Register a callback to receive NDEF message from the tag
+** from the NFA_NDEF_DATA_EVT.
+**
+** Returns: None
+**
+*******************************************************************************/
+//register a callback to receive NDEF message from the tag
+//from the NFA_NDEF_DATA_EVT;
+void nativeNfcTag_registerNdefTypeHandler ()
+{
+ ALOGD ("%s", __FUNCTION__);
+ sNdefTypeHandlerHandle = NFA_HANDLE_INVALID;
+ NFA_RegisterNDefTypeHandler (TRUE, NFA_TNF_DEFAULT, (UINT8 *) "", 0, ndefHandlerCallback);
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcTag_deregisterNdefTypeHandler
+**
+** Description: No longer need to receive NDEF message from the tag.
+**
+** Returns: None
+**
+*******************************************************************************/
+void nativeNfcTag_deregisterNdefTypeHandler ()
+{
+ ALOGD ("%s", __FUNCTION__);
+ NFA_DeregisterNDefTypeHandler (sNdefTypeHandlerHandle);
+ sNdefTypeHandlerHandle = NFA_HANDLE_INVALID;
+}
+
+
+/*****************************************************************************
+**
+** JNI functions for Android 4.0.3
+**
+*****************************************************************************/
+static JNINativeMethod gMethods[] =
+{
+ {"doConnect", "(I)I", (void *)nativeNfcTag_doConnect},
+ {"doDisconnect", "()Z", (void *)nativeNfcTag_doDisconnect},
+ {"doReconnect", "()I", (void *)nativeNfcTag_doReconnect},
+ {"doHandleReconnect", "(I)I", (void *)nativeNfcTag_doHandleReconnect},
+ {"doTransceive", "([BZ[I)[B", (void *)nativeNfcTag_doTransceive},
+ {"doGetNdefType", "(II)I", (void *)nativeNfcTag_doGetNdefType},
+ {"doCheckNdef", "([I)I", (void *)nativeNfcTag_doCheckNdef},
+ {"doRead", "()[B", (void *)nativeNfcTag_doRead},
+ {"doWrite", "([B)Z", (void *)nativeNfcTag_doWrite},
+ {"doPresenceCheck", "()Z", (void *)nativeNfcTag_doPresenceCheck},
+ {"doIsIsoDepNdefFormatable", "([B[B)Z", (void *)nativeNfcTag_doIsIsoDepNdefFormatable},
+ {"doNdefFormat", "([B)Z", (void *)nativeNfcTag_doNdefFormat},
+ {"doMakeReadonly", "([B)Z", (void *)nativeNfcTag_doMakeReadonly},
+};
+
+
+/*******************************************************************************
+**
+** Function: register_com_android_nfc_NativeNfcTag
+**
+** Description: Regisgter JNI functions with Java Virtual Machine.
+** e: Environment of JVM.
+**
+** Returns: Status of registration.
+**
+*******************************************************************************/
+int register_com_android_nfc_NativeNfcTag (JNIEnv *e)
+{
+ ALOGD ("%s", __FUNCTION__);
+ return jniRegisterNativeMethods (e, gNativeNfcTagClassName, gMethods, NELEM (gMethods));
+}
+
+
+} /* namespace android */
diff --git a/nci/jni/NativeP2pDevice.cpp b/nci/jni/NativeP2pDevice.cpp
new file mode 100644
index 0000000..57f9dad
--- /dev/null
+++ b/nci/jni/NativeP2pDevice.cpp
@@ -0,0 +1,93 @@
+/*
+ * 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 "OverrideLog.h"
+#include "NfcJniUtil.h"
+#include "JavaClassConstants.h"
+
+
+namespace android
+{
+
+
+static jboolean nativeP2pDeviceDoConnect (JNIEnv* e, jobject o)
+{
+ ALOGD ("%s", __FUNCTION__);
+ return JNI_TRUE;
+}
+
+
+static jboolean nativeP2pDeviceDoDisconnect (JNIEnv* e, jobject o)
+{
+ ALOGD ("%s", __FUNCTION__);
+ return JNI_TRUE;
+}
+
+
+static jbyteArray nativeP2pDeviceDoTransceive (JNIEnv* e, jobject o, jbyteArray data)
+{
+ ALOGD ("%s", __FUNCTION__);
+ return NULL;
+}
+
+
+static jbyteArray nativeP2pDeviceDoReceive (JNIEnv* e, jobject o)
+{
+ ALOGD ("%s", __FUNCTION__);
+ return NULL;
+}
+
+
+static jboolean nativeP2pDeviceDoSend (JNIEnv* e, jobject o, jbyteArray buf)
+{
+ ALOGD ("%s", __FUNCTION__);
+ return JNI_TRUE;
+}
+
+
+/*****************************************************************************
+**
+** Description: JNI functions
+**
+*****************************************************************************/
+static JNINativeMethod gMethods[] =
+{
+ {"doConnect", "()Z", (void *) nativeP2pDeviceDoConnect},
+ {"doDisconnect", "()Z", (void *) nativeP2pDeviceDoDisconnect},
+ {"doTransceive", "([B)[B", (void *) nativeP2pDeviceDoTransceive},
+ {"doReceive", "()[B", (void *) nativeP2pDeviceDoReceive},
+ {"doSend", "([B)Z", (void *) nativeP2pDeviceDoSend},
+};
+
+
+/*******************************************************************************
+**
+** Function: register_com_android_nfc_NativeP2pDevice
+**
+** Description: Regisgter JNI functions with Java Virtual Machine.
+** e: Environment of JVM.
+**
+** Returns: Status of registration.
+**
+*******************************************************************************/
+int register_com_android_nfc_NativeP2pDevice (JNIEnv* e)
+{
+ return jniRegisterNativeMethods (e, gNativeP2pDeviceClassName,
+ gMethods, NELEM(gMethods));
+}
+
+
+} // namepspace android
diff --git a/nci/jni/NativeSecureElement.cpp b/nci/jni/NativeSecureElement.cpp
new file mode 100755
index 0000000..1a2a73a
--- /dev/null
+++ b/nci/jni/NativeSecureElement.cpp
@@ -0,0 +1,245 @@
+/*
+ * 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 "OverrideLog.h"
+#include "SecureElement.h"
+#include "JavaClassConstants.h"
+#include "PowerSwitch.h"
+
+
+namespace android
+{
+
+
+extern void com_android_nfc_NfcManager_disableDiscovery (JNIEnv* e, jobject o);
+extern void com_android_nfc_NfcManager_enableDiscovery (JNIEnv* e, jobject o, jint mode);
+extern int gGeneralTransceiveTimeout;
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcSecureElement_doOpenSecureElementConnection
+**
+** Description: Connect to the secure element.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: Handle of secure element. 0 is failure.
+**
+*******************************************************************************/
+static jint nativeNfcSecureElement_doOpenSecureElementConnection (JNIEnv* e, jobject o)
+{
+ ALOGD("%s: enter", __FUNCTION__);
+ bool stat = true;
+ jint secElemHandle = 0;
+ SecureElement &se = SecureElement::getInstance();
+
+ if (se.isActivatedInListenMode()) {
+ ALOGD("Denying SE open due to SE listen mode active");
+ goto TheEnd;
+ }
+
+ if (se.isRfFieldOn()) {
+ ALOGD("Denying SE open due to SE in active RF field");
+ goto TheEnd;
+ }
+ //tell the controller to power up to get ready for sec elem operations
+ PowerSwitch::getInstance ().setLevel (PowerSwitch::FULL_POWER);
+ PowerSwitch::getInstance ().setModeOn (PowerSwitch::SE_CONNECTED);
+
+ //if controller is not routing AND there is no pipe connected,
+ //then turn on the sec elem
+ if (! se.isBusy())
+ stat = se.activate(0);
+
+ if (stat)
+ {
+ //establish a pipe to sec elem
+ stat = se.connectEE();
+ if (stat)
+ secElemHandle = se.mActiveEeHandle;
+ else
+ se.deactivate (0);
+ }
+
+ //if code fails to connect to the secure element, and nothing is active, then
+ //tell the controller to power down
+ if ((!stat) && (! PowerSwitch::getInstance ().setModeOff (PowerSwitch::SE_CONNECTED)))
+ {
+ PowerSwitch::getInstance ().setLevel (PowerSwitch::LOW_POWER);
+ }
+
+TheEnd:
+ ALOGD("%s: exit; return handle=0x%X", __FUNCTION__, secElemHandle);
+ return secElemHandle;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcSecureElement_doDisconnectSecureElementConnection
+**
+** Description: Disconnect from the secure element.
+** e: JVM environment.
+** o: Java object.
+** handle: Handle of secure element.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+static jboolean nativeNfcSecureElement_doDisconnectSecureElementConnection (JNIEnv* e, jobject o, jint handle)
+{
+ ALOGD("%s: enter; handle=0x%04x", __FUNCTION__, handle);
+ bool stat = false;
+
+ stat = SecureElement::getInstance().disconnectEE (handle);
+
+ //if controller is not routing AND there is no pipe connected,
+ //then turn off the sec elem
+ if (! SecureElement::getInstance().isBusy())
+ SecureElement::getInstance().deactivate (handle);
+
+ //if nothing is active after this, then tell the controller to power down
+ if (! PowerSwitch::getInstance ().setModeOff (PowerSwitch::SE_CONNECTED))
+ PowerSwitch::getInstance ().setLevel (PowerSwitch::LOW_POWER);
+
+ ALOGD("%s: exit", __FUNCTION__);
+ return stat ? JNI_TRUE : JNI_FALSE;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcSecureElement_doTransceive
+**
+** Description: Send data to the secure element; retrieve response.
+** e: JVM environment.
+** o: Java object.
+** handle: Secure element's handle.
+** data: Data to send.
+**
+** Returns: Buffer of received data.
+**
+*******************************************************************************/
+static jbyteArray nativeNfcSecureElement_doTransceive (JNIEnv* e, jobject o, jint handle, jbyteArray data)
+{
+ UINT8* buf = NULL;
+ INT32 buflen = 0;
+ const INT32 recvBufferMaxSize = 1024;
+ UINT8 recvBuffer [recvBufferMaxSize];
+ INT32 recvBufferActualSize = 0;
+ jbyteArray result = NULL;
+
+ buf = (UINT8*) e->GetByteArrayElements (data, NULL);
+ buflen = e->GetArrayLength (data);
+
+ ALOGD("%s: enter; handle=0x%X; buf len=%ld", __FUNCTION__, handle, buflen);
+ SecureElement::getInstance().transceive (buf, buflen, recvBuffer, recvBufferMaxSize, recvBufferActualSize, gGeneralTransceiveTimeout);
+
+ //copy results back to java
+ result = e->NewByteArray (recvBufferActualSize);
+ if (result != NULL)
+ {
+ e->SetByteArrayRegion (result, 0, recvBufferActualSize, (jbyte *) recvBuffer);
+ }
+
+ e->ReleaseByteArrayElements (data, (jbyte *) buf, JNI_ABORT);
+ ALOGD("%s: exit: recv len=%ld", __FUNCTION__, recvBufferActualSize);
+ return result;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcSecureElement_doGetUid
+**
+** Description: Get the secure element's unique ID.
+** e: JVM environment.
+** o: Java object.
+** handle: Handle of secure element.
+**
+** Returns: Secure element's unique ID.
+**
+*******************************************************************************/
+static jbyteArray nativeNfcSecureElement_doGetUid (JNIEnv* e, jobject o, jint handle)
+{
+ ALOGD("%s: enter; handle=0x%X", __FUNCTION__, handle);
+ jbyteArray secureElementUid = NULL;
+
+ SecureElement::getInstance ().getUiccId (handle, secureElementUid);
+
+ ALOGD("%s: exit", __FUNCTION__);
+ return secureElementUid;
+}
+
+
+/*******************************************************************************
+**
+** Function: nativeNfcSecureElement_doGetTechList
+**
+** Description: Get a list of technologies that the secure element supports.
+** e: JVM environment.
+** o: Java object.
+** handle: Handle of secure element.
+**
+** Returns: Array of technologies.
+**
+*******************************************************************************/
+static jintArray nativeNfcSecureElement_doGetTechList (JNIEnv* e, jobject o, jint handle)
+{
+ ALOGD("%s: enter; handle=0x%X", __FUNCTION__, handle);
+ jintArray techList = NULL;
+
+ SecureElement::getInstance().getTechnologyList (handle, techList);
+
+ ALOGD("%s: exit", __FUNCTION__);
+ return techList;
+}
+
+
+/*****************************************************************************
+**
+** Description: JNI functions
+**
+*****************************************************************************/
+static JNINativeMethod gMethods[] =
+{
+ {"doNativeOpenSecureElementConnection", "()I", (void *) nativeNfcSecureElement_doOpenSecureElementConnection},
+ {"doNativeDisconnectSecureElementConnection", "(I)Z", (void *) nativeNfcSecureElement_doDisconnectSecureElementConnection},
+ {"doTransceive", "(I[B)[B", (void *) nativeNfcSecureElement_doTransceive},
+ {"doGetUid", "(I)[B", (void *) nativeNfcSecureElement_doGetUid},
+ {"doGetTechList", "(I)[I", (void *) nativeNfcSecureElement_doGetTechList},
+};
+
+
+/*******************************************************************************
+**
+** Function: register_com_android_nfc_NativeNfcSecureElement
+**
+** Description: Regisgter JNI functions with Java Virtual Machine.
+** e: Environment of JVM.
+**
+** Returns: Status of registration.
+**
+*******************************************************************************/
+int register_com_android_nfc_NativeNfcSecureElement(JNIEnv *e)
+{
+ return jniRegisterNativeMethods(e, gNativeNfcSecureElementClassName,
+ gMethods, NELEM(gMethods));
+}
+
+
+} // namespace android
+
diff --git a/nci/jni/NfcJniUtil.cpp b/nci/jni/NfcJniUtil.cpp
new file mode 100755
index 0000000..9921cae
--- /dev/null
+++ b/nci/jni/NfcJniUtil.cpp
@@ -0,0 +1,150 @@
+/*
+ * 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 "NfcJniUtil.h"
+#include <errno.h>
+
+
+/*******************************************************************************
+**
+** Function: JNI_OnLoad
+**
+** Description: Register all JNI functions with Java Virtual Machine.
+** jvm: Java Virtual Machine.
+** reserved: Not used.
+**
+** Returns: JNI version.
+**
+*******************************************************************************/
+jint JNI_OnLoad (JavaVM *jvm, void *reserved)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ JNIEnv *e = NULL;
+
+ // Check JNI version
+ if (jvm->GetEnv ((void **) &e, JNI_VERSION_1_6))
+ return JNI_ERR;
+
+ if (android::register_com_android_nfc_NativeNfcManager (e) == -1)
+ return JNI_ERR;
+ if (android::register_com_android_nfc_NativeLlcpServiceSocket (e) == -1)
+ return JNI_ERR;
+ if (android::register_com_android_nfc_NativeLlcpSocket (e) == -1)
+ return JNI_ERR;
+ if (android::register_com_android_nfc_NativeNfcTag (e) == -1)
+ return JNI_ERR;
+ if (android::register_com_android_nfc_NativeLlcpConnectionlessSocket (e) == -1)
+ return JNI_ERR;
+ if (android::register_com_android_nfc_NativeP2pDevice (e) == -1)
+ return JNI_ERR;
+ if (android::register_com_android_nfc_NativeNfcSecureElement (e) == -1)
+ return JNI_ERR;
+ ALOGD ("%s: exit", __FUNCTION__);
+ return JNI_VERSION_1_6;
+}
+
+
+namespace android
+{
+
+
+/*******************************************************************************
+**
+** Function: nfc_jni_cache_object
+**
+** Description:
+**
+** Returns: Status code.
+**
+*******************************************************************************/
+int nfc_jni_cache_object (JNIEnv *e, const char *className, jobject *cachedObj)
+{
+ jclass cls = NULL;
+ jobject obj = NULL;
+ jmethodID ctor = 0;
+
+ cls = e->FindClass (className);
+ if(cls == NULL)
+ {
+ ALOGE ("%s: find class error", __FUNCTION__);
+ return -1;
+ }
+
+ ctor = e->GetMethodID (cls, "<init>", "()V");
+ obj = e->NewObject (cls, ctor);
+ if (obj == NULL)
+ {
+ ALOGE ("%s: create object error", __FUNCTION__);
+ return -1;
+ }
+
+ *cachedObj = e->NewGlobalRef (obj);
+ if (*cachedObj == NULL)
+ {
+ e->DeleteLocalRef (obj);
+ ALOGE ("%s: global ref error", __FUNCTION__);
+ return -1;
+ }
+ e->DeleteLocalRef (obj);
+ return 0;
+}
+
+
+/*******************************************************************************
+**
+** Function: nfc_jni_get_nfc_socket_handle
+**
+** Description: Get the value of "mHandle" member variable.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: Value of mHandle.
+**
+*******************************************************************************/
+int nfc_jni_get_nfc_socket_handle (JNIEnv *e, jobject o)
+{
+ jclass c = NULL;
+ jfieldID f = 0;
+
+ c = e->GetObjectClass (o);
+ f = e->GetFieldID (c, "mHandle", "I");
+ return e->GetIntField (o, f);
+}
+
+
+/*******************************************************************************
+**
+** Function: nfc_jni_get_nat
+**
+** Description: Get the value of "mNative" member variable.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: Pointer to the value of mNative.
+**
+*******************************************************************************/
+struct nfc_jni_native_data* nfc_jni_get_nat(JNIEnv *e, jobject o)
+{
+ jclass c = NULL;
+ jfieldID f = 0;
+
+ /* Retrieve native structure address */
+ c = e->GetObjectClass(o);
+ f = e->GetFieldID(c, "mNative", "I");
+ return (struct nfc_jni_native_data*)e->GetIntField(o, f);
+}
+
+
+} // namespace android
diff --git a/nci/jni/NfcJniUtil.h b/nci/jni/NfcJniUtil.h
new file mode 100755
index 0000000..8caa0b8
--- /dev/null
+++ b/nci/jni/NfcJniUtil.h
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+#pragma once
+#define LOG_TAG "BrcmNfcJni"
+#include <JNIHelp.h>
+#include <jni.h>
+#include <pthread.h>
+#include <sys/queue.h>
+#include <semaphore.h>
+
+
+/* Discovery modes -- keep in sync with NFCManager.DISCOVERY_MODE_* */
+#define DISCOVERY_MODE_TAG_READER 0
+#define DISCOVERY_MODE_NFCIP1 1
+#define DISCOVERY_MODE_CARD_EMULATION 2
+#define DISCOVERY_MODE_TABLE_SIZE 3
+
+#define DISCOVERY_MODE_DISABLED 0
+#define DISCOVERY_MODE_ENABLED 1
+
+#define MODE_P2P_TARGET 0
+#define MODE_P2P_INITIATOR 1
+
+
+/* Properties values */
+#define PROPERTY_LLCP_LTO 0
+#define PROPERTY_LLCP_MIU 1
+#define PROPERTY_LLCP_WKS 2
+#define PROPERTY_LLCP_OPT 3
+#define PROPERTY_NFC_DISCOVERY_A 4
+#define PROPERTY_NFC_DISCOVERY_B 5
+#define PROPERTY_NFC_DISCOVERY_F 6
+#define PROPERTY_NFC_DISCOVERY_15693 7
+#define PROPERTY_NFC_DISCOVERY_NCFIP 8
+
+
+/* Error codes */
+#define ERROR_BUFFER_TOO_SMALL -12
+#define ERROR_INSUFFICIENT_RESOURCES -9
+
+
+/* Pre-defined tag type values. These must match the values in
+ * Ndef.java in the framework.
+ */
+#define NDEF_UNKNOWN_TYPE -1
+#define NDEF_TYPE1_TAG 1
+#define NDEF_TYPE2_TAG 2
+#define NDEF_TYPE3_TAG 3
+#define NDEF_TYPE4_TAG 4
+#define NDEF_MIFARE_CLASSIC_TAG 101
+
+
+/* Pre-defined card read/write state values. These must match the values in
+ * Ndef.java in the framework.
+ */
+#define NDEF_MODE_READ_ONLY 1
+#define NDEF_MODE_READ_WRITE 2
+#define NDEF_MODE_UNKNOWN 3
+
+
+/* Name strings for target types. These *must* match the values in TagTechnology.java */
+#define TARGET_TYPE_UNKNOWN -1
+#define TARGET_TYPE_ISO14443_3A 1
+#define TARGET_TYPE_ISO14443_3B 2
+#define TARGET_TYPE_ISO14443_4 3
+#define TARGET_TYPE_FELICA 4
+#define TARGET_TYPE_ISO15693 5
+#define TARGET_TYPE_NDEF 6
+#define TARGET_TYPE_NDEF_FORMATABLE 7
+#define TARGET_TYPE_MIFARE_CLASSIC 8
+#define TARGET_TYPE_MIFARE_UL 9
+
+
+//define a few NXP error codes that NFC service expects;
+//see external/libnfc-nxp/src/phLibNfcStatus.h;
+//see external/libnfc-nxp/inc/phNfcStatus.h
+#define NFCSTATUS_SUCCESS (0x0000)
+#define NFCSTATUS_FAILED (0x00FF)
+
+//default general trasceive timeout in millisecond
+#define DEFAULT_GENERAL_TRANS_TIMEOUT 1000
+
+struct nfc_jni_native_data
+{
+ /* Thread handle */
+ pthread_t thread;
+ int running;
+
+ /* Our VM */
+ JavaVM *vm;
+ int env_version;
+
+ /* Reference to the NFCManager instance */
+ jobject manager;
+
+ /* Cached objects */
+ jobject cached_NfcTag;
+ jobject cached_P2pDevice;
+
+ /* Secure Element selected */
+ int seId;
+
+ /* LLCP params */
+ int lto;
+ int miu;
+ int wks;
+ int opt;
+
+ int tech_mask;
+
+ /* Tag detected */
+ jobject tag;
+
+ int tHandle;
+ int tProtocols[16];
+ int handles[16];
+};
+
+
+extern "C"
+{
+ jint JNI_OnLoad(JavaVM *jvm, void *reserved);
+}
+
+
+namespace android
+{
+ int nfc_jni_cache_object (JNIEnv *e, const char *clsname, jobject *cached_obj);
+ int nfc_jni_get_nfc_socket_handle (JNIEnv *e, jobject o);
+ struct nfc_jni_native_data* nfc_jni_get_nat (JNIEnv *e, jobject o);
+ int register_com_android_nfc_NativeNfcManager (JNIEnv *e);
+ int register_com_android_nfc_NativeNfcTag (JNIEnv *e);
+ int register_com_android_nfc_NativeP2pDevice (JNIEnv *e);
+ int register_com_android_nfc_NativeLlcpConnectionlessSocket (JNIEnv *e);
+ int register_com_android_nfc_NativeLlcpServiceSocket (JNIEnv *e);
+ int register_com_android_nfc_NativeLlcpSocket (JNIEnv *e);
+ int register_com_android_nfc_NativeNfcSecureElement (JNIEnv *e);
+} // namespace android
diff --git a/nci/jni/NfcTag.cpp b/nci/jni/NfcTag.cpp
new file mode 100755
index 0000000..b94355f
--- /dev/null
+++ b/nci/jni/NfcTag.cpp
@@ -0,0 +1,1325 @@
+/*
+ * 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.
+ */
+
+/*
+ * Tag-reading, tag-writing operations.
+ */
+#include "OverrideLog.h"
+#include "NfcTag.h"
+#include "JavaClassConstants.h"
+extern "C"
+{
+ #include "rw_int.h"
+}
+
+
+/*******************************************************************************
+**
+** Function: NfcTag
+**
+** Description: Initialize member variables.
+**
+** Returns: None
+**
+*******************************************************************************/
+NfcTag::NfcTag ()
+: mNativeData (NULL),
+ mActivationState (Idle),
+ mProtocol(NFC_PROTOCOL_UNKNOWN),
+ mNumTechList (0),
+ mtT1tMaxMessageSize (0),
+ mReadCompletedStatus (NFA_STATUS_OK),
+ mLastKovioUidLen (0),
+ mNdefDetectionTimedOut (false)
+{
+ memset (mTechList, 0, sizeof(mTechList));
+ memset (mTechHandles, 0, sizeof(mTechHandles));
+ memset (mTechLibNfcTypes, 0, sizeof(mTechLibNfcTypes));
+ memset (mTechParams, 0, sizeof(mTechParams));
+ memset(mLastKovioUid, 0, NFC_KOVIO_MAX_LEN);
+}
+
+
+/*******************************************************************************
+**
+** Function: getInstance
+**
+** Description: Get a reference to the singleton NfcTag object.
+**
+** Returns: Reference to NfcTag object.
+**
+*******************************************************************************/
+NfcTag& NfcTag::getInstance ()
+{
+ static NfcTag tag;
+ return tag;
+}
+
+
+/*******************************************************************************
+**
+** Function: initialize
+**
+** Description: Reset member variables.
+** native: Native data.
+**
+** Returns: None
+**
+*******************************************************************************/
+void NfcTag::initialize (nfc_jni_native_data* native)
+{
+ mNativeData = native;
+ mActivationState = Idle;
+ mProtocol = NFC_PROTOCOL_UNKNOWN;
+ mNumTechList = 0;
+ mtT1tMaxMessageSize = 0;
+ mReadCompletedStatus = NFA_STATUS_OK;
+ resetTechnologies ();
+}
+
+
+/*******************************************************************************
+**
+** Function: abort
+**
+** Description: Unblock all operations.
+**
+** Returns: None
+**
+*******************************************************************************/
+void NfcTag::abort ()
+{
+ SyncEventGuard g (mReadCompleteEvent);
+ mReadCompleteEvent.notifyOne ();
+}
+
+
+/*******************************************************************************
+**
+** Function: getActivationState
+**
+** Description: What is the current state: Idle, Sleep, or Activated.
+**
+** Returns: Idle, Sleep, or Activated.
+**
+*******************************************************************************/
+NfcTag::ActivationState NfcTag::getActivationState ()
+{
+ return mActivationState;
+}
+
+
+/*******************************************************************************
+**
+** Function: setDeactivationState
+**
+** Description: Set the current state: Idle or Sleep.
+** deactivated: state of deactivation.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void NfcTag::setDeactivationState (tNFA_DEACTIVATED& deactivated)
+{
+ static const char fn [] = "NfcTag::setDeactivationState";
+ mActivationState = Idle;
+ mNdefDetectionTimedOut = false;
+ if (deactivated.type == NFA_DEACTIVATE_TYPE_SLEEP)
+ mActivationState = Sleep;
+ ALOGD ("%s: state=%u", fn, mActivationState);
+}
+
+
+/*******************************************************************************
+**
+** Function: setActivationState
+**
+** Description: Set the current state to Active.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void NfcTag::setActivationState ()
+{
+ static const char fn [] = "NfcTag::setActivationState";
+ mNdefDetectionTimedOut = false;
+ mActivationState = Active;
+ ALOGD ("%s: state=%u", fn, mActivationState);
+}
+
+
+/*******************************************************************************
+**
+** Function: getProtocol
+**
+** Description: Get the protocol of the current tag.
+**
+** Returns: Protocol number.
+**
+*******************************************************************************/
+tNFC_PROTOCOL NfcTag::getProtocol()
+{
+ return mProtocol;
+}
+
+/*******************************************************************************
+**
+** Function TimeDiff
+**
+** Description Computes time difference in milliseconds.
+**
+** Returns Time difference in milliseconds
+**
+*******************************************************************************/
+UINT32 TimeDiff(timespec start, timespec end)
+{
+ timespec temp;
+ if ((end.tv_nsec-start.tv_nsec)<0)
+ {
+ temp.tv_sec = end.tv_sec-start.tv_sec-1;
+ temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
+ }
+ else
+ {
+ temp.tv_sec = end.tv_sec-start.tv_sec;
+ temp.tv_nsec = end.tv_nsec-start.tv_nsec;
+ }
+
+ return (temp.tv_sec * 1000) + (temp.tv_nsec / 1000000);
+}
+
+/*******************************************************************************
+**
+** Function: IsSameKovio
+**
+** Description: Checks if tag activate is the same (UID) Kovio tag previously
+** activated. This is needed due to a problem with some Kovio
+** tags re-activating multiple times.
+** activationData: data from activation.
+**
+** Returns: true if the activation is from the same tag previously
+** activated, false otherwise
+**
+*******************************************************************************/
+bool NfcTag::IsSameKovio(tNFA_ACTIVATED& activationData)
+{
+ static const char fn [] = "NfcTag::IsSameKovio";
+ ALOGD ("%s: enter", fn);
+ tNFC_ACTIVATE_DEVT& rfDetail = activationData.activate_ntf;
+
+ if (rfDetail.protocol != NFC_PROTOCOL_KOVIO)
+ return false;
+
+ memcpy (&(mTechParams[0]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param));
+ if (mTechParams [0].mode != NFC_DISCOVERY_TYPE_POLL_KOVIO)
+ return false;
+
+ struct timespec now;
+ clock_gettime(CLOCK_REALTIME, &now);
+
+ bool rVal = false;
+ if (mTechParams[0].param.pk.uid_len == mLastKovioUidLen)
+ {
+ if (memcmp(mLastKovioUid, &mTechParams [0].param.pk.uid, mTechParams[0].param.pk.uid_len) == 0)
+ {
+ //same tag
+ if (TimeDiff(mLastKovioTime, now) < 500)
+ {
+ // same tag within 500 ms, ignore activation
+ rVal = true;
+ }
+ }
+ }
+
+ // save Kovio tag info
+ if (!rVal)
+ {
+ if ((mLastKovioUidLen = mTechParams[0].param.pk.uid_len) > NFC_KOVIO_MAX_LEN)
+ mLastKovioUidLen = NFC_KOVIO_MAX_LEN;
+ memcpy(mLastKovioUid, mTechParams[0].param.pk.uid, mLastKovioUidLen);
+ }
+ mLastKovioTime = now;
+ ALOGD ("%s: exit, is same Kovio=%d", fn, rVal);
+ return rVal;
+}
+
+/*******************************************************************************
+**
+** Function: discoverTechnologies
+**
+** Description: Discover the technologies that NFC service needs by interpreting
+** the data strucutures from the stack.
+** activationData: data from activation.
+**
+** Returns: None
+**
+*******************************************************************************/
+void NfcTag::discoverTechnologies (tNFA_ACTIVATED& activationData)
+{
+ static const char fn [] = "NfcTag::discoverTechnologies (activation)";
+ ALOGD ("%s: enter", fn);
+ tNFC_ACTIVATE_DEVT& rfDetail = activationData.activate_ntf;
+
+ mNumTechList = 0;
+ mTechHandles [mNumTechList] = rfDetail.rf_disc_id;
+ mTechLibNfcTypes [mNumTechList] = rfDetail.protocol;
+
+ //save the stack's data structure for interpretation later
+ memcpy (&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param));
+
+ switch (rfDetail.protocol)
+ {
+ case NFC_PROTOCOL_T1T:
+ mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API
+ break;
+
+ case NFC_PROTOCOL_T2T:
+ mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API
+ // could be MifFare UL or Classic or Kovio
+ {
+ // need to look at first byte of uid to find manuf.
+ tNFC_RF_TECH_PARAMS tech_params;
+ memcpy (&tech_params, &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param));
+
+ if ((tech_params.param.pa.nfcid1[0] == 0x04 && rfDetail.rf_tech_param.param.pa.sel_rsp == 0) ||
+ rfDetail.rf_tech_param.param.pa.sel_rsp == 0x18 ||
+ rfDetail.rf_tech_param.param.pa.sel_rsp == 0x08)
+ {
+ if (rfDetail.rf_tech_param.param.pa.sel_rsp == 0)
+ {
+ mNumTechList++;
+ mTechHandles [mNumTechList] = rfDetail.rf_disc_id;
+ mTechLibNfcTypes [mNumTechList] = rfDetail.protocol;
+ //save the stack's data structure for interpretation later
+ memcpy (&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param));
+ mTechList [mNumTechList] = TARGET_TYPE_MIFARE_UL; //is TagTechnology.MIFARE_ULTRALIGHT by Java API
+ }
+ }
+ }
+ break;
+
+ case NFC_PROTOCOL_T3T:
+ mTechList [mNumTechList] = TARGET_TYPE_FELICA;
+ break;
+
+ case NFC_PROTOCOL_ISO_DEP: //type-4 tag uses technology ISO-DEP and technology A or B
+ mTechList [mNumTechList] = TARGET_TYPE_ISO14443_4; //is TagTechnology.ISO_DEP by Java API
+ if ( (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_A) ||
+ (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_A_ACTIVE) ||
+ (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_A) ||
+ (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE) )
+ {
+ mNumTechList++;
+ mTechHandles [mNumTechList] = rfDetail.rf_disc_id;
+ mTechLibNfcTypes [mNumTechList] = rfDetail.protocol;
+ mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API
+ //save the stack's data structure for interpretation later
+ memcpy (&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param));
+ }
+ else if ( (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_B) ||
+ (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_B_PRIME) ||
+ (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_B) ||
+ (rfDetail.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_B_PRIME) )
+ {
+ mNumTechList++;
+ mTechHandles [mNumTechList] = rfDetail.rf_disc_id;
+ mTechLibNfcTypes [mNumTechList] = rfDetail.protocol;
+ mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3B; //is TagTechnology.NFC_B by Java API
+ //save the stack's data structure for interpretation later
+ memcpy (&(mTechParams[mNumTechList]), &(rfDetail.rf_tech_param), sizeof(rfDetail.rf_tech_param));
+ }
+ break;
+
+ case NFC_PROTOCOL_15693: //is TagTechnology.NFC_V by Java API
+ mTechList [mNumTechList] = TARGET_TYPE_ISO15693;
+ break;
+
+ case NFC_PROTOCOL_KOVIO:
+ ALOGE ("%s: Kovio", fn);
+ mNumTechList--; // no tech classes for Kovio
+ break;
+
+ default:
+ ALOGE ("%s: unknown protocol ????", fn);
+ mTechList [mNumTechList] = TARGET_TYPE_UNKNOWN;
+ break;
+ }
+
+ mNumTechList++;
+ for (int i=0; i < mNumTechList; i++)
+ {
+ ALOGD ("%s: index=%d; tech=%d; handle=%d; nfc type=%d", fn,
+ i, mTechList[i], mTechHandles[i], mTechLibNfcTypes[i]);
+ }
+ ALOGD ("%s: exit", fn);
+}
+
+
+/*******************************************************************************
+**
+** Function: discoverTechnologies
+**
+** Description: Discover the technologies that NFC service needs by interpreting
+** the data strucutures from the stack.
+** discoveryData: data from discovery events(s).
+**
+** Returns: None
+**
+*******************************************************************************/
+void NfcTag::discoverTechnologies (tNFA_DISC_RESULT& discoveryData)
+{
+ static const char fn [] = "NfcTag::discoverTechnologies (discovery)";
+ tNFC_RESULT_DEVT& discovery_ntf = discoveryData.discovery_ntf;
+
+ ALOGD ("%s: enter: rf disc. id=%u; protocol=%u, mNumTechList=%u", fn, discovery_ntf.rf_disc_id, discovery_ntf.protocol, mNumTechList);
+ if (mNumTechList >= MAX_NUM_TECHNOLOGY)
+ {
+ ALOGE ("%s: exceed max=%d", fn, MAX_NUM_TECHNOLOGY);
+ goto TheEnd;
+ }
+ mTechHandles [mNumTechList] = discovery_ntf.rf_disc_id;
+ mTechLibNfcTypes [mNumTechList] = discovery_ntf.protocol;
+
+ //save the stack's data structure for interpretation later
+ memcpy (&(mTechParams[mNumTechList]), &(discovery_ntf.rf_tech_param), sizeof(discovery_ntf.rf_tech_param));
+
+ switch (discovery_ntf.protocol)
+ {
+ case NFC_PROTOCOL_T1T:
+ mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API
+ break;
+
+ case NFC_PROTOCOL_T2T:
+ mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API
+ //type-2 tags are identitical to Mifare Ultralight, so Ultralight is also discovered
+ if (discovery_ntf.rf_tech_param.param.pa.sel_rsp == 0)
+ {
+ // mifare Ultralight
+ mNumTechList++;
+ mTechHandles [mNumTechList] = discovery_ntf.rf_disc_id;
+ mTechLibNfcTypes [mNumTechList] = discovery_ntf.protocol;
+ mTechList [mNumTechList] = TARGET_TYPE_MIFARE_UL; //is TagTechnology.MIFARE_ULTRALIGHT by Java API
+ }
+
+ //save the stack's data structure for interpretation later
+ memcpy (&(mTechParams[mNumTechList]), &(discovery_ntf.rf_tech_param), sizeof(discovery_ntf.rf_tech_param));
+ break;
+
+ case NFC_PROTOCOL_T3T:
+ mTechList [mNumTechList] = TARGET_TYPE_FELICA;
+ break;
+
+ case NFC_PROTOCOL_ISO_DEP: //type-4 tag uses technology ISO-DEP and technology A or B
+ mTechList [mNumTechList] = TARGET_TYPE_ISO14443_4; //is TagTechnology.ISO_DEP by Java API
+ if ( (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_A) ||
+ (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_A_ACTIVE) ||
+ (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_A) ||
+ (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE) )
+ {
+ mNumTechList++;
+ mTechHandles [mNumTechList] = discovery_ntf.rf_disc_id;
+ mTechLibNfcTypes [mNumTechList] = discovery_ntf.protocol;
+ mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3A; //is TagTechnology.NFC_A by Java API
+ //save the stack's data structure for interpretation later
+ memcpy (&(mTechParams[mNumTechList]), &(discovery_ntf.rf_tech_param), sizeof(discovery_ntf.rf_tech_param));
+ }
+ else if ( (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_B) ||
+ (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_B_PRIME) ||
+ (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_B) ||
+ (discovery_ntf.rf_tech_param.mode == NFC_DISCOVERY_TYPE_LISTEN_B_PRIME) )
+ {
+ mNumTechList++;
+ mTechHandles [mNumTechList] = discovery_ntf.rf_disc_id;
+ mTechLibNfcTypes [mNumTechList] = discovery_ntf.protocol;
+ mTechList [mNumTechList] = TARGET_TYPE_ISO14443_3B; //is TagTechnology.NFC_B by Java API
+ //save the stack's data structure for interpretation later
+ memcpy (&(mTechParams[mNumTechList]), &(discovery_ntf.rf_tech_param), sizeof(discovery_ntf.rf_tech_param));
+ }
+ break;
+
+ case NFC_PROTOCOL_15693: //is TagTechnology.NFC_V by Java API
+ mTechList [mNumTechList] = TARGET_TYPE_ISO15693;
+ break;
+
+ default:
+ ALOGE ("%s: unknown protocol ????", fn);
+ mTechList [mNumTechList] = TARGET_TYPE_UNKNOWN;
+ break;
+ }
+
+ mNumTechList++;
+ if (discovery_ntf.more == FALSE)
+ {
+ for (int i=0; i < mNumTechList; i++)
+ {
+ ALOGD ("%s: index=%d; tech=%d; handle=%d; nfc type=%d", fn,
+ i, mTechList[i], mTechHandles[i], mTechLibNfcTypes[i]);
+ }
+ }
+
+TheEnd:
+ ALOGD ("%s: exit", fn);
+}
+
+
+/*******************************************************************************
+**
+** Function: createNativeNfcTag
+**
+** Description: Create a brand new Java NativeNfcTag object;
+** fill the objects's member variables with data;
+** notify NFC service;
+** activationData: data from activation.
+**
+** Returns: None
+**
+*******************************************************************************/
+void NfcTag::createNativeNfcTag (tNFA_ACTIVATED& activationData)
+{
+ static const char fn [] = "NfcTag::createNativeNfcTag";
+ ALOGD ("%s: enter", fn);
+ JNIEnv* e = NULL;
+ jclass tag_cls = NULL;
+ jmethodID ctor = NULL;
+ jobject tag = NULL;
+
+ //acquire a pointer to the Java virtual machine
+ mNativeData->vm->AttachCurrentThread (&e, NULL);
+ if (e == NULL)
+ {
+ ALOGE("%s: jni env is null", fn);
+ goto TheEnd;
+ }
+
+ tag_cls = e->GetObjectClass (mNativeData->cached_NfcTag);
+ if (e->ExceptionCheck())
+ {
+ e->ExceptionClear();
+ ALOGE("%s: failed to get class", fn);
+ goto TheEnd;
+ }
+
+ //create a new Java NativeNfcTag object
+ ctor = e->GetMethodID (tag_cls, "<init>", "()V");
+ tag = e->NewObject (tag_cls, ctor);
+
+ //fill NativeNfcTag's mProtocols, mTechList, mTechHandles, mTechLibNfcTypes
+ fillNativeNfcTagMembers1 (e, tag_cls, tag);
+
+ //fill NativeNfcTag's members: mHandle, mConnectedTechnology
+ fillNativeNfcTagMembers2 (e, tag_cls, tag, activationData);
+
+ //fill NativeNfcTag's members: mTechPollBytes
+ fillNativeNfcTagMembers3 (e, tag_cls, tag, activationData);
+
+ //fill NativeNfcTag's members: mTechActBytes
+ fillNativeNfcTagMembers4 (e, tag_cls, tag, activationData);
+
+ //fill NativeNfcTag's members: mUid
+ fillNativeNfcTagMembers5 (e, tag_cls, tag, activationData);
+
+ if (mNativeData->tag != NULL) {
+ e->DeleteGlobalRef (mNativeData->tag);
+ }
+ mNativeData->tag = e->NewGlobalRef (tag);
+
+ //notify NFC service about this new tag
+ ALOGD ("%s: try notify nfc service", fn);
+ e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifyNdefMessageListeners, tag);
+ if (e->ExceptionCheck())
+ {
+ e->ExceptionClear();
+ ALOGE ("%s: fail notify nfc service", fn);
+ }
+ e->DeleteLocalRef (tag);
+
+TheEnd:
+ mNativeData->vm->DetachCurrentThread ();
+ ALOGD ("%s: exit", fn);
+}
+
+
+/*******************************************************************************
+**
+** Function: fillNativeNfcTagMembers1
+**
+** Description: Fill NativeNfcTag's members: mProtocols, mTechList, mTechHandles, mTechLibNfcTypes.
+** e: JVM environment.
+** tag_cls: Java NativeNfcTag class.
+** tag: Java NativeNfcTag object.
+**
+** Returns: None
+**
+*******************************************************************************/
+void NfcTag::fillNativeNfcTagMembers1 (JNIEnv* e, jclass tag_cls, jobject tag)
+{
+ static const char fn [] = "NfcTag::fillNativeNfcTagMembers1";
+ ALOGD ("%s", fn);
+ jfieldID f = NULL;
+
+ //create objects that represent NativeNfcTag's member variables
+ jintArray techList = e->NewIntArray (mNumTechList);
+ jintArray handleList = e->NewIntArray (mNumTechList);
+ jintArray typeList = e->NewIntArray (mNumTechList);
+
+ jint* technologies = e->GetIntArrayElements (techList, NULL);
+ jint* handles = e->GetIntArrayElements (handleList, NULL);
+ jint* types = e->GetIntArrayElements (typeList, NULL);
+ for (int i = 0; i < mNumTechList; i++)
+ {
+ mNativeData->tProtocols [i] = mTechLibNfcTypes [i];
+ mNativeData->handles [i] = mTechHandles [i];
+ technologies [i] = mTechList [i];
+ handles [i] = mTechHandles [i];
+ types [i] = mTechLibNfcTypes [i];
+ }
+ e->ReleaseIntArrayElements (techList, technologies, 0);
+ e->ReleaseIntArrayElements (handleList, handles, 0);
+ e->ReleaseIntArrayElements (typeList, types, 0);
+
+ f = e->GetFieldID (tag_cls, "mTechList", "[I");
+ e->SetObjectField (tag, f, techList);
+
+ f = e->GetFieldID (tag_cls, "mTechHandles", "[I");
+ e->SetObjectField (tag, f, handleList);
+
+ f = e->GetFieldID (tag_cls, "mTechLibNfcTypes", "[I");
+ e->SetObjectField (tag, f, typeList);
+}
+
+
+/*******************************************************************************
+**
+** Function: fillNativeNfcTagMembers2
+**
+** Description: Fill NativeNfcTag's members: mConnectedTechIndex or mConnectedTechnology.
+** The original Google's implementation is in set_target_pollBytes(
+** in com_android_nfc_NativeNfcTag.cpp;
+** e: JVM environment.
+** tag_cls: Java NativeNfcTag class.
+** tag: Java NativeNfcTag object.
+** activationData: data from activation.
+**
+** Returns: None
+**
+*******************************************************************************/
+//fill NativeNfcTag's members: mHandle, mConnectedTechnology
+void NfcTag::fillNativeNfcTagMembers2 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData)
+{
+ static const char fn [] = "NfcTag::fillNativeNfcTagMembers2";
+ ALOGD ("%s", fn);
+ jfieldID f = NULL;
+
+ f = e->GetFieldID (tag_cls, "mConnectedTechIndex", "I");
+ e->SetIntField (tag, f, (jint) 0);
+}
+
+
+/*******************************************************************************
+**
+** Function: fillNativeNfcTagMembers3
+**
+** Description: Fill NativeNfcTag's members: mTechPollBytes.
+** The original Google's implementation is in set_target_pollBytes(
+** in com_android_nfc_NativeNfcTag.cpp;
+** e: JVM environment.
+** tag_cls: Java NativeNfcTag class.
+** tag: Java NativeNfcTag object.
+** activationData: data from activation.
+**
+** Returns: None
+**
+*******************************************************************************/
+void NfcTag::fillNativeNfcTagMembers3 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData)
+{
+ static const char fn [] = "NfcTag::fillNativeNfcTagMembers3";
+ jfieldID f = NULL;
+ jbyteArray pollBytes = e->NewByteArray (0);
+ jobjectArray techPollBytes = e->NewObjectArray (mNumTechList, e->GetObjectClass(pollBytes), 0);
+ int len = 0;
+
+ for (int i = 0; i < mNumTechList; i++)
+ {
+ ALOGD ("%s: index=%d; rf tech params mode=%u", fn, i, mTechParams [i].mode);
+ switch (mTechParams [i].mode)
+ {
+ case NFC_DISCOVERY_TYPE_POLL_A:
+ case NFC_DISCOVERY_TYPE_POLL_A_ACTIVE:
+ case NFC_DISCOVERY_TYPE_LISTEN_A:
+ case NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE:
+ ALOGD ("%s: tech A", fn);
+ pollBytes = e->NewByteArray (2);
+ e->SetByteArrayRegion (pollBytes, 0, 2,
+ (jbyte*) mTechParams [i].param.pa.sens_res);
+ break;
+
+ case NFC_DISCOVERY_TYPE_POLL_B:
+ case NFC_DISCOVERY_TYPE_POLL_B_PRIME:
+ case NFC_DISCOVERY_TYPE_LISTEN_B:
+ case NFC_DISCOVERY_TYPE_LISTEN_B_PRIME:
+ if (mTechList [i] == TARGET_TYPE_ISO14443_3B) //is TagTechnology.NFC_B by Java API
+ {
+ /*****************
+ see NFC Forum Digital Protocol specification; section 5.6.2;
+ in SENSB_RES response, byte 6 through 9 is Application Data, byte 10-12 or 13 is Protocol Info;
+ used by public API: NfcB.getApplicationData(), NfcB.getProtocolInfo();
+ *****************/
+ ALOGD ("%s: tech B; TARGET_TYPE_ISO14443_3B", fn);
+ len = mTechParams [i].param.pb.sensb_res_len;
+ len = len - 4; //subtract 4 bytes for NFCID0 at byte 2 through 5
+ pollBytes = e->NewByteArray (len);
+ e->SetByteArrayRegion (pollBytes, 0, len, (jbyte*) (mTechParams [i].param.pb.sensb_res+4));
+ }
+ else
+ pollBytes = e->NewByteArray (0);
+ break;
+
+ case NFC_DISCOVERY_TYPE_POLL_F:
+ case NFC_DISCOVERY_TYPE_POLL_F_ACTIVE:
+ case NFC_DISCOVERY_TYPE_LISTEN_F:
+ case NFC_DISCOVERY_TYPE_LISTEN_F_ACTIVE:
+ {
+ /****************
+ see NFC Forum Type 3 Tag Operation Specification; sections 2.3.2, 2.3.1.2;
+ see NFC Forum Digital Protocol Specification; sections 6.6.2;
+ PMm: manufacture parameter; 8 bytes;
+ System Code: 2 bytes;
+ ****************/
+ ALOGD ("%s: tech F", fn);
+ UINT8 result [10]; //return result to NFC service
+ memset (result, 0, sizeof(result));
+ len = 10;
+
+ /****
+ for (int ii = 0; ii < mTechParams [i].param.pf.sensf_res_len; ii++)
+ {
+ ALOGD ("%s: tech F, sendf_res[%d]=%d (0x%x)",
+ fn, ii, mTechParams [i].param.pf.sensf_res[ii],mTechParams [i].param.pf.sensf_res[ii]);
+ }
+ ***/
+ memcpy (result, mTechParams [i].param.pf.sensf_res + 8, 8); //copy PMm
+ if (activationData.params.t3t.num_system_codes > 0) //copy the first System Code
+ {
+ UINT16 systemCode = *(activationData.params.t3t.p_system_codes);
+ result [8] = (UINT8) (systemCode >> 8);
+ result [9] = (UINT8) systemCode;
+ ALOGD ("%s: tech F; sys code=0x%X 0x%X", fn, result [8], result [9]);
+ }
+ pollBytes = e->NewByteArray (len);
+ e->SetByteArrayRegion (pollBytes, 0, len, (jbyte*) result);
+ }
+ break;
+
+ case NFC_DISCOVERY_TYPE_POLL_ISO15693:
+ case NFC_DISCOVERY_TYPE_LISTEN_ISO15693:
+ {
+ ALOGD ("%s: tech iso 15693", fn);
+ //iso 15693 response flags: 1 octet
+ //iso 15693 Data Structure Format Identifier (DSF ID): 1 octet
+ //used by public API: NfcV.getDsfId(), NfcV.getResponseFlags();
+ uint8_t data [2]= {activationData.params.i93.afi, activationData.params.i93.dsfid};
+ pollBytes = e->NewByteArray (2);
+ e->SetByteArrayRegion (pollBytes, 0, 2, (jbyte *) data);
+ }
+ break;
+
+ default:
+ ALOGE ("%s: tech unknown ????", fn);
+ pollBytes = e->NewByteArray(0);
+ break;
+ } //switch: every type of technology
+ e->SetObjectArrayElement (techPollBytes, i, pollBytes);
+ } //for: every technology in the array
+ f = e->GetFieldID (tag_cls, "mTechPollBytes", "[[B");
+ e->SetObjectField (tag, f, techPollBytes);
+}
+
+
+/*******************************************************************************
+**
+** Function: fillNativeNfcTagMembers4
+**
+** Description: Fill NativeNfcTag's members: mTechActBytes.
+** The original Google's implementation is in set_target_activationBytes()
+** in com_android_nfc_NativeNfcTag.cpp;
+** e: JVM environment.
+** tag_cls: Java NativeNfcTag class.
+** tag: Java NativeNfcTag object.
+** activationData: data from activation.
+**
+** Returns: None
+**
+*******************************************************************************/
+void NfcTag::fillNativeNfcTagMembers4 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData)
+{
+ static const char fn [] = "NfcTag::fillNativeNfcTagMembers4";
+ jfieldID f = NULL;
+ jbyteArray actBytes = e->NewByteArray (0);
+ jobjectArray techActBytes = e->NewObjectArray (mNumTechList, e->GetObjectClass(actBytes), 0);
+ jbyteArray uid = NULL;
+ int len = 0;
+
+ for (int i = 0; i < mNumTechList; i++)
+ {
+ ALOGD ("%s: index=%d", fn, i);
+ switch (mTechLibNfcTypes[i])
+ {
+ case NFC_PROTOCOL_T1T:
+ {
+ ALOGD ("%s: T1T; tech A", fn);
+ actBytes = e->NewByteArray (1);
+ e->SetByteArrayRegion (actBytes, 0, 1,
+ (jbyte*) &mTechParams [i].param.pa.sel_rsp);
+ }
+ break;
+
+ case NFC_PROTOCOL_T2T:
+ {
+ ALOGD ("%s: T2T; tech A", fn);
+ actBytes = e->NewByteArray (1);
+ e->SetByteArrayRegion (actBytes, 0, 1,
+ (jbyte*) &mTechParams [i].param.pa.sel_rsp);
+ }
+ break;
+
+ case NFC_PROTOCOL_T3T: //felica
+ {
+ ALOGD ("%s: T3T; felica; tech F", fn);
+ //really, there is no data
+ actBytes = e->NewByteArray (0);
+ }
+ break;
+
+ case NFC_PROTOCOL_ISO_DEP: //t4t
+ {
+ if (mTechList [i] == TARGET_TYPE_ISO14443_4) //is TagTechnology.ISO_DEP by Java API
+ {
+ if ( (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A) ||
+ (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A_ACTIVE) ||
+ (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_A) ||
+ (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE) )
+ {
+ //see NFC Forum Digital Protocol specification, section 11.6.2, "RATS Response"; search for "historical bytes";
+ //copy historical bytes into Java object;
+ //the public API, IsoDep.getHistoricalBytes(), returns this data;
+ if (activationData.activate_ntf.intf_param.type == NFC_INTERFACE_ISO_DEP)
+ {
+ tNFC_INTF_PA_ISO_DEP& pa_iso = activationData.activate_ntf.intf_param.intf_param.pa_iso;
+ ALOGD ("%s: T4T; ISO_DEP for tech A; copy historical bytes; len=%u", fn, pa_iso.his_byte_len);
+ actBytes = e->NewByteArray (pa_iso.his_byte_len);
+ if (pa_iso.his_byte_len > 0)
+ e->SetByteArrayRegion (actBytes, 0, pa_iso.his_byte_len, (jbyte*) (pa_iso.his_byte));
+ }
+ else
+ {
+ ALOGE ("%s: T4T; ISO_DEP for tech A; wrong interface=%u", fn, activationData.activate_ntf.intf_param.type);
+ actBytes = e->NewByteArray (0);
+ }
+ }
+ else if ( (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_B) ||
+ (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_B_PRIME) ||
+ (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_B) ||
+ (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_B_PRIME) )
+ {
+ //see NFC Forum Digital Protocol specification, section 12.6.2, "ATTRIB Response";
+ //copy higher-layer response bytes into Java object;
+ //the public API, IsoDep.getHiLayerResponse(), returns this data;
+ if (activationData.activate_ntf.intf_param.type == NFC_INTERFACE_ISO_DEP)
+ {
+ tNFC_INTF_PB_ISO_DEP& pb_iso = activationData.activate_ntf.intf_param.intf_param.pb_iso;
+ ALOGD ("%s: T4T; ISO_DEP for tech B; copy response bytes; len=%u", fn, pb_iso.hi_info_len);
+ actBytes = e->NewByteArray (pb_iso.hi_info_len);
+ if (pb_iso.hi_info_len > 0)
+ e->SetByteArrayRegion (actBytes, 0, pb_iso.hi_info_len, (jbyte*) (pb_iso.hi_info));
+ }
+ else
+ {
+ ALOGE ("%s: T4T; ISO_DEP for tech B; wrong interface=%u", fn, activationData.activate_ntf.intf_param.type);
+ actBytes = e->NewByteArray (0);
+ }
+ }
+ }
+ else if (mTechList [i] == TARGET_TYPE_ISO14443_3A) //is TagTechnology.NFC_A by Java API
+ {
+ ALOGD ("%s: T4T; tech A", fn);
+ actBytes = e->NewByteArray (1);
+ e->SetByteArrayRegion (actBytes, 0, 1, (jbyte*) &mTechParams [i].param.pa.sel_rsp);
+ }
+ else
+ {
+ actBytes = e->NewByteArray (0);
+ }
+ } //case NFC_PROTOCOL_ISO_DEP: //t4t
+ break;
+
+ case NFC_PROTOCOL_15693:
+ {
+ ALOGD ("%s: tech iso 15693", fn);
+ //iso 15693 response flags: 1 octet
+ //iso 15693 Data Structure Format Identifier (DSF ID): 1 octet
+ //used by public API: NfcV.getDsfId(), NfcV.getResponseFlags();
+ uint8_t data [2]= {activationData.params.i93.afi, activationData.params.i93.dsfid};
+ actBytes = e->NewByteArray (2);
+ e->SetByteArrayRegion (actBytes, 0, 2, (jbyte *) data);
+ }
+ break;
+
+ default:
+ ALOGD ("%s: tech unknown ????", fn);
+ actBytes = e->NewByteArray (0);
+ break;
+ }//switch
+ e->SetObjectArrayElement (techActBytes, i, actBytes);
+ } //for: every technology in the array
+ f = e->GetFieldID (tag_cls, "mTechActBytes", "[[B");
+ e->SetObjectField (tag, f, techActBytes);
+}
+
+
+/*******************************************************************************
+**
+** Function: fillNativeNfcTagMembers5
+**
+** Description: Fill NativeNfcTag's members: mUid.
+** The original Google's implementation is in nfc_jni_Discovery_notification_callback()
+** in com_android_nfc_NativeNfcManager.cpp;
+** e: JVM environment.
+** tag_cls: Java NativeNfcTag class.
+** tag: Java NativeNfcTag object.
+** activationData: data from activation.
+**
+** Returns: None
+**
+*******************************************************************************/
+void NfcTag::fillNativeNfcTagMembers5 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData)
+{
+ static const char fn [] = "NfcTag::fillNativeNfcTagMembers5";
+ jfieldID f = NULL;
+ int len = 0;
+ jbyteArray uid = NULL;
+
+ switch (mTechParams [0].mode)
+ {
+ case NFC_DISCOVERY_TYPE_POLL_KOVIO:
+ ALOGD ("%s: Kovio", fn);
+ len = mTechParams [0].param.pk.uid_len;
+ uid = e->NewByteArray (len);
+ e->SetByteArrayRegion (uid, 0, len,
+ (jbyte*) &mTechParams [0].param.pk.uid);
+ break;
+
+ case NFC_DISCOVERY_TYPE_POLL_A:
+ case NFC_DISCOVERY_TYPE_POLL_A_ACTIVE:
+ case NFC_DISCOVERY_TYPE_LISTEN_A:
+ case NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE:
+ ALOGD ("%s: tech A", fn);
+ len = mTechParams [0].param.pa.nfcid1_len;
+ uid = e->NewByteArray (len);
+ e->SetByteArrayRegion (uid, 0, len,
+ (jbyte*) &mTechParams [0].param.pa.nfcid1);
+ break;
+
+ case NFC_DISCOVERY_TYPE_POLL_B:
+ case NFC_DISCOVERY_TYPE_POLL_B_PRIME:
+ case NFC_DISCOVERY_TYPE_LISTEN_B:
+ case NFC_DISCOVERY_TYPE_LISTEN_B_PRIME:
+ ALOGD ("%s: tech B", fn);
+ uid = e->NewByteArray (NFC_NFCID0_MAX_LEN);
+ e->SetByteArrayRegion (uid, 0, NFC_NFCID0_MAX_LEN,
+ (jbyte*) &mTechParams [0].param.pb.nfcid0);
+ break;
+
+ case NFC_DISCOVERY_TYPE_POLL_F:
+ case NFC_DISCOVERY_TYPE_POLL_F_ACTIVE:
+ case NFC_DISCOVERY_TYPE_LISTEN_F:
+ case NFC_DISCOVERY_TYPE_LISTEN_F_ACTIVE:
+ ALOGD ("%s: tech F", fn);
+ uid = e->NewByteArray (NFC_NFCID2_LEN);
+ e->SetByteArrayRegion (uid, 0, NFC_NFCID2_LEN,
+ (jbyte*) &mTechParams [0].param.pf.nfcid2);
+ break;
+
+ case NFC_DISCOVERY_TYPE_POLL_ISO15693:
+ case NFC_DISCOVERY_TYPE_LISTEN_ISO15693:
+ {
+ ALOGD ("%s: tech iso 15693", fn);
+ jbyte data [I93_UID_BYTE_LEN]; //8 bytes
+ for (int i=0; i<I93_UID_BYTE_LEN; ++i) //reverse the ID
+ data[i] = activationData.params.i93.uid [I93_UID_BYTE_LEN - i - 1];
+ uid = e->NewByteArray (I93_UID_BYTE_LEN);
+ e->SetByteArrayRegion (uid, 0, I93_UID_BYTE_LEN, data);
+ }
+ break;
+
+ default:
+ ALOGE ("%s: tech unknown ????", fn);
+ uid = e->NewByteArray (0);
+ break;
+ } //if
+ f = e->GetFieldID(tag_cls, "mUid", "[B");
+ e->SetObjectField(tag, f, uid);
+}
+
+
+/*******************************************************************************
+**
+** Function: isP2pDiscovered
+**
+** Description: Does the peer support P2P?
+**
+** Returns: True if the peer supports P2P.
+**
+*******************************************************************************/
+bool NfcTag::isP2pDiscovered ()
+{
+ static const char fn [] = "NfcTag::isP2pDiscovered";
+ bool retval = false;
+
+ for (int i = 0; i < mNumTechList; i++)
+ {
+ if (mTechLibNfcTypes[i] == NFA_PROTOCOL_NFC_DEP)
+ {
+ //if remote device supports P2P
+ ALOGD ("%s: discovered P2P", fn);
+ retval = true;
+ break;
+ }
+ }
+ ALOGD ("%s: return=%u", fn, retval);
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: selectP2p
+**
+** Description: Select the preferred P2P technology if there is a choice.
+**
+** Returns: None
+**
+*******************************************************************************/
+void NfcTag::selectP2p()
+{
+ static const char fn [] = "NfcTag::selectP2p";
+ UINT8 rfDiscoveryId = 0;
+
+ for (int i = 0; i < mNumTechList; i++)
+ {
+ //if remote device does not support P2P, just skip it
+ if (mTechLibNfcTypes[i] != NFA_PROTOCOL_NFC_DEP)
+ continue;
+
+ //if remote device supports tech F;
+ //tech F is preferred because it is faster than tech A
+ if ( (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_F) ||
+ (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_F_ACTIVE) )
+ {
+ rfDiscoveryId = mTechHandles[i];
+ break; //no need to search further
+ }
+ else if ( (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A) ||
+ (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A_ACTIVE) )
+ {
+ //only choose tech A if tech F is unavailable
+ if (rfDiscoveryId == 0)
+ rfDiscoveryId = mTechHandles[i];
+ }
+ }
+
+ if (rfDiscoveryId > 0)
+ {
+ ALOGD ("%s: select P2P; target rf discov id=0x%X", fn, rfDiscoveryId);
+ tNFA_STATUS stat = NFA_Select (rfDiscoveryId, NFA_PROTOCOL_NFC_DEP, NFA_INTERFACE_NFC_DEP);
+ if (stat != NFA_STATUS_OK)
+ ALOGE ("%s: fail select P2P; error=0x%X", fn, stat);
+ }
+ else
+ ALOGE ("%s: cannot find P2P", fn);
+ resetTechnologies ();
+}
+
+
+/*******************************************************************************
+**
+** Function: resetTechnologies
+**
+** Description: Clear all data related to the technology, protocol of the tag.
+**
+** Returns: None
+**
+*******************************************************************************/
+void NfcTag::resetTechnologies ()
+{
+ static const char fn [] = "NfcTag::resetTechnologies";
+ ALOGD ("%s", fn);
+ mNumTechList = 0;
+ memset (mTechList, 0, sizeof(mTechList));
+ memset (mTechHandles, 0, sizeof(mTechHandles));
+ memset (mTechLibNfcTypes, 0, sizeof(mTechLibNfcTypes));
+ memset (mTechParams, 0, sizeof(mTechParams));
+}
+
+
+/*******************************************************************************
+**
+** Function: selectFirstTag
+**
+** Description: When multiple tags are discovered, just select the first one to activate.
+**
+** Returns: None
+**
+*******************************************************************************/
+void NfcTag::selectFirstTag ()
+{
+ static const char fn [] = "NfcTag::selectFirstTag";
+ ALOGD ("%s: nfa target h=0x%X; protocol=0x%X",
+ fn, mTechHandles [0], mTechLibNfcTypes [0]);
+ tNFA_INTF_TYPE rf_intf = NFA_INTERFACE_FRAME;
+
+ if (mTechLibNfcTypes [0] == NFA_PROTOCOL_ISO_DEP)
+ {
+ rf_intf = NFA_INTERFACE_ISO_DEP;
+ }
+ else if (mTechLibNfcTypes [0] == NFA_PROTOCOL_NFC_DEP)
+ rf_intf = NFA_INTERFACE_NFC_DEP;
+ else
+ rf_intf = NFA_INTERFACE_FRAME;
+
+ tNFA_STATUS stat = NFA_Select (mTechHandles [0], mTechLibNfcTypes [0], rf_intf);
+ if (stat != NFA_STATUS_OK)
+ ALOGE ("%s: fail select; error=0x%X", fn, stat);
+}
+
+
+/*******************************************************************************
+**
+** Function: getT1tMaxMessageSize
+**
+** Description: Get the maximum size (octet) that a T1T can store.
+**
+** Returns: Maximum size in octets.
+**
+*******************************************************************************/
+int NfcTag::getT1tMaxMessageSize ()
+{
+ static const char fn [] = "NfcTag::getT1tMaxMessageSize";
+
+ if (mProtocol != NFC_PROTOCOL_T1T)
+ {
+ ALOGE ("%s: wrong protocol %u", fn, mProtocol);
+ return 0;
+ }
+ return mtT1tMaxMessageSize;
+}
+
+
+/*******************************************************************************
+**
+** Function: calculateT1tMaxMessageSize
+**
+** Description: Calculate type-1 tag's max message size based on header ROM bytes.
+** activate: reference to activation data.
+**
+** Returns: None
+**
+*******************************************************************************/
+void NfcTag::calculateT1tMaxMessageSize (tNFA_ACTIVATED& activate)
+{
+ static const char fn [] = "NfcTag::calculateT1tMaxMessageSize";
+
+ //make sure the tag is type-1
+ if (activate.activate_ntf.protocol != NFC_PROTOCOL_T1T)
+ {
+ mtT1tMaxMessageSize = 0;
+ return;
+ }
+
+ //examine the first byte of header ROM bytes
+ switch (activate.params.t1t.hr[0])
+ {
+ case RW_T1T_IS_TOPAZ96:
+ mtT1tMaxMessageSize = 90;
+ break;
+ case RW_T1T_IS_TOPAZ512:
+ mtT1tMaxMessageSize = 462;
+ break;
+ default:
+ ALOGE ("%s: unknown T1T HR0=%u", fn, activate.params.t1t.hr[0]);
+ mtT1tMaxMessageSize = 0;
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: isMifareUltralight
+**
+** Description: Whether the currently activated tag is Mifare Ultralight.
+**
+** Returns: True if tag is Mifare Ultralight.
+**
+*******************************************************************************/
+bool NfcTag::isMifareUltralight ()
+{
+ static const char fn [] = "NfcTag::isMifareUltralight";
+ bool retval = false;
+
+ for (int i =0; i < mNumTechList; i++)
+ {
+ if ( (mTechParams[i].mode == NFC_DISCOVERY_TYPE_POLL_A) ||
+ (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_A) ||
+ (mTechParams[i].mode == NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE) )
+ {
+ //see NFC Digital Protocol, section 4.6.3 (SENS_RES); section 4.8.2 (SEL_RES).
+ //see Mifare Type Identification Procedure, section 5.1 (ATQA), 5.2 (SAK).
+ if ( (mTechParams[i].param.pa.sens_res[0] == 0x44) &&
+ (mTechParams[i].param.pa.sens_res[1] == 0) )
+ {
+ // SyncEventGuard g (mReadCompleteEvent);
+ // mReadCompletedStatus = NFA_STATUS_BUSY;
+ // ALOGD ("%s: read block 0x10", fn);
+ // tNFA_STATUS stat = NFA_RwT2tRead (0x10);
+ // if (stat == NFA_STATUS_OK)
+ // mReadCompleteEvent.wait ();
+ //
+ // //if read-completion status is failure, then the tag is
+ // //definitely Mifare Ultralight;
+ // //if read-completion status is OK, then the tag is
+ // //definitely Mifare Ultralight C;
+ // retval = (mReadCompletedStatus == NFA_STATUS_FAILED);
+ retval = true;
+ }
+ break;
+ }
+ }
+ ALOGD ("%s: return=%u", fn, retval);
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: isT2tNackResponse
+**
+** Description: Whether the response is a T2T NACK response.
+** See NFC Digital Protocol Technical Specification (2010-11-17).
+** Chapter 9 (Type 2 Tag Platform), section 9.6 (READ).
+** response: buffer contains T2T response.
+** responseLen: length of the response.
+**
+** Returns: True if the response is NACK
+**
+*******************************************************************************/
+bool NfcTag::isT2tNackResponse (const UINT8* response, UINT32 responseLen)
+{
+ static const char fn [] = "NfcTag::isT2tNackResponse";
+ bool isNack = false;
+
+ if (responseLen == 1)
+ {
+ if (response[0] == 0xA)
+ isNack = false; //an ACK response, so definitely not a NACK
+ else
+ isNack = true; //assume every value is a NACK
+ }
+ ALOGD ("%s: return %u", fn, isNack);
+ return isNack;
+}
+
+
+/*******************************************************************************
+**
+** Function: isNdefDetectionTimedOut
+**
+** Description: Whether NDEF-detection algorithm timed out.
+**
+** Returns: True if NDEF-detection algorithm timed out.
+**
+*******************************************************************************/
+bool NfcTag::isNdefDetectionTimedOut ()
+{
+ return mNdefDetectionTimedOut;
+}
+
+
+/*******************************************************************************
+**
+** Function: connectionEventHandler
+**
+** Description: Handle connection-related events.
+** event: event code.
+** data: pointer to event data.
+**
+** Returns: None
+**
+*******************************************************************************/
+void NfcTag::connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* data)
+{
+ static const char fn [] = "NfcTag::connectionEventHandler";
+
+ switch (event)
+ {
+ case NFA_DISC_RESULT_EVT:
+ {
+ tNFA_DISC_RESULT& disc_result = data->disc_result;
+ if (disc_result.status == NFA_STATUS_OK)
+ {
+ discoverTechnologies (disc_result);
+ }
+ }
+ break;
+
+ case NFA_ACTIVATED_EVT:
+ // Only do tag detection if we are polling and it is not 'EE Direct RF' activation
+ // (which may happen when we are activated as a tag).
+ if (data->activated.activate_ntf.rf_tech_param.mode < NCI_DISCOVERY_TYPE_LISTEN_A
+ && data->activated.activate_ntf.intf_param.type != NFC_INTERFACE_EE_DIRECT_RF)
+ {
+ tNFA_ACTIVATED& activated = data->activated;
+ if (IsSameKovio(activated))
+ break;
+ mProtocol = activated.activate_ntf.protocol;
+ calculateT1tMaxMessageSize (activated);
+ discoverTechnologies (activated);
+ createNativeNfcTag (activated);
+ }
+ break;
+
+ case NFA_DEACTIVATED_EVT:
+ mProtocol = NFC_PROTOCOL_UNKNOWN;
+ resetTechnologies ();
+ break;
+
+ case NFA_READ_CPLT_EVT:
+ {
+ SyncEventGuard g (mReadCompleteEvent);
+ mReadCompletedStatus = data->status;
+ mReadCompleteEvent.notifyOne ();
+ }
+ break;
+
+ case NFA_NDEF_DETECT_EVT:
+ {
+ tNFA_NDEF_DETECT& ndef_detect = data->ndef_detect;
+ mNdefDetectionTimedOut = ndef_detect.status == NFA_STATUS_TIMEOUT;
+ if (mNdefDetectionTimedOut)
+ ALOGE ("%s: NDEF detection timed out", fn);
+ }
+ }
+}
+
diff --git a/nci/jni/NfcTag.h b/nci/jni/NfcTag.h
new file mode 100755
index 0000000..7fa56ee
--- /dev/null
+++ b/nci/jni/NfcTag.h
@@ -0,0 +1,419 @@
+/*
+ * 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.
+ */
+
+/*
+ * Tag-reading, tag-writing operations.
+ */
+
+#pragma once
+#include "SyncEvent.h"
+#include "NfcJniUtil.h"
+extern "C"
+{
+ #include "nfa_rw_api.h"
+}
+
+
+class NfcTag
+{
+public:
+ enum ActivationState {Idle, Sleep, Active};
+ static const int MAX_NUM_TECHNOLOGY = 10; //max number of technologies supported by one or more tags
+ int mTechList [MAX_NUM_TECHNOLOGY]; //array of NFC technologies according to NFC service
+ int mTechHandles [MAX_NUM_TECHNOLOGY]; //array of tag handles according to NFC service
+ int mTechLibNfcTypes [MAX_NUM_TECHNOLOGY]; //array of detailed tag types according to NFC service
+ int mNumTechList; //current number of NFC technologies in the list
+
+ /*******************************************************************************
+ **
+ ** Function: NfcTag
+ **
+ ** Description: Initialize member variables.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ NfcTag ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: getInstance
+ **
+ ** Description: Get a reference to the singleton NfcTag object.
+ **
+ ** Returns: Reference to NfcTag object.
+ **
+ *******************************************************************************/
+ static NfcTag& getInstance ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: initialize
+ **
+ ** Description: Reset member variables.
+ ** native: Native data.
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void initialize (nfc_jni_native_data* native);
+
+
+ /*******************************************************************************
+ **
+ ** Function: abort
+ **
+ ** Description: Unblock all operations.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void abort ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: connectionEventHandler
+ **
+ ** Description: Handle connection-related events.
+ ** event: event code.
+ ** data: pointer to event data.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* data);
+
+
+ /*******************************************************************************
+ **
+ ** Function: getActivationState
+ **
+ ** Description: What is the current state: Idle, Sleep, or Activated.
+ **
+ ** Returns: Idle, Sleep, or Activated.
+ **
+ *******************************************************************************/
+ ActivationState getActivationState ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: setDeactivationState
+ **
+ ** Description: Set the current state: Idle or Sleep.
+ ** deactivated: state of deactivation.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void setDeactivationState (tNFA_DEACTIVATED& deactivated);
+
+
+ /*******************************************************************************
+ **
+ ** Function: setActivationState
+ **
+ ** Description: Set the current state to Active.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void setActivationState ();
+
+ /*******************************************************************************
+ **
+ ** Function: getProtocol
+ **
+ ** Description: Get the protocol of the current tag.
+ **
+ ** Returns: Protocol number.
+ **
+ *******************************************************************************/
+ tNFC_PROTOCOL getProtocol ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: isP2pDiscovered
+ **
+ ** Description: Does the peer support P2P?
+ **
+ ** Returns: True if the peer supports P2P.
+ **
+ *******************************************************************************/
+ bool isP2pDiscovered ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: selectP2p
+ **
+ ** Description: Select the preferred P2P technology if there is a choice.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void selectP2p ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: selectFirstTag
+ **
+ ** Description: When multiple tags are discovered, just select the first one to activate.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void selectFirstTag ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: getT1tMaxMessageSize
+ **
+ ** Description: Get the maximum size (octet) that a T1T can store.
+ **
+ ** Returns: Maximum size in octets.
+ **
+ *******************************************************************************/
+ int getT1tMaxMessageSize ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: isMifareUltralight
+ **
+ ** Description: Whether the currently activated tag is Mifare Ultralight.
+ **
+ ** Returns: True if tag is Mifare Ultralight.
+ **
+ *******************************************************************************/
+ bool isMifareUltralight ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: isT2tNackResponse
+ **
+ ** Description: Whether the response is a T2T NACK response.
+ ** See NFC Digital Protocol Technical Specification (2010-11-17).
+ ** Chapter 9 (Type 2 Tag Platform), section 9.6 (READ).
+ ** response: buffer contains T2T response.
+ ** responseLen: length of the response.
+ **
+ ** Returns: True if the response is NACK
+ **
+ *******************************************************************************/
+ bool isT2tNackResponse (const UINT8* response, UINT32 responseLen);
+
+ /*******************************************************************************
+ **
+ ** Function: isNdefDetectionTimedOut
+ **
+ ** Description: Whether NDEF-detection algorithm has timed out.
+ **
+ ** Returns: True if NDEF-detection algorithm timed out.
+ **
+ *******************************************************************************/
+ bool isNdefDetectionTimedOut ();
+
+private:
+ nfc_jni_native_data* mNativeData;
+ ActivationState mActivationState;
+ tNFC_PROTOCOL mProtocol;
+ int mtT1tMaxMessageSize; //T1T max NDEF message size
+ tNFA_STATUS mReadCompletedStatus;
+ int mLastKovioUidLen; // len of uid of last Kovio tag activated
+ bool mNdefDetectionTimedOut; // whether NDEF detection algorithm timed out
+ tNFC_RF_TECH_PARAMS mTechParams [MAX_NUM_TECHNOLOGY]; //array of technology parameters
+ SyncEvent mReadCompleteEvent;
+ struct timespec mLastKovioTime; // time of last Kovio tag activation
+ UINT8 mLastKovioUid[NFC_KOVIO_MAX_LEN]; // uid of last Kovio tag activated
+
+
+ /*******************************************************************************
+ **
+ ** Function: IsSameKovio
+ **
+ ** Description: Checks if tag activate is the same (UID) Kovio tag previously
+ ** activated. This is needed due to a problem with some Kovio
+ ** tags re-activating multiple times.
+ ** activationData: data from activation.
+ **
+ ** Returns: true if the activation is from the same tag previously
+ ** activated, false otherwise
+ **
+ *******************************************************************************/
+ bool IsSameKovio(tNFA_ACTIVATED& activationData);
+
+ /*******************************************************************************
+ **
+ ** Function: discoverTechnologies
+ **
+ ** Description: Discover the technologies that NFC service needs by interpreting
+ ** the data strucutures from the stack.
+ ** activationData: data from activation.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void discoverTechnologies (tNFA_ACTIVATED& activationData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: discoverTechnologies
+ **
+ ** Description: Discover the technologies that NFC service needs by interpreting
+ ** the data strucutures from the stack.
+ ** discoveryData: data from discovery events(s).
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void discoverTechnologies (tNFA_DISC_RESULT& discoveryData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: createNativeNfcTag
+ **
+ ** Description: Create a brand new Java NativeNfcTag object;
+ ** fill the objects's member variables with data;
+ ** notify NFC service;
+ ** activationData: data from activation.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void createNativeNfcTag (tNFA_ACTIVATED& activationData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: fillNativeNfcTagMembers1
+ **
+ ** Description: Fill NativeNfcTag's members: mProtocols, mTechList, mTechHandles, mTechLibNfcTypes.
+ ** e: JVM environment.
+ ** tag_cls: Java NativeNfcTag class.
+ ** tag: Java NativeNfcTag object.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void fillNativeNfcTagMembers1 (JNIEnv* e, jclass tag_cls, jobject tag);
+
+
+ /*******************************************************************************
+ **
+ ** Function: fillNativeNfcTagMembers2
+ **
+ ** Description: Fill NativeNfcTag's members: mConnectedTechIndex or mConnectedTechnology.
+ ** The original Google's implementation is in set_target_pollBytes(
+ ** in com_android_nfc_NativeNfcTag.cpp;
+ ** e: JVM environment.
+ ** tag_cls: Java NativeNfcTag class.
+ ** tag: Java NativeNfcTag object.
+ ** activationData: data from activation.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void fillNativeNfcTagMembers2 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: fillNativeNfcTagMembers3
+ **
+ ** Description: Fill NativeNfcTag's members: mTechPollBytes.
+ ** The original Google's implementation is in set_target_pollBytes(
+ ** in com_android_nfc_NativeNfcTag.cpp;
+ ** e: JVM environment.
+ ** tag_cls: Java NativeNfcTag class.
+ ** tag: Java NativeNfcTag object.
+ ** activationData: data from activation.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void fillNativeNfcTagMembers3 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: fillNativeNfcTagMembers4
+ **
+ ** Description: Fill NativeNfcTag's members: mTechActBytes.
+ ** The original Google's implementation is in set_target_activationBytes()
+ ** in com_android_nfc_NativeNfcTag.cpp;
+ ** e: JVM environment.
+ ** tag_cls: Java NativeNfcTag class.
+ ** tag: Java NativeNfcTag object.
+ ** activationData: data from activation.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void fillNativeNfcTagMembers4 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: fillNativeNfcTagMembers5
+ **
+ ** Description: Fill NativeNfcTag's members: mUid.
+ ** The original Google's implementation is in nfc_jni_Discovery_notification_callback()
+ ** in com_android_nfc_NativeNfcManager.cpp;
+ ** e: JVM environment.
+ ** tag_cls: Java NativeNfcTag class.
+ ** tag: Java NativeNfcTag object.
+ ** activationData: data from activation.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void fillNativeNfcTagMembers5 (JNIEnv* e, jclass tag_cls, jobject tag, tNFA_ACTIVATED& activationData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: resetTechnologies
+ **
+ ** Description: Clear all data related to the technology, protocol of the tag.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void resetTechnologies ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: calculateT1tMaxMessageSize
+ **
+ ** Description: Calculate type-1 tag's max message size based on header ROM bytes.
+ ** activate: reference to activation data.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void calculateT1tMaxMessageSize (tNFA_ACTIVATED& activate);
+};
+
diff --git a/nci/jni/PeerToPeer.cpp b/nci/jni/PeerToPeer.cpp
new file mode 100644
index 0000000..7994e2a
--- /dev/null
+++ b/nci/jni/PeerToPeer.cpp
@@ -0,0 +1,1840 @@
+/*
+ * 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.
+ */
+
+/*
+ * Communicate with a peer using NFC-DEP, LLCP, SNEP.
+ */
+#include "OverrideLog.h"
+#include "PeerToPeer.h"
+#include "NfcJniUtil.h"
+#include "llcp_defs.h"
+#include "config.h"
+#include "JavaClassConstants.h"
+
+using namespace android;
+
+namespace android
+{
+ extern void nativeNfcTag_registerNdefTypeHandler ();
+ extern void nativeNfcTag_deregisterNdefTypeHandler ();
+}
+
+
+PeerToPeer PeerToPeer::sP2p;
+const std::string P2pServer::sSnepServiceName ("urn:nfc:sn:snep");
+
+
+/*******************************************************************************
+**
+** Function: PeerToPeer
+**
+** Description: Initialize member variables.
+**
+** Returns: None
+**
+*******************************************************************************/
+PeerToPeer::PeerToPeer ()
+: mRemoteWKS (0),
+ mIsP2pListening (false),
+ mP2pListenTechMask (NFA_TECHNOLOGY_MASK_A
+ | NFA_TECHNOLOGY_MASK_F
+ | NFA_TECHNOLOGY_MASK_A_ACTIVE
+ | NFA_TECHNOLOGY_MASK_F_ACTIVE),
+ mNextJniHandle (1)
+{
+ unsigned long num = 0;
+ memset (mServers, 0, sizeof(mServers));
+ memset (mClients, 0, sizeof(mClients));
+}
+
+
+/*******************************************************************************
+**
+** Function: ~PeerToPeer
+**
+** Description: Free all resources.
+**
+** Returns: None
+**
+*******************************************************************************/
+PeerToPeer::~PeerToPeer ()
+{
+}
+
+
+/*******************************************************************************
+**
+** Function: getInstance
+**
+** Description: Get the singleton PeerToPeer object.
+**
+** Returns: Singleton PeerToPeer object.
+**
+*******************************************************************************/
+PeerToPeer& PeerToPeer::getInstance ()
+{
+ return sP2p;
+}
+
+
+/*******************************************************************************
+**
+** Function: initialize
+**
+** Description: Initialize member variables.
+**
+** Returns: None
+**
+*******************************************************************************/
+void PeerToPeer::initialize ()
+{
+ ALOGD ("PeerToPeer::initialize");
+ unsigned long num = 0;
+
+ if (GetNumValue ("P2P_LISTEN_TECH_MASK", &num, sizeof (num)))
+ mP2pListenTechMask = num;
+}
+
+
+/*******************************************************************************
+**
+** Function: findServerLocked
+**
+** Description: Find a PeerToPeer object by connection handle.
+** Assumes mMutex is already held
+** nfaP2pServerHandle: Connectin handle.
+**
+** Returns: PeerToPeer object.
+**
+*******************************************************************************/
+sp<P2pServer> PeerToPeer::findServerLocked (tNFA_HANDLE nfaP2pServerHandle)
+{
+ for (int i = 0; i < sMax; i++)
+ {
+ if ( (mServers[i] != NULL)
+ && (mServers[i]->mNfaP2pServerHandle == nfaP2pServerHandle) )
+ {
+ return (mServers [i]);
+ }
+ }
+
+ // If here, not found
+ return NULL;
+}
+
+
+/*******************************************************************************
+**
+** Function: findServerLocked
+**
+** Description: Find a PeerToPeer object by connection handle.
+** Assumes mMutex is already held
+** serviceName: service name.
+**
+** Returns: PeerToPeer object.
+**
+*******************************************************************************/
+sp<P2pServer> PeerToPeer::findServerLocked (tJNI_HANDLE jniHandle)
+{
+ for (int i = 0; i < sMax; i++)
+ {
+ if ( (mServers[i] != NULL)
+ && (mServers[i]->mJniHandle == jniHandle) )
+ {
+ return (mServers [i]);
+ }
+ }
+
+ // If here, not found
+ return NULL;
+}
+
+
+/*******************************************************************************
+**
+** Function: findServerLocked
+**
+** Description: Find a PeerToPeer object by service name
+** Assumes mMutex is already heldf
+** serviceName: service name.
+**
+** Returns: PeerToPeer object.
+**
+*******************************************************************************/
+sp<P2pServer> PeerToPeer::findServerLocked (const char *serviceName)
+{
+ for (int i = 0; i < sMax; i++)
+ {
+ if ( (mServers[i] != NULL) && (mServers[i]->mServiceName.compare(serviceName) == 0) )
+ return (mServers [i]);
+ }
+
+ // If here, not found
+ return NULL;
+}
+
+
+/*******************************************************************************
+**
+** Function: registerServer
+**
+** Description: Let a server start listening for peer's connection request.
+** jniHandle: Connection handle.
+** serviceName: Server's service name.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool PeerToPeer::registerServer (tJNI_HANDLE jniHandle, const char *serviceName)
+{
+ static const char fn [] = "PeerToPeer::registerServer";
+ ALOGD ("%s: enter; service name: %s JNI handle: %u", fn, serviceName, jniHandle);
+ tNFA_STATUS stat = NFA_STATUS_OK;
+ sp<P2pServer> pSrv = NULL;
+ UINT8 serverSap = NFA_P2P_ANY_SAP;
+
+ mMutex.lock();
+ // Check if already registered
+ if ((pSrv = findServerLocked(serviceName)) != NULL)
+ {
+ ALOGD ("%s: service name=%s already registered, handle: 0x%04x", fn, serviceName, pSrv->mNfaP2pServerHandle);
+
+ // Update JNI handle
+ pSrv->mJniHandle = jniHandle;
+ mMutex.unlock();
+ return (true);
+ }
+
+ for (int ii = 0; ii < sMax; ii++)
+ {
+ if (mServers[ii] == NULL)
+ {
+ pSrv = mServers[ii] = new P2pServer(jniHandle, serviceName);
+
+ ALOGD ("%s: added new p2p server index: %d handle: %u name: %s", fn, ii, jniHandle, serviceName);
+ break;
+ }
+ }
+ mMutex.unlock();
+
+ if (pSrv == NULL)
+ {
+ ALOGE ("%s: service name=%s no free entry", fn, serviceName);
+ return (false);
+ }
+
+ if (pSrv->registerWithStack()) {
+ ALOGD ("%s: got new p2p server h=0x%X", fn, pSrv->mNfaP2pServerHandle);
+ return (true);
+ } else {
+ ALOGE ("%s: invalid server handle", fn);
+ removeServer (jniHandle);
+ return (false);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: removeServer
+**
+** Description: Free resources related to a server.
+** jniHandle: Connection handle.
+**
+** Returns: None
+**
+*******************************************************************************/
+void PeerToPeer::removeServer (tJNI_HANDLE jniHandle)
+{
+ static const char fn [] = "PeerToPeer::removeServer";
+
+ AutoMutex mutex(mMutex);
+
+ for (int i = 0; i < sMax; i++)
+ {
+ if ( (mServers[i] != NULL) && (mServers[i]->mJniHandle == jniHandle) )
+ {
+ ALOGD ("%s: server jni_handle: %u; nfa_handle: 0x%04x; name: %s; index=%d",
+ fn, jniHandle, mServers[i]->mNfaP2pServerHandle, mServers[i]->mServiceName.c_str(), i);
+
+ mServers [i] = NULL;
+ return;
+ }
+ }
+ ALOGE ("%s: unknown server jni handle: %u", fn, jniHandle);
+}
+
+
+/*******************************************************************************
+**
+** Function: llcpActivatedHandler
+**
+** Description: Receive LLLCP-activated event from stack.
+** nat: JVM-related data.
+** activated: Event data.
+**
+** Returns: None
+**
+*******************************************************************************/
+void PeerToPeer::llcpActivatedHandler (nfc_jni_native_data* nat, tNFA_LLCP_ACTIVATED& activated)
+{
+ static const char fn [] = "PeerToPeer::llcpActivatedHandler";
+ ALOGD ("%s: enter", fn);
+ JNIEnv* e = NULL;
+ jclass tag_cls = NULL;
+ jobject tag = NULL;
+ jmethodID ctor = 0;
+ jfieldID f = 0;
+
+ //no longer need to receive NDEF message from a tag
+ android::nativeNfcTag_deregisterNdefTypeHandler ();
+
+ mRemoteWKS = activated.remote_wks;
+
+ nat->vm->AttachCurrentThread (&e, NULL);
+ if (e == NULL)
+ {
+ ALOGE ("%s: jni env is null", fn);
+ return;
+ }
+
+ ALOGD ("%s: get object class", fn);
+ tag_cls = e->GetObjectClass (nat->cached_P2pDevice);
+ if (e->ExceptionCheck())
+ {
+ e->ExceptionClear();
+ ALOGE ("%s: fail get p2p device", fn);
+ goto TheEnd;
+ }
+
+ ALOGD ("%s: instantiate", fn);
+ /* New target instance */
+ ctor = e->GetMethodID (tag_cls, "<init>", "()V");
+ tag = e->NewObject (tag_cls, ctor);
+
+ /* Set P2P Target mode */
+ f = e->GetFieldID (tag_cls, "mMode", "I");
+
+ if (activated.is_initiator == TRUE)
+ {
+ ALOGD ("%s: p2p initiator", fn);
+ e->SetIntField (tag, f, (jint) MODE_P2P_INITIATOR);
+ }
+ else
+ {
+ ALOGD ("%s: p2p target", fn);
+ e->SetIntField (tag, f, (jint) MODE_P2P_TARGET);
+ }
+
+ /* Set tag handle */
+ f = e->GetFieldID (tag_cls, "mHandle", "I");
+ e->SetIntField (tag, f, (jint) 0x1234); // ?? This handle is not used for anything
+
+ if (nat->tag != NULL)
+ {
+ e->DeleteGlobalRef (nat->tag);
+ }
+ nat->tag = e->NewGlobalRef (tag);
+
+ ALOGD ("%s: notify nfc service", fn);
+
+ /* Notify manager that new a P2P device was found */
+ e->CallVoidMethod (nat->manager, android::gCachedNfcManagerNotifyLlcpLinkActivation, tag);
+ if (e->ExceptionCheck())
+ {
+ e->ExceptionClear();
+ ALOGE ("%s: fail notify", fn);
+ }
+
+ e->DeleteLocalRef (tag);
+
+TheEnd:
+ nat->vm->DetachCurrentThread ();
+ ALOGD ("%s: exit", fn);
+}
+
+
+/*******************************************************************************
+**
+** Function: llcpDeactivatedHandler
+**
+** Description: Receive LLLCP-deactivated event from stack.
+** nat: JVM-related data.
+** deactivated: Event data.
+**
+** Returns: None
+**
+*******************************************************************************/
+void PeerToPeer::llcpDeactivatedHandler (nfc_jni_native_data* nat, tNFA_LLCP_DEACTIVATED& deactivated)
+{
+ static const char fn [] = "PeerToPeer::llcpDeactivatedHandler";
+ ALOGD ("%s: enter", fn);
+ JNIEnv* e = NULL;
+
+ nat->vm->AttachCurrentThread (&e, NULL);
+ if (e == NULL)
+ {
+ ALOGE ("%s: jni env is null", fn);
+ return;
+ }
+
+ ALOGD ("%s: notify nfc service", fn);
+ /* Notify manager that the LLCP is lost or deactivated */
+ e->CallVoidMethod (nat->manager, android::gCachedNfcManagerNotifyLlcpLinkDeactivated, nat->tag);
+ if (e->ExceptionCheck())
+ {
+ e->ExceptionClear();
+ ALOGE ("%s: fail notify", fn);
+ }
+
+ nat->vm->DetachCurrentThread ();
+
+ //let the tag-reading code handle NDEF data event
+ android::nativeNfcTag_registerNdefTypeHandler ();
+ ALOGD ("%s: exit", fn);
+}
+
+
+/*******************************************************************************
+**
+** Function: accept
+**
+** Description: Accept a peer's request to connect.
+** serverJniHandle: Server's handle.
+** connJniHandle: Connection handle.
+** maxInfoUnit: Maximum information unit.
+** recvWindow: Receive window size.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool PeerToPeer::accept (tJNI_HANDLE serverJniHandle, tJNI_HANDLE connJniHandle, int maxInfoUnit, int recvWindow)
+{
+ static const char fn [] = "PeerToPeer::accept";
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ sp<NfaConn> *pConn = NULL;
+ bool stat = false;
+ int ii = 0;
+ sp<P2pServer> pSrv = NULL;
+
+ ALOGD ("%s: enter; server jni handle: %u; conn jni handle: %u; maxInfoUnit: %d; recvWindow: %d", fn,
+ serverJniHandle, connJniHandle, maxInfoUnit, recvWindow);
+
+ mMutex.lock();
+ if ((pSrv = findServerLocked (serverJniHandle)) == NULL)
+ {
+ ALOGE ("%s: unknown server jni handle: %u", fn, serverJniHandle);
+ mMutex.unlock();
+ return (false);
+ }
+ mMutex.unlock();
+
+ return pSrv->accept(serverJniHandle, connJniHandle, maxInfoUnit, recvWindow);
+}
+
+
+/*******************************************************************************
+**
+** Function: deregisterServer
+**
+** Description: Stop a P2pServer from listening for peer.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool PeerToPeer::deregisterServer (tJNI_HANDLE jniHandle)
+{
+ static const char fn [] = "PeerToPeer::deregisterServer";
+ ALOGD ("%s: enter; JNI handle: %u", fn, jniHandle);
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ sp<P2pServer> pSrv = NULL;
+
+ mMutex.lock();
+ if ((pSrv = findServerLocked (jniHandle)) == NULL)
+ {
+ ALOGE ("%s: unknown service handle: %u", fn, jniHandle);
+ mMutex.unlock();
+ return (false);
+ }
+ mMutex.unlock();
+
+ {
+ // Server does not call NFA_P2pDisconnect(), so unblock the accept()
+ SyncEventGuard guard (pSrv->mConnRequestEvent);
+ pSrv->mConnRequestEvent.notifyOne();
+ }
+
+ nfaStat = NFA_P2pDeregister (pSrv->mNfaP2pServerHandle);
+ if (nfaStat != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: deregister error=0x%X", fn, nfaStat);
+ }
+
+ removeServer (jniHandle);
+
+ ALOGD ("%s: exit", fn);
+ return true;
+}
+
+
+/*******************************************************************************
+**
+** Function: createClient
+**
+** Description: Create a P2pClient object for a new out-bound connection.
+** jniHandle: Connection handle.
+** miu: Maximum information unit.
+** rw: Receive window size.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool PeerToPeer::createClient (tJNI_HANDLE jniHandle, UINT16 miu, UINT8 rw)
+{
+ static const char fn [] = "PeerToPeer::createClient";
+ int i = 0;
+ ALOGD ("%s: enter: jni h: %u miu: %u rw: %u", fn, jniHandle, miu, rw);
+
+ mMutex.lock();
+ sp<P2pClient> client = NULL;
+ for (i = 0; i < sMax; i++)
+ {
+ if (mClients[i] == NULL)
+ {
+ mClients [i] = client = new P2pClient();
+
+ mClients [i]->mClientConn->mJniHandle = jniHandle;
+ mClients [i]->mClientConn->mMaxInfoUnit = miu;
+ mClients [i]->mClientConn->mRecvWindow = rw;
+ break;
+ }
+ }
+ mMutex.unlock();
+
+ if (client == NULL)
+ {
+ ALOGE ("%s: fail", fn);
+ return (false);
+ }
+
+ ALOGD ("%s: pClient: 0x%p assigned for client jniHandle: %u", fn, client.get(), jniHandle);
+
+ {
+ SyncEventGuard guard (mClients[i]->mRegisteringEvent);
+ NFA_P2pRegisterClient (NFA_P2P_DLINK_TYPE, nfaClientCallback);
+ mClients[i]->mRegisteringEvent.wait(); //wait for NFA_P2P_REG_CLIENT_EVT
+ }
+
+ if (mClients[i]->mNfaP2pClientHandle != NFA_HANDLE_INVALID)
+ {
+ ALOGD ("%s: exit; new client jniHandle: %u NFA Handle: 0x%04x", fn, jniHandle, client->mClientConn->mNfaConnHandle);
+ return (true);
+ }
+ else
+ {
+ ALOGE ("%s: FAILED; new client jniHandle: %u NFA Handle: 0x%04x", fn, jniHandle, client->mClientConn->mNfaConnHandle);
+ removeConn (jniHandle);
+ return (false);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: removeConn
+**
+** Description: Free resources related to a connection.
+** jniHandle: Connection handle.
+**
+** Returns: None
+**
+*******************************************************************************/
+void PeerToPeer::removeConn(tJNI_HANDLE jniHandle)
+{
+ static const char fn[] = "PeerToPeer::removeConn";
+ int ii = 0, jj = 0;
+
+ AutoMutex mutex(mMutex);
+ // If the connection is a for a client, delete the client itself
+ for (ii = 0; ii < sMax; ii++)
+ {
+ if ((mClients[ii] != NULL) && (mClients[ii]->mClientConn->mJniHandle == jniHandle))
+ {
+ if (mClients[ii]->mNfaP2pClientHandle != NFA_HANDLE_INVALID)
+ NFA_P2pDeregister (mClients[ii]->mNfaP2pClientHandle);
+
+ mClients[ii] = NULL;
+ ALOGD ("%s: deleted client handle: %u index: %u", fn, jniHandle, ii);
+ return;
+ }
+ }
+
+ // If the connection is for a server, just delete the connection
+ for (ii = 0; ii < sMax; ii++)
+ {
+ if (mServers[ii] != NULL)
+ {
+ if (mServers[ii]->removeServerConnection(jniHandle)) {
+ return;
+ }
+ }
+ }
+
+ ALOGE ("%s: could not find handle: %u", fn, jniHandle);
+}
+
+
+/*******************************************************************************
+**
+** Function: connectConnOriented
+**
+** Description: Estabish a connection-oriented connection to a peer.
+** jniHandle: Connection handle.
+** serviceName: Peer's service name.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool PeerToPeer::connectConnOriented (tJNI_HANDLE jniHandle, const char* serviceName)
+{
+ static const char fn [] = "PeerToPeer::connectConnOriented";
+ ALOGD ("%s: enter; h: %u service name=%s", fn, jniHandle, serviceName);
+ bool stat = createDataLinkConn (jniHandle, serviceName, 0);
+ ALOGD ("%s: exit; h: %u stat: %u", fn, jniHandle, stat);
+ return stat;
+}
+
+
+/*******************************************************************************
+**
+** Function: connectConnOriented
+**
+** Description: Estabish a connection-oriented connection to a peer.
+** jniHandle: Connection handle.
+** destinationSap: Peer's service access point.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool PeerToPeer::connectConnOriented (tJNI_HANDLE jniHandle, UINT8 destinationSap)
+{
+ static const char fn [] = "PeerToPeer::connectConnOriented";
+ ALOGD ("%s: enter; h: %u dest sap: 0x%X", fn, jniHandle, destinationSap);
+ bool stat = createDataLinkConn (jniHandle, NULL, destinationSap);
+ ALOGD ("%s: exit; h: %u stat: %u", fn, jniHandle, stat);
+ return stat;
+}
+
+
+/*******************************************************************************
+**
+** Function: createDataLinkConn
+**
+** Description: Estabish a connection-oriented connection to a peer.
+** jniHandle: Connection handle.
+** serviceName: Peer's service name.
+** destinationSap: Peer's service access point.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool PeerToPeer::createDataLinkConn (tJNI_HANDLE jniHandle, const char* serviceName, UINT8 destinationSap)
+{
+ static const char fn [] = "PeerToPeer::createDataLinkConn";
+ ALOGD ("%s: enter", fn);
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ sp<P2pClient> pClient = NULL;
+
+ if ((pClient = findClient (jniHandle)) == NULL)
+ {
+ ALOGE ("%s: can't find client, JNI handle: %u", fn, jniHandle);
+ return (false);
+ }
+
+ {
+ SyncEventGuard guard (pClient->mConnectingEvent);
+ pClient->mIsConnecting = true;
+
+ if (serviceName)
+ nfaStat = NFA_P2pConnectByName (pClient->mNfaP2pClientHandle,
+ const_cast<char*>(serviceName), pClient->mClientConn->mMaxInfoUnit,
+ pClient->mClientConn->mRecvWindow);
+ else if (destinationSap)
+ nfaStat = NFA_P2pConnectBySap (pClient->mNfaP2pClientHandle, destinationSap,
+ pClient->mClientConn->mMaxInfoUnit, pClient->mClientConn->mRecvWindow);
+ if (nfaStat == NFA_STATUS_OK)
+ {
+ ALOGD ("%s: wait for connected event mConnectingEvent: 0x%p", fn, pClient.get());
+ pClient->mConnectingEvent.wait();
+ }
+ }
+
+ if (nfaStat == NFA_STATUS_OK)
+ {
+ if (pClient->mClientConn->mNfaConnHandle == NFA_HANDLE_INVALID)
+ {
+ removeConn (jniHandle);
+ nfaStat = NFA_STATUS_FAILED;
+ }
+ else
+ pClient->mIsConnecting = false;
+ }
+ else
+ {
+ removeConn (jniHandle);
+ ALOGE ("%s: fail; error=0x%X", fn, nfaStat);
+ }
+
+ ALOGD ("%s: exit", fn);
+ return nfaStat == NFA_STATUS_OK;
+}
+
+
+/*******************************************************************************
+**
+** Function: findClient
+**
+** Description: Find a PeerToPeer object with a client connection handle.
+** nfaConnHandle: Connection handle.
+**
+** Returns: PeerToPeer object.
+**
+*******************************************************************************/
+sp<P2pClient> PeerToPeer::findClient (tNFA_HANDLE nfaConnHandle)
+{
+ AutoMutex mutex(mMutex);
+ for (int i = 0; i < sMax; i++)
+ {
+ if ((mClients[i] != NULL) && (mClients[i]->mNfaP2pClientHandle == nfaConnHandle))
+ return (mClients[i]);
+ }
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function: findClient
+**
+** Description: Find a PeerToPeer object with a client connection handle.
+** jniHandle: Connection handle.
+**
+** Returns: PeerToPeer object.
+**
+*******************************************************************************/
+sp<P2pClient> PeerToPeer::findClient (tJNI_HANDLE jniHandle)
+{
+ AutoMutex mutex(mMutex);
+ for (int i = 0; i < sMax; i++)
+ {
+ if ((mClients[i] != NULL) && (mClients[i]->mClientConn->mJniHandle == jniHandle))
+ return (mClients[i]);
+ }
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function: findClientCon
+**
+** Description: Find a PeerToPeer object with a client connection handle.
+** nfaConnHandle: Connection handle.
+**
+** Returns: PeerToPeer object.
+**
+*******************************************************************************/
+sp<P2pClient> PeerToPeer::findClientCon (tNFA_HANDLE nfaConnHandle)
+{
+ AutoMutex mutex(mMutex);
+ for (int i = 0; i < sMax; i++)
+ {
+ if ((mClients[i] != NULL) && (mClients[i]->mClientConn->mNfaConnHandle == nfaConnHandle))
+ return (mClients[i]);
+ }
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function: findConnection
+**
+** Description: Find a PeerToPeer object with a connection handle.
+** nfaConnHandle: Connection handle.
+**
+** Returns: PeerToPeer object.
+**
+*******************************************************************************/
+sp<NfaConn> PeerToPeer::findConnection (tNFA_HANDLE nfaConnHandle)
+{
+ int ii = 0, jj = 0;
+
+ AutoMutex mutex(mMutex);
+ // First, look through all the client control blocks
+ for (ii = 0; ii < sMax; ii++)
+ {
+ if ( (mClients[ii] != NULL)
+ && (mClients[ii]->mClientConn->mNfaConnHandle == nfaConnHandle) ) {
+ return mClients[ii]->mClientConn;
+ }
+ }
+
+ // Not found yet. Look through all the server control blocks
+ for (ii = 0; ii < sMax; ii++)
+ {
+ if (mServers[ii] != NULL)
+ {
+ sp<NfaConn> conn = mServers[ii]->findServerConnection(nfaConnHandle);
+ if (conn != NULL) {
+ return conn;
+ }
+ }
+ }
+
+ // Not found...
+ return NULL;
+}
+
+
+/*******************************************************************************
+**
+** Function: findConnection
+**
+** Description: Find a PeerToPeer object with a connection handle.
+** jniHandle: Connection handle.
+**
+** Returns: PeerToPeer object.
+**
+*******************************************************************************/
+sp<NfaConn> PeerToPeer::findConnection (tJNI_HANDLE jniHandle)
+{
+ int ii = 0, jj = 0;
+
+ AutoMutex mutex(mMutex);
+ // First, look through all the client control blocks
+ for (ii = 0; ii < sMax; ii++)
+ {
+ if ( (mClients[ii] != NULL)
+ && (mClients[ii]->mClientConn->mJniHandle == jniHandle) ) {
+ return mClients[ii]->mClientConn;
+ }
+ }
+
+ // Not found yet. Look through all the server control blocks
+ for (ii = 0; ii < sMax; ii++)
+ {
+ if (mServers[ii] != NULL)
+ {
+ sp<NfaConn> conn = mServers[ii]->findServerConnection(jniHandle);
+ if (conn != NULL) {
+ return conn;
+ }
+ }
+ }
+
+ // Not found...
+ return NULL;
+}
+
+
+/*******************************************************************************
+**
+** Function: send
+**
+** Description: Send data to peer.
+** jniHandle: Handle of connection.
+** buffer: Buffer of data.
+** bufferLen: Length of data.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool PeerToPeer::send (tJNI_HANDLE jniHandle, UINT8 *buffer, UINT16 bufferLen)
+{
+ static const char fn [] = "PeerToPeer::send";
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ sp<NfaConn> pConn = NULL;
+
+ if ((pConn = findConnection (jniHandle)) == NULL)
+ {
+ ALOGE ("%s: can't find connection handle: %u", fn, jniHandle);
+ return (false);
+ }
+
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: send data; jniHandle: %u nfaHandle: 0x%04X",
+ fn, pConn->mJniHandle, pConn->mNfaConnHandle);
+
+ while (true)
+ {
+ SyncEventGuard guard (pConn->mCongEvent);
+ nfaStat = NFA_P2pSendData (pConn->mNfaConnHandle, bufferLen, buffer);
+ if (nfaStat == NFA_STATUS_CONGESTED)
+ pConn->mCongEvent.wait (); //wait for NFA_P2P_CONGEST_EVT
+ else
+ break;
+
+ if (pConn->mNfaConnHandle == NFA_HANDLE_INVALID) //peer already disconnected
+ {
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: peer disconnected", fn);
+ return (false);
+ }
+ }
+
+ if (nfaStat == NFA_STATUS_OK)
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: exit OK; JNI handle: %u NFA Handle: 0x%04x", fn, jniHandle, pConn->mNfaConnHandle);
+ else
+ ALOGE ("%s: Data not sent; JNI handle: %u NFA Handle: 0x%04x error: 0x%04x",
+ fn, jniHandle, pConn->mNfaConnHandle, nfaStat);
+
+ return nfaStat == NFA_STATUS_OK;
+}
+
+
+/*******************************************************************************
+**
+** Function: receive
+**
+** Description: Receive data from peer.
+** jniHandle: Handle of connection.
+** buffer: Buffer to store data.
+** bufferLen: Max length of buffer.
+** actualLen: Actual length received.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool PeerToPeer::receive (tJNI_HANDLE jniHandle, UINT8* buffer, UINT16 bufferLen, UINT16& actualLen)
+{
+ static const char fn [] = "PeerToPeer::receive";
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: enter; jniHandle: %u bufferLen: %u", fn, jniHandle, bufferLen);
+ sp<NfaConn> pConn = NULL;
+ tNFA_STATUS stat = NFA_STATUS_FAILED;
+ UINT32 actualDataLen2 = 0;
+ BOOLEAN isMoreData = TRUE;
+ bool retVal = false;
+
+ if ((pConn = findConnection (jniHandle)) == NULL)
+ {
+ ALOGE ("%s: can't find connection handle: %u", fn, jniHandle);
+ return (false);
+ }
+
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: jniHandle: %u nfaHandle: 0x%04X buf len=%u", fn, pConn->mJniHandle, pConn->mNfaConnHandle, bufferLen);
+
+ while (pConn->mNfaConnHandle != NFA_HANDLE_INVALID)
+ {
+ //NFA_P2pReadData() is synchronous
+ stat = NFA_P2pReadData (pConn->mNfaConnHandle, bufferLen, &actualDataLen2, buffer, &isMoreData);
+ if ((stat == NFA_STATUS_OK) && (actualDataLen2 > 0)) //received some data
+ {
+ actualLen = (UINT16) actualDataLen2;
+ retVal = true;
+ break;
+ }
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: waiting for data...", fn);
+ {
+ SyncEventGuard guard (pConn->mReadEvent);
+ pConn->mReadEvent.wait();
+ }
+ } //while
+
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: exit; nfa h: 0x%X ok: %u actual len: %u", fn, pConn->mNfaConnHandle, retVal, actualLen);
+ return retVal;
+}
+
+
+/*******************************************************************************
+**
+** Function: disconnectConnOriented
+**
+** Description: Disconnect a connection-oriented connection with peer.
+** jniHandle: Handle of connection.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool PeerToPeer::disconnectConnOriented (tJNI_HANDLE jniHandle)
+{
+ static const char fn [] = "PeerToPeer::disconnectConnOriented";
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ sp<P2pClient> pClient = NULL;
+ sp<NfaConn> pConn = NULL;
+
+ ALOGD ("%s: enter; jni handle: %u", fn, jniHandle);
+
+ if ((pConn = findConnection(jniHandle)) == NULL)
+ {
+ ALOGE ("%s: can't find connection handle: %u", fn, jniHandle);
+ return (false);
+ }
+
+ // If this is a client, he may not be connected yet, so unblock him just in case
+ if ( ((pClient = findClient(jniHandle)) != NULL) && (pClient->mIsConnecting) )
+ {
+ SyncEventGuard guard (pClient->mConnectingEvent);
+ pClient->mConnectingEvent.notifyOne();
+ return (true);
+ }
+
+ {
+ SyncEventGuard guard1 (pConn->mCongEvent);
+ pConn->mCongEvent.notifyOne (); //unblock send() if congested
+ }
+ {
+ SyncEventGuard guard2 (pConn->mReadEvent);
+ pConn->mReadEvent.notifyOne (); //unblock receive()
+ }
+
+ if (pConn->mNfaConnHandle != NFA_HANDLE_INVALID)
+ {
+ ALOGD ("%s: try disconn nfa h=0x%04X", fn, pConn->mNfaConnHandle);
+ SyncEventGuard guard (pConn->mDisconnectingEvent);
+ nfaStat = NFA_P2pDisconnect (pConn->mNfaConnHandle, FALSE);
+
+ if (nfaStat != NFA_STATUS_OK)
+ ALOGE ("%s: fail p2p disconnect", fn);
+ else
+ pConn->mDisconnectingEvent.wait();
+ }
+
+ mDisconnectMutex.lock ();
+ removeConn (jniHandle);
+ mDisconnectMutex.unlock ();
+
+ ALOGD ("%s: exit; jni handle: %u", fn, jniHandle);
+ return nfaStat == NFA_STATUS_OK;
+}
+
+
+/*******************************************************************************
+**
+** Function: getRemoteMaxInfoUnit
+**
+** Description: Get peer's max information unit.
+** jniHandle: Handle of the connection.
+**
+** Returns: Peer's max information unit.
+**
+*******************************************************************************/
+UINT16 PeerToPeer::getRemoteMaxInfoUnit (tJNI_HANDLE jniHandle)
+{
+ static const char fn [] = "PeerToPeer::getRemoteMaxInfoUnit";
+ sp<NfaConn> pConn = NULL;
+
+ if ((pConn = findConnection(jniHandle)) == NULL)
+ {
+ ALOGE ("%s: can't find client jniHandle: %u", fn, jniHandle);
+ return 0;
+ }
+ ALOGD ("%s: jniHandle: %u MIU: %u", fn, jniHandle, pConn->mRemoteMaxInfoUnit);
+ return (pConn->mRemoteMaxInfoUnit);
+}
+
+
+/*******************************************************************************
+**
+** Function: getRemoteRecvWindow
+**
+** Description: Get peer's receive window size.
+** jniHandle: Handle of the connection.
+**
+** Returns: Peer's receive window size.
+**
+*******************************************************************************/
+UINT8 PeerToPeer::getRemoteRecvWindow (tJNI_HANDLE jniHandle)
+{
+ static const char fn [] = "PeerToPeer::getRemoteRecvWindow";
+ ALOGD ("%s: client jni handle: %u", fn, jniHandle);
+ sp<NfaConn> pConn = NULL;
+
+ if ((pConn = findConnection(jniHandle)) == NULL)
+ {
+ ALOGE ("%s: can't find client", fn);
+ return 0;
+ }
+ return pConn->mRemoteRecvWindow;
+}
+
+/*******************************************************************************
+**
+** Function: setP2pListenMask
+**
+** Description: Sets the p2p listen technology mask.
+** p2pListenMask: the p2p listen mask to be set?
+**
+** Returns: None
+**
+*******************************************************************************/
+void PeerToPeer::setP2pListenMask (tNFA_TECHNOLOGY_MASK p2pListenMask) {
+ mP2pListenTechMask = p2pListenMask;
+}
+
+/*******************************************************************************
+**
+** Function: enableP2pListening
+**
+** Description: Start/stop polling/listening to peer that supports P2P.
+** isEnable: Is enable polling/listening?
+**
+** Returns: None
+**
+*******************************************************************************/
+void PeerToPeer::enableP2pListening (bool isEnable)
+{
+ static const char fn [] = "PeerToPeer::enableP2pListening";
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+
+ ALOGD ("%s: enter isEnable: %u mIsP2pListening: %u", fn, isEnable, mIsP2pListening);
+
+ // If request to enable P2P listening, and we were not already listening
+ if ( (isEnable == true) && (mIsP2pListening == false) && (mP2pListenTechMask != 0) )
+ {
+ SyncEventGuard guard (mSetTechEvent);
+ if ((nfaStat = NFA_SetP2pListenTech (mP2pListenTechMask)) == NFA_STATUS_OK)
+ {
+ mSetTechEvent.wait ();
+ mIsP2pListening = true;
+ }
+ else
+ ALOGE ("%s: fail enable listen; error=0x%X", fn, nfaStat);
+ }
+ else if ( (isEnable == false) && (mIsP2pListening == true) )
+ {
+ SyncEventGuard guard (mSetTechEvent);
+ // Request to disable P2P listening, check if it was enabled
+ if ((nfaStat = NFA_SetP2pListenTech(0)) == NFA_STATUS_OK)
+ {
+ mSetTechEvent.wait ();
+ mIsP2pListening = false;
+ }
+ else
+ ALOGE ("%s: fail disable listen; error=0x%X", fn, nfaStat);
+ }
+ ALOGD ("%s: exit; mIsP2pListening: %u", fn, mIsP2pListening);
+}
+
+
+/*******************************************************************************
+**
+** Function: handleNfcOnOff
+**
+** Description: Handle events related to turning NFC on/off by the user.
+** isOn: Is NFC turning on?
+**
+** Returns: None
+**
+*******************************************************************************/
+void PeerToPeer::handleNfcOnOff (bool isOn)
+{
+ static const char fn [] = "PeerToPeer::handleNfcOnOff";
+ ALOGD ("%s: enter; is on=%u", fn, isOn);
+ tNFA_STATUS stat = NFA_STATUS_FAILED;
+
+ mIsP2pListening = false; // In both cases, P2P will not be listening
+
+ AutoMutex mutex(mMutex);
+ if (isOn)
+ {
+ // Start with no clients or servers
+ memset (mServers, 0, sizeof(mServers));
+ memset (mClients, 0, sizeof(mClients));
+ }
+ else
+ {
+ int ii = 0, jj = 0;
+
+ // Disconnect through all the clients
+ for (ii = 0; ii < sMax; ii++)
+ {
+ if (mClients[ii] != NULL)
+ {
+ if (mClients[ii]->mClientConn->mNfaConnHandle == NFA_HANDLE_INVALID)
+ {
+ SyncEventGuard guard (mClients[ii]->mConnectingEvent);
+ mClients[ii]->mConnectingEvent.notifyOne();
+ }
+ else
+ {
+ mClients[ii]->mClientConn->mNfaConnHandle = NFA_HANDLE_INVALID;
+ {
+ SyncEventGuard guard1 (mClients[ii]->mClientConn->mCongEvent);
+ mClients[ii]->mClientConn->mCongEvent.notifyOne (); //unblock send()
+ }
+ {
+ SyncEventGuard guard2 (mClients[ii]->mClientConn->mReadEvent);
+ mClients[ii]->mClientConn->mReadEvent.notifyOne (); //unblock receive()
+ }
+ }
+ }
+ } //loop
+
+ // Now look through all the server control blocks
+ for (ii = 0; ii < sMax; ii++)
+ {
+ if (mServers[ii] != NULL)
+ {
+ mServers[ii]->unblockAll();
+ }
+ } //loop
+
+ }
+ ALOGD ("%s: exit", fn);
+}
+
+
+/*******************************************************************************
+**
+** Function: nfaServerCallback
+**
+** Description: Receive LLCP-related events from the stack.
+** p2pEvent: Event code.
+** eventData: Event data.
+**
+** Returns: None
+**
+*******************************************************************************/
+void PeerToPeer::nfaServerCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* eventData)
+{
+ static const char fn [] = "PeerToPeer::nfaServerCallback";
+ sp<P2pServer> pSrv = NULL;
+ sp<NfaConn> pConn = NULL;
+
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: enter; event=0x%X", fn, p2pEvent);
+
+ switch (p2pEvent)
+ {
+ case NFA_P2P_REG_SERVER_EVT: // NFA_P2pRegisterServer() has started to listen
+ ALOGD ("%s: NFA_P2P_REG_SERVER_EVT; handle: 0x%04x; service sap=0x%02x name: %s", fn,
+ eventData->reg_server.server_handle, eventData->reg_server.server_sap, eventData->reg_server.service_name);
+
+ sP2p.mMutex.lock();
+ pSrv = sP2p.findServerLocked(eventData->reg_server.service_name);
+ sP2p.mMutex.unlock();
+ if (pSrv == NULL)
+ {
+ ALOGE ("%s: NFA_P2P_REG_SERVER_EVT for unknown service: %s", fn, eventData->reg_server.service_name);
+ }
+ else
+ {
+ SyncEventGuard guard (pSrv->mRegServerEvent);
+ pSrv->mNfaP2pServerHandle = eventData->reg_server.server_handle;
+ pSrv->mRegServerEvent.notifyOne(); //unblock registerServer()
+ }
+ break;
+
+ case NFA_P2P_ACTIVATED_EVT: //remote device has activated
+ ALOGD ("%s: NFA_P2P_ACTIVATED_EVT; handle: 0x%04x", fn, eventData->activated.handle);
+ break;
+
+ case NFA_P2P_DEACTIVATED_EVT:
+ ALOGD ("%s: NFA_P2P_DEACTIVATED_EVT; handle: 0x%04x", fn, eventData->activated.handle);
+ break;
+
+ case NFA_P2P_CONN_REQ_EVT:
+ ALOGD ("%s: NFA_P2P_CONN_REQ_EVT; nfa server h=0x%04x; nfa conn h=0x%04x; remote sap=0x%02x", fn,
+ eventData->conn_req.server_handle, eventData->conn_req.conn_handle, eventData->conn_req.remote_sap);
+
+ sP2p.mMutex.lock();
+ pSrv = sP2p.findServerLocked(eventData->conn_req.server_handle);
+ sP2p.mMutex.unlock();
+ if (pSrv == NULL)
+ {
+ ALOGE ("%s: NFA_P2P_CONN_REQ_EVT; unknown server h", fn);
+ return;
+ }
+ ALOGD ("%s: NFA_P2P_CONN_REQ_EVT; server jni h=%u", fn, pSrv->mJniHandle);
+
+ // Look for a connection block that is waiting (handle invalid)
+ if ((pConn = pSrv->findServerConnection((tNFA_HANDLE) NFA_HANDLE_INVALID)) == NULL)
+ {
+ ALOGE ("%s: NFA_P2P_CONN_REQ_EVT; server not listening", fn);
+ }
+ else
+ {
+ SyncEventGuard guard (pSrv->mConnRequestEvent);
+ pConn->mNfaConnHandle = eventData->conn_req.conn_handle;
+ pConn->mRemoteMaxInfoUnit = eventData->conn_req.remote_miu;
+ pConn->mRemoteRecvWindow = eventData->conn_req.remote_rw;
+ ALOGD ("%s: NFA_P2P_CONN_REQ_EVT; server jni h=%u; conn jni h=%u; notify conn req", fn, pSrv->mJniHandle, pConn->mJniHandle);
+ pSrv->mConnRequestEvent.notifyOne(); //unblock accept()
+ }
+ break;
+
+ case NFA_P2P_CONNECTED_EVT:
+ ALOGD ("%s: NFA_P2P_CONNECTED_EVT; h=0x%x remote sap=0x%X", fn,
+ eventData->connected.client_handle, eventData->connected.remote_sap);
+ break;
+
+ case NFA_P2P_DISC_EVT:
+ ALOGD ("%s: NFA_P2P_DISC_EVT; h=0x%04x; reason=0x%X", fn, eventData->disc.handle, eventData->disc.reason);
+ // Look for the connection block
+ if ((pConn = sP2p.findConnection(eventData->disc.handle)) == NULL)
+ {
+ ALOGE ("%s: NFA_P2P_DISC_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->disc.handle);
+ }
+ else
+ {
+ sP2p.mDisconnectMutex.lock ();
+ pConn->mNfaConnHandle = NFA_HANDLE_INVALID;
+ {
+ ALOGD ("%s: NFA_P2P_DISC_EVT; try guard disconn event", fn);
+ SyncEventGuard guard3 (pConn->mDisconnectingEvent);
+ pConn->mDisconnectingEvent.notifyOne ();
+ ALOGD ("%s: NFA_P2P_DISC_EVT; notified disconn event", fn);
+ }
+ {
+ ALOGD ("%s: NFA_P2P_DISC_EVT; try guard congest event", fn);
+ SyncEventGuard guard1 (pConn->mCongEvent);
+ pConn->mCongEvent.notifyOne (); //unblock write (if congested)
+ ALOGD ("%s: NFA_P2P_DISC_EVT; notified congest event", fn);
+ }
+ {
+ ALOGD ("%s: NFA_P2P_DISC_EVT; try guard read event", fn);
+ SyncEventGuard guard2 (pConn->mReadEvent);
+ pConn->mReadEvent.notifyOne (); //unblock receive()
+ ALOGD ("%s: NFA_P2P_DISC_EVT; notified read event", fn);
+ }
+ sP2p.mDisconnectMutex.unlock ();
+ }
+ break;
+
+ case NFA_P2P_DATA_EVT:
+ // Look for the connection block
+ if ((pConn = sP2p.findConnection(eventData->data.handle)) == NULL)
+ {
+ ALOGE ("%s: NFA_P2P_DATA_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->data.handle);
+ }
+ else
+ {
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: NFA_P2P_DATA_EVT; h=0x%X; remote sap=0x%X", fn,
+ eventData->data.handle, eventData->data.remote_sap);
+ SyncEventGuard guard (pConn->mReadEvent);
+ pConn->mReadEvent.notifyOne();
+ }
+ break;
+
+ case NFA_P2P_CONGEST_EVT:
+ // Look for the connection block
+ if ((pConn = sP2p.findConnection(eventData->congest.handle)) == NULL)
+ {
+ ALOGE ("%s: NFA_P2P_CONGEST_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->congest.handle);
+ }
+ else
+ {
+ ALOGD ("%s: NFA_P2P_CONGEST_EVT; nfa handle: 0x%04x congested: %u", fn,
+ eventData->congest.handle, eventData->congest.is_congested);
+ if (eventData->congest.is_congested == FALSE)
+ {
+ SyncEventGuard guard (pConn->mCongEvent);
+ pConn->mCongEvent.notifyOne();
+ }
+ }
+ break;
+
+ default:
+ ALOGE ("%s: unknown event 0x%X ????", fn, p2pEvent);
+ break;
+ }
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: exit", fn);
+}
+
+
+/*******************************************************************************
+**
+** Function: nfaClientCallback
+**
+** Description: Receive LLCP-related events from the stack.
+** p2pEvent: Event code.
+** eventData: Event data.
+**
+** Returns: None
+**
+*******************************************************************************/
+void PeerToPeer::nfaClientCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* eventData)
+{
+ static const char fn [] = "PeerToPeer::nfaClientCallback";
+ sp<NfaConn> pConn = NULL;
+ sp<P2pClient> pClient = NULL;
+
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: enter; event=%u", fn, p2pEvent);
+
+ switch (p2pEvent)
+ {
+ case NFA_P2P_REG_CLIENT_EVT:
+ // Look for a client that is trying to register
+ if ((pClient = sP2p.findClient ((tNFA_HANDLE)NFA_HANDLE_INVALID)) == NULL)
+ {
+ ALOGE ("%s: NFA_P2P_REG_CLIENT_EVT: can't find waiting client", fn);
+ }
+ else
+ {
+ ALOGD ("%s: NFA_P2P_REG_CLIENT_EVT; Conn Handle: 0x%04x, pClient: 0x%p", fn, eventData->reg_client.client_handle, pClient.get());
+
+ SyncEventGuard guard (pClient->mRegisteringEvent);
+ pClient->mNfaP2pClientHandle = eventData->reg_client.client_handle;
+ pClient->mRegisteringEvent.notifyOne();
+ }
+ break;
+
+ case NFA_P2P_ACTIVATED_EVT:
+ // Look for a client that is trying to register
+ if ((pClient = sP2p.findClient (eventData->activated.handle)) == NULL)
+ {
+ ALOGE ("%s: NFA_P2P_ACTIVATED_EVT: can't find client", fn);
+ }
+ else
+ {
+ ALOGD ("%s: NFA_P2P_ACTIVATED_EVT; Conn Handle: 0x%04x, pClient: 0x%p", fn, eventData->activated.handle, pClient.get());
+ }
+ break;
+
+ case NFA_P2P_DEACTIVATED_EVT:
+ ALOGD ("%s: NFA_P2P_DEACTIVATED_EVT: conn handle: 0x%X", fn, eventData->deactivated.handle);
+ break;
+
+ case NFA_P2P_CONNECTED_EVT:
+ // Look for the client that is trying to connect
+ if ((pClient = sP2p.findClient (eventData->connected.client_handle)) == NULL)
+ {
+ ALOGE ("%s: NFA_P2P_CONNECTED_EVT: can't find client: 0x%04x", fn, eventData->connected.client_handle);
+ }
+ else
+ {
+ ALOGD ("%s: NFA_P2P_CONNECTED_EVT; client_handle=0x%04x conn_handle: 0x%04x remote sap=0x%X pClient: 0x%p", fn,
+ eventData->connected.client_handle, eventData->connected.conn_handle, eventData->connected.remote_sap, pClient.get());
+
+ SyncEventGuard guard (pClient->mConnectingEvent);
+ pClient->mClientConn->mNfaConnHandle = eventData->connected.conn_handle;
+ pClient->mClientConn->mRemoteMaxInfoUnit = eventData->connected.remote_miu;
+ pClient->mClientConn->mRemoteRecvWindow = eventData->connected.remote_rw;
+ pClient->mConnectingEvent.notifyOne(); //unblock createDataLinkConn()
+ }
+ break;
+
+ case NFA_P2P_DISC_EVT:
+ ALOGD ("%s: NFA_P2P_DISC_EVT; h=0x%04x; reason=0x%X", fn, eventData->disc.handle, eventData->disc.reason);
+ // Look for the connection block
+ if ((pConn = sP2p.findConnection(eventData->disc.handle)) == NULL)
+ {
+ // If no connection, may be a client that is trying to connect
+ if ((pClient = sP2p.findClientCon ((tNFA_HANDLE)NFA_HANDLE_INVALID)) == NULL)
+ {
+ ALOGE ("%s: NFA_P2P_DISC_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->disc.handle);
+ return;
+ }
+ // Unblock createDataLinkConn()
+ SyncEventGuard guard (pClient->mConnectingEvent);
+ pClient->mConnectingEvent.notifyOne();
+ }
+ else
+ {
+ sP2p.mDisconnectMutex.lock ();
+ pConn->mNfaConnHandle = NFA_HANDLE_INVALID;
+ {
+ ALOGD ("%s: NFA_P2P_DISC_EVT; try guard disconn event", fn);
+ SyncEventGuard guard3 (pConn->mDisconnectingEvent);
+ pConn->mDisconnectingEvent.notifyOne ();
+ ALOGD ("%s: NFA_P2P_DISC_EVT; notified disconn event", fn);
+ }
+ {
+ ALOGD ("%s: NFA_P2P_DISC_EVT; try guard congest event", fn);
+ SyncEventGuard guard1 (pConn->mCongEvent);
+ pConn->mCongEvent.notifyOne(); //unblock write (if congested)
+ ALOGD ("%s: NFA_P2P_DISC_EVT; notified congest event", fn);
+ }
+ {
+ ALOGD ("%s: NFA_P2P_DISC_EVT; try guard read event", fn);
+ SyncEventGuard guard2 (pConn->mReadEvent);
+ pConn->mReadEvent.notifyOne(); //unblock receive()
+ ALOGD ("%s: NFA_P2P_DISC_EVT; notified read event", fn);
+ }
+ sP2p.mDisconnectMutex.unlock ();
+ }
+ break;
+
+ case NFA_P2P_DATA_EVT:
+ // Look for the connection block
+ if ((pConn = sP2p.findConnection(eventData->data.handle)) == NULL)
+ {
+ ALOGE ("%s: NFA_P2P_DATA_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->data.handle);
+ }
+ else
+ {
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: NFA_P2P_DATA_EVT; h=0x%X; remote sap=0x%X", fn,
+ eventData->data.handle, eventData->data.remote_sap);
+ SyncEventGuard guard (pConn->mReadEvent);
+ pConn->mReadEvent.notifyOne();
+ }
+ break;
+
+ case NFA_P2P_CONGEST_EVT:
+ // Look for the connection block
+ if ((pConn = sP2p.findConnection(eventData->congest.handle)) == NULL)
+ {
+ ALOGE ("%s: NFA_P2P_CONGEST_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->congest.handle);
+ }
+ else
+ {
+ ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: NFA_P2P_CONGEST_EVT; nfa handle: 0x%04x congested: %u", fn,
+ eventData->congest.handle, eventData->congest.is_congested);
+
+ SyncEventGuard guard (pConn->mCongEvent);
+ pConn->mCongEvent.notifyOne();
+ }
+ break;
+
+ default:
+ ALOGE ("%s: unknown event 0x%X ????", fn, p2pEvent);
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: connectionEventHandler
+**
+** Description: Receive events from the stack.
+** event: Event code.
+** eventData: Event data.
+**
+** Returns: None
+**
+*******************************************************************************/
+void PeerToPeer::connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* eventData)
+{
+ switch (event)
+ {
+ case NFA_SET_P2P_LISTEN_TECH_EVT:
+ {
+ SyncEventGuard guard (mSetTechEvent);
+ mSetTechEvent.notifyOne(); //unblock NFA_SetP2pListenTech()
+ break;
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: getNextJniHandle
+**
+** Description: Get a new JNI handle.
+**
+** Returns: A new JNI handle.
+**
+*******************************************************************************/
+PeerToPeer::tJNI_HANDLE PeerToPeer::getNewJniHandle ()
+{
+ tJNI_HANDLE newHandle = 0;
+
+ mNewJniHandleMutex.lock ();
+ newHandle = mNextJniHandle++;
+ mNewJniHandleMutex.unlock ();
+ return newHandle;
+}
+
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+
+/*******************************************************************************
+**
+** Function: P2pServer
+**
+** Description: Initialize member variables.
+**
+** Returns: None
+**
+*******************************************************************************/
+P2pServer::P2pServer(PeerToPeer::tJNI_HANDLE jniHandle, const char* serviceName)
+: mNfaP2pServerHandle (NFA_HANDLE_INVALID),
+ mJniHandle (jniHandle)
+{
+ mServiceName.assign (serviceName);
+
+ memset (mServerConn, 0, sizeof(mServerConn));
+}
+
+bool P2pServer::registerWithStack()
+{
+ static const char fn [] = "P2pServer::registerWithStack";
+ ALOGD ("%s: enter; service name: %s JNI handle: %u", fn, mServiceName.c_str(), mJniHandle);
+ tNFA_STATUS stat = NFA_STATUS_OK;
+ UINT8 serverSap = NFA_P2P_ANY_SAP;
+
+ /**********************
+ default values for all LLCP parameters:
+ - Local Link MIU (LLCP_MIU)
+ - Option parameter (LLCP_OPT_VALUE)
+ - Response Waiting Time Index (LLCP_WAITING_TIME)
+ - Local Link Timeout (LLCP_LTO_VALUE)
+ - Inactivity Timeout as initiator role (LLCP_INIT_INACTIVITY_TIMEOUT)
+ - Inactivity Timeout as target role (LLCP_TARGET_INACTIVITY_TIMEOUT)
+ - Delay SYMM response (LLCP_DELAY_RESP_TIME)
+ - Data link connection timeout (LLCP_DATA_LINK_CONNECTION_TOUT)
+ - Delay timeout to send first PDU as initiator (LLCP_DELAY_TIME_TO_SEND_FIRST_PDU)
+ ************************/
+ stat = NFA_P2pSetLLCPConfig (LLCP_MAX_MIU,
+ LLCP_OPT_VALUE,
+ LLCP_WAITING_TIME,
+ LLCP_LTO_VALUE,
+ 0, //use 0 for infinite timeout for symmetry procedure when acting as initiator
+ 0, //use 0 for infinite timeout for symmetry procedure when acting as target
+ LLCP_DELAY_RESP_TIME,
+ LLCP_DATA_LINK_CONNECTION_TOUT,
+ LLCP_DELAY_TIME_TO_SEND_FIRST_PDU);
+ if (stat != NFA_STATUS_OK)
+ ALOGE ("%s: fail set LLCP config; error=0x%X", fn, stat);
+
+ if (sSnepServiceName.compare(mServiceName) == 0)
+ serverSap = LLCP_SAP_SNEP; //LLCP_SAP_SNEP == 4
+
+ {
+ SyncEventGuard guard (mRegServerEvent);
+ stat = NFA_P2pRegisterServer (serverSap, NFA_P2P_DLINK_TYPE, const_cast<char*>(mServiceName.c_str()),
+ PeerToPeer::nfaServerCallback);
+ if (stat != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: fail register p2p server; error=0x%X", fn, stat);
+ return (false);
+ }
+ ALOGD ("%s: wait for listen-completion event", fn);
+ // Wait for NFA_P2P_REG_SERVER_EVT
+ mRegServerEvent.wait ();
+ }
+
+ return (mNfaP2pServerHandle != NFA_HANDLE_INVALID);
+}
+
+bool P2pServer::accept(PeerToPeer::tJNI_HANDLE serverJniHandle, PeerToPeer::tJNI_HANDLE connJniHandle,
+ int maxInfoUnit, int recvWindow)
+{
+ static const char fn [] = "P2pServer::accept";
+ tNFA_STATUS nfaStat = NFA_STATUS_OK;
+
+ sp<NfaConn> connection = allocateConnection(connJniHandle);
+ if (connection == NULL) {
+ ALOGE ("%s: failed to allocate new server connection", fn);
+ return false;
+ }
+
+ {
+ // Wait for NFA_P2P_CONN_REQ_EVT or NFA_NDEF_DATA_EVT when remote device requests connection
+ SyncEventGuard guard (mConnRequestEvent);
+ ALOGD ("%s: serverJniHandle: %u; connJniHandle: %u; wait for incoming connection", fn,
+ serverJniHandle, connJniHandle);
+ mConnRequestEvent.wait();
+ ALOGD ("%s: serverJniHandle: %u; connJniHandle: %u; nfa conn h: 0x%X; got incoming connection", fn,
+ serverJniHandle, connJniHandle, connection->mNfaConnHandle);
+ }
+
+ if (connection->mNfaConnHandle == NFA_HANDLE_INVALID)
+ {
+ removeServerConnection(connJniHandle);
+ ALOGD ("%s: no handle assigned", fn);
+ return (false);
+ }
+
+ ALOGD ("%s: serverJniHandle: %u; connJniHandle: %u; nfa conn h: 0x%X; try accept", fn,
+ serverJniHandle, connJniHandle, connection->mNfaConnHandle);
+ nfaStat = NFA_P2pAcceptConn (connection->mNfaConnHandle, maxInfoUnit, recvWindow);
+
+ if (nfaStat != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: fail to accept remote; error=0x%X", fn, nfaStat);
+ return (false);
+ }
+
+ ALOGD ("%s: exit; serverJniHandle: %u; connJniHandle: %u; nfa conn h: 0x%X", fn,
+ serverJniHandle, connJniHandle, connection->mNfaConnHandle);
+ return (true);
+}
+
+void P2pServer::unblockAll()
+{
+ AutoMutex mutex(mMutex);
+ for (int jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++)
+ {
+ if (mServerConn[jj] != NULL)
+ {
+ mServerConn[jj]->mNfaConnHandle = NFA_HANDLE_INVALID;
+ {
+ SyncEventGuard guard1 (mServerConn[jj]->mCongEvent);
+ mServerConn[jj]->mCongEvent.notifyOne (); //unblock write (if congested)
+ }
+ {
+ SyncEventGuard guard2 (mServerConn[jj]->mReadEvent);
+ mServerConn[jj]->mReadEvent.notifyOne (); //unblock receive()
+ }
+ }
+ }
+}
+
+sp<NfaConn> P2pServer::allocateConnection (PeerToPeer::tJNI_HANDLE jniHandle)
+{
+ AutoMutex mutex(mMutex);
+ // First, find a free connection block to handle the connection
+ for (int ii = 0; ii < MAX_NFA_CONNS_PER_SERVER; ii++)
+ {
+ if (mServerConn[ii] == NULL)
+ {
+ mServerConn[ii] = new NfaConn;
+ mServerConn[ii]->mJniHandle = jniHandle;
+ return mServerConn[ii];
+ }
+ }
+
+ return NULL;
+}
+
+
+/*******************************************************************************
+**
+** Function: findServerConnection
+**
+** Description: Find a P2pServer that has the handle.
+** nfaConnHandle: NFA connection handle.
+**
+** Returns: P2pServer object.
+**
+*******************************************************************************/
+sp<NfaConn> P2pServer::findServerConnection (tNFA_HANDLE nfaConnHandle)
+{
+ int jj = 0;
+
+ AutoMutex mutex(mMutex);
+ for (jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++)
+ {
+ if ( (mServerConn[jj] != NULL) && (mServerConn[jj]->mNfaConnHandle == nfaConnHandle) )
+ return (mServerConn[jj]);
+ }
+
+ // If here, not found
+ return (NULL);
+}
+
+/*******************************************************************************
+**
+** Function: findServerConnection
+**
+** Description: Find a P2pServer that has the handle.
+** nfaConnHandle: NFA connection handle.
+**
+** Returns: P2pServer object.
+**
+*******************************************************************************/
+sp<NfaConn> P2pServer::findServerConnection (PeerToPeer::tJNI_HANDLE jniHandle)
+{
+ int jj = 0;
+
+ AutoMutex mutex(mMutex);
+ for (jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++)
+ {
+ if ( (mServerConn[jj] != NULL) && (mServerConn[jj]->mJniHandle == jniHandle) )
+ return (mServerConn[jj]);
+ }
+
+ // If here, not found
+ return (NULL);
+}
+
+/*******************************************************************************
+**
+** Function: removeServerConnection
+**
+** Description: Find a P2pServer that has the handle.
+** nfaConnHandle: NFA connection handle.
+**
+** Returns: P2pServer object.
+**
+*******************************************************************************/
+bool P2pServer::removeServerConnection (PeerToPeer::tJNI_HANDLE jniHandle)
+{
+ int jj = 0;
+
+ AutoMutex mutex(mMutex);
+ for (jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++)
+ {
+ if ( (mServerConn[jj] != NULL) && (mServerConn[jj]->mJniHandle == jniHandle) ) {
+ mServerConn[jj] = NULL;
+ return true;
+ }
+ }
+
+ // If here, not found
+ return false;
+}
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+
+/*******************************************************************************
+**
+** Function: P2pClient
+**
+** Description: Initialize member variables.
+**
+** Returns: None
+**
+*******************************************************************************/
+P2pClient::P2pClient ()
+: mNfaP2pClientHandle (NFA_HANDLE_INVALID),
+ mIsConnecting (false)
+{
+ mClientConn = new NfaConn();
+}
+
+
+/*******************************************************************************
+**
+** Function: ~P2pClient
+**
+** Description: Free all resources.
+**
+** Returns: None
+**
+*******************************************************************************/
+P2pClient::~P2pClient ()
+{
+}
+
+
+/////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
+
+
+/*******************************************************************************
+**
+** Function: NfaConn
+**
+** Description: Initialize member variables.
+**
+** Returns: None
+**
+*******************************************************************************/
+NfaConn::NfaConn()
+: mNfaConnHandle (NFA_HANDLE_INVALID),
+ mJniHandle (0),
+ mMaxInfoUnit (0),
+ mRecvWindow (0),
+ mRemoteMaxInfoUnit (0),
+ mRemoteRecvWindow (0)
+{
+}
+
diff --git a/nci/jni/PeerToPeer.h b/nci/jni/PeerToPeer.h
new file mode 100644
index 0000000..3e8ffec
--- /dev/null
+++ b/nci/jni/PeerToPeer.h
@@ -0,0 +1,779 @@
+/*
+ * 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.
+ */
+
+/*
+ * Communicate with a peer using NFC-DEP, LLCP, SNEP.
+ */
+#pragma once
+#include <utils/RefBase.h>
+#include <utils/StrongPointer.h>
+#include "SyncEvent.h"
+#include "NfcJniUtil.h"
+#include <string>
+extern "C"
+{
+ #include "nfa_p2p_api.h"
+ #include "nfa_snep_api.h"
+}
+
+class P2pServer;
+class P2pClient;
+class NfaConn;
+#define MAX_NFA_CONNS_PER_SERVER 5
+
+/*****************************************************************************
+**
+** Name: PeerToPeer
+**
+** Description: Communicate with a peer using NFC-DEP, LLCP, SNEP.
+**
+*****************************************************************************/
+class PeerToPeer
+{
+public:
+ typedef unsigned int tJNI_HANDLE;
+
+ /*******************************************************************************
+ **
+ ** Function: PeerToPeer
+ **
+ ** Description: Initialize member variables.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ PeerToPeer ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: ~PeerToPeer
+ **
+ ** Description: Free all resources.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ ~PeerToPeer ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: getInstance
+ **
+ ** Description: Get the singleton PeerToPeer object.
+ **
+ ** Returns: Singleton PeerToPeer object.
+ **
+ *******************************************************************************/
+ static PeerToPeer& getInstance();
+
+
+ /*******************************************************************************
+ **
+ ** Function: initialize
+ **
+ ** Description: Initialize member variables.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void initialize ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: llcpActivatedHandler
+ **
+ ** Description: Receive LLLCP-activated event from stack.
+ ** nat: JVM-related data.
+ ** activated: Event data.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void llcpActivatedHandler (nfc_jni_native_data* nativeData, tNFA_LLCP_ACTIVATED& activated);
+
+
+ /*******************************************************************************
+ **
+ ** Function: llcpDeactivatedHandler
+ **
+ ** Description: Receive LLLCP-deactivated event from stack.
+ ** nat: JVM-related data.
+ ** deactivated: Event data.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void llcpDeactivatedHandler (nfc_jni_native_data* nativeData, tNFA_LLCP_DEACTIVATED& deactivated);
+
+
+ /*******************************************************************************
+ **
+ ** Function: connectionEventHandler
+ **
+ ** Description: Receive events from the stack.
+ ** event: Event code.
+ ** eventData: Event data.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* eventData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: registerServer
+ **
+ ** Description: Let a server start listening for peer's connection request.
+ ** jniHandle: Connection handle.
+ ** serviceName: Server's service name.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool registerServer (tJNI_HANDLE jniHandle, const char* serviceName);
+
+
+ /*******************************************************************************
+ **
+ ** Function: deregisterServer
+ **
+ ** Description: Stop a P2pServer from listening for peer.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool deregisterServer (tJNI_HANDLE jniHandle);
+
+
+ /*******************************************************************************
+ **
+ ** Function: accept
+ **
+ ** Description: Accept a peer's request to connect.
+ ** serverJniHandle: Server's handle.
+ ** connJniHandle: Connection handle.
+ ** maxInfoUnit: Maximum information unit.
+ ** recvWindow: Receive window size.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool accept (tJNI_HANDLE serverJniHandle, tJNI_HANDLE connJniHandle, int maxInfoUnit, int recvWindow);
+
+
+ /*******************************************************************************
+ **
+ ** Function: createClient
+ **
+ ** Description: Create a P2pClient object for a new out-bound connection.
+ ** jniHandle: Connection handle.
+ ** miu: Maximum information unit.
+ ** rw: Receive window size.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool createClient (tJNI_HANDLE jniHandle, UINT16 miu, UINT8 rw);
+
+
+ /*******************************************************************************
+ **
+ ** Function: connectConnOriented
+ **
+ ** Description: Estabish a connection-oriented connection to a peer.
+ ** jniHandle: Connection handle.
+ ** serviceName: Peer's service name.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool connectConnOriented (tJNI_HANDLE jniHandle, const char* serviceName);
+
+
+ /*******************************************************************************
+ **
+ ** Function: connectConnOriented
+ **
+ ** Description: Estabish a connection-oriented connection to a peer.
+ ** jniHandle: Connection handle.
+ ** destinationSap: Peer's service access point.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool connectConnOriented (tJNI_HANDLE jniHandle, UINT8 destinationSap);
+
+
+ /*******************************************************************************
+ **
+ ** Function: send
+ **
+ ** Description: Send data to peer.
+ ** jniHandle: Handle of connection.
+ ** buffer: Buffer of data.
+ ** bufferLen: Length of data.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool send (tJNI_HANDLE jniHandle, UINT8* buffer, UINT16 bufferLen);
+
+
+ /*******************************************************************************
+ **
+ ** Function: receive
+ **
+ ** Description: Receive data from peer.
+ ** jniHandle: Handle of connection.
+ ** buffer: Buffer to store data.
+ ** bufferLen: Max length of buffer.
+ ** actualLen: Actual length received.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool receive (tJNI_HANDLE jniHandle, UINT8* buffer, UINT16 bufferLen, UINT16& actualLen);
+
+
+ /*******************************************************************************
+ **
+ ** Function: disconnectConnOriented
+ **
+ ** Description: Disconnect a connection-oriented connection with peer.
+ ** jniHandle: Handle of connection.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool disconnectConnOriented (tJNI_HANDLE jniHandle);
+
+
+ /*******************************************************************************
+ **
+ ** Function: getRemoteMaxInfoUnit
+ **
+ ** Description: Get peer's max information unit.
+ ** jniHandle: Handle of the connection.
+ **
+ ** Returns: Peer's max information unit.
+ **
+ *******************************************************************************/
+ UINT16 getRemoteMaxInfoUnit (tJNI_HANDLE jniHandle);
+
+
+ /*******************************************************************************
+ **
+ ** Function: getRemoteRecvWindow
+ **
+ ** Description: Get peer's receive window size.
+ ** jniHandle: Handle of the connection.
+ **
+ ** Returns: Peer's receive window size.
+ **
+ *******************************************************************************/
+ UINT8 getRemoteRecvWindow (tJNI_HANDLE jniHandle);
+
+
+ /*******************************************************************************
+ **
+ ** Function: setP2pListenMask
+ **
+ ** Description: Sets the p2p listen technology mask.
+ ** p2pListenMask: the p2p listen mask to be set?
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void setP2pListenMask (tNFA_TECHNOLOGY_MASK p2pListenMask);
+
+ /*******************************************************************************
+ **
+ ** Function: enableP2pListening
+ **
+ ** Description: Start/stop polling/listening to peer that supports P2P.
+ ** isEnable: Is enable polling/listening?
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void enableP2pListening (bool isEnable);
+
+
+ /*******************************************************************************
+ **
+ ** Function: handleNfcOnOff
+ **
+ ** Description: Handle events related to turning NFC on/off by the user.
+ ** isOn: Is NFC turning on?
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void handleNfcOnOff (bool isOn);
+
+
+ /*******************************************************************************
+ **
+ ** Function: getNextJniHandle
+ **
+ ** Description: Get a new JNI handle.
+ **
+ ** Returns: A new JNI handle.
+ **
+ *******************************************************************************/
+ tJNI_HANDLE getNewJniHandle ();
+
+ /*******************************************************************************
+ **
+ ** Function: nfaServerCallback
+ **
+ ** Description: Receive LLCP-related events from the stack.
+ ** p2pEvent: Event code.
+ ** eventData: Event data.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ static void nfaServerCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA *eventData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: nfaClientCallback
+ **
+ ** Description: Receive LLCP-related events from the stack.
+ ** p2pEvent: Event code.
+ ** eventData: Event data.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ static void nfaClientCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA *eventData);
+
+private:
+ static const int sMax = 10;
+ static PeerToPeer sP2p;
+
+ // Variables below only accessed from a single thread
+ UINT16 mRemoteWKS; // Peer's well known services
+ bool mIsP2pListening; // If P2P listening is enabled or not
+ tNFA_TECHNOLOGY_MASK mP2pListenTechMask; // P2P Listen mask
+
+ // Variable below is protected by mNewJniHandleMutex
+ tJNI_HANDLE mNextJniHandle;
+
+ // Variables below protected by mMutex
+ // A note on locking order: mMutex in PeerToPeer is *ALWAYS*
+ // locked before any locks / guards in P2pServer / P2pClient
+ Mutex mMutex;
+ android::sp<P2pServer> mServers [sMax];
+ android::sp<P2pClient> mClients [sMax];
+
+ // Synchronization variables
+ SyncEvent mSetTechEvent; // completion event for NFA_SetP2pListenTech()
+ SyncEvent mSnepDefaultServerStartStopEvent; // completion event for NFA_SnepStartDefaultServer(), NFA_SnepStopDefaultServer()
+ SyncEvent mSnepRegisterEvent; // completion event for NFA_SnepRegisterClient()
+ Mutex mDisconnectMutex; // synchronize the disconnect operation
+ Mutex mNewJniHandleMutex; // synchronize the creation of a new JNI handle
+
+ /*******************************************************************************
+ **
+ ** Function: snepClientCallback
+ **
+ ** Description: Receive SNEP-related events from the stack.
+ ** snepEvent: Event code.
+ ** eventData: Event data.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ static void snepClientCallback (tNFA_SNEP_EVT snepEvent, tNFA_SNEP_EVT_DATA *eventData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: ndefTypeCallback
+ **
+ ** Description: Receive NDEF-related events from the stack.
+ ** ndefEvent: Event code.
+ ** eventData: Event data.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ static void ndefTypeCallback (tNFA_NDEF_EVT event, tNFA_NDEF_EVT_DATA *evetnData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: findServer
+ **
+ ** Description: Find a PeerToPeer object by connection handle.
+ ** nfaP2pServerHandle: Connectin handle.
+ **
+ ** Returns: PeerToPeer object.
+ **
+ *******************************************************************************/
+ android::sp<P2pServer> findServerLocked (tNFA_HANDLE nfaP2pServerHandle);
+
+
+ /*******************************************************************************
+ **
+ ** Function: findServer
+ **
+ ** Description: Find a PeerToPeer object by connection handle.
+ ** serviceName: service name.
+ **
+ ** Returns: PeerToPeer object.
+ **
+ *******************************************************************************/
+ android::sp<P2pServer> findServerLocked (tJNI_HANDLE jniHandle);
+
+
+ /*******************************************************************************
+ **
+ ** Function: findServer
+ **
+ ** Description: Find a PeerToPeer object by service name
+ ** serviceName: service name.
+ **
+ ** Returns: PeerToPeer object.
+ **
+ *******************************************************************************/
+ android::sp<P2pServer> findServerLocked (const char *serviceName);
+
+
+ /*******************************************************************************
+ **
+ ** Function: removeServer
+ **
+ ** Description: Free resources related to a server.
+ ** jniHandle: Connection handle.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void removeServer (tJNI_HANDLE jniHandle);
+
+
+ /*******************************************************************************
+ **
+ ** Function: removeConn
+ **
+ ** Description: Free resources related to a connection.
+ ** jniHandle: Connection handle.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void removeConn (tJNI_HANDLE jniHandle);
+
+
+ /*******************************************************************************
+ **
+ ** Function: createDataLinkConn
+ **
+ ** Description: Establish a connection-oriented connection to a peer.
+ ** jniHandle: Connection handle.
+ ** serviceName: Peer's service name.
+ ** destinationSap: Peer's service access point.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool createDataLinkConn (tJNI_HANDLE jniHandle, const char* serviceName, UINT8 destinationSap);
+
+
+ /*******************************************************************************
+ **
+ ** Function: findClient
+ **
+ ** Description: Find a PeerToPeer object with a client connection handle.
+ ** nfaConnHandle: Connection handle.
+ **
+ ** Returns: PeerToPeer object.
+ **
+ *******************************************************************************/
+ android::sp<P2pClient> findClient (tNFA_HANDLE nfaConnHandle);
+
+
+ /*******************************************************************************
+ **
+ ** Function: findClient
+ **
+ ** Description: Find a PeerToPeer object with a client connection handle.
+ ** jniHandle: Connection handle.
+ **
+ ** Returns: PeerToPeer object.
+ **
+ *******************************************************************************/
+ android::sp<P2pClient> findClient (tJNI_HANDLE jniHandle);
+
+
+ /*******************************************************************************
+ **
+ ** Function: findClientCon
+ **
+ ** Description: Find a PeerToPeer object with a client connection handle.
+ ** nfaConnHandle: Connection handle.
+ **
+ ** Returns: PeerToPeer object.
+ **
+ *******************************************************************************/
+ android::sp<P2pClient> findClientCon (tNFA_HANDLE nfaConnHandle);
+
+
+ /*******************************************************************************
+ **
+ ** Function: findConnection
+ **
+ ** Description: Find a PeerToPeer object with a connection handle.
+ ** nfaConnHandle: Connection handle.
+ **
+ ** Returns: PeerToPeer object.
+ **
+ *******************************************************************************/
+ android::sp<NfaConn> findConnection (tNFA_HANDLE nfaConnHandle);
+
+
+ /*******************************************************************************
+ **
+ ** Function: findConnection
+ **
+ ** Description: Find a PeerToPeer object with a connection handle.
+ ** jniHandle: Connection handle.
+ **
+ ** Returns: PeerToPeer object.
+ **
+ *******************************************************************************/
+ android::sp<NfaConn> findConnection (tJNI_HANDLE jniHandle);
+};
+
+
+/*****************************************************************************
+**
+** Name: NfaConn
+**
+** Description: Store information about a connection related to a peer.
+**
+*****************************************************************************/
+class NfaConn : public android::RefBase
+{
+public:
+ tNFA_HANDLE mNfaConnHandle; // NFA handle of the P2P connection
+ PeerToPeer::tJNI_HANDLE mJniHandle; // JNI handle of the P2P connection
+ UINT16 mMaxInfoUnit;
+ UINT8 mRecvWindow;
+ UINT16 mRemoteMaxInfoUnit;
+ UINT8 mRemoteRecvWindow;
+ SyncEvent mReadEvent; // event for reading
+ SyncEvent mCongEvent; // event for congestion
+ SyncEvent mDisconnectingEvent; // event for disconnecting
+
+
+ /*******************************************************************************
+ **
+ ** Function: NfaConn
+ **
+ ** Description: Initialize member variables.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ NfaConn();
+};
+
+
+/*****************************************************************************
+**
+** Name: P2pServer
+**
+** Description: Store information about an in-bound connection from a peer.
+**
+*****************************************************************************/
+class P2pServer : public android::RefBase
+{
+public:
+ static const std::string sSnepServiceName;
+
+ tNFA_HANDLE mNfaP2pServerHandle; // NFA p2p handle of local server
+ PeerToPeer::tJNI_HANDLE mJniHandle; // JNI Handle
+ SyncEvent mRegServerEvent; // for NFA_P2pRegisterServer()
+ SyncEvent mConnRequestEvent; // for accept()
+ std::string mServiceName;
+
+ /*******************************************************************************
+ **
+ ** Function: P2pServer
+ **
+ ** Description: Initialize member variables.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ P2pServer (PeerToPeer::tJNI_HANDLE jniHandle, const char* serviceName);
+
+ /*******************************************************************************
+ **
+ ** Function: registerWithStack
+ **
+ ** Description: Register this server with the stack.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool registerWithStack();
+
+ /*******************************************************************************
+ **
+ ** Function: accept
+ **
+ ** Description: Accept a peer's request to connect.
+ ** serverJniHandle: Server's handle.
+ ** connJniHandle: Connection handle.
+ ** maxInfoUnit: Maximum information unit.
+ ** recvWindow: Receive window size.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool accept (PeerToPeer::tJNI_HANDLE serverJniHandle, PeerToPeer::tJNI_HANDLE connJniHandle,
+ int maxInfoUnit, int recvWindow);
+
+ /*******************************************************************************
+ **
+ ** Function: unblockAll
+ **
+ ** Description: Unblocks all server connections
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ void unblockAll();
+
+ /*******************************************************************************
+ **
+ ** Function: findServerConnection
+ **
+ ** Description: Find a P2pServer that has the handle.
+ ** nfaConnHandle: NFA connection handle.
+ **
+ ** Returns: P2pServer object.
+ **
+ *******************************************************************************/
+ android::sp<NfaConn> findServerConnection (tNFA_HANDLE nfaConnHandle);
+
+ /*******************************************************************************
+ **
+ ** Function: findServerConnection
+ **
+ ** Description: Find a P2pServer that has the handle.
+ ** jniHandle: JNI connection handle.
+ **
+ ** Returns: P2pServer object.
+ **
+ *******************************************************************************/
+ android::sp<NfaConn> findServerConnection (PeerToPeer::tJNI_HANDLE jniHandle);
+
+ /*******************************************************************************
+ **
+ ** Function: removeServerConnection
+ **
+ ** Description: Remove a server connection with the provided handle.
+ ** jniHandle: JNI connection handle.
+ **
+ ** Returns: True if connection found and removed.
+ **
+ *******************************************************************************/
+ bool removeServerConnection(PeerToPeer::tJNI_HANDLE jniHandle);
+
+private:
+ Mutex mMutex;
+ // mServerConn is protected by mMutex
+ android::sp<NfaConn> mServerConn[MAX_NFA_CONNS_PER_SERVER];
+
+ /*******************************************************************************
+ **
+ ** Function: allocateConnection
+ **
+ ** Description: Allocate a new connection to accept on
+ ** jniHandle: JNI connection handle.
+ **
+ ** Returns: Allocated connection object
+ ** NULL if the maximum number of connections was reached
+ **
+ *******************************************************************************/
+ android::sp<NfaConn> allocateConnection (PeerToPeer::tJNI_HANDLE jniHandle);
+};
+
+
+/*****************************************************************************
+**
+** Name: P2pClient
+**
+** Description: Store information about an out-bound connection to a peer.
+**
+*****************************************************************************/
+class P2pClient : public android::RefBase
+{
+public:
+ tNFA_HANDLE mNfaP2pClientHandle; // NFA p2p handle of client
+ bool mIsConnecting; // Set true while connecting
+ android::sp<NfaConn> mClientConn;
+ SyncEvent mRegisteringEvent; // For client registration
+ SyncEvent mConnectingEvent; // for NFA_P2pConnectByName or Sap()
+ SyncEvent mSnepEvent; // To wait for SNEP completion
+
+ /*******************************************************************************
+ **
+ ** Function: P2pClient
+ **
+ ** Description: Initialize member variables.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ P2pClient ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: ~P2pClient
+ **
+ ** Description: Free all resources.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ ~P2pClient ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: unblock
+ **
+ ** Description: Unblocks any threads that are locked on this connection
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void unblock();
+};
+
diff --git a/nci/jni/Pn544Interop.cpp b/nci/jni/Pn544Interop.cpp
new file mode 100644
index 0000000..be92c75
--- /dev/null
+++ b/nci/jni/Pn544Interop.cpp
@@ -0,0 +1,153 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+**
+** Name: Pn544Interop.cpp
+**
+** Description: Implement operations that provide compatibility with NXP
+** PN544 controller. Specifically facilitate peer-to-peer
+** operations with PN544 controller.
+**
+*****************************************************************************/
+#include "OverrideLog.h"
+#include "Pn544Interop.h"
+#include "IntervalTimer.h"
+#include "Mutex.h"
+#include "NfcTag.h"
+namespace android
+{
+ extern void startStopPolling (bool isStartPolling);
+}
+
+
+/*****************************************************************************
+**
+** private variables and functions
+**
+*****************************************************************************/
+
+
+static const int gIntervalTime = 1000; //millisecond between the check to restore polling
+static IntervalTimer gTimer;
+static Mutex gMutex;
+static void pn544InteropStartPolling (union sigval); //callback function for interval timer
+static bool gIsBusy = false; //is timer busy?
+static bool gAbortNow = false; //stop timer during next callback
+
+
+/*******************************************************************************
+**
+** Function: pn544InteropStopPolling
+**
+** Description: Stop polling to let NXP PN544 controller poll.
+** PN544 should activate in P2P mode.
+**
+** Returns: None
+**
+*******************************************************************************/
+void pn544InteropStopPolling ()
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ gMutex.lock ();
+ gTimer.kill ();
+ android::startStopPolling (false);
+ gIsBusy = true;
+ gAbortNow = false;
+ gTimer.set (gIntervalTime, pn544InteropStartPolling); //after some time, start polling again
+ gMutex.unlock ();
+ ALOGD ("%s: exit", __FUNCTION__);
+}
+
+
+/*******************************************************************************
+**
+** Function: pn544InteropStartPolling
+**
+** Description: Start polling when activation state is idle.
+** sigval: Unused.
+**
+** Returns: None
+**
+*******************************************************************************/
+void pn544InteropStartPolling (union sigval)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ gMutex.lock ();
+ NfcTag::ActivationState state = NfcTag::getInstance ().getActivationState ();
+
+ if (gAbortNow)
+ {
+ ALOGD ("%s: abort now", __FUNCTION__);
+ gIsBusy = false;
+ goto TheEnd;
+ }
+
+ if (state == NfcTag::Idle)
+ {
+ ALOGD ("%s: start polling", __FUNCTION__);
+ android::startStopPolling (true);
+ gIsBusy = false;
+ }
+ else
+ {
+ ALOGD ("%s: try again later", __FUNCTION__);
+ gTimer.set (gIntervalTime, pn544InteropStartPolling); //after some time, start polling again
+ }
+
+TheEnd:
+ gMutex.unlock ();
+ ALOGD ("%s: exit", __FUNCTION__);
+}
+
+
+/*******************************************************************************
+**
+** Function: pn544InteropIsBusy
+**
+** Description: Is the code performing operations?
+**
+** Returns: True if the code is busy.
+**
+*******************************************************************************/
+bool pn544InteropIsBusy ()
+{
+ bool isBusy = false;
+ gMutex.lock ();
+ isBusy = gIsBusy;
+ gMutex.unlock ();
+ ALOGD ("%s: %u", __FUNCTION__, isBusy);
+ return isBusy;
+}
+
+
+/*******************************************************************************
+**
+** Function: pn544InteropAbortNow
+**
+** Description: Request to abort all operations.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void pn544InteropAbortNow ()
+{
+ ALOGD ("%s", __FUNCTION__);
+ gMutex.lock ();
+ gAbortNow = true;
+ gMutex.unlock ();
+}
+
diff --git a/nci/jni/Pn544Interop.h b/nci/jni/Pn544Interop.h
new file mode 100644
index 0000000..c9a2df6
--- /dev/null
+++ b/nci/jni/Pn544Interop.h
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+**
+** Name: Pn544Interop.h
+**
+** Description: Implement operations that provide compatibility with NXP
+** PN544 controller. Specifically facilitate peer-to-peer
+** operations with PN544 controller.
+**
+*****************************************************************************/
+#pragma once
+#include "NfcJniUtil.h"
+
+
+/*******************************************************************************
+**
+** Function: pn544InteropStopPolling
+**
+** Description: Stop polling to let NXP PN544 controller poll.
+** PN544 should activate in P2P mode.
+**
+** Returns: None
+**
+*******************************************************************************/
+void pn544InteropStopPolling ();
+
+
+/*******************************************************************************
+**
+** Function: pn544InteropIsBusy
+**
+** Description: Is the code performing operations?
+**
+** Returns: True if the code is busy.
+**
+*******************************************************************************/
+bool pn544InteropIsBusy ();
+
+
+/*******************************************************************************
+**
+** Function: pn544InteropAbortNow
+**
+** Description: Request to abort all operations.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void pn544InteropAbortNow ();
diff --git a/nci/jni/PowerSwitch.cpp b/nci/jni/PowerSwitch.cpp
new file mode 100755
index 0000000..9d58c74
--- /dev/null
+++ b/nci/jni/PowerSwitch.cpp
@@ -0,0 +1,439 @@
+/*
+ * 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.
+ */
+
+/*
+ * Adjust the controller's power states.
+ */
+#include "OverrideLog.h"
+#include "PowerSwitch.h"
+#include "NfcJniUtil.h"
+#include "config.h"
+#include "SecureElement.h"
+
+
+namespace android
+{
+ void doStartupConfig ();
+}
+
+
+PowerSwitch PowerSwitch::sPowerSwitch;
+const PowerSwitch::PowerActivity PowerSwitch::DISCOVERY=0x01;
+const PowerSwitch::PowerActivity PowerSwitch::SE_ROUTING=0x02;
+const PowerSwitch::PowerActivity PowerSwitch::SE_CONNECTED=0x04;
+
+/*******************************************************************************
+**
+** Function: PowerSwitch
+**
+** Description: Initialize member variables.
+**
+** Returns: None
+**
+*******************************************************************************/
+PowerSwitch::PowerSwitch ()
+: mCurrLevel (UNKNOWN_LEVEL),
+ mCurrDeviceMgtPowerState (NFA_DM_PWR_STATE_UNKNOWN),
+ mDesiredScreenOffPowerState (0),
+ mCurrActivity(0)
+{
+}
+
+
+/*******************************************************************************
+**
+** Function: ~PowerSwitch
+**
+** Description: Release all resources.
+**
+** Returns: None
+**
+*******************************************************************************/
+PowerSwitch::~PowerSwitch ()
+{
+}
+
+
+/*******************************************************************************
+**
+** Function: getInstance
+**
+** Description: Get the singleton of this object.
+**
+** Returns: Reference to this object.
+**
+*******************************************************************************/
+PowerSwitch& PowerSwitch::getInstance ()
+{
+ return sPowerSwitch;
+}
+
+
+/*******************************************************************************
+**
+** Function: initialize
+**
+** Description: Initialize member variables.
+**
+** Returns: None
+**
+*******************************************************************************/
+void PowerSwitch::initialize (PowerLevel level)
+{
+ static const char fn [] = "PowerSwitch::initialize";
+
+ mMutex.lock ();
+
+ ALOGD ("%s: level=%s (%u)", fn, powerLevelToString(level), level);
+ GetNumValue (NAME_SCREEN_OFF_POWER_STATE, &mDesiredScreenOffPowerState, sizeof(mDesiredScreenOffPowerState));
+ ALOGD ("%s: desired screen-off state=%d", fn, mDesiredScreenOffPowerState);
+
+ switch (level)
+ {
+ case FULL_POWER:
+ mCurrDeviceMgtPowerState = NFA_DM_PWR_MODE_FULL;
+ mCurrLevel = level;
+ break;
+
+ case UNKNOWN_LEVEL:
+ mCurrDeviceMgtPowerState = NFA_DM_PWR_STATE_UNKNOWN;
+ mCurrLevel = level;
+ break;
+
+ default:
+ ALOGE ("%s: not handled", fn);
+ break;
+ }
+ mMutex.unlock ();
+}
+
+
+/*******************************************************************************
+**
+** Function: getLevel
+**
+** Description: Get the current power level of the controller.
+**
+** Returns: Power level.
+**
+*******************************************************************************/
+PowerSwitch::PowerLevel PowerSwitch::getLevel ()
+{
+ PowerLevel level = UNKNOWN_LEVEL;
+ mMutex.lock ();
+ level = mCurrLevel;
+ mMutex.unlock ();
+ return level;
+}
+
+
+/*******************************************************************************
+**
+** Function: setLevel
+**
+** Description: Set the controller's power level.
+** level: power level.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool PowerSwitch::setLevel (PowerLevel newLevel)
+{
+ static const char fn [] = "PowerSwitch::setLevel";
+ bool retval = false;
+
+ mMutex.lock ();
+
+ ALOGD ("%s: level=%s (%u)", fn, powerLevelToString(newLevel), newLevel);
+ if (mCurrLevel == newLevel)
+ {
+ retval = true;
+ goto TheEnd;
+ }
+
+ switch (newLevel)
+ {
+ case FULL_POWER:
+ if (mCurrDeviceMgtPowerState == NFA_DM_PWR_MODE_OFF_SLEEP)
+ retval = setPowerOffSleepState (false);
+ break;
+
+ case LOW_POWER:
+ case POWER_OFF:
+ if (isPowerOffSleepFeatureEnabled())
+ retval = setPowerOffSleepState (true);
+ else if (mDesiredScreenOffPowerState == 1) //.conf file desires full-power
+ {
+ mCurrLevel = FULL_POWER;
+ retval = true;
+ }
+ break;
+
+ default:
+ ALOGE ("%s: not handled", fn);
+ break;
+ }
+
+TheEnd:
+ mMutex.unlock ();
+ return retval;
+}
+
+/*******************************************************************************
+**
+** Function: setModeOff
+**
+** Description: Set a mode to be deactive.
+**
+** Returns: True if any mode is still active.
+**
+*******************************************************************************/
+bool PowerSwitch::setModeOff (PowerActivity deactivated)
+{
+ bool retVal = false;
+
+ mMutex.lock ();
+ mCurrActivity &= ~deactivated;
+ retVal = mCurrActivity != 0;
+ ALOGD ("PowerSwitch::setModeOff(deactivated=0x%x) : mCurrActivity=0x%x", deactivated, mCurrActivity);
+ mMutex.unlock ();
+ return retVal;
+}
+
+
+/*******************************************************************************
+**
+** Function: setModeOn
+**
+** Description: Set a mode to be active.
+**
+** Returns: True if any mode is active.
+**
+*******************************************************************************/
+bool PowerSwitch::setModeOn (PowerActivity activated)
+{
+ bool retVal = false;
+
+ mMutex.lock ();
+ mCurrActivity |= activated;
+ retVal = mCurrActivity != 0;
+ ALOGD ("PowerSwitch::setModeOn(activated=0x%x) : mCurrActivity=0x%x", activated, mCurrActivity);
+ mMutex.unlock ();
+ return retVal;
+}
+
+
+/*******************************************************************************
+**
+** Function: setPowerOffSleepState
+**
+** Description: Adjust controller's power-off-sleep state.
+** sleep: whether to enter sleep state.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool PowerSwitch::setPowerOffSleepState (bool sleep)
+{
+ static const char fn [] = "PowerSwitch::setPowerOffSleepState";
+ ALOGD ("%s: enter; sleep=%u", fn, sleep);
+ tNFA_STATUS stat = NFA_STATUS_FAILED;
+ bool retval = false;
+
+ if (sleep) //enter power-off-sleep state
+ {
+ //make sure the current power state is ON
+ if (mCurrDeviceMgtPowerState != NFA_DM_PWR_MODE_OFF_SLEEP)
+ {
+ SyncEventGuard guard (mPowerStateEvent);
+ ALOGD ("%s: try power off", fn);
+ stat = NFA_PowerOffSleepMode (TRUE);
+ if (stat == NFA_STATUS_OK)
+ {
+ mPowerStateEvent.wait ();
+ mCurrLevel = LOW_POWER;
+ }
+ else
+ {
+ ALOGE ("%s: API fail; stat=0x%X", fn, stat);
+ goto TheEnd;
+ }
+ }
+ else
+ {
+ ALOGE ("%s: power is not ON; curr device mgt power state=%s (%u)", fn,
+ deviceMgtPowerStateToString (mCurrDeviceMgtPowerState), mCurrDeviceMgtPowerState);
+ goto TheEnd;
+ }
+ }
+ else //exit power-off-sleep state
+ {
+ //make sure the current power state is OFF
+ if (mCurrDeviceMgtPowerState != NFA_DM_PWR_MODE_FULL)
+ {
+ mCurrDeviceMgtPowerState = NFA_DM_PWR_STATE_UNKNOWN;
+ SyncEventGuard guard (mPowerStateEvent);
+ ALOGD ("%s: try full power", fn);
+ stat = NFA_PowerOffSleepMode (FALSE);
+ if (stat == NFA_STATUS_OK)
+ {
+ mPowerStateEvent.wait ();
+ if (mCurrDeviceMgtPowerState != NFA_DM_PWR_MODE_FULL)
+ {
+ ALOGE ("%s: unable to full power; curr device mgt power stat=%s (%u)", fn,
+ deviceMgtPowerStateToString (mCurrDeviceMgtPowerState), mCurrDeviceMgtPowerState);
+ goto TheEnd;
+ }
+ android::doStartupConfig ();
+ mCurrLevel = FULL_POWER;
+ }
+ else
+ {
+ ALOGE ("%s: API fail; stat=0x%X", fn, stat);
+ goto TheEnd;
+ }
+ }
+ else
+ {
+ ALOGE ("%s: not in power-off state; curr device mgt power state=%s (%u)", fn,
+ deviceMgtPowerStateToString (mCurrDeviceMgtPowerState), mCurrDeviceMgtPowerState);
+ goto TheEnd;
+ }
+ }
+
+ retval = true;
+TheEnd:
+ ALOGD ("%s: exit; return %u", fn, retval);
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: deviceMgtPowerStateToString
+**
+** Description: Decode power level to a string.
+** deviceMgtPowerState: power level.
+**
+** Returns: Text representation of power level.
+**
+*******************************************************************************/
+const char* PowerSwitch::deviceMgtPowerStateToString (UINT8 deviceMgtPowerState)
+{
+ switch (deviceMgtPowerState)
+ {
+ case NFA_DM_PWR_MODE_FULL:
+ return "DM-FULL";
+ case NFA_DM_PWR_MODE_OFF_SLEEP:
+ return "DM-OFF";
+ default:
+ return "DM-unknown????";
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: powerLevelToString
+**
+** Description: Decode power level to a string.
+** level: power level.
+**
+** Returns: Text representation of power level.
+**
+*******************************************************************************/
+const char* PowerSwitch::powerLevelToString (PowerLevel level)
+{
+ switch (level)
+ {
+ case UNKNOWN_LEVEL:
+ return "PS-UNKNOWN";
+ case FULL_POWER:
+ return "PS-FULL";
+ case LOW_POWER:
+ return "PS-LOW-POWER";
+ case POWER_OFF:
+ return "PS-POWER-OFF";
+ default:
+ return "PS-unknown????";
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: abort
+**
+** Description: Abort and unblock currrent operation.
+**
+** Returns: None
+**
+*******************************************************************************/
+void PowerSwitch::abort ()
+{
+ static const char fn [] = "PowerSwitch::abort";
+ ALOGD ("%s", fn);
+ SyncEventGuard guard (mPowerStateEvent);
+ mPowerStateEvent.notifyOne ();
+}
+
+
+/*******************************************************************************
+**
+** Function: deviceManagementCallback
+**
+** Description: Callback function for the stack.
+** event: event ID.
+** eventData: event's data.
+**
+** Returns: None
+**
+*******************************************************************************/
+void PowerSwitch::deviceManagementCallback (UINT8 event, tNFA_DM_CBACK_DATA* eventData)
+{
+ static const char fn [] = "PowerSwitch::deviceManagementCallback";
+
+ switch (event)
+ {
+ case NFA_DM_PWR_MODE_CHANGE_EVT:
+ {
+ tNFA_DM_PWR_MODE_CHANGE& power_mode = eventData->power_mode;
+ ALOGD ("%s: NFA_DM_PWR_MODE_CHANGE_EVT; status=%u; device mgt power mode=%s (%u)", fn,
+ power_mode.status, sPowerSwitch.deviceMgtPowerStateToString (power_mode.power_mode), power_mode.power_mode);
+ SyncEventGuard guard (sPowerSwitch.mPowerStateEvent);
+ if (power_mode.status == NFA_STATUS_OK)
+ sPowerSwitch.mCurrDeviceMgtPowerState = power_mode.power_mode;
+ sPowerSwitch.mPowerStateEvent.notifyOne ();
+ }
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: isPowerOffSleepFeatureEnabled
+**
+** Description: Whether power-off-sleep feature is enabled in .conf file.
+**
+** Returns: True if feature is enabled.
+**
+*******************************************************************************/
+bool PowerSwitch::isPowerOffSleepFeatureEnabled ()
+{
+ return mDesiredScreenOffPowerState == 0;
+}
+
diff --git a/nci/jni/PowerSwitch.h b/nci/jni/PowerSwitch.h
new file mode 100755
index 0000000..d311c23
--- /dev/null
+++ b/nci/jni/PowerSwitch.h
@@ -0,0 +1,258 @@
+/*
+ * 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.
+ */
+
+/*
+ * Adjust the controller's power states.
+ */
+#pragma once
+#include "nfa_api.h"
+#include "SyncEvent.h"
+
+
+/*****************************************************************************
+**
+** Name: PowerSwitch
+**
+** Description: Adjust the controller's power states.
+**
+*****************************************************************************/
+class PowerSwitch
+{
+public:
+
+
+ /*******************************************************************************
+ **
+ ** Description: UNKNOWN_LEVEL: power level is unknown because the stack is off.
+ ** FULL_POWER: controller is in full-power state.
+ ** LOW_POWER: controller is in lower-power state.
+ **
+ *******************************************************************************/
+ enum PowerLevel {UNKNOWN_LEVEL, FULL_POWER, LOW_POWER, POWER_OFF};
+
+ /*******************************************************************************
+ **
+ ** Description: DISCOVERY: Discovery is enabled
+ ** SE_ROUTING: Routing to SE is enabled.
+ ** SE_CONNECTED: SE is connected.
+ **
+ *******************************************************************************/
+ typedef int PowerActivity;
+ static const PowerActivity DISCOVERY;
+ static const PowerActivity SE_ROUTING;
+ static const PowerActivity SE_CONNECTED;
+
+ /*******************************************************************************
+ **
+ ** Description: Platform Power Level, copied from NativeNfcBrcmPowerMode.java.
+ ** UNKNOWN_LEVEL: power level is unknown.
+ ** POWER_OFF: The phone is turned OFF
+ ** SCREEN_OFF: The phone is turned ON but screen is OFF
+ ** SCREEN_ON_LOCKED: The phone is turned ON, screen is ON but user locked
+ ** SCREEN_ON_UNLOCKED: The phone is turned ON, screen is ON, and user unlocked
+ **
+ *******************************************************************************/
+ static const int PLATFORM_UNKNOWN_LEVEL = 0;
+ static const int PLATFORM_POWER_OFF = 1;
+ static const int PLATFORM_SCREEN_OFF = 2;
+ static const int PLATFORM_SCREEN_ON_LOCKED = 3;
+ static const int PLATFORM_SCREEN_ON_UNLOCKED = 4;
+
+ static const int VBAT_MONITOR_ENABLED = 1;
+ static const int VBAT_MONITOR_PRIMARY_THRESHOLD = 5;
+ static const int VBAT_MONITOR_SECONDARY_THRESHOLD = 8;
+ /*******************************************************************************
+ **
+ ** Function: PowerSwitch
+ **
+ ** Description: Initialize member variables.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ PowerSwitch ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: ~PowerSwitch
+ **
+ ** Description: Release all resources.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ ~PowerSwitch ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: getInstance
+ **
+ ** Description: Get the singleton of this object.
+ **
+ ** Returns: Reference to this object.
+ **
+ *******************************************************************************/
+ static PowerSwitch& getInstance ();
+
+ /*******************************************************************************
+ **
+ ** Function: initialize
+ **
+ ** Description: Initialize member variables.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void initialize (PowerLevel level);
+
+
+ /*******************************************************************************
+ **
+ ** Function: getLevel
+ **
+ ** Description: Get the current power level of the controller.
+ **
+ ** Returns: Power level.
+ **
+ *******************************************************************************/
+ PowerLevel getLevel ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: setLevel
+ **
+ ** Description: Set the controller's power level.
+ ** level: power level.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool setLevel (PowerLevel level);
+
+
+ /*******************************************************************************
+ **
+ ** Function: setModeOff
+ **
+ ** Description: Set a mode to be deactive.
+ **
+ ** Returns: True if any mode is still active.
+ **
+ *******************************************************************************/
+ bool setModeOff (PowerActivity deactivated);
+
+
+ /*******************************************************************************
+ **
+ ** Function: setModeOn
+ **
+ ** Description: Set a mode to be active.
+ **
+ ** Returns: True if any mode is active.
+ **
+ *******************************************************************************/
+ bool setModeOn (PowerActivity activated);
+
+
+ /*******************************************************************************
+ **
+ ** Function: abort
+ **
+ ** Description: Abort and unblock currrent operation.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void abort ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: deviceManagementCallback
+ **
+ ** Description: Callback function for the stack.
+ ** event: event ID.
+ ** eventData: event's data.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ static void deviceManagementCallback (UINT8 event, tNFA_DM_CBACK_DATA* eventData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: isPowerOffSleepFeatureEnabled
+ **
+ ** Description: Whether power-off-sleep feature is enabled in .conf file.
+ **
+ ** Returns: True if feature is enabled.
+ **
+ *******************************************************************************/
+ bool isPowerOffSleepFeatureEnabled ();
+
+private:
+ PowerLevel mCurrLevel;
+ UINT8 mCurrDeviceMgtPowerState; //device management power state; such as NFA_DM_PWR_STATE_???
+ int mDesiredScreenOffPowerState; //read from .conf file; 0=power-off-sleep; 1=full power; 2=CE4 power
+ static PowerSwitch sPowerSwitch; //singleton object
+ static const UINT8 NFA_DM_PWR_STATE_UNKNOWN = -1; //device management power state power state is unknown
+ SyncEvent mPowerStateEvent;
+ PowerActivity mCurrActivity;
+ Mutex mMutex;
+
+
+ /*******************************************************************************
+ **
+ ** Function: setPowerOffSleepState
+ **
+ ** Description: Adjust controller's power-off-sleep state.
+ ** sleep: whether to enter sleep state.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool setPowerOffSleepState (bool sleep);
+
+
+ /*******************************************************************************
+ **
+ ** Function: deviceMgtPowerStateToString
+ **
+ ** Description: Decode power level to a string.
+ ** deviceMgtPowerState: power level.
+ **
+ ** Returns: Text representation of power level.
+ **
+ *******************************************************************************/
+ const char* deviceMgtPowerStateToString (UINT8 deviceMgtPowerState);
+
+
+ /*******************************************************************************
+ **
+ ** Function: powerLevelToString
+ **
+ ** Description: Decode power level to a string.
+ ** level: power level.
+ **
+ ** Returns: Text representation of power level.
+ **
+ *******************************************************************************/
+ const char* powerLevelToString (PowerLevel level);
+};
diff --git a/nci/jni/RouteDataSet.cpp b/nci/jni/RouteDataSet.cpp
new file mode 100644
index 0000000..1458776
--- /dev/null
+++ b/nci/jni/RouteDataSet.cpp
@@ -0,0 +1,555 @@
+/*
+ * 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.
+ */
+
+/*
+ * Import and export general routing data using a XML file.
+ */
+#include "OverrideLog.h"
+#include "RouteDataSet.h"
+#include "libxml/xmlmemory.h"
+#include <errno.h>
+#include <sys/stat.h>
+
+extern char bcm_nfc_location[];
+
+
+/*******************************************************************************
+**
+** Function: AidBuffer
+**
+** Description: Parse a string of hex numbers. Store result in an array of
+** bytes.
+** aid: string of hex numbers.
+**
+** Returns: None.
+**
+*******************************************************************************/
+AidBuffer::AidBuffer (std::string& aid)
+: mBuffer (NULL),
+ mBufferLen (0)
+{
+ unsigned int num = 0;
+ const char delimiter = ':';
+ std::string::size_type pos1 = 0;
+ std::string::size_type pos2 = aid.find_first_of (delimiter);
+
+ //parse the AID string; each hex number is separated by a colon;
+ mBuffer = new UINT8 [aid.length()];
+ while (true)
+ {
+ num = 0;
+ if (pos2 == std::string::npos)
+ {
+ sscanf (aid.substr(pos1).c_str(), "%x", &num);
+ mBuffer [mBufferLen] = (UINT8) num;
+ mBufferLen++;
+ break;
+ }
+ else
+ {
+ sscanf (aid.substr(pos1, pos2-pos1+1).c_str(), "%x", &num);
+ mBuffer [mBufferLen] = (UINT8) num;
+ mBufferLen++;
+ pos1 = pos2 + 1;
+ pos2 = aid.find_first_of (delimiter, pos1);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: ~AidBuffer
+**
+** Description: Release all resources.
+**
+** Returns: None.
+**
+*******************************************************************************/
+AidBuffer::~AidBuffer ()
+{
+ delete [] mBuffer;
+}
+
+
+/*******************************************************************************/
+/*******************************************************************************/
+
+
+const char* RouteDataSet::sConfigFile = "/param/route.xml";
+
+
+/*******************************************************************************
+**
+** Function: ~RouteDataSet
+**
+** Description: Release all resources.
+**
+** Returns: None.
+**
+*******************************************************************************/
+RouteDataSet::~RouteDataSet ()
+{
+ deleteDatabase ();
+}
+
+
+/*******************************************************************************
+**
+** Function: initialize
+**
+** Description: Initialize resources.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool RouteDataSet::initialize ()
+{
+ static const char fn [] = "RouteDataSet::initialize";
+ ALOGD ("%s: enter", fn);
+ //check that the libxml2 version in use is compatible
+ //with the version the software has been compiled with
+ LIBXML_TEST_VERSION
+ ALOGD ("%s: exit; return=true", fn);
+ return true;
+}
+
+
+/*******************************************************************************
+**
+** Function: deleteDatabase
+**
+** Description: Delete all routes stored in all databases.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void RouteDataSet::deleteDatabase ()
+{
+ static const char fn [] = "RouteDataSet::deleteDatabase";
+ ALOGD ("%s: default db size=%u; sec elem db size=%u", fn, mDefaultRouteDatabase.size(), mSecElemRouteDatabase.size());
+ Database::iterator it;
+
+ for (it = mDefaultRouteDatabase.begin(); it != mDefaultRouteDatabase.end(); it++)
+ delete (*it);
+ mDefaultRouteDatabase.clear ();
+
+ for (it = mSecElemRouteDatabase.begin(); it != mSecElemRouteDatabase.end(); it++)
+ delete (*it);
+ mSecElemRouteDatabase.clear ();
+}
+
+
+/*******************************************************************************
+**
+** Function: import
+**
+** Description: Import data from an XML file. Fill the databases.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool RouteDataSet::import ()
+{
+ static const char fn [] = "RouteDataSet::import";
+ ALOGD ("%s: enter", fn);
+ bool retval = false;
+ xmlDocPtr doc;
+ xmlNodePtr node1;
+ std::string strFilename(bcm_nfc_location);
+ strFilename += sConfigFile;
+
+ deleteDatabase ();
+
+ doc = xmlParseFile (strFilename.c_str());
+ if (doc == NULL)
+ {
+ ALOGD ("%s: fail parse", fn);
+ goto TheEnd;
+ }
+
+ node1 = xmlDocGetRootElement (doc);
+ if (node1 == NULL)
+ {
+ ALOGE ("%s: fail root element", fn);
+ goto TheEnd;
+ }
+ ALOGD ("%s: root=%s", fn, node1->name);
+
+ node1 = node1->xmlChildrenNode;
+ while (node1) //loop through all elements in <Routes ...
+ {
+ if (xmlStrcmp(node1->name, (const xmlChar*) "Route")==0)
+ {
+ xmlChar* value = xmlGetProp (node1, (const xmlChar*) "Type");
+ if (value && (xmlStrcmp (value, (const xmlChar*) "SecElemSelectedRoutes") == 0))
+ {
+ ALOGD ("%s: found SecElemSelectedRoutes", fn);
+ xmlNodePtr node2 = node1->xmlChildrenNode;
+ while (node2) //loop all elements in <Route Type="SecElemSelectedRoutes" ...
+ {
+ if (xmlStrcmp(node2->name, (const xmlChar*) "Proto")==0)
+ importProtocolRoute (node2, mSecElemRouteDatabase);
+ else if (xmlStrcmp(node2->name, (const xmlChar*) "Tech")==0)
+ importTechnologyRoute (node2, mSecElemRouteDatabase);
+ node2 = node2->next;
+ } //loop all elements in <Route Type="SecElemSelectedRoutes" ...
+ }
+ else if (value && (xmlStrcmp (value, (const xmlChar*) "DefaultRoutes") == 0))
+ {
+ ALOGD ("%s: found DefaultRoutes", fn);
+ xmlNodePtr node2 = node1->xmlChildrenNode;
+ while (node2) //loop all elements in <Route Type="DefaultRoutes" ...
+ {
+ if (xmlStrcmp(node2->name, (const xmlChar*) "Proto")==0)
+ importProtocolRoute (node2, mDefaultRouteDatabase);
+ else if (xmlStrcmp(node2->name, (const xmlChar*) "Tech")==0)
+ importTechnologyRoute (node2, mDefaultRouteDatabase);
+ node2 = node2->next;
+ } //loop all elements in <Route Type="DefaultRoutes" ...
+ }
+ if (value)
+ xmlFree (value);
+ } //check <Route ...
+ node1 = node1->next;
+ } //loop through all elements in <Routes ...
+ retval = true;
+
+TheEnd:
+ xmlFreeDoc (doc);
+ xmlCleanupParser ();
+ ALOGD ("%s: exit; return=%u", fn, retval);
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: saveToFile
+**
+** Description: Save XML data from a string into a file.
+** routesXml: XML that represents routes.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool RouteDataSet::saveToFile (const char* routesXml)
+{
+ static const char fn [] = "RouteDataSet::saveToFile";
+ FILE* fh = NULL;
+ size_t actualWritten = 0;
+ bool retval = false;
+ std::string filename (bcm_nfc_location);
+
+ filename.append (sConfigFile);
+ fh = fopen (filename.c_str (), "w");
+ if (fh == NULL)
+ {
+ ALOGE ("%s: fail to open file", fn);
+ return false;
+ }
+
+ actualWritten = fwrite (routesXml, sizeof(char), strlen(routesXml), fh);
+ retval = actualWritten == strlen(routesXml);
+ fclose (fh);
+ ALOGD ("%s: wrote %u bytes", fn, actualWritten);
+ if (retval == false)
+ ALOGE ("%s: error during write", fn);
+
+ //set file permission to
+ //owner read, write; group read; other read
+ chmod (filename.c_str (), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: loadFromFile
+**
+** Description: Load XML data from file into a string.
+** routesXml: string to receive XML data.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool RouteDataSet::loadFromFile (std::string& routesXml)
+{
+ static const char fn [] = "RouteDataSet::loadFromFile";
+ FILE* fh = NULL;
+ size_t actual = 0;
+ char buffer [1024];
+ std::string filename (bcm_nfc_location);
+
+ filename.append (sConfigFile);
+ fh = fopen (filename.c_str (), "r");
+ if (fh == NULL)
+ {
+ ALOGD ("%s: fail to open file", fn);
+ return false;
+ }
+
+ while (true)
+ {
+ actual = fread (buffer, sizeof(char), sizeof(buffer), fh);
+ if (actual == 0)
+ break;
+ routesXml.append (buffer, actual);
+ }
+ fclose (fh);
+ ALOGD ("%s: read %u bytes", fn, routesXml.length());
+ return true;
+}
+
+
+
+
+/*******************************************************************************
+**
+** Function: importProtocolRoute
+**
+** Description: Parse data for protocol routes.
+** element: XML node for one protocol route.
+** database: store data in this database.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void RouteDataSet::importProtocolRoute (xmlNodePtr& element, Database& database)
+{
+ static const char fn [] = "RouteDataSet::importProtocolRoute";
+ const xmlChar* id = (const xmlChar*) "Id";
+ const xmlChar* secElem = (const xmlChar*) "SecElem";
+ const xmlChar* trueString = (const xmlChar*) "true";
+ const xmlChar* switchOn = (const xmlChar*) "SwitchOn";
+ const xmlChar* switchOff = (const xmlChar*) "SwitchOff";
+ const xmlChar* batteryOff = (const xmlChar*) "BatteryOff";
+ RouteDataForProtocol* data = new RouteDataForProtocol;
+ xmlChar* value = NULL;
+
+ ALOGD_IF (sDebug, "%s: element=%s", fn, element->name);
+ value = xmlGetProp (element, id);
+ if (value)
+ {
+ if (xmlStrcmp (value, (const xmlChar*) "T1T") == 0)
+ data->mProtocol = NFA_PROTOCOL_MASK_T1T;
+ else if (xmlStrcmp (value, (const xmlChar*) "T2T") == 0)
+ data->mProtocol = NFA_PROTOCOL_MASK_T2T;
+ else if (xmlStrcmp (value, (const xmlChar*) "T3T") == 0)
+ data->mProtocol = NFA_PROTOCOL_MASK_T3T;
+ else if (xmlStrcmp (value, (const xmlChar*) "IsoDep") == 0)
+ data->mProtocol = NFA_PROTOCOL_MASK_ISO_DEP;
+ xmlFree (value);
+ ALOGD_IF (sDebug, "%s: %s=0x%X", fn, id, data->mProtocol);
+ }
+
+ value = xmlGetProp (element, secElem);
+ if (value)
+ {
+ data->mNfaEeHandle = strtol ((char*) value, NULL, 16);
+ xmlFree (value);
+ data->mNfaEeHandle = data->mNfaEeHandle | NFA_HANDLE_GROUP_EE;
+ ALOGD_IF (sDebug, "%s: %s=0x%X", fn, secElem, data->mNfaEeHandle);
+ }
+
+ value = xmlGetProp (element, switchOn);
+ if (value)
+ {
+ data->mSwitchOn = (xmlStrcmp (value, trueString) == 0);
+ xmlFree (value);
+ }
+
+ value = xmlGetProp (element, switchOff);
+ if (value)
+ {
+ data->mSwitchOff = (xmlStrcmp (value, trueString) == 0);
+ xmlFree (value);
+ }
+
+ value = xmlGetProp (element, batteryOff);
+ if (value)
+ {
+ data->mBatteryOff = (xmlStrcmp (value, trueString) == 0);
+ xmlFree (value);
+ }
+ database.push_back (data);
+}
+
+
+/*******************************************************************************
+**
+** Function: importTechnologyRoute
+**
+** Description: Parse data for technology routes.
+** element: XML node for one technology route.
+** database: store data in this database.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void RouteDataSet::importTechnologyRoute (xmlNodePtr& element, Database& database)
+{
+ static const char fn [] = "RouteDataSet::importTechnologyRoute";
+ const xmlChar* id = (const xmlChar*) "Id";
+ const xmlChar* secElem = (const xmlChar*) "SecElem";
+ const xmlChar* trueString = (const xmlChar*) "true";
+ const xmlChar* switchOn = (const xmlChar*) "SwitchOn";
+ const xmlChar* switchOff = (const xmlChar*) "SwitchOff";
+ const xmlChar* batteryOff = (const xmlChar*) "BatteryOff";
+ RouteDataForTechnology* data = new RouteDataForTechnology;
+ xmlChar* value = NULL;
+
+ ALOGD_IF (sDebug, "%s: element=%s", fn, element->name);
+ value = xmlGetProp (element, id);
+ if (value)
+ {
+ if (xmlStrcmp (value, (const xmlChar*) "NfcA") == 0)
+ data->mTechnology = NFA_TECHNOLOGY_MASK_A;
+ else if (xmlStrcmp (value, (const xmlChar*) "NfcB") == 0)
+ data->mTechnology = NFA_TECHNOLOGY_MASK_B;
+ else if (xmlStrcmp (value, (const xmlChar*) "NfcF") == 0)
+ data->mTechnology = NFA_TECHNOLOGY_MASK_F;
+ xmlFree (value);
+ ALOGD_IF (sDebug, "%s: %s=0x%X", fn, id, data->mTechnology);
+ }
+
+ value = xmlGetProp (element, secElem);
+ if (value)
+ {
+ data->mNfaEeHandle = strtol ((char*) value, NULL, 16);
+ xmlFree (value);
+ data->mNfaEeHandle = data->mNfaEeHandle | NFA_HANDLE_GROUP_EE;
+ ALOGD_IF (sDebug, "%s: %s=0x%X", fn, secElem, data->mNfaEeHandle);
+ }
+
+ value = xmlGetProp (element, switchOn);
+ if (value)
+ {
+ data->mSwitchOn = (xmlStrcmp (value, trueString) == 0);
+ xmlFree (value);
+ }
+
+ value = xmlGetProp (element, switchOff);
+ if (value)
+ {
+ data->mSwitchOff = (xmlStrcmp (value, trueString) == 0);
+ xmlFree (value);
+ }
+
+ value = xmlGetProp (element, batteryOff);
+ if (value)
+ {
+ data->mBatteryOff = (xmlStrcmp (value, trueString) == 0);
+ xmlFree (value);
+ }
+ database.push_back (data);
+}
+
+
+/*******************************************************************************
+**
+** Function: deleteFile
+**
+** Description: Delete route data XML file.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool RouteDataSet::deleteFile ()
+{
+ static const char fn [] = "RouteDataSet::deleteFile";
+ std::string filename (bcm_nfc_location);
+ filename.append (sConfigFile);
+ int stat = remove (filename.c_str());
+ ALOGD ("%s: exit %u", fn, stat==0);
+ return stat == 0;
+}
+
+
+/*******************************************************************************
+**
+** Function: getDatabase
+**
+** Description: Obtain a database of routing data.
+** selection: which database.
+**
+** Returns: Pointer to database.
+**
+*******************************************************************************/
+RouteDataSet::Database* RouteDataSet::getDatabase (DatabaseSelection selection)
+{
+ switch (selection)
+ {
+ case DefaultRouteDatabase:
+ return &mDefaultRouteDatabase;
+ case SecElemRouteDatabase:
+ return &mSecElemRouteDatabase;
+ }
+ return NULL;
+}
+
+
+/*******************************************************************************
+**
+** Function: printDiagnostic
+**
+** Description: Print some diagnostic output.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void RouteDataSet::printDiagnostic ()
+{
+ static const char fn [] = "RouteDataSet::printDiagnostic";
+ Database* db = getDatabase (DefaultRouteDatabase);
+
+ ALOGD ("%s: default route database", fn);
+ for (Database::iterator iter = db->begin(); iter != db->end(); iter++)
+ {
+ RouteData* routeData = *iter;
+ switch (routeData->mRouteType)
+ {
+ case RouteData::ProtocolRoute:
+ {
+ RouteDataForProtocol* proto = (RouteDataForProtocol*) routeData;
+ ALOGD ("%s: ee h=0x%X; protocol=0x%X", fn, proto->mNfaEeHandle, proto->mProtocol);
+ }
+ break;
+ }
+ }
+
+ ALOGD ("%s: sec elem route database", fn);
+ db = getDatabase (SecElemRouteDatabase);
+ for (Database::iterator iter2 = db->begin(); iter2 != db->end(); iter2++)
+ {
+ RouteData* routeData = *iter2;
+ switch (routeData->mRouteType)
+ {
+ case RouteData::ProtocolRoute:
+ {
+ RouteDataForProtocol* proto = (RouteDataForProtocol*) routeData;
+ ALOGD ("%s: ee h=0x%X; protocol=0x%X", fn, proto->mNfaEeHandle, proto->mProtocol);
+ }
+ break;
+ case RouteData::TechnologyRoute:
+ {
+ RouteDataForTechnology* tech = (RouteDataForTechnology*) routeData;
+ ALOGD ("%s: ee h=0x%X; technology=0x%X", fn, tech->mNfaEeHandle, tech->mTechnology);
+ }
+ break;
+ }
+ }
+}
diff --git a/nci/jni/RouteDataSet.h b/nci/jni/RouteDataSet.h
new file mode 100644
index 0000000..d2a09b8
--- /dev/null
+++ b/nci/jni/RouteDataSet.h
@@ -0,0 +1,308 @@
+/*
+ * 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.
+ */
+
+/*
+ * Import and export general routing data using a XML file.
+ */
+#pragma once
+#include "NfcJniUtil.h"
+#include "nfa_api.h"
+#include <libxml/parser.h>
+#include <vector>
+#include <string>
+
+
+/*****************************************************************************
+**
+** Name: RouteData
+**
+** Description: Base class for every kind of route data.
+**
+*****************************************************************************/
+class RouteData
+{
+public:
+ enum RouteType {ProtocolRoute, TechnologyRoute};
+ RouteType mRouteType;
+
+protected:
+ RouteData (RouteType routeType) : mRouteType (routeType)
+ {}
+};
+
+
+
+
+/*****************************************************************************
+**
+** Name: RouteDataForProtocol
+**
+** Description: Data for protocol routes.
+**
+*****************************************************************************/
+class RouteDataForProtocol : public RouteData
+{
+public:
+ int mNfaEeHandle; //for example 0x4f3, 0x4f4
+ bool mSwitchOn;
+ bool mSwitchOff;
+ bool mBatteryOff;
+ tNFA_PROTOCOL_MASK mProtocol;
+
+ RouteDataForProtocol () : RouteData (ProtocolRoute), mNfaEeHandle (NFA_HANDLE_INVALID),
+ mSwitchOn (false), mSwitchOff (false), mBatteryOff (false),
+ mProtocol (0)
+ {}
+};
+
+
+/*****************************************************************************
+**
+** Name: RouteDataForTechnology
+**
+** Description: Data for technology routes.
+**
+*****************************************************************************/
+class RouteDataForTechnology : public RouteData
+{
+public:
+ int mNfaEeHandle; //for example 0x4f3, 0x4f4
+ bool mSwitchOn;
+ bool mSwitchOff;
+ bool mBatteryOff;
+ tNFA_TECHNOLOGY_MASK mTechnology;
+
+ RouteDataForTechnology () : RouteData (TechnologyRoute), mNfaEeHandle (NFA_HANDLE_INVALID),
+ mSwitchOn (false), mSwitchOff (false), mBatteryOff (false),
+ mTechnology (0)
+ {}
+};
+
+
+/*****************************************************************************/
+/*****************************************************************************/
+
+
+/*****************************************************************************
+**
+** Name: AidBuffer
+**
+** Description: Buffer to store AID after converting a string of hex
+** values to bytes.
+**
+*****************************************************************************/
+class AidBuffer
+{
+public:
+
+ /*******************************************************************************
+ **
+ ** Function: AidBuffer
+ **
+ ** Description: Parse a string of hex numbers. Store result in an array of
+ ** bytes.
+ ** aid: string of hex numbers.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ AidBuffer (std::string& aid);
+
+
+ /*******************************************************************************
+ **
+ ** Function: ~AidBuffer
+ **
+ ** Description: Release all resources.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ ~AidBuffer ();
+
+
+ UINT8* buffer () {return mBuffer;};
+ int length () {return mBufferLen;};
+
+private:
+ UINT8* mBuffer;
+ UINT32 mBufferLen;
+};
+
+
+/*****************************************************************************/
+/*****************************************************************************/
+
+
+/*****************************************************************************
+**
+** Name: RouteDataSet
+**
+** Description: Import and export general routing data using a XML file.
+** See /data/bcm/param/route.xml
+**
+*****************************************************************************/
+class RouteDataSet
+{
+public:
+ typedef std::vector<RouteData*> Database;
+ enum DatabaseSelection {DefaultRouteDatabase, SecElemRouteDatabase};
+
+
+ /*******************************************************************************
+ **
+ ** Function: ~RouteDataSet
+ **
+ ** Description: Release all resources.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ ~RouteDataSet ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: initialize
+ **
+ ** Description: Initialize resources.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool initialize ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: import
+ **
+ ** Description: Import data from an XML file. Fill the database.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool import ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: getDatabase
+ **
+ ** Description: Obtain a database of routing data.
+ ** selection: which database.
+ **
+ ** Returns: Pointer to database.
+ **
+ *******************************************************************************/
+ Database* getDatabase (DatabaseSelection selection);
+
+
+ /*******************************************************************************
+ **
+ ** Function: saveToFile
+ **
+ ** Description: Save XML data from a string into a file.
+ ** routesXml: XML that represents routes.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ static bool saveToFile (const char* routesXml);
+
+
+ /*******************************************************************************
+ **
+ ** Function: loadFromFile
+ **
+ ** Description: Load XML data from file into a string.
+ ** routesXml: string to receive XML data.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ static bool loadFromFile (std::string& routesXml);
+
+
+ /*******************************************************************************
+ **
+ ** Function: deleteFile
+ **
+ ** Description: Delete route data XML file.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ static bool deleteFile ();
+
+ /*******************************************************************************
+ **
+ ** Function: printDiagnostic
+ **
+ ** Description: Print some diagnostic output.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void printDiagnostic ();
+
+private:
+ Database mSecElemRouteDatabase; //routes when NFC service selects sec elem
+ Database mDefaultRouteDatabase; //routes when NFC service deselects sec elem
+ static const char* sConfigFile;
+ static const bool sDebug = false;
+
+
+ /*******************************************************************************
+ **
+ ** Function: deleteDatabase
+ **
+ ** Description: Delete all routes stored in all databases.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void deleteDatabase ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: importProtocolRoute
+ **
+ ** Description: Parse data for protocol routes.
+ ** element: XML node for one protocol route.
+ ** database: store data in this database.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void importProtocolRoute (xmlNodePtr& element, Database& database);
+
+
+ /*******************************************************************************
+ **
+ ** Function: importTechnologyRoute
+ **
+ ** Description: Parse data for technology routes.
+ ** element: XML node for one technology route.
+ ** database: store data in this database.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void importTechnologyRoute (xmlNodePtr& element, Database& database);
+};
+
diff --git a/nci/jni/SecureElement.cpp b/nci/jni/SecureElement.cpp
new file mode 100755
index 0000000..3c9256b
--- /dev/null
+++ b/nci/jni/SecureElement.cpp
@@ -0,0 +1,2189 @@
+/*
+ * 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.
+ */
+
+/*
+ * Communicate with secure elements that are attached to the NFC
+ * controller.
+ */
+#include <semaphore.h>
+#include <errno.h>
+#include "OverrideLog.h"
+#include "SecureElement.h"
+#include "config.h"
+#include "PowerSwitch.h"
+#include "HostAidRouter.h"
+#include "JavaClassConstants.h"
+
+
+/*****************************************************************************
+**
+** public variables
+**
+*****************************************************************************/
+int gSEId = -1; // secure element ID to use in connectEE(), -1 means not set
+int gGatePipe = -1; // gate id or static pipe id to use in connectEE(), -1 means not set
+bool gUseStaticPipe = false; // if true, use gGatePipe as static pipe id. if false, use as gate id
+
+namespace android
+{
+ extern void startRfDiscovery (bool isStart);
+}
+
+//////////////////////////////////////////////
+//////////////////////////////////////////////
+
+
+SecureElement SecureElement::sSecElem;
+const char* SecureElement::APP_NAME = "nfc_jni";
+
+
+/*******************************************************************************
+**
+** Function: SecureElement
+**
+** Description: Initialize member variables.
+**
+** Returns: None
+**
+*******************************************************************************/
+SecureElement::SecureElement ()
+: mActiveEeHandle (NFA_HANDLE_INVALID),
+ mDestinationGate (4), //loopback gate
+ mNfaHciHandle (NFA_HANDLE_INVALID),
+ mNativeData (NULL),
+ mIsInit (false),
+ mActualNumEe (0),
+ mNumEePresent(0),
+ mbNewEE (true), // by default we start w/thinking there are new EE
+ mNewPipeId (0),
+ mNewSourceGate (0),
+ mActiveSeOverride(0),
+ mCommandStatus (NFA_STATUS_OK),
+ mIsPiping (false),
+ mCurrentRouteSelection (NoRoute),
+ mActualResponseSize(0),
+ mUseOberthurWarmReset (false),
+ mActivatedInListenMode (false),
+ mOberthurWarmResetCommand (3),
+ mRfFieldIsOn(false)
+{
+ memset (&mEeInfo, 0, sizeof(mEeInfo));
+ memset (&mUiccInfo, 0, sizeof(mUiccInfo));
+ memset (&mHciCfg, 0, sizeof(mHciCfg));
+ memset (mResponseData, 0, sizeof(mResponseData));
+ memset (mAidForEmptySelect, 0, sizeof(mAidForEmptySelect));
+ memset (&mLastRfFieldToggle, 0, sizeof(mLastRfFieldToggle));
+}
+
+
+/*******************************************************************************
+**
+** Function: ~SecureElement
+**
+** Description: Release all resources.
+**
+** Returns: None
+**
+*******************************************************************************/
+SecureElement::~SecureElement ()
+{
+}
+
+
+/*******************************************************************************
+**
+** Function: getInstance
+**
+** Description: Get the SecureElement singleton object.
+**
+** Returns: SecureElement object.
+**
+*******************************************************************************/
+SecureElement& SecureElement::getInstance()
+{
+ return sSecElem;
+}
+
+
+/*******************************************************************************
+**
+** Function: setActiveSeOverride
+**
+** Description: Specify which secure element to turn on.
+** activeSeOverride: ID of secure element
+**
+** Returns: None
+**
+*******************************************************************************/
+void SecureElement::setActiveSeOverride(UINT8 activeSeOverride)
+{
+ ALOGD ("SecureElement::setActiveSeOverride, seid=0x%X", activeSeOverride);
+ mActiveSeOverride = activeSeOverride;
+}
+
+
+/*******************************************************************************
+**
+** Function: initialize
+**
+** Description: Initialize all member variables.
+** native: Native data.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool SecureElement::initialize (nfc_jni_native_data* native)
+{
+ static const char fn [] = "SecureElement::initialize";
+ tNFA_STATUS nfaStat;
+ UINT8 xx = 0, yy = 0;
+ unsigned long num = 0;
+
+ ALOGD ("%s: enter", fn);
+
+ if (GetNumValue("NFA_HCI_DEFAULT_DEST_GATE", &num, sizeof(num)))
+ mDestinationGate = num;
+ ALOGD ("%s: Default destination gate: %d", fn, mDestinationGate);
+
+ // active SE, if not set active all SEs
+ if (GetNumValue("ACTIVE_SE", &num, sizeof(num)))
+ mActiveSeOverride = num;
+ ALOGD ("%s: Active SE override: %d", fn, mActiveSeOverride);
+
+ if (GetNumValue("OBERTHUR_WARM_RESET_COMMAND", &num, sizeof(num)))
+ {
+ mUseOberthurWarmReset = true;
+ mOberthurWarmResetCommand = (UINT8) num;
+ }
+
+ mActiveEeHandle = NFA_HANDLE_INVALID;
+ mNfaHciHandle = NFA_HANDLE_INVALID;
+
+ mNativeData = native;
+ mActualNumEe = MAX_NUM_EE;
+ mbNewEE = true;
+ mNewPipeId = 0;
+ mNewSourceGate = 0;
+ mCurrentRouteSelection = NoRoute;
+ memset (mEeInfo, 0, sizeof(mEeInfo));
+ memset (&mUiccInfo, 0, sizeof(mUiccInfo));
+ memset (&mHciCfg, 0, sizeof(mHciCfg));
+ mUsedAids.clear ();
+ memset(mAidForEmptySelect, 0, sizeof(mAidForEmptySelect));
+
+ // Get Fresh EE info.
+ if (! getEeInfo())
+ return (false);
+
+ {
+ SyncEventGuard guard (mEeRegisterEvent);
+ ALOGD ("%s: try ee register", fn);
+ nfaStat = NFA_EeRegister (nfaEeCallback);
+ if (nfaStat != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: fail ee register; error=0x%X", fn, nfaStat);
+ return (false);
+ }
+ mEeRegisterEvent.wait ();
+ }
+
+ // If the controller has an HCI Network, register for that
+ for (xx = 0; xx < mActualNumEe; xx++)
+ {
+ if ((mEeInfo[xx].num_interface > 0) && (mEeInfo[xx].ee_interface[0] == NCI_NFCEE_INTERFACE_HCI_ACCESS) )
+ {
+ ALOGD ("%s: Found HCI network, try hci register", fn);
+
+ SyncEventGuard guard (mHciRegisterEvent);
+
+ nfaStat = NFA_HciRegister (const_cast<char*>(APP_NAME), nfaHciCallback, TRUE);
+ if (nfaStat != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: fail hci register; error=0x%X", fn, nfaStat);
+ return (false);
+ }
+ mHciRegisterEvent.wait();
+ break;
+ }
+ }
+
+ mRouteDataSet.initialize ();
+ mRouteDataSet.import (); //read XML file
+ HostAidRouter::getInstance().initialize ();
+
+ GetStrValue(NAME_AID_FOR_EMPTY_SELECT, (char*)&mAidForEmptySelect[0], sizeof(mAidForEmptySelect));
+
+ mIsInit = true;
+ ALOGD ("%s: exit", fn);
+ return (true);
+}
+
+
+/*******************************************************************************
+**
+** Function: finalize
+**
+** Description: Release all resources.
+**
+** Returns: None
+**
+*******************************************************************************/
+void SecureElement::finalize ()
+{
+ static const char fn [] = "SecureElement::finalize";
+ ALOGD ("%s: enter", fn);
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+
+ NFA_EeDeregister (nfaEeCallback);
+
+ if (mNfaHciHandle != NFA_HANDLE_INVALID)
+ NFA_HciDeregister (const_cast<char*>(APP_NAME));
+
+ mNfaHciHandle = NFA_HANDLE_INVALID;
+ mNativeData = NULL;
+ mIsInit = false;
+ mActualNumEe = 0;
+ mNumEePresent = 0;
+ mNewPipeId = 0;
+ mNewSourceGate = 0;
+ mIsPiping = false;
+ memset (mEeInfo, 0, sizeof(mEeInfo));
+ memset (&mUiccInfo, 0, sizeof(mUiccInfo));
+
+ ALOGD ("%s: exit", fn);
+}
+
+
+/*******************************************************************************
+**
+** Function: getEeInfo
+**
+** Description: Get latest information about execution environments from stack.
+**
+** Returns: True if at least 1 EE is available.
+**
+*******************************************************************************/
+bool SecureElement::getEeInfo()
+{
+ static const char fn [] = "SecureElement::getEeInfo";
+ ALOGD ("%s: enter; mbNewEE=%d, mActualNumEe=%d", fn, mbNewEE, mActualNumEe);
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ UINT8 xx = 0, yy = 0;
+
+ // If mbNewEE is true then there is new EE info.
+ if (mbNewEE)
+ {
+ mActualNumEe = MAX_NUM_EE;
+
+ if ((nfaStat = NFA_EeGetInfo (&mActualNumEe, mEeInfo)) != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: fail get info; error=0x%X", fn, nfaStat);
+ mActualNumEe = 0;
+ }
+ else
+ {
+ mbNewEE = false;
+
+ ALOGD ("%s: num EEs discovered: %u", fn, mActualNumEe);
+ if (mActualNumEe != 0)
+ {
+ for (UINT8 xx = 0; xx < mActualNumEe; xx++)
+ {
+ if ((mEeInfo[xx].num_interface != 0) && (mEeInfo[xx].ee_interface[0] != NCI_NFCEE_INTERFACE_HCI_ACCESS) )
+ mNumEePresent++;
+
+ ALOGD ("%s: EE[%u] Handle: 0x%04x Status: %s Num I/f: %u: (0x%02x, 0x%02x) Num TLVs: %u",
+ fn, xx, mEeInfo[xx].ee_handle, eeStatusToString(mEeInfo[xx].ee_status), mEeInfo[xx].num_interface,
+ mEeInfo[xx].ee_interface[0], mEeInfo[xx].ee_interface[1], mEeInfo[xx].num_tlvs);
+
+ for (yy = 0; yy < mEeInfo[xx].num_tlvs; yy++)
+ {
+ ALOGD ("%s: EE[%u] TLV[%u] Tag: 0x%02x Len: %u Values[]: 0x%02x 0x%02x 0x%02x ...",
+ fn, xx, yy, mEeInfo[xx].ee_tlv[yy].tag, mEeInfo[xx].ee_tlv[yy].len, mEeInfo[xx].ee_tlv[yy].info[0],
+ mEeInfo[xx].ee_tlv[yy].info[1], mEeInfo[xx].ee_tlv[yy].info[2]);
+ }
+ }
+ }
+ }
+ }
+ ALOGD ("%s: exit; mActualNumEe=%d, mNumEePresent=%d", fn, mActualNumEe,mNumEePresent);
+ return (mActualNumEe != 0);
+}
+
+
+/*******************************************************************************
+**
+** Function TimeDiff
+**
+** Description Computes time difference in milliseconds.
+**
+** Returns Time difference in milliseconds
+**
+*******************************************************************************/
+static UINT32 TimeDiff(timespec start, timespec end)
+{
+ end.tv_sec -= start.tv_sec;
+ end.tv_nsec -= start.tv_nsec;
+
+ if (end.tv_nsec < 0) {
+ end.tv_nsec += 10e8;
+ end.tv_sec -=1;
+ }
+
+ return (end.tv_sec * 1000) + (end.tv_nsec / 10e5);
+}
+
+/*******************************************************************************
+**
+** Function: isRfFieldOn
+**
+** Description: Can be used to determine if the SE is in an RF field
+**
+** Returns: True if the SE is activated in an RF field
+**
+*******************************************************************************/
+bool SecureElement::isRfFieldOn() {
+ AutoMutex mutex(mMutex);
+ if (mRfFieldIsOn) {
+ return true;
+ }
+ struct timespec now;
+ int ret = clock_gettime(CLOCK_MONOTONIC, &now);
+ if (ret == -1) {
+ ALOGE("isRfFieldOn(): clock_gettime failed");
+ return false;
+ }
+ if (TimeDiff(mLastRfFieldToggle, now) < 50) {
+ // If it was less than 50ms ago that RF field
+ // was turned off, still return ON.
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/*******************************************************************************
+**
+** Function: isActivatedInListenMode
+**
+** Description: Can be used to determine if the SE is activated in listen mode
+**
+** Returns: True if the SE is activated in listen mode
+**
+*******************************************************************************/
+bool SecureElement::isActivatedInListenMode() {
+ return mActivatedInListenMode;
+}
+
+/*******************************************************************************
+**
+** Function: getListOfEeHandles
+**
+** Description: Get the list of handles of all execution environments.
+** e: Java Virtual Machine.
+**
+** Returns: List of handles of all execution environments.
+**
+*******************************************************************************/
+jintArray SecureElement::getListOfEeHandles (JNIEnv* e)
+{
+ static const char fn [] = "SecureElement::getListOfEeHandles";
+ ALOGD ("%s: enter", fn);
+ if (mNumEePresent == 0)
+ return NULL;
+ jintArray list = NULL;
+
+ if (!mIsInit)
+ {
+ ALOGE ("%s: not init", fn);
+ return (NULL);
+ }
+
+ // Get Fresh EE info.
+ if (! getEeInfo())
+ return (NULL);
+
+ list = e->NewIntArray (mNumEePresent); //allocate array
+ jint jj = 0;
+ int cnt = 0;
+ for (int ii = 0; ii < mActualNumEe && cnt < mNumEePresent; ii++)
+ {
+ ALOGD ("%s: %u = 0x%X", fn, ii, mEeInfo[ii].ee_handle);
+ if ((mEeInfo[ii].num_interface == 0) || (mEeInfo[ii].ee_interface[0] == NCI_NFCEE_INTERFACE_HCI_ACCESS) )
+ {
+ continue;
+ }
+
+ jj = mEeInfo[ii].ee_handle & ~NFA_HANDLE_GROUP_EE;
+ e->SetIntArrayRegion (list, cnt++, 1, &jj);
+ }
+ //e->DeleteLocalRef (list);
+
+ ALOGD("%s: exit", fn);
+ return list;
+}
+
+
+/*******************************************************************************
+**
+** Function: activate
+**
+** Description: Turn on the secure element.
+** seID: ID of secure element.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool SecureElement::activate (jint seID)
+{
+ static const char fn [] = "SecureElement::activate";
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ int numActivatedEe = 0;
+
+ ALOGD ("%s: enter; seID=0x%X", fn, seID);
+
+ if (!mIsInit)
+ {
+ ALOGE ("%s: not init", fn);
+ return false;
+ }
+
+ if (mActiveEeHandle != NFA_HANDLE_INVALID)
+ {
+ ALOGD ("%s: already active", fn);
+ return true;
+ }
+
+ // Get Fresh EE info if needed.
+ if (! getEeInfo())
+ {
+ ALOGE ("%s: no EE info", fn);
+ return false;
+ }
+
+ mActiveEeHandle = getDefaultEeHandle();
+ ALOGD ("%s: active ee h=0x%X, override se=0x%X", fn, mActiveEeHandle, mActiveSeOverride);
+ if (mActiveEeHandle == NFA_HANDLE_INVALID)
+ {
+ ALOGE ("%s: ee not found", fn);
+ return false;
+ }
+
+ UINT16 override_se = 0;
+ if (mActiveSeOverride)
+ override_se = NFA_HANDLE_GROUP_EE | mActiveSeOverride;
+
+ if (mRfFieldIsOn) {
+ ALOGE("%s: RF field indication still on, resetting", fn);
+ mRfFieldIsOn = false;
+ }
+
+ ALOGD ("%s: override seid=0x%X", fn, override_se );
+ //activate every discovered secure element
+ for (int index=0; index < mActualNumEe; index++)
+ {
+ tNFA_EE_INFO& eeItem = mEeInfo[index];
+
+ if ((eeItem.ee_handle == EE_HANDLE_0xF3) || (eeItem.ee_handle == EE_HANDLE_0xF4))
+ {
+ if (override_se && (override_se != eeItem.ee_handle) )
+ continue; // do not enable all SEs; only the override one
+
+ if (eeItem.ee_status != NFC_NFCEE_STATUS_INACTIVE)
+ {
+ ALOGD ("%s: h=0x%X already activated", fn, eeItem.ee_handle);
+ numActivatedEe++;
+ continue;
+ }
+
+ {
+ SyncEventGuard guard (mEeSetModeEvent);
+ ALOGD ("%s: set EE mode activate; h=0x%X", fn, eeItem.ee_handle);
+ if ((nfaStat = NFA_EeModeSet (eeItem.ee_handle, NFA_EE_MD_ACTIVATE)) == NFA_STATUS_OK)
+ {
+ mEeSetModeEvent.wait (); //wait for NFA_EE_MODE_SET_EVT
+ if (eeItem.ee_status == NFC_NFCEE_STATUS_ACTIVE)
+ numActivatedEe++;
+ }
+ else
+ ALOGE ("%s: NFA_EeModeSet failed; error=0x%X", fn, nfaStat);
+ }
+ }
+ } //for
+
+ for (UINT8 xx = 0; xx < mActualNumEe; xx++)
+ {
+ if ((mEeInfo[xx].num_interface != 0) && (mEeInfo[xx].ee_interface[0] != NCI_NFCEE_INTERFACE_HCI_ACCESS) &&
+ (mEeInfo[xx].ee_status != NFC_NFCEE_STATUS_INACTIVE))
+ {
+ mActiveEeHandle = mEeInfo[xx].ee_handle;
+ break;
+ }
+ }
+
+ ALOGD ("%s: exit; ok=%u", fn, numActivatedEe > 0);
+ return numActivatedEe > 0;
+}
+
+
+/*******************************************************************************
+**
+** Function: deactivate
+**
+** Description: Turn off the secure element.
+** seID: ID of secure element.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool SecureElement::deactivate (jint seID)
+{
+ static const char fn [] = "SecureElement::deactivate";
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ int numDeactivatedEe = 0;
+ bool retval = false;
+
+ ALOGD ("%s: enter; seID=0x%X, mActiveEeHandle=0x%X", fn, seID, mActiveEeHandle);
+
+ if (!mIsInit)
+ {
+ ALOGE ("%s: not init", fn);
+ goto TheEnd;
+ }
+
+ //if the controller is routing to sec elems or piping,
+ //then the secure element cannot be deactivated
+ if ((mCurrentRouteSelection == SecElemRoute) || mIsPiping)
+ {
+ ALOGE ("%s: still busy", fn);
+ goto TheEnd;
+ }
+
+ if (mActiveEeHandle == NFA_HANDLE_INVALID)
+ {
+ ALOGE ("%s: invalid EE handle", fn);
+ goto TheEnd;
+ }
+
+ mActiveEeHandle = NFA_HANDLE_INVALID;
+ retval = true;
+
+TheEnd:
+ ALOGD ("%s: exit; ok=%u", fn, retval);
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: notifyTransactionListenersOfAid
+**
+** Description: Notify the NFC service about a transaction event from secure element.
+** aid: Buffer contains application ID.
+** aidLen: Length of application ID.
+**
+** Returns: None
+**
+*******************************************************************************/
+void SecureElement::notifyTransactionListenersOfAid (const UINT8* aidBuffer, UINT8 aidBufferLen)
+{
+ static const char fn [] = "SecureElement::notifyTransactionListenersOfAid";
+ ALOGD ("%s: enter; aid len=%u", fn, aidBufferLen);
+
+ if (aidBufferLen == 0)
+ return;
+
+ jobject tlvJavaArray = NULL;
+ JNIEnv* e = NULL;
+ UINT8* tlv = 0;
+ const UINT16 tlvMaxLen = aidBufferLen + 10;
+ UINT16 tlvActualLen = 0;
+ bool stat = false;
+
+ mNativeData->vm->AttachCurrentThread (&e, NULL);
+ if (e == NULL)
+ {
+ ALOGE ("%s: jni env is null", fn);
+ return;
+ }
+
+ tlv = new UINT8 [tlvMaxLen];
+ if (tlv == NULL)
+ {
+ ALOGE ("%s: fail allocate tlv", fn);
+ goto TheEnd;
+ }
+
+ memcpy (tlv, aidBuffer, aidBufferLen);
+ tlvActualLen = aidBufferLen;
+
+ tlvJavaArray = e->NewByteArray (tlvActualLen);
+ if (tlvJavaArray == NULL)
+ {
+ ALOGE ("%s: fail allocate array", fn);
+ goto TheEnd;
+ }
+
+ e->SetByteArrayRegion ((jbyteArray)tlvJavaArray, 0, tlvActualLen, (jbyte *)tlv);
+ if (e->ExceptionCheck())
+ {
+ e->ExceptionClear();
+ ALOGE ("%s: fail fill array", fn);
+ goto TheEnd;
+ }
+
+ e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifyTransactionListeners, tlvJavaArray);
+ if (e->ExceptionCheck())
+ {
+ e->ExceptionClear();
+ ALOGE ("%s: fail notify", fn);
+ goto TheEnd;
+ }
+
+TheEnd:
+ if (tlvJavaArray)
+ e->DeleteLocalRef (tlvJavaArray);
+ mNativeData->vm->DetachCurrentThread ();
+ delete [] tlv;
+ ALOGD ("%s: exit", fn);
+}
+
+
+/*******************************************************************************
+**
+** Function: connectEE
+**
+** Description: Connect to the execution environment.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool SecureElement::connectEE ()
+{
+ static const char fn [] = "SecureElement::connectEE";
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ bool retVal = false;
+ UINT8 destHost = 0;
+ unsigned long num = 0;
+ char pipeConfName[40];
+ tNFA_HANDLE eeHandle = mActiveEeHandle;
+
+ ALOGD ("%s: enter, mActiveEeHandle: 0x%04x, SEID: 0x%x, pipe_gate_num=%d, use pipe=%d",
+ fn, mActiveEeHandle, gSEId, gGatePipe, gUseStaticPipe);
+
+ if (!mIsInit)
+ {
+ ALOGE ("%s: not init", fn);
+ return (false);
+ }
+
+ if (gSEId != -1)
+ {
+ eeHandle = gSEId | NFA_HANDLE_GROUP_EE;
+ ALOGD ("%s: Using SEID: 0x%x", fn, eeHandle );
+ }
+
+ if (eeHandle == NFA_HANDLE_INVALID)
+ {
+ ALOGE ("%s: invalid handle 0x%X", fn, eeHandle);
+ return (false);
+ }
+
+ tNFA_EE_INFO *pEE = findEeByHandle (eeHandle);
+
+ if (pEE == NULL)
+ {
+ ALOGE ("%s: Handle 0x%04x NOT FOUND !!", fn, eeHandle);
+ return (false);
+ }
+
+ // Disable RF discovery completely while the DH is connected
+ android::startRfDiscovery(false);
+
+ mNewSourceGate = 0;
+
+ if (gGatePipe == -1)
+ {
+ // pipe/gate num was not specifed by app, get from config file
+ mNewPipeId = 0;
+
+ // Construct the PIPE name based on the EE handle (e.g. NFA_HCI_STATIC_PIPE_ID_F3 for UICC0).
+ snprintf (pipeConfName, sizeof(pipeConfName), "NFA_HCI_STATIC_PIPE_ID_%02X", eeHandle & NFA_HANDLE_MASK);
+
+ if (GetNumValue(pipeConfName, &num, sizeof(num)) && (num != 0))
+ {
+ mNewPipeId = num;
+ ALOGD ("%s: Using static pipe id: 0x%X", __FUNCTION__, mNewPipeId);
+ }
+ else
+ {
+ ALOGD ("%s: Did not find value '%s' defined in the .conf", __FUNCTION__, pipeConfName);
+ }
+ }
+ else
+ {
+ if (gUseStaticPipe)
+ {
+ mNewPipeId = gGatePipe;
+ }
+ else
+ {
+ mNewPipeId = 0;
+ mDestinationGate= gGatePipe;
+ }
+ }
+
+ // If the .conf file had a static pipe to use, just use it.
+ if (mNewPipeId != 0)
+ {
+ UINT8 host = (mNewPipeId == STATIC_PIPE_0x70) ? 0x02 : 0x03;
+ UINT8 gate = (mNewPipeId == STATIC_PIPE_0x70) ? 0xF0 : 0xF1;
+ nfaStat = NFA_HciAddStaticPipe(mNfaHciHandle, host, gate, mNewPipeId);
+ if (nfaStat != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: fail create static pipe; error=0x%X", fn, nfaStat);
+ retVal = false;
+ goto TheEnd;
+ }
+ }
+ else
+ {
+ if ( (pEE->num_tlvs >= 1) && (pEE->ee_tlv[0].tag == NFA_EE_TAG_HCI_HOST_ID) )
+ destHost = pEE->ee_tlv[0].info[0];
+ else
+ destHost = 2;
+
+ // Get a list of existing gates and pipes
+ {
+ ALOGD ("%s: get gate, pipe list", fn);
+ SyncEventGuard guard (mPipeListEvent);
+ nfaStat = NFA_HciGetGateAndPipeList (mNfaHciHandle);
+ if (nfaStat == NFA_STATUS_OK)
+ {
+ mPipeListEvent.wait();
+ if (mHciCfg.status == NFA_STATUS_OK)
+ {
+ for (UINT8 xx = 0; xx < mHciCfg.num_pipes; xx++)
+ {
+ if ( (mHciCfg.pipe[xx].dest_host == destHost)
+ && (mHciCfg.pipe[xx].dest_gate == mDestinationGate) )
+ {
+ mNewSourceGate = mHciCfg.pipe[xx].local_gate;
+ mNewPipeId = mHciCfg.pipe[xx].pipe_id;
+
+ ALOGD ("%s: found configured gate: 0x%02x pipe: 0x%02x", fn, mNewSourceGate, mNewPipeId);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (mNewSourceGate == 0)
+ {
+ ALOGD ("%s: allocate gate", fn);
+ //allocate a source gate and store in mNewSourceGate
+ SyncEventGuard guard (mAllocateGateEvent);
+ if ((nfaStat = NFA_HciAllocGate (mNfaHciHandle)) != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: fail allocate source gate; error=0x%X", fn, nfaStat);
+ goto TheEnd;
+ }
+ mAllocateGateEvent.wait ();
+ if (mCommandStatus != NFA_STATUS_OK)
+ goto TheEnd;
+ }
+
+ if (mNewPipeId == 0)
+ {
+ ALOGD ("%s: create pipe", fn);
+ SyncEventGuard guard (mCreatePipeEvent);
+ nfaStat = NFA_HciCreatePipe (mNfaHciHandle, mNewSourceGate, destHost, mDestinationGate);
+ if (nfaStat != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: fail create pipe; error=0x%X", fn, nfaStat);
+ goto TheEnd;
+ }
+ mCreatePipeEvent.wait ();
+ if (mCommandStatus != NFA_STATUS_OK)
+ goto TheEnd;
+ }
+
+ {
+ ALOGD ("%s: open pipe", fn);
+ SyncEventGuard guard (mPipeOpenedEvent);
+ nfaStat = NFA_HciOpenPipe (mNfaHciHandle, mNewPipeId);
+ if (nfaStat != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: fail open pipe; error=0x%X", fn, nfaStat);
+ goto TheEnd;
+ }
+ mPipeOpenedEvent.wait ();
+ if (mCommandStatus != NFA_STATUS_OK)
+ goto TheEnd;
+ }
+ }
+
+ retVal = true;
+
+TheEnd:
+ mIsPiping = retVal;
+ if (!retVal)
+ {
+ // if open failed we need to de-allocate the gate
+ disconnectEE(0);
+ }
+
+ ALOGD ("%s: exit; ok=%u", fn, retVal);
+ return retVal;
+}
+
+
+/*******************************************************************************
+**
+** Function: disconnectEE
+**
+** Description: Disconnect from the execution environment.
+** seID: ID of secure element.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool SecureElement::disconnectEE (jint seID)
+{
+ static const char fn [] = "SecureElement::disconnectEE";
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ tNFA_HANDLE eeHandle = seID;
+
+ ALOGD("%s: seID=0x%X; handle=0x%04x", fn, seID, eeHandle);
+
+ if (mUseOberthurWarmReset)
+ {
+ //send warm-reset command to Oberthur secure element which deselects the applet;
+ //this is an Oberthur-specific command;
+ ALOGD("%s: try warm-reset on pipe id 0x%X; cmd=0x%X", fn, mNewPipeId, mOberthurWarmResetCommand);
+ SyncEventGuard guard (mRegistryEvent);
+ nfaStat = NFA_HciSetRegistry (mNfaHciHandle, mNewPipeId,
+ 1, 1, &mOberthurWarmResetCommand);
+ if (nfaStat == NFA_STATUS_OK)
+ {
+ mRegistryEvent.wait ();
+ ALOGD("%s: completed warm-reset on pipe 0x%X", fn, mNewPipeId);
+ }
+ }
+
+ if (mNewSourceGate)
+ {
+ SyncEventGuard guard (mDeallocateGateEvent);
+ if ((nfaStat = NFA_HciDeallocGate (mNfaHciHandle, mNewSourceGate)) == NFA_STATUS_OK)
+ mDeallocateGateEvent.wait ();
+ else
+ ALOGE ("%s: fail dealloc gate; error=0x%X", fn, nfaStat);
+ }
+ mIsPiping = false;
+ // Re-enable RF discovery
+ // Note that it only effactuates the current configuration,
+ // so if polling/listening were configured OFF (forex because
+ // the screen was off), they will stay OFF with this call.
+ android::startRfDiscovery(true);
+ return true;
+}
+
+
+/*******************************************************************************
+**
+** Function: transceive
+**
+** Description: Send data to the secure element; read it's response.
+** xmitBuffer: Data to transmit.
+** xmitBufferSize: Length of data.
+** recvBuffer: Buffer to receive response.
+** recvBufferMaxSize: Maximum size of buffer.
+** recvBufferActualSize: Actual length of response.
+** timeoutMillisec: timeout in millisecond.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool SecureElement::transceive (UINT8* xmitBuffer, INT32 xmitBufferSize, UINT8* recvBuffer,
+ INT32 recvBufferMaxSize, INT32& recvBufferActualSize, INT32 timeoutMillisec)
+{
+ static const char fn [] = "SecureElement::transceive";
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ bool isSuccess = false;
+ bool waitOk = false;
+ UINT8 newSelectCmd[NCI_MAX_AID_LEN + 10];
+
+ ALOGD ("%s: enter; xmitBufferSize=%ld; recvBufferMaxSize=%ld; timeout=%ld", fn, xmitBufferSize, recvBufferMaxSize, timeoutMillisec);
+
+ // Check if we need to replace an "empty" SELECT command.
+ // 1. Has there been a AID configured, and
+ // 2. Is that AID a valid length (i.e 16 bytes max), and
+ // 3. Is the APDU at least 4 bytes (for header), and
+ // 4. Is INS == 0xA4 (SELECT command), and
+ // 5. Is P1 == 0x04 (SELECT by AID), and
+ // 6. Is the APDU len 4 or 5 bytes.
+ //
+ // Note, the length of the configured AID is in the first
+ // byte, and AID starts from the 2nd byte.
+ if (mAidForEmptySelect[0] // 1
+ && (mAidForEmptySelect[0] <= NCI_MAX_AID_LEN) // 2
+ && (xmitBufferSize >= 4) // 3
+ && (xmitBuffer[1] == 0xA4) // 4
+ && (xmitBuffer[2] == 0x04) // 5
+ && (xmitBufferSize <= 5)) // 6
+ {
+ UINT8 idx = 0;
+
+ // Copy APDU command header from the input buffer.
+ memcpy(&newSelectCmd[0], &xmitBuffer[0], 4);
+ idx = 4;
+
+ // Set the Lc value to length of the new AID
+ newSelectCmd[idx++] = mAidForEmptySelect[0];
+
+ // Copy the AID
+ memcpy(&newSelectCmd[idx], &mAidForEmptySelect[1], mAidForEmptySelect[0]);
+ idx += mAidForEmptySelect[0];
+
+ // If there is an Le (5th byte of APDU), add it to the end.
+ if (xmitBufferSize == 5)
+ newSelectCmd[idx++] = xmitBuffer[4];
+
+ // Point to the new APDU
+ xmitBuffer = &newSelectCmd[0];
+ xmitBufferSize = idx;
+
+ ALOGD ("%s: Empty AID SELECT cmd detected, substituting AID from config file, new length=%d", fn, idx);
+ }
+
+ {
+ SyncEventGuard guard (mTransceiveEvent);
+ mActualResponseSize = 0;
+ memset (mResponseData, 0, sizeof(mResponseData));
+ if ((mNewPipeId == STATIC_PIPE_0x70) || (mNewPipeId == STATIC_PIPE_0x71))
+ nfaStat = NFA_HciSendEvent (mNfaHciHandle, mNewPipeId, EVT_SEND_DATA, xmitBufferSize, xmitBuffer, sizeof(mResponseData), mResponseData, 0);
+ else
+ nfaStat = NFA_HciSendEvent (mNfaHciHandle, mNewPipeId, NFA_HCI_EVT_POST_DATA, xmitBufferSize, xmitBuffer, sizeof(mResponseData), mResponseData, 0);
+
+ if (nfaStat == NFA_STATUS_OK)
+ {
+ waitOk = mTransceiveEvent.wait (timeoutMillisec);
+ if (waitOk == false) //timeout occurs
+ {
+ ALOGE ("%s: wait response timeout", fn);
+ goto TheEnd;
+ }
+ }
+ else
+ {
+ ALOGE ("%s: fail send data; error=0x%X", fn, nfaStat);
+ goto TheEnd;
+ }
+ }
+
+ if (mActualResponseSize > recvBufferMaxSize)
+ recvBufferActualSize = recvBufferMaxSize;
+ else
+ recvBufferActualSize = mActualResponseSize;
+
+ memcpy (recvBuffer, mResponseData, recvBufferActualSize);
+ isSuccess = true;
+
+TheEnd:
+ ALOGD ("%s: exit; isSuccess: %d; recvBufferActualSize: %ld", fn, isSuccess, recvBufferActualSize);
+ return (isSuccess);
+}
+
+
+/*******************************************************************************
+**
+** Function: notifyListenModeState
+**
+** Description: Notify the NFC service about whether the SE was activated
+** in listen mode.
+** isActive: Whether the secure element is activated.
+**
+** Returns: None
+**
+*******************************************************************************/
+void SecureElement::notifyListenModeState (bool isActivated) {
+ static const char fn [] = "SecureElement::notifyListenMode";
+ JNIEnv *e = NULL;
+
+ ALOGD ("%s: enter; listen mode active=%u", fn, isActivated);
+ mNativeData->vm->AttachCurrentThread (&e, NULL);
+
+ if (e == NULL)
+ {
+ ALOGE ("%s: jni env is null", fn);
+ return;
+ }
+
+ mActivatedInListenMode = isActivated;
+ if (isActivated) {
+ e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifySeListenActivated);
+ }
+ else {
+ e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifySeListenDeactivated);
+ }
+
+ if (e->ExceptionCheck())
+ {
+ e->ExceptionClear();
+ ALOGE ("%s: fail notify", fn);
+ }
+
+ mNativeData->vm->DetachCurrentThread ();
+ ALOGD ("%s: exit", fn);
+}
+
+/*******************************************************************************
+**
+** Function: notifyRfFieldEvent
+**
+** Description: Notify the NFC service about RF field events from the stack.
+** isActive: Whether any secure element is activated.
+**
+** Returns: None
+**
+*******************************************************************************/
+void SecureElement::notifyRfFieldEvent (bool isActive)
+{
+ static const char fn [] = "SecureElement::notifyRfFieldEvent";
+ JNIEnv *e = NULL;
+
+ ALOGD ("%s: enter; is active=%u", fn, isActive);
+ mNativeData->vm->AttachCurrentThread (&e, NULL);
+
+ if (e == NULL)
+ {
+ ALOGE ("%s: jni env is null", fn);
+ return;
+ }
+
+ mMutex.lock();
+ int ret = clock_gettime (CLOCK_MONOTONIC, &mLastRfFieldToggle);
+ if (ret == -1) {
+ ALOGE("%s: clock_gettime failed", fn);
+ // There is no good choice here...
+ }
+ if (isActive) {
+ mRfFieldIsOn = true;
+ e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifySeFieldActivated);
+ }
+ else {
+ mRfFieldIsOn = false;
+ e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifySeFieldDeactivated);
+ }
+ mMutex.unlock();
+
+ if (e->ExceptionCheck())
+ {
+ e->ExceptionClear();
+ ALOGE ("%s: fail notify", fn);
+ }
+ mNativeData->vm->DetachCurrentThread ();
+ ALOGD ("%s: exit", fn);
+}
+
+
+/*******************************************************************************
+**
+** Function: storeUiccInfo
+**
+** Description: Store a copy of the execution environment information from the stack.
+** info: execution environment information.
+**
+** Returns: None
+**
+*******************************************************************************/
+void SecureElement::storeUiccInfo (tNFA_EE_DISCOVER_REQ& info)
+{
+ static const char fn [] = "SecureElement::storeUiccInfo";
+ ALOGD ("%s: Status: %u Num EE: %u", fn, info.status, info.num_ee);
+
+ SyncEventGuard guard (mUiccInfoEvent);
+ memcpy (&mUiccInfo, &info, sizeof(mUiccInfo));
+ for (UINT8 xx = 0; xx < info.num_ee; xx++)
+ {
+ //for each technology (A, B, F, B'), print the bit field that shows
+ //what protocol(s) is support by that technology
+ ALOGD ("%s EE[%u] Handle: 0x%04x techA: 0x%02x techB: 0x%02x techF: 0x%02x techBprime: 0x%02x",
+ fn, xx, info.ee_disc_info[xx].ee_handle,
+ info.ee_disc_info[xx].la_protocol,
+ info.ee_disc_info[xx].lb_protocol,
+ info.ee_disc_info[xx].lf_protocol,
+ info.ee_disc_info[xx].lbp_protocol);
+ }
+ mUiccInfoEvent.notifyOne ();
+}
+
+
+/*******************************************************************************
+**
+** Function: getUiccId
+**
+** Description: Get the ID of the secure element.
+** eeHandle: Handle to the secure element.
+** uid: Array to receive the ID.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool SecureElement::getUiccId (tNFA_HANDLE eeHandle, jbyteArray& uid)
+{
+ static const char fn [] = "SecureElement::getUiccId";
+ ALOGD ("%s: ee h=0x%X", fn, eeHandle);
+ bool retval = false;
+ JNIEnv* e = NULL;
+
+ mNativeData->vm->AttachCurrentThread (&e, NULL);
+ if (e == NULL)
+ {
+ ALOGE ("%s: jni env is null", fn);
+ return false;
+ }
+
+ findUiccByHandle (eeHandle);
+ //cannot get UID from the stack; nothing to do
+
+TheEnd:
+ mNativeData->vm->DetachCurrentThread ();
+ ALOGD ("%s: exit; ret=%u", fn, retval);
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: getTechnologyList
+**
+** Description: Get all the technologies supported by a secure element.
+** eeHandle: Handle of secure element.
+** techList: List to receive the technologies.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool SecureElement::getTechnologyList (tNFA_HANDLE eeHandle, jintArray& techList)
+{
+ static const char fn [] = "SecureElement::getTechnologyList";
+ ALOGD ("%s: ee h=0x%X", fn, eeHandle);
+ bool retval = false;
+ JNIEnv* e = NULL;
+ jint theList = 0;
+
+ mNativeData->vm->AttachCurrentThread (&e, NULL);
+ if (e == NULL)
+ {
+ ALOGE ("%s: jni env is null", fn);
+ return false;
+ }
+
+ tNFA_EE_DISCOVER_INFO *pUICC = findUiccByHandle (eeHandle);
+
+ if (pUICC->la_protocol != 0)
+ theList = TARGET_TYPE_ISO14443_3A;
+ else if (pUICC->lb_protocol != 0)
+ theList = TARGET_TYPE_ISO14443_3B;
+ else if (pUICC->lf_protocol != 0)
+ theList = TARGET_TYPE_FELICA;
+ else if (pUICC->lbp_protocol != 0)
+ theList = TARGET_TYPE_ISO14443_3B;
+ else
+ theList = TARGET_TYPE_UNKNOWN;
+
+TheEnd:
+ mNativeData->vm->DetachCurrentThread ();
+ ALOGD ("%s: exit; ret=%u", fn, retval);
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: adjustRoutes
+**
+** Description: Adjust routes in the controller's listen-mode routing table.
+** selection: which set of routes to configure the controller.
+**
+** Returns: None
+**
+*******************************************************************************/
+void SecureElement::adjustRoutes (RouteSelection selection)
+{
+ static const char fn [] = "SecureElement::adjustRoutes";
+ ALOGD ("%s: enter; selection=%u", fn, selection);
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ RouteDataSet::Database* db = mRouteDataSet.getDatabase (RouteDataSet::DefaultRouteDatabase);
+
+ if (selection == SecElemRoute)
+ db = mRouteDataSet.getDatabase (RouteDataSet::SecElemRouteDatabase);
+
+ mCurrentRouteSelection = selection;
+ adjustProtocolRoutes (db, selection);
+ adjustTechnologyRoutes (db, selection);
+ HostAidRouter::getInstance ().deleteAllRoutes (); //stop all AID routes to host
+
+ if (db->empty())
+ {
+ ALOGD ("%s: no route configuration", fn);
+ goto TheEnd;
+ }
+
+
+TheEnd:
+ NFA_EeUpdateNow (); //apply new routes now
+ ALOGD ("%s: exit", fn);
+}
+
+
+/*******************************************************************************
+**
+** Function: applyRoutes
+**
+** Description: Read route data from file and apply them again.
+**
+** Returns: None
+**
+*******************************************************************************/
+void SecureElement::applyRoutes ()
+{
+ static const char fn [] = "SecureElement::applyRoutes";
+ ALOGD ("%s: enter", fn);
+ if (mCurrentRouteSelection != NoRoute)
+ {
+ mRouteDataSet.import (); //read XML file
+ adjustRoutes (mCurrentRouteSelection);
+ }
+ ALOGD ("%s: exit", fn);
+}
+
+
+/*******************************************************************************
+**
+** Function: adjustProtocolRoutes
+**
+** Description: Adjust default routing based on protocol in NFC listen mode.
+** isRouteToEe: Whether routing to EE (true) or host (false).
+**
+** Returns: None
+**
+*******************************************************************************/
+void SecureElement::adjustProtocolRoutes (RouteDataSet::Database* db, RouteSelection routeSelection)
+{
+ static const char fn [] = "SecureElement::adjustProtocolRoutes";
+ ALOGD ("%s: enter", fn);
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ const tNFA_PROTOCOL_MASK protoMask = NFA_PROTOCOL_MASK_ISO_DEP;
+
+ ///////////////////////
+ // delete route to host
+ ///////////////////////
+ {
+ ALOGD ("%s: delete route to host", fn);
+ SyncEventGuard guard (mRoutingEvent);
+ if ((nfaStat = NFA_EeSetDefaultProtoRouting (NFA_EE_HANDLE_DH, 0, 0, 0)) == NFA_STATUS_OK)
+ mRoutingEvent.wait ();
+ else
+ ALOGE ("%s: fail delete route to host; error=0x%X", fn, nfaStat);
+ }
+
+ ///////////////////////
+ // delete route to every sec elem
+ ///////////////////////
+ for (int i=0; i < mActualNumEe; i++)
+ {
+ if ((mEeInfo[i].num_interface != 0) &&
+ (mEeInfo[i].ee_interface[0] != NFC_NFCEE_INTERFACE_HCI_ACCESS) &&
+ (mEeInfo[i].ee_status == NFA_EE_STATUS_ACTIVE))
+ {
+ ALOGD ("%s: delete route to EE h=0x%X", fn, mEeInfo[i].ee_handle);
+ SyncEventGuard guard (mRoutingEvent);
+ if ((nfaStat = NFA_EeSetDefaultProtoRouting (mEeInfo[i].ee_handle, 0, 0, 0)) == NFA_STATUS_OK)
+ mRoutingEvent.wait ();
+ else
+ ALOGE ("%s: fail delete route to EE; error=0x%X", fn, nfaStat);
+ }
+ }
+
+ //////////////////////
+ // configure route for every discovered sec elem
+ //////////////////////
+ for (int i=0; i < mActualNumEe; i++)
+ {
+ //if sec elem is active
+ if ((mEeInfo[i].num_interface != 0) &&
+ (mEeInfo[i].ee_interface[0] != NFC_NFCEE_INTERFACE_HCI_ACCESS) &&
+ (mEeInfo[i].ee_status == NFA_EE_STATUS_ACTIVE))
+ {
+ tNFA_PROTOCOL_MASK protocolsSwitchOn = 0; //all protocols that are active at full power
+ tNFA_PROTOCOL_MASK protocolsSwitchOff = 0; //all protocols that are active when phone is turned off
+ tNFA_PROTOCOL_MASK protocolsBatteryOff = 0; //all protocols that are active when there is no power
+
+ //for every route in XML, look for protocol route;
+ //collect every protocol according to it's desired power mode
+ for (RouteDataSet::Database::iterator iter = db->begin(); iter != db->end(); iter++)
+ {
+ RouteData* routeData = *iter;
+ RouteDataForProtocol* route = NULL;
+ if (routeData->mRouteType != RouteData::ProtocolRoute)
+ continue; //skip other kinds of routing data
+ route = (RouteDataForProtocol*) (*iter);
+ if (route->mNfaEeHandle == mEeInfo[i].ee_handle)
+ {
+ if (route->mSwitchOn)
+ protocolsSwitchOn |= route->mProtocol;
+ if (route->mSwitchOff)
+ protocolsSwitchOff |= route->mProtocol;
+ if (route->mBatteryOff)
+ protocolsBatteryOff |= route->mProtocol;
+ }
+ }
+
+ if (protocolsSwitchOn | protocolsSwitchOff | protocolsBatteryOff)
+ {
+ ALOGD ("%s: route to EE h=0x%X", fn, mEeInfo[i].ee_handle);
+ SyncEventGuard guard (mRoutingEvent);
+ nfaStat = NFA_EeSetDefaultProtoRouting (mEeInfo[i].ee_handle,
+ protocolsSwitchOn, protocolsSwitchOff, protocolsBatteryOff);
+ if (nfaStat == NFA_STATUS_OK)
+ mRoutingEvent.wait ();
+ else
+ ALOGE ("%s: fail route to EE; error=0x%X", fn, nfaStat);
+ }
+ } //if sec elem is active
+ } //for every discovered sec elem
+
+ //////////////////////
+ // configure route to host
+ //////////////////////
+ {
+ tNFA_PROTOCOL_MASK protocolsSwitchOn = 0; //all protocols that are active at full power
+ tNFA_PROTOCOL_MASK protocolsSwitchOff = 0; //all protocols that are active when phone is turned off
+ tNFA_PROTOCOL_MASK protocolsBatteryOff = 0; //all protocols that are active when there is no power
+
+ //for every route in XML, look for protocol route;
+ //collect every protocol according to it's desired power mode
+ for (RouteDataSet::Database::iterator iter = db->begin(); iter != db->end(); iter++)
+ {
+ RouteData* routeData = *iter;
+ RouteDataForProtocol* route = NULL;
+ if (routeData->mRouteType != RouteData::ProtocolRoute)
+ continue; //skip other kinds of routing data
+ route = (RouteDataForProtocol*) (*iter);
+ if (route->mNfaEeHandle == NFA_EE_HANDLE_DH)
+ {
+ if (route->mSwitchOn)
+ protocolsSwitchOn |= route->mProtocol;
+ if (route->mSwitchOff)
+ protocolsSwitchOff |= route->mProtocol;
+ if (route->mBatteryOff)
+ protocolsBatteryOff |= route->mProtocol;
+ }
+ }
+
+ if (protocolsSwitchOn | protocolsSwitchOff | protocolsBatteryOff)
+ {
+ ALOGD ("%s: route to EE h=0x%X", fn, NFA_EE_HANDLE_DH);
+ SyncEventGuard guard (mRoutingEvent);
+ nfaStat = NFA_EeSetDefaultProtoRouting (NFA_EE_HANDLE_DH,
+ protocolsSwitchOn, protocolsSwitchOff, protocolsBatteryOff);
+ if (nfaStat == NFA_STATUS_OK)
+ mRoutingEvent.wait ();
+ else
+ ALOGE ("%s: fail route to EE; error=0x%X", fn, nfaStat);
+ }
+ }
+
+ //////////////////////
+ // if route database is empty, setup a default route
+ //////////////////////
+ if (db->empty())
+ {
+ tNFA_HANDLE eeHandle = NFA_EE_HANDLE_DH;
+ if (routeSelection == SecElemRoute)
+ eeHandle = getDefaultEeHandle ();
+ ALOGD ("%s: route to default EE h=0x%X", fn, eeHandle);
+ SyncEventGuard guard (mRoutingEvent);
+ nfaStat = NFA_EeSetDefaultProtoRouting (eeHandle, protoMask, 0, 0);
+ if (nfaStat == NFA_STATUS_OK)
+ mRoutingEvent.wait ();
+ else
+ ALOGE ("%s: fail route to EE; error=0x%X", fn, nfaStat);
+ }
+ ALOGD ("%s: exit", fn);
+}
+
+
+/*******************************************************************************
+**
+** Function: adjustTechnologyRoutes
+**
+** Description: Adjust default routing based on technology in NFC listen mode.
+** isRouteToEe: Whether routing to EE (true) or host (false).
+**
+** Returns: None
+**
+*******************************************************************************/
+void SecureElement::adjustTechnologyRoutes (RouteDataSet::Database* db, RouteSelection routeSelection)
+{
+ static const char fn [] = "SecureElement::adjustTechnologyRoutes";
+ ALOGD ("%s: enter", fn);
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ const tNFA_TECHNOLOGY_MASK techMask = NFA_TECHNOLOGY_MASK_A | NFA_TECHNOLOGY_MASK_B;
+
+ ///////////////////////
+ // delete route to host
+ ///////////////////////
+ {
+ ALOGD ("%s: delete route to host", fn);
+ SyncEventGuard guard (mRoutingEvent);
+ if ((nfaStat = NFA_EeSetDefaultTechRouting (NFA_EE_HANDLE_DH, 0, 0, 0)) == NFA_STATUS_OK)
+ mRoutingEvent.wait ();
+ else
+ ALOGE ("%s: fail delete route to host; error=0x%X", fn, nfaStat);
+ }
+
+ ///////////////////////
+ // delete route to every sec elem
+ ///////////////////////
+ for (int i=0; i < mActualNumEe; i++)
+ {
+ if ((mEeInfo[i].num_interface != 0) &&
+ (mEeInfo[i].ee_interface[0] != NFC_NFCEE_INTERFACE_HCI_ACCESS) &&
+ (mEeInfo[i].ee_status == NFA_EE_STATUS_ACTIVE))
+ {
+ ALOGD ("%s: delete route to EE h=0x%X", fn, mEeInfo[i].ee_handle);
+ SyncEventGuard guard (mRoutingEvent);
+ if ((nfaStat = NFA_EeSetDefaultTechRouting (mEeInfo[i].ee_handle, 0, 0, 0)) == NFA_STATUS_OK)
+ mRoutingEvent.wait ();
+ else
+ ALOGE ("%s: fail delete route to EE; error=0x%X", fn, nfaStat);
+ }
+ }
+
+ //////////////////////
+ // configure route for every discovered sec elem
+ //////////////////////
+ for (int i=0; i < mActualNumEe; i++)
+ {
+ //if sec elem is active
+ if ((mEeInfo[i].num_interface != 0) &&
+ (mEeInfo[i].ee_interface[0] != NFC_NFCEE_INTERFACE_HCI_ACCESS) &&
+ (mEeInfo[i].ee_status == NFA_EE_STATUS_ACTIVE))
+ {
+ tNFA_TECHNOLOGY_MASK techsSwitchOn = 0; //all techs that are active at full power
+ tNFA_TECHNOLOGY_MASK techsSwitchOff = 0; //all techs that are active when phone is turned off
+ tNFA_TECHNOLOGY_MASK techsBatteryOff = 0; //all techs that are active when there is no power
+
+ //for every route in XML, look for tech route;
+ //collect every tech according to it's desired power mode
+ for (RouteDataSet::Database::iterator iter = db->begin(); iter != db->end(); iter++)
+ {
+ RouteData* routeData = *iter;
+ RouteDataForTechnology* route = NULL;
+ if (routeData->mRouteType != RouteData::TechnologyRoute)
+ continue; //skip other kinds of routing data
+ route = (RouteDataForTechnology*) (*iter);
+ if (route->mNfaEeHandle == mEeInfo[i].ee_handle)
+ {
+ if (route->mSwitchOn)
+ techsSwitchOn |= route->mTechnology;
+ if (route->mSwitchOff)
+ techsSwitchOff |= route->mTechnology;
+ if (route->mBatteryOff)
+ techsBatteryOff |= route->mTechnology;
+ }
+ }
+
+ if (techsSwitchOn | techsSwitchOff | techsBatteryOff)
+ {
+ ALOGD ("%s: route to EE h=0x%X", fn, mEeInfo[i].ee_handle);
+ SyncEventGuard guard (mRoutingEvent);
+ nfaStat = NFA_EeSetDefaultTechRouting (mEeInfo[i].ee_handle,
+ techsSwitchOn, techsSwitchOff, techsBatteryOff);
+ if (nfaStat == NFA_STATUS_OK)
+ mRoutingEvent.wait ();
+ else
+ ALOGE ("%s: fail route to EE; error=0x%X", fn, nfaStat);
+ }
+ } //if sec elem is active
+ } //for every discovered sec elem
+
+ //////////////////////
+ // configure route to host
+ //////////////////////
+ {
+ tNFA_TECHNOLOGY_MASK techsSwitchOn = 0; //all techs that are active at full power
+ tNFA_TECHNOLOGY_MASK techsSwitchOff = 0; //all techs that are active when phone is turned off
+ tNFA_TECHNOLOGY_MASK techsBatteryOff = 0; //all techs that are active when there is no power
+
+ //for every route in XML, look for protocol route;
+ //collect every protocol according to it's desired power mode
+ for (RouteDataSet::Database::iterator iter = db->begin(); iter != db->end(); iter++)
+ {
+ RouteData* routeData = *iter;
+ RouteDataForTechnology * route = NULL;
+ if (routeData->mRouteType != RouteData::TechnologyRoute)
+ continue; //skip other kinds of routing data
+ route = (RouteDataForTechnology*) (*iter);
+ if (route->mNfaEeHandle == NFA_EE_HANDLE_DH)
+ {
+ if (route->mSwitchOn)
+ techsSwitchOn |= route->mTechnology;
+ if (route->mSwitchOff)
+ techsSwitchOff |= route->mTechnology;
+ if (route->mBatteryOff)
+ techsBatteryOff |= route->mTechnology;
+ }
+ }
+
+ if (techsSwitchOn | techsSwitchOff | techsBatteryOff)
+ {
+ ALOGD ("%s: route to EE h=0x%X", fn, NFA_EE_HANDLE_DH);
+ SyncEventGuard guard (mRoutingEvent);
+ nfaStat = NFA_EeSetDefaultTechRouting (NFA_EE_HANDLE_DH,
+ techsSwitchOn, techsSwitchOff, techsBatteryOff);
+ if (nfaStat == NFA_STATUS_OK)
+ mRoutingEvent.wait ();
+ else
+ ALOGE ("%s: fail route to EE; error=0x%X", fn, nfaStat);
+ }
+ }
+
+ //////////////////////
+ // if route database is empty, setup a default route
+ //////////////////////
+ if (db->empty())
+ {
+ tNFA_HANDLE eeHandle = NFA_EE_HANDLE_DH;
+ if (routeSelection == SecElemRoute)
+ eeHandle = getDefaultEeHandle ();
+ ALOGD ("%s: route to default EE h=0x%X", fn, eeHandle);
+ SyncEventGuard guard (mRoutingEvent);
+ nfaStat = NFA_EeSetDefaultTechRouting (eeHandle, techMask, 0, 0);
+ if (nfaStat == NFA_STATUS_OK)
+ mRoutingEvent.wait ();
+ else
+ ALOGE ("%s: fail route to EE; error=0x%X", fn, nfaStat);
+ }
+ ALOGD ("%s: exit", fn);
+}
+
+
+/*******************************************************************************
+**
+** Function: nfaEeCallback
+**
+** Description: Receive execution environment-related events from stack.
+** event: Event code.
+** eventData: Event data.
+**
+** Returns: None
+**
+*******************************************************************************/
+void SecureElement::nfaEeCallback (tNFA_EE_EVT event, tNFA_EE_CBACK_DATA* eventData)
+{
+ static const char fn [] = "SecureElement::nfaEeCallback";
+
+ switch (event)
+ {
+ case NFA_EE_REGISTER_EVT:
+ {
+ SyncEventGuard guard (sSecElem.mEeRegisterEvent);
+ ALOGD ("%s: NFA_EE_REGISTER_EVT; status=%u", fn, eventData->ee_register);
+ sSecElem.mEeRegisterEvent.notifyOne();
+ }
+ break;
+
+ case NFA_EE_MODE_SET_EVT:
+ {
+ ALOGD ("%s: NFA_EE_MODE_SET_EVT; status: 0x%04X handle: 0x%04X mActiveEeHandle: 0x%04X", fn,
+ eventData->mode_set.status, eventData->mode_set.ee_handle, sSecElem.mActiveEeHandle);
+
+ if (eventData->mode_set.status == NFA_STATUS_OK)
+ {
+ tNFA_EE_INFO *pEE = sSecElem.findEeByHandle (eventData->mode_set.ee_handle);
+ if (pEE)
+ {
+ pEE->ee_status ^= 1;
+ ALOGD ("%s: NFA_EE_MODE_SET_EVT; pEE->ee_status: %s (0x%04x)", fn, SecureElement::eeStatusToString(pEE->ee_status), pEE->ee_status);
+ }
+ else
+ ALOGE ("%s: NFA_EE_MODE_SET_EVT; EE: 0x%04x not found. mActiveEeHandle: 0x%04x", fn, eventData->mode_set.ee_handle, sSecElem.mActiveEeHandle);
+ }
+ SyncEventGuard guard (sSecElem.mEeSetModeEvent);
+ sSecElem.mEeSetModeEvent.notifyOne();
+ }
+ break;
+
+ case NFA_EE_SET_TECH_CFG_EVT:
+ {
+ ALOGD ("%s: NFA_EE_SET_TECH_CFG_EVT; status=0x%X", fn, eventData->status);
+ SyncEventGuard guard (sSecElem.mRoutingEvent);
+ sSecElem.mRoutingEvent.notifyOne ();
+ }
+ break;
+
+ case NFA_EE_SET_PROTO_CFG_EVT:
+ {
+ ALOGD ("%s: NFA_EE_SET_PROTO_CFG_EVT; status=0x%X", fn, eventData->status);
+ SyncEventGuard guard (sSecElem.mRoutingEvent);
+ sSecElem.mRoutingEvent.notifyOne ();
+ }
+ break;
+
+ case NFA_EE_ACTION_EVT:
+ {
+ tNFA_EE_ACTION& action = eventData->action;
+ if (action.trigger == NFC_EE_TRIG_SELECT)
+ ALOGD ("%s: NFA_EE_ACTION_EVT; h=0x%X; trigger=select (0x%X)", fn, action.ee_handle, action.trigger);
+ else if (action.trigger == NFC_EE_TRIG_APP_INIT)
+ {
+ tNFC_APP_INIT& app_init = action.param.app_init;
+ ALOGD ("%s: NFA_EE_ACTION_EVT; h=0x%X; trigger=app-init (0x%X); aid len=%u; data len=%u", fn,
+ action.ee_handle, action.trigger, app_init.len_aid, app_init.len_data);
+ //if app-init operation is successful;
+ //app_init.data[] contains two bytes, which are the status codes of the event;
+ //app_init.data[] does not contain an APDU response;
+ //see EMV Contactless Specification for Payment Systems; Book B; Entry Point Specification;
+ //version 2.1; March 2011; section 3.3.3.5;
+ if ( (app_init.len_data > 1) &&
+ (app_init.data[0] == 0x90) &&
+ (app_init.data[1] == 0x00) )
+ {
+ sSecElem.notifyTransactionListenersOfAid (app_init.aid, app_init.len_aid);
+ }
+ }
+ else if (action.trigger == NFC_EE_TRIG_RF_PROTOCOL)
+ ALOGD ("%s: NFA_EE_ACTION_EVT; h=0x%X; trigger=rf protocol (0x%X)", fn, action.ee_handle, action.trigger);
+ else if (action.trigger == NFC_EE_TRIG_RF_TECHNOLOGY)
+ ALOGD ("%s: NFA_EE_ACTION_EVT; h=0x%X; trigger=rf tech (0x%X)", fn, action.ee_handle, action.trigger);
+ else
+ ALOGE ("%s: NFA_EE_ACTION_EVT; h=0x%X; unknown trigger (0x%X)", fn, action.ee_handle, action.trigger);
+ }
+ break;
+
+ case NFA_EE_DISCOVER_REQ_EVT:
+ ALOGD ("%s: NFA_EE_DISCOVER_REQ_EVT; status=0x%X; num ee=%u", __FUNCTION__,
+ eventData->discover_req.status, eventData->discover_req.num_ee);
+ sSecElem.storeUiccInfo (eventData->discover_req);
+ break;
+
+ case NFA_EE_NO_CB_ERR_EVT:
+ ALOGD ("%s: NFA_EE_NO_CB_ERR_EVT status=%u", fn, eventData->status);
+ break;
+
+ case NFA_EE_ADD_AID_EVT:
+ {
+ ALOGD ("%s: NFA_EE_ADD_AID_EVT status=%u", fn, eventData->status);
+ SyncEventGuard guard (sSecElem.mAidAddRemoveEvent);
+ sSecElem.mAidAddRemoveEvent.notifyOne ();
+ }
+ break;
+
+ case NFA_EE_REMOVE_AID_EVT:
+ {
+ ALOGD ("%s: NFA_EE_REMOVE_AID_EVT status=%u", fn, eventData->status);
+ SyncEventGuard guard (sSecElem.mAidAddRemoveEvent);
+ sSecElem.mAidAddRemoveEvent.notifyOne ();
+ }
+ break;
+
+ case NFA_EE_NEW_EE_EVT:
+ {
+ ALOGD ("%s: NFA_EE_NEW_EE_EVT h=0x%X; status=%u", fn,
+ eventData->new_ee.ee_handle, eventData->new_ee.ee_status);
+ // Indicate there are new EE
+ sSecElem.mbNewEE = true;
+ }
+ break;
+
+ default:
+ ALOGE ("%s: unknown event=%u ????", fn, event);
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function getSeVerInfo
+**
+** Description Gets version information and id for a secure element. The
+** seIndex parmeter is the zero based index of the secure
+** element to get verion info for. The version infommation
+** is returned as a string int the verInfo parameter.
+**
+** Returns ture on success, false on failure
+**
+*******************************************************************************/
+bool SecureElement::getSeVerInfo(int seIndex, char * verInfo, int verInfoSz, UINT8 * seid)
+{
+ ALOGD("%s: enter, seIndex=%d", __FUNCTION__, seIndex);
+
+ if (seIndex > (mActualNumEe-1))
+ {
+ ALOGE("%s: invalid se index: %d, only %d SEs in system", __FUNCTION__, seIndex, mActualNumEe);
+ return false;
+ }
+
+ *seid = mEeInfo[seIndex].ee_handle;
+
+ if ((mEeInfo[seIndex].num_interface == 0) || (mEeInfo[seIndex].ee_interface[0] == NCI_NFCEE_INTERFACE_HCI_ACCESS) )
+ {
+ return false;
+ }
+
+ strncpy(verInfo, "Version info not available", verInfoSz-1);
+ verInfo[verInfoSz-1] = '\0';
+
+ UINT8 pipe = (mEeInfo[seIndex].ee_handle == EE_HANDLE_0xF3) ? 0x70 : 0x71;
+ UINT8 host = (pipe == STATIC_PIPE_0x70) ? 0x02 : 0x03;
+ UINT8 gate = (pipe == STATIC_PIPE_0x70) ? 0xF0 : 0xF1;
+
+ tNFA_STATUS nfaStat = NFA_HciAddStaticPipe(mNfaHciHandle, host, gate, pipe);
+ if (nfaStat != NFA_STATUS_OK)
+ {
+ ALOGE ("%s: NFA_HciAddStaticPipe() failed, pipe = 0x%x, error=0x%X", __FUNCTION__, pipe, nfaStat);
+ return true;
+ }
+
+ SyncEventGuard guard (mVerInfoEvent);
+ if (NFA_STATUS_OK == (nfaStat = NFA_HciGetRegistry (mNfaHciHandle, pipe, 0x02)))
+ {
+ if (false == mVerInfoEvent.wait(200))
+ {
+ ALOGE ("%s: wait response timeout", __FUNCTION__);
+ }
+ else
+ {
+ snprintf(verInfo, verInfoSz-1, "Oberthur OS S/N: 0x%02x%02x%02x", mVerInfo[0], mVerInfo[1], mVerInfo[2]);
+ verInfo[verInfoSz-1] = '\0';
+ }
+ }
+ else
+ {
+ ALOGE ("%s: NFA_HciGetRegistry () failed: 0x%X", __FUNCTION__, nfaStat);
+ }
+ return true;
+}
+
+/*******************************************************************************
+**
+** Function getActualNumEe
+**
+** Description Returns number of secure elements we know about.
+**
+** Returns Number of secure elements we know about.
+**
+*******************************************************************************/
+UINT8 SecureElement::getActualNumEe()
+{
+ return mActualNumEe;
+}
+
+/*******************************************************************************
+**
+** Function: nfaHciCallback
+**
+** Description: Receive Host Controller Interface-related events from stack.
+** event: Event code.
+** eventData: Event data.
+**
+** Returns: None
+**
+*******************************************************************************/
+void SecureElement::nfaHciCallback (tNFA_HCI_EVT event, tNFA_HCI_EVT_DATA* eventData)
+{
+ static const char fn [] = "SecureElement::nfaHciCallback";
+ ALOGD ("%s: event=0x%X", fn, event);
+
+ switch (event)
+ {
+ case NFA_HCI_REGISTER_EVT:
+ {
+ ALOGD ("%s: NFA_HCI_REGISTER_EVT; status=0x%X; handle=0x%X", fn,
+ eventData->hci_register.status, eventData->hci_register.hci_handle);
+ SyncEventGuard guard (sSecElem.mHciRegisterEvent);
+ sSecElem.mNfaHciHandle = eventData->hci_register.hci_handle;
+ sSecElem.mHciRegisterEvent.notifyOne();
+ }
+ break;
+
+ case NFA_HCI_ALLOCATE_GATE_EVT:
+ {
+ ALOGD ("%s: NFA_HCI_ALLOCATE_GATE_EVT; status=0x%X; gate=0x%X", fn, eventData->status, eventData->allocated.gate);
+ SyncEventGuard guard (sSecElem.mAllocateGateEvent);
+ sSecElem.mCommandStatus = eventData->status;
+ sSecElem.mNewSourceGate = (eventData->allocated.status == NFA_STATUS_OK) ? eventData->allocated.gate : 0;
+ sSecElem.mAllocateGateEvent.notifyOne();
+ }
+ break;
+
+ case NFA_HCI_DEALLOCATE_GATE_EVT:
+ {
+ tNFA_HCI_DEALLOCATE_GATE& deallocated = eventData->deallocated;
+ ALOGD ("%s: NFA_HCI_DEALLOCATE_GATE_EVT; status=0x%X; gate=0x%X", fn, deallocated.status, deallocated.gate);
+ SyncEventGuard guard (sSecElem.mDeallocateGateEvent);
+ sSecElem.mDeallocateGateEvent.notifyOne();
+ }
+ break;
+
+ case NFA_HCI_GET_GATE_PIPE_LIST_EVT:
+ {
+ ALOGD ("%s: NFA_HCI_GET_GATE_PIPE_LIST_EVT; status=0x%X; num_pipes: %u num_gates: %u", fn,
+ eventData->gates_pipes.status, eventData->gates_pipes.num_pipes, eventData->gates_pipes.num_gates);
+ SyncEventGuard guard (sSecElem.mPipeListEvent);
+ sSecElem.mCommandStatus = eventData->gates_pipes.status;
+ sSecElem.mHciCfg = eventData->gates_pipes;
+ sSecElem.mPipeListEvent.notifyOne();
+ }
+ break;
+
+ case NFA_HCI_CREATE_PIPE_EVT:
+ {
+ ALOGD ("%s: NFA_HCI_CREATE_PIPE_EVT; status=0x%X; pipe=0x%X; src gate=0x%X; dest host=0x%X; dest gate=0x%X", fn,
+ eventData->created.status, eventData->created.pipe, eventData->created.source_gate, eventData->created.dest_host, eventData->created.dest_gate);
+ SyncEventGuard guard (sSecElem.mCreatePipeEvent);
+ sSecElem.mCommandStatus = eventData->created.status;
+ sSecElem.mNewPipeId = eventData->created.pipe;
+ sSecElem.mCreatePipeEvent.notifyOne();
+ }
+ break;
+
+ case NFA_HCI_OPEN_PIPE_EVT:
+ {
+ ALOGD ("%s: NFA_HCI_OPEN_PIPE_EVT; status=0x%X; pipe=0x%X", fn, eventData->opened.status, eventData->opened.pipe);
+ SyncEventGuard guard (sSecElem.mPipeOpenedEvent);
+ sSecElem.mCommandStatus = eventData->opened.status;
+ sSecElem.mPipeOpenedEvent.notifyOne();
+ }
+ break;
+
+ case NFA_HCI_EVENT_SENT_EVT:
+ ALOGD ("%s: NFA_HCI_EVENT_SENT_EVT; status=0x%X", fn, eventData->evt_sent.status);
+ break;
+
+ case NFA_HCI_RSP_RCVD_EVT: //response received from secure element
+ {
+ tNFA_HCI_RSP_RCVD& rsp_rcvd = eventData->rsp_rcvd;
+ ALOGD ("%s: NFA_HCI_RSP_RCVD_EVT; status: 0x%X; code: 0x%X; pipe: 0x%X; len: %u", fn,
+ rsp_rcvd.status, rsp_rcvd.rsp_code, rsp_rcvd.pipe, rsp_rcvd.rsp_len);
+ }
+ break;
+
+ case NFA_HCI_GET_REG_RSP_EVT :
+ ALOGD ("%s: NFA_HCI_GET_REG_RSP_EVT; status: 0x%X; pipe: 0x%X, len: %d", fn,
+ eventData->registry.status, eventData->registry.pipe, eventData->registry.data_len);
+ if (eventData->registry.data_len >= 19 && ((eventData->registry.pipe == STATIC_PIPE_0x70) || (eventData->registry.pipe == STATIC_PIPE_0x71)))
+ {
+ SyncEventGuard guard (sSecElem.mVerInfoEvent);
+ // Oberthur OS version is in bytes 16,17, and 18
+ sSecElem.mVerInfo[0] = eventData->registry.reg_data[16];
+ sSecElem.mVerInfo[1] = eventData->registry.reg_data[17];
+ sSecElem.mVerInfo[2] = eventData->registry.reg_data[18];
+ sSecElem.mVerInfoEvent.notifyOne ();
+ }
+ break;
+
+ case NFA_HCI_EVENT_RCVD_EVT:
+ ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; code: 0x%X; pipe: 0x%X; data len: %u", fn,
+ eventData->rcvd_evt.evt_code, eventData->rcvd_evt.pipe, eventData->rcvd_evt.evt_len);
+ if ((eventData->rcvd_evt.pipe == STATIC_PIPE_0x70) || (eventData->rcvd_evt.pipe == STATIC_PIPE_0x71))
+ {
+ ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; data from static pipe", fn);
+ SyncEventGuard guard (sSecElem.mTransceiveEvent);
+ sSecElem.mActualResponseSize = (eventData->rcvd_evt.evt_len > MAX_RESPONSE_SIZE) ? MAX_RESPONSE_SIZE : eventData->rcvd_evt.evt_len;
+ sSecElem.mTransceiveEvent.notifyOne ();
+ }
+ else if (eventData->rcvd_evt.evt_code == NFA_HCI_EVT_POST_DATA)
+ {
+ ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; NFA_HCI_EVT_POST_DATA", fn);
+ SyncEventGuard guard (sSecElem.mTransceiveEvent);
+ sSecElem.mActualResponseSize = (eventData->rcvd_evt.evt_len > MAX_RESPONSE_SIZE) ? MAX_RESPONSE_SIZE : eventData->rcvd_evt.evt_len;
+ sSecElem.mTransceiveEvent.notifyOne ();
+ }
+ else if (eventData->rcvd_evt.evt_code == NFA_HCI_EVT_TRANSACTION)
+ {
+ ALOGD ("%s: NFA_HCI_EVENT_RCVD_EVT; NFA_HCI_EVT_TRANSACTION", fn);
+ // If we got an AID, notify any listeners
+ if ((eventData->rcvd_evt.evt_len > 3) && (eventData->rcvd_evt.p_evt_buf[0] == 0x81) )
+ sSecElem.notifyTransactionListenersOfAid (&eventData->rcvd_evt.p_evt_buf[2], eventData->rcvd_evt.p_evt_buf[1]);
+ }
+ break;
+
+ case NFA_HCI_SET_REG_RSP_EVT: //received response to write registry command
+ {
+ tNFA_HCI_REGISTRY& registry = eventData->registry;
+ ALOGD ("%s: NFA_HCI_SET_REG_RSP_EVT; status=0x%X; pipe=0x%X", fn, registry.status, registry.pipe);
+ SyncEventGuard guard (sSecElem.mRegistryEvent);
+ sSecElem.mRegistryEvent.notifyOne ();
+ break;
+ }
+
+ default:
+ ALOGE ("%s: unknown event code=0x%X ????", fn, event);
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: findEeByHandle
+**
+** Description: Find information about an execution environment.
+** eeHandle: Handle to execution environment.
+**
+** Returns: Information about an execution environment.
+**
+*******************************************************************************/
+tNFA_EE_INFO *SecureElement::findEeByHandle (tNFA_HANDLE eeHandle)
+{
+ for (UINT8 xx = 0; xx < mActualNumEe; xx++)
+ {
+ if (mEeInfo[xx].ee_handle == eeHandle)
+ return (&mEeInfo[xx]);
+ }
+ return (NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function: getDefaultEeHandle
+**
+** Description: Get the handle to the execution environment.
+**
+** Returns: Handle to the execution environment.
+**
+*******************************************************************************/
+tNFA_HANDLE SecureElement::getDefaultEeHandle ()
+{
+ // Find the first EE that is not the HCI Access i/f.
+ for (UINT8 xx = 0; xx < mActualNumEe; xx++)
+ {
+ if ((mEeInfo[xx].num_interface != 0) && (mEeInfo[xx].ee_interface[0] != NCI_NFCEE_INTERFACE_HCI_ACCESS) )
+ return (mEeInfo[xx].ee_handle);
+ }
+ return NFA_HANDLE_INVALID;
+}
+
+
+ /*******************************************************************************
+ **
+ ** Function: findUiccByHandle
+ **
+ ** Description: Find information about an execution environment.
+ ** eeHandle: Handle of the execution environment.
+ **
+ ** Returns: Information about the execution environment.
+ **
+ *******************************************************************************/
+tNFA_EE_DISCOVER_INFO *SecureElement::findUiccByHandle (tNFA_HANDLE eeHandle)
+{
+ for (UINT8 index = 0; index < mUiccInfo.num_ee; index++)
+ {
+ if (mUiccInfo.ee_disc_info[index].ee_handle == eeHandle)
+ {
+ return (&mUiccInfo.ee_disc_info[index]);
+ }
+ }
+ ALOGE ("SecureElement::findUiccByHandle: ee h=0x%4x not found", eeHandle);
+ return NULL;
+}
+
+
+/*******************************************************************************
+**
+** Function: eeStatusToString
+**
+** Description: Convert status code to status text.
+** status: Status code
+**
+** Returns: None
+**
+*******************************************************************************/
+const char* SecureElement::eeStatusToString (UINT8 status)
+{
+ switch (status)
+ {
+ case NFC_NFCEE_STATUS_ACTIVE:
+ return("Connected/Active");
+ case NFC_NFCEE_STATUS_INACTIVE:
+ return("Connected/Inactive");
+ case NFC_NFCEE_STATUS_REMOVED:
+ return("Removed");
+ }
+ return("?? Unknown ??");
+}
+
+
+/*******************************************************************************
+**
+** Function: connectionEventHandler
+**
+** Description: Receive card-emulation related events from stack.
+** event: Event code.
+** eventData: Event data.
+**
+** Returns: None
+**
+*******************************************************************************/
+void SecureElement::connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* eventData)
+{
+ switch (event)
+ {
+ case NFA_CE_UICC_LISTEN_CONFIGURED_EVT:
+ {
+ SyncEventGuard guard (mUiccListenEvent);
+ mUiccListenEvent.notifyOne ();
+ }
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function: routeToSecureElement
+**
+** Description: Adjust controller's listen-mode routing table so transactions
+** are routed to the secure elements.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool SecureElement::routeToSecureElement ()
+{
+ static const char fn [] = "SecureElement::routeToSecureElement";
+ ALOGD ("%s: enter", fn);
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ tNFA_TECHNOLOGY_MASK tech_mask = NFA_TECHNOLOGY_MASK_A | NFA_TECHNOLOGY_MASK_B;
+ bool retval = false;
+
+ if (! mIsInit)
+ {
+ ALOGE ("%s: not init", fn);
+ return false;
+ }
+
+ if (mCurrentRouteSelection == SecElemRoute)
+ {
+ ALOGE ("%s: already sec elem route", fn);
+ return true;
+ }
+
+ if (mActiveEeHandle == NFA_HANDLE_INVALID)
+ {
+ ALOGE ("%s: invalid EE handle", fn);
+ return false;
+ }
+
+ adjustRoutes (SecElemRoute);
+
+ {
+ unsigned long num = 0;
+ if (GetNumValue("UICC_LISTEN_TECH_MASK", &num, sizeof(num)))
+ tech_mask = num;
+ ALOGD ("%s: start UICC listen; h=0x%X; tech mask=0x%X", fn, mActiveEeHandle, tech_mask);
+ SyncEventGuard guard (mUiccListenEvent);
+ nfaStat = NFA_CeConfigureUiccListenTech (mActiveEeHandle, tech_mask);
+ if (nfaStat == NFA_STATUS_OK)
+ {
+ mUiccListenEvent.wait ();
+ retval = true;
+ }
+ else
+ ALOGE ("%s: fail to start UICC listen", fn);
+ }
+
+ ALOGD ("%s: exit; ok=%u", fn, retval);
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: routeToDefault
+**
+** Description: Adjust controller's listen-mode routing table so transactions
+** are routed to the default destination.
+**
+** Returns: True if ok.
+**
+*******************************************************************************/
+bool SecureElement::routeToDefault ()
+{
+ static const char fn [] = "SecureElement::routeToDefault";
+ tNFA_STATUS nfaStat = NFA_STATUS_FAILED;
+ bool retval = false;
+
+ ALOGD ("%s: enter", fn);
+ if (! mIsInit)
+ {
+ ALOGE ("%s: not init", fn);
+ return false;
+ }
+
+ if (mCurrentRouteSelection == DefaultRoute)
+ {
+ ALOGD ("%s: already default route", fn);
+ return true;
+ }
+
+ if (mActiveEeHandle != NFA_HANDLE_INVALID)
+ {
+ ALOGD ("%s: stop UICC listen; EE h=0x%X", fn, mActiveEeHandle);
+ SyncEventGuard guard (mUiccListenEvent);
+ nfaStat = NFA_CeConfigureUiccListenTech (mActiveEeHandle, 0);
+ if (nfaStat == NFA_STATUS_OK)
+ {
+ mUiccListenEvent.wait ();
+ retval = true;
+ }
+ else
+ ALOGE ("%s: fail to stop UICC listen", fn);
+ }
+ else
+ retval = true;
+
+ adjustRoutes (DefaultRoute);
+
+ ALOGD ("%s: exit; ok=%u", fn, retval);
+ return retval;
+}
+
+
+/*******************************************************************************
+**
+** Function: isBusy
+**
+** Description: Whether controller is routing listen-mode events to
+** secure elements or a pipe is connected.
+**
+** Returns: True if either case is true.
+**
+*******************************************************************************/
+bool SecureElement::isBusy ()
+{
+ bool retval = (mCurrentRouteSelection == SecElemRoute) || mIsPiping;
+ ALOGD ("SecureElement::isBusy: %u", retval);
+ return retval;
+}
+
diff --git a/nci/jni/SecureElement.h b/nci/jni/SecureElement.h
new file mode 100755
index 0000000..1758590
--- /dev/null
+++ b/nci/jni/SecureElement.h
@@ -0,0 +1,607 @@
+/*
+ * 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.
+ */
+
+/*
+ * Communicate with secure elements that are attached to the NFC
+ * controller.
+ */
+#pragma once
+#include "SyncEvent.h"
+#include "DataQueue.h"
+#include "NfcJniUtil.h"
+#include "RouteDataSet.h"
+extern "C"
+{
+ #include "nfa_ee_api.h"
+ #include "nfa_hci_api.h"
+ #include "nfa_hci_defs.h"
+ #include "nfa_ce_api.h"
+}
+
+
+class SecureElement
+{
+public:
+ tNFA_HANDLE mActiveEeHandle;
+
+
+ /*******************************************************************************
+ **
+ ** Function: getInstance
+ **
+ ** Description: Get the SecureElement singleton object.
+ **
+ ** Returns: SecureElement object.
+ **
+ *******************************************************************************/
+ static SecureElement& getInstance ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: initialize
+ **
+ ** Description: Initialize all member variables.
+ ** native: Native data.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool initialize (nfc_jni_native_data* native);
+
+
+ /*******************************************************************************
+ **
+ ** Function: finalize
+ **
+ ** Description: Release all resources.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void finalize ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: getListOfEeHandles
+ **
+ ** Description: Get the list of handles of all execution environments.
+ ** e: Java Virtual Machine.
+ **
+ ** Returns: List of handles of all execution environments.
+ **
+ *******************************************************************************/
+ jintArray getListOfEeHandles (JNIEnv* e);
+
+
+ /*******************************************************************************
+ **
+ ** Function: activate
+ **
+ ** Description: Turn on the secure element.
+ ** seID: ID of secure element.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool activate (jint seID);
+
+
+ /*******************************************************************************
+ **
+ ** Function: deactivate
+ **
+ ** Description: Turn off the secure element.
+ ** seID: ID of secure element.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool deactivate (jint seID);
+
+
+ /*******************************************************************************
+ **
+ ** Function: connectEE
+ **
+ ** Description: Connect to the execution environment.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool connectEE ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: disconnectEE
+ **
+ ** Description: Disconnect from the execution environment.
+ ** seID: ID of secure element.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool disconnectEE (jint seID);
+
+
+ /*******************************************************************************
+ **
+ ** Function: transceive
+ **
+ ** Description: Send data to the secure element; read it's response.
+ ** xmitBuffer: Data to transmit.
+ ** xmitBufferSize: Length of data.
+ ** recvBuffer: Buffer to receive response.
+ ** recvBufferMaxSize: Maximum size of buffer.
+ ** recvBufferActualSize: Actual length of response.
+ ** timeoutMillisec: timeout in millisecond
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool transceive (UINT8* xmitBuffer, INT32 xmitBufferSize, UINT8* recvBuffer,
+ INT32 recvBufferMaxSize, INT32& recvBufferActualSize, INT32 timeoutMillisec);
+
+ /*******************************************************************************
+ **
+ ** Function: notifyListenModeState
+ **
+ ** Description: Notify the NFC service about whether the SE was activated
+ ** in listen mode.
+ ** isActive: Whether the secure element is activated.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void notifyListenModeState (bool isActivated);
+
+ /*******************************************************************************
+ **
+ ** Function: notifyRfFieldEvent
+ **
+ ** Description: Notify the NFC service about RF field events from the stack.
+ ** isActive: Whether any secure element is activated.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void notifyRfFieldEvent (bool isActive);
+
+
+ /*******************************************************************************
+ **
+ ** Function: storeUiccInfo
+ **
+ ** Description: Store a copy of the execution environment information from the stack.
+ ** info: execution environment information.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void storeUiccInfo (tNFA_EE_DISCOVER_REQ& info);
+
+
+ /*******************************************************************************
+ **
+ ** Function: getUiccId
+ **
+ ** Description: Get the ID of the secure element.
+ ** eeHandle: Handle to the secure element.
+ ** uid: Array to receive the ID.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool getUiccId (tNFA_HANDLE eeHandle, jbyteArray& uid);
+
+
+ /*******************************************************************************
+ **
+ ** Function: getTechnologyList
+ **
+ ** Description: Get all the technologies supported by a secure element.
+ ** eeHandle: Handle of secure element.
+ ** techList: List to receive the technologies.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool getTechnologyList (tNFA_HANDLE eeHandle, jintArray& techList);
+
+
+ /*******************************************************************************
+ **
+ ** Function: notifyTransactionListenersOfAid
+ **
+ ** Description: Notify the NFC service about a transaction event from secure element.
+ ** aid: Buffer contains application ID.
+ ** aidLen: Length of application ID.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void notifyTransactionListenersOfAid (const UINT8* aid, UINT8 aidLen);
+
+
+ /*******************************************************************************
+ **
+ ** Function: notifyTransactionListenersOfTlv
+ **
+ ** Description: Notify the NFC service about a transaction event from secure element.
+ ** The type-length-value contains AID and parameter.
+ ** tlv: type-length-value encoded in Basic Encoding Rule.
+ ** tlvLen: Length tlv.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void notifyTransactionListenersOfTlv (const UINT8* tlv, UINT8 tlvLen);
+
+
+ /*******************************************************************************
+ **
+ ** Function: connectionEventHandler
+ **
+ ** Description: Receive card-emulation related events from stack.
+ ** event: Event code.
+ ** eventData: Event data.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* eventData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: applyRoutes
+ **
+ ** Description: Read route data from XML and apply them again
+ ** to every secure element.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void applyRoutes ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: setActiveSeOverride
+ **
+ ** Description: Specify which secure element to turn on.
+ ** activeSeOverride: ID of secure element
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void setActiveSeOverride (UINT8 activeSeOverride);
+
+
+ /*******************************************************************************
+ **
+ ** Function: routeToSecureElement
+ **
+ ** Description: Adjust controller's listen-mode routing table so transactions
+ ** are routed to the secure elements as specified in route.xml.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool routeToSecureElement ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: routeToDefault
+ **
+ ** Description: Adjust controller's listen-mode routing table so transactions
+ ** are routed to the default destination specified in route.xml.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool routeToDefault ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: isBusy
+ **
+ ** Description: Whether NFC controller is routing listen-mode events or a pipe is connected.
+ **
+ ** Returns: True if either case is true.
+ **
+ *******************************************************************************/
+ bool isBusy ();
+
+
+ /*******************************************************************************
+ **
+ ** Function getActualNumEe
+ **
+ ** Description Returns number of secure elements we know about.
+ **
+ ** Returns Number of secure elements we know about.
+ **
+ *******************************************************************************/
+ UINT8 getActualNumEe();
+
+
+ /*******************************************************************************
+ **
+ ** Function getSeVerInfo
+ **
+ ** Description Gets version information and id for a secure element. The
+ ** seIndex parmeter is the zero based index of the secure
+ ** element to get verion info for. The version infommation
+ ** is returned as a string int the verInfo parameter.
+ **
+ ** Returns ture on success, false on failure
+ **
+ *******************************************************************************/
+ bool getSeVerInfo(int seIndex, char * verInfo, int verInfoSz, UINT8 * seid);
+
+
+ /*******************************************************************************
+ **
+ ** Function: isActivatedInListenMode
+ **
+ ** Description: Can be used to determine if the SE is activated in listen mode
+ **
+ ** Returns: True if the SE is activated in listen mode
+ **
+ *******************************************************************************/
+ bool isActivatedInListenMode();
+
+ /*******************************************************************************
+ **
+ ** Function: isRfFieldOn
+ **
+ ** Description: Can be used to determine if the SE is in an RF field
+ **
+ ** Returns: True if the SE is activated in an RF field
+ **
+ *******************************************************************************/
+ bool isRfFieldOn();
+
+private:
+ static const unsigned int MAX_RESPONSE_SIZE = 1024;
+ enum RouteSelection {NoRoute, DefaultRoute, SecElemRoute};
+ static const int MAX_NUM_EE = 5; //max number of EE's
+ static const UINT8 STATIC_PIPE_0x70 = 0x70; //Broadcom's proprietary static pipe
+ static const UINT8 STATIC_PIPE_0x71 = 0x71; //Broadcom's proprietary static pipe
+ static const UINT8 EVT_SEND_DATA = 0x10; //see specification ETSI TS 102 622 v9.0.0 (Host Controller Interface); section 9.3.3.3
+ static const tNFA_HANDLE EE_HANDLE_0xF3 = 0x4F3; //handle to secure element in slot 0
+ static const tNFA_HANDLE EE_HANDLE_0xF4 = 0x4F4; //handle to secure element in slot 1
+ static SecureElement sSecElem;
+ static const char* APP_NAME;
+
+ UINT8 mDestinationGate; //destination gate of the UICC
+ tNFA_HANDLE mNfaHciHandle; //NFA handle to NFA's HCI component
+ nfc_jni_native_data* mNativeData;
+ bool mIsInit; // whether EE is initialized
+ UINT8 mActualNumEe; // actual number of EE's reported by the stack
+ UINT8 mNumEePresent; // actual number of usable EE's
+ bool mbNewEE;
+ UINT8 mNewPipeId;
+ UINT8 mNewSourceGate;
+ UINT16 mActiveSeOverride; // active "enable" seid, 0 means activate all SEs
+ tNFA_STATUS mCommandStatus; //completion status of the last command
+ bool mIsPiping; //is a pipe connected to the controller?
+ RouteSelection mCurrentRouteSelection;
+ int mActualResponseSize; //number of bytes in the response received from secure element
+ bool mUseOberthurWarmReset; //whether to use warm-reset command
+ bool mActivatedInListenMode; // whether we're activated in listen mode
+ UINT8 mOberthurWarmResetCommand; //warm-reset command byte
+ tNFA_EE_INFO mEeInfo [MAX_NUM_EE]; //actual size stored in mActualNumEe
+ tNFA_EE_DISCOVER_REQ mUiccInfo;
+ tNFA_HCI_GET_GATE_PIPE_LIST mHciCfg;
+ SyncEvent mEeRegisterEvent;
+ SyncEvent mHciRegisterEvent;
+ SyncEvent mEeSetModeEvent;
+ SyncEvent mPipeListEvent;
+ SyncEvent mCreatePipeEvent;
+ SyncEvent mPipeOpenedEvent;
+ SyncEvent mAllocateGateEvent;
+ SyncEvent mDeallocateGateEvent;
+ SyncEvent mRoutingEvent;
+ SyncEvent mUiccInfoEvent;
+ SyncEvent mUiccListenEvent;
+ SyncEvent mAidAddRemoveEvent;
+ SyncEvent mTransceiveEvent;
+ SyncEvent mVerInfoEvent;
+ SyncEvent mRegistryEvent;
+ UINT8 mVerInfo [3];
+ UINT8 mResponseData [MAX_RESPONSE_SIZE];
+ RouteDataSet mRouteDataSet; //routing data
+ std::vector<std::string> mUsedAids; //AID's that are used in current routes
+ UINT8 mAidForEmptySelect[NCI_MAX_AID_LEN+1];
+ Mutex mMutex; // protects fields below
+ bool mRfFieldIsOn; // last known RF field state
+ struct timespec mLastRfFieldToggle; // last time RF field went off
+ /*******************************************************************************
+ **
+ ** Function: SecureElement
+ **
+ ** Description: Initialize member variables.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ SecureElement ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: ~SecureElement
+ **
+ ** Description: Release all resources.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ ~SecureElement ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: nfaEeCallback
+ **
+ ** Description: Receive execution environment-related events from stack.
+ ** event: Event code.
+ ** eventData: Event data.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ static void nfaEeCallback (tNFA_EE_EVT event, tNFA_EE_CBACK_DATA* eventData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: nfaHciCallback
+ **
+ ** Description: Receive Host Controller Interface-related events from stack.
+ ** event: Event code.
+ ** eventData: Event data.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ static void nfaHciCallback (tNFA_HCI_EVT event, tNFA_HCI_EVT_DATA* eventData);
+
+
+ /*******************************************************************************
+ **
+ ** Function: findEeByHandle
+ **
+ ** Description: Find information about an execution environment.
+ ** eeHandle: Handle to execution environment.
+ **
+ ** Returns: Information about an execution environment.
+ **
+ *******************************************************************************/
+ tNFA_EE_INFO *findEeByHandle (tNFA_HANDLE eeHandle);
+
+
+ /*******************************************************************************
+ **
+ ** Function: findUiccByHandle
+ **
+ ** Description: Find information about an execution environment.
+ ** eeHandle: Handle of the execution environment.
+ **
+ ** Returns: Information about the execution environment.
+ **
+ *******************************************************************************/
+ tNFA_EE_DISCOVER_INFO *findUiccByHandle (tNFA_HANDLE eeHandle);
+
+
+ /*******************************************************************************
+ **
+ ** Function: getDefaultEeHandle
+ **
+ ** Description: Get the handle to the execution environment.
+ **
+ ** Returns: Handle to the execution environment.
+ **
+ *******************************************************************************/
+ tNFA_HANDLE getDefaultEeHandle ();
+
+
+ /*******************************************************************************
+ **
+ ** Function: adjustRoutes
+ **
+ ** Description: Adjust routes in the controller's listen-mode routing table.
+ ** selection: which set of routes to configure the controller.
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void adjustRoutes (RouteSelection selection);
+
+
+ /*******************************************************************************
+ **
+ ** Function: adjustProtocolRoutes
+ **
+ ** Description: Adjust default routing based on protocol in NFC listen mode.
+ ** isRouteToEe: Whether routing to EE (true) or host (false).
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void adjustProtocolRoutes (RouteDataSet::Database* db, RouteSelection routeSelection);
+
+
+ /*******************************************************************************
+ **
+ ** Function: adjustTechnologyRoutes
+ **
+ ** Description: Adjust default routing based on technology in NFC listen mode.
+ ** isRouteToEe: Whether routing to EE (true) or host (false).
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ void adjustTechnologyRoutes (RouteDataSet::Database* db, RouteSelection routeSelection);
+
+
+ /*******************************************************************************
+ **
+ ** Function: getEeInfo
+ **
+ ** Description: Get latest information about execution environments from stack.
+ **
+ ** Returns: True if at least 1 EE is available.
+ **
+ *******************************************************************************/
+ bool getEeInfo ();
+
+ /*******************************************************************************
+ **
+ ** Function: eeStatusToString
+ **
+ ** Description: Convert status code to status text.
+ ** status: Status code
+ **
+ ** Returns: None
+ **
+ *******************************************************************************/
+ static const char* eeStatusToString (UINT8 status);
+
+
+ /*******************************************************************************
+ **
+ ** Function: encodeAid
+ **
+ ** Description: Encode AID in type-length-value using Basic Encoding Rule.
+ ** tlv: Buffer to store TLV.
+ ** tlvMaxLen: TLV buffer's maximum length.
+ ** tlvActualLen: TLV buffer's actual length.
+ ** aid: Buffer of Application ID.
+ ** aidLen: Aid buffer's actual length.
+ **
+ ** Returns: True if ok.
+ **
+ *******************************************************************************/
+ bool encodeAid (UINT8* tlv, UINT16 tlvMaxLen, UINT16& tlvActualLen, const UINT8* aid, UINT8 aidLen);
+};
+
diff --git a/nci/jni/SyncEvent.h b/nci/jni/SyncEvent.h
new file mode 100644
index 0000000..5fd389e
--- /dev/null
+++ b/nci/jni/SyncEvent.h
@@ -0,0 +1,171 @@
+/*
+ * 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.
+ */
+
+/*
+ * Synchronize two or more threads using a condition variable and a mutex.
+ */
+#pragma once
+#include "CondVar.h"
+#include "Mutex.h"
+
+
+class SyncEvent
+{
+public:
+ /*******************************************************************************
+ **
+ ** Function: ~SyncEvent
+ **
+ ** Description: Cleanup all resources.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ ~SyncEvent ()
+ {
+ }
+
+
+ /*******************************************************************************
+ **
+ ** Function: start
+ **
+ ** Description: Start a synchronization operation.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void start ()
+ {
+ mMutex.lock ();
+ }
+
+
+ /*******************************************************************************
+ **
+ ** Function: wait
+ **
+ ** Description: Block the thread and wait for the event to occur.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void wait ()
+ {
+ mCondVar.wait (mMutex);
+ }
+
+
+ /*******************************************************************************
+ **
+ ** Function: wait
+ **
+ ** Description: Block the thread and wait for the event to occur.
+ ** millisec: Timeout in milliseconds.
+ **
+ ** Returns: True if wait is successful; false if timeout occurs.
+ **
+ *******************************************************************************/
+ bool wait (long millisec)
+ {
+ bool retVal = mCondVar.wait (mMutex, millisec);
+ return retVal;
+ }
+
+
+ /*******************************************************************************
+ **
+ ** Function: notifyOne
+ **
+ ** Description: Notify a blocked thread that the event has occured. Unblocks it.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void notifyOne ()
+ {
+ mCondVar.notifyOne ();
+ }
+
+
+ /*******************************************************************************
+ **
+ ** Function: end
+ **
+ ** Description: End a synchronization operation.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void end ()
+ {
+ mMutex.unlock ();
+ }
+
+private:
+ CondVar mCondVar;
+ Mutex mMutex;
+};
+
+
+/*****************************************************************************/
+/*****************************************************************************/
+
+
+/*****************************************************************************
+**
+** Name: SyncEventGuard
+**
+** Description: Automatically start and end a synchronization event.
+**
+*****************************************************************************/
+class SyncEventGuard
+{
+public:
+ /*******************************************************************************
+ **
+ ** Function: SyncEventGuard
+ **
+ ** Description: Start a synchronization operation.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ SyncEventGuard (SyncEvent& event)
+ : mEvent (event)
+ {
+ event.start (); //automatically start operation
+ };
+
+
+ /*******************************************************************************
+ **
+ ** Function: ~SyncEventGuard
+ **
+ ** Description: End a synchronization operation.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ ~SyncEventGuard ()
+ {
+ mEvent.end (); //automatically end operation
+ };
+
+private:
+ SyncEvent& mEvent;
+};
+
diff --git a/nci/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java b/nci/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java
new file mode 100755
index 0000000..db78496
--- /dev/null
+++ b/nci/src/com/android/nfc/dhimpl/NativeLlcpConnectionlessSocket.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.nfc.dhimpl;
+
+import com.android.nfc.DeviceHost;
+import com.android.nfc.LlcpPacket;
+
+import java.io.IOException;
+
+/**
+ * LlcpConnectionlessSocket represents a LLCP Connectionless object to be used
+ * in a connectionless communication
+ */
+public class NativeLlcpConnectionlessSocket implements DeviceHost.LlcpConnectionlessSocket {
+
+ private int mHandle;
+ private int mSap;
+ private int mLinkMiu;
+
+ public NativeLlcpConnectionlessSocket() { }
+
+ public native boolean doSendTo(int sap, byte[] data);
+
+ public native LlcpPacket doReceiveFrom(int linkMiu);
+
+ public native boolean doClose();
+
+ @Override
+ public int getLinkMiu(){
+ return mLinkMiu;
+ }
+
+ @Override
+ public int getSap(){
+ return mSap;
+ }
+
+ @Override
+ public void send(int sap, byte[] data) throws IOException {
+ if (!doSendTo(sap, data)) {
+ throw new IOException();
+ }
+ }
+
+ @Override
+ public LlcpPacket receive() throws IOException {
+ LlcpPacket packet = doReceiveFrom(mLinkMiu);
+ if (packet == null) {
+ throw new IOException();
+ }
+ return packet;
+ }
+
+ public int getHandle(){
+ return mHandle;
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (!doClose()) {
+ throw new IOException();
+ }
+ }
+}
diff --git a/nci/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java b/nci/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java
new file mode 100755
index 0000000..3a7e57f
--- /dev/null
+++ b/nci/src/com/android/nfc/dhimpl/NativeLlcpServiceSocket.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.nfc.dhimpl;
+
+import com.android.nfc.DeviceHost;
+import com.android.nfc.DeviceHost.LlcpSocket;
+
+import java.io.IOException;
+
+/**
+ * LlcpServiceSocket represents a LLCP Service to be used in a
+ * Connection-oriented communication
+ */
+public class NativeLlcpServiceSocket implements DeviceHost.LlcpServerSocket {
+ private int mHandle;
+ private int mLocalMiu;
+ private int mLocalRw;
+ private int mLocalLinearBufferLength;
+ private int mSap;
+ private String mServiceName;
+
+ public NativeLlcpServiceSocket(){ }
+
+ private native NativeLlcpSocket doAccept(int miu, int rw, int linearBufferLength);
+ @Override
+ public LlcpSocket accept() throws IOException {
+ LlcpSocket socket = doAccept(mLocalMiu, mLocalRw, mLocalLinearBufferLength);
+ if (socket == null) throw new IOException();
+ return socket;
+ }
+
+ private native boolean doClose();
+ @Override
+ public void close() throws IOException {
+ if (!doClose()) {
+ throw new IOException();
+ }
+ }
+}
diff --git a/nci/src/com/android/nfc/dhimpl/NativeLlcpSocket.java b/nci/src/com/android/nfc/dhimpl/NativeLlcpSocket.java
new file mode 100755
index 0000000..69506c5
--- /dev/null
+++ b/nci/src/com/android/nfc/dhimpl/NativeLlcpSocket.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.nfc.dhimpl;
+
+import com.android.nfc.DeviceHost;
+
+import java.io.IOException;
+
+/**
+ * LlcpClientSocket represents a LLCP Connection-Oriented client to be used in a
+ * connection-oriented communication
+ */
+public class NativeLlcpSocket implements DeviceHost.LlcpSocket {
+ private int mHandle;
+ private int mSap;
+ private int mLocalMiu;
+ private int mLocalRw;
+
+ public NativeLlcpSocket(){ }
+
+ private native boolean doConnect(int nSap);
+ @Override
+ public void connectToSap(int sap) throws IOException {
+ if (!doConnect(sap)) {
+ throw new IOException();
+ }
+ }
+
+ private native boolean doConnectBy(String sn);
+ @Override
+ public void connectToService(String serviceName) throws IOException {
+ if (!doConnectBy(serviceName)) {
+ throw new IOException();
+ }
+ }
+
+ private native boolean doClose();
+ @Override
+ public void close() throws IOException {
+ if (!doClose()) {
+ throw new IOException();
+ }
+ }
+
+ private native boolean doSend(byte[] data);
+ @Override
+ public void send(byte[] data) throws IOException {
+ if (!doSend(data)) {
+ throw new IOException();
+ }
+ }
+
+ private native int doReceive(byte[] recvBuff);
+ @Override
+ public int receive(byte[] recvBuff) throws IOException {
+ int receiveLength = doReceive(recvBuff);
+ if (receiveLength == -1) {
+ throw new IOException();
+ }
+ return receiveLength;
+ }
+
+ private native int doGetRemoteSocketMiu();
+ @Override
+ public int getRemoteMiu() { return doGetRemoteSocketMiu(); }
+
+ private native int doGetRemoteSocketRw();
+ @Override
+ public int getRemoteRw() { return doGetRemoteSocketRw(); }
+
+ @Override
+ public int getLocalSap(){
+ return mSap;
+ }
+
+ @Override
+ public int getLocalMiu(){
+ return mLocalMiu;
+ }
+
+ @Override
+ public int getLocalRw(){
+ return mLocalRw;
+ }
+}
diff --git a/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java b/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java
new file mode 100755
index 0000000..1437e5d
--- /dev/null
+++ b/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java
@@ -0,0 +1,378 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.nfc.dhimpl;
+
+import com.android.nfc.DeviceHost;
+import com.android.nfc.LlcpException;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.nfc.ErrorCodes;
+import android.nfc.tech.Ndef;
+import android.nfc.tech.TagTechnology;
+import android.util.Log;
+
+/**
+ * Native interface to the NFC Manager functions
+ */
+public class NativeNfcManager implements DeviceHost {
+ private static final String TAG = "NativeNfcManager";
+ static final String PREF = "NciDeviceHost";
+
+ static final int DEFAULT_LLCP_MIU = 1980;
+ static final int DEFAULT_LLCP_RWSIZE = 2;
+
+ static final String DRIVER_NAME = "android-nci";
+
+ private static final byte[][] EE_WIPE_APDUS = {
+ {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
+ {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00,
+ (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x20, (byte)0x10, (byte)0x00},
+ {(byte)0x80, (byte)0xe2, (byte)0x01, (byte)0x03, (byte)0x00},
+ {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
+ {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00,
+ (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x30, (byte)0x30, (byte)0x00},
+ {(byte)0x80, (byte)0xb4, (byte)0x00, (byte)0x00, (byte)0x00},
+ {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
+ };
+
+ static {
+ System.loadLibrary("nfc_nci_jni");
+ }
+
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String INTERNAL_TARGET_DESELECTED_ACTION = "com.android.nfc.action.INTERNAL_TARGET_DESELECTED";
+
+ /* Native structure */
+ private int mNative;
+
+ private final DeviceHostListener mListener;
+ private final Context mContext;
+
+ public NativeNfcManager(Context context, DeviceHostListener listener) {
+ mListener = listener;
+ initializeNativeStructure();
+ mContext = context;
+ }
+
+ public native boolean initializeNativeStructure();
+
+ private native boolean doDownload();
+
+ public native int doGetLastError();
+
+ @Override
+ public void checkFirmware() {
+ }
+
+ private native boolean doInitialize();
+
+ @Override
+ public boolean initialize() {
+ SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = prefs.edit();
+
+ if (prefs.getBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false)) {
+ try {
+ Thread.sleep (12000);
+ editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false);
+ editor.apply();
+ } catch (InterruptedException e) { }
+ }
+
+ return doInitialize();
+ }
+
+ private native boolean doDeinitialize();
+
+ @Override
+ public boolean deinitialize() {
+ SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = prefs.edit();
+
+ editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false);
+ editor.apply();
+
+ return doDeinitialize();
+ }
+
+ @Override
+ public String getName() {
+ return DRIVER_NAME;
+ }
+
+ @Override
+ public native void enableDiscovery();
+
+ @Override
+ public native void disableDiscovery();
+
+ @Override
+ public native int[] doGetSecureElementList();
+
+ @Override
+ public native void doSelectSecureElement();
+
+ @Override
+ public native void doDeselectSecureElement();
+
+
+ private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap,
+ String sn);
+
+ @Override
+ public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn)
+ throws LlcpException {
+ LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn);
+ if (socket != null) {
+ return socket;
+ } else {
+ /* Get Error Status */
+ int error = doGetLastError();
+
+ Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
+
+ switch (error) {
+ case ErrorCodes.ERROR_BUFFER_TO_SMALL:
+ case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
+ throw new LlcpException(error);
+ default:
+ throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
+ }
+ }
+ }
+
+ private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu,
+ int rw, int linearBufferLength);
+ @Override
+ public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu,
+ int rw, int linearBufferLength) throws LlcpException {
+ LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength);
+ if (socket != null) {
+ return socket;
+ } else {
+ /* Get Error Status */
+ int error = doGetLastError();
+
+ Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
+
+ switch (error) {
+ case ErrorCodes.ERROR_BUFFER_TO_SMALL:
+ case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
+ throw new LlcpException(error);
+ default:
+ throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
+ }
+ }
+ }
+
+ private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw,
+ int linearBufferLength);
+ @Override
+ public LlcpSocket createLlcpSocket(int sap, int miu, int rw,
+ int linearBufferLength) throws LlcpException {
+ LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength);
+ if (socket != null) {
+ return socket;
+ } else {
+ /* Get Error Status */
+ int error = doGetLastError();
+
+ Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
+
+ switch (error) {
+ case ErrorCodes.ERROR_BUFFER_TO_SMALL:
+ case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
+ throw new LlcpException(error);
+ default:
+ throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
+ }
+ }
+ }
+
+ @Override
+ public native boolean doCheckLlcp();
+
+ @Override
+ public native boolean doActivateLlcp();
+
+ private native void doResetTimeouts();
+
+ @Override
+ public void resetTimeouts() {
+ doResetTimeouts();
+ }
+
+ @Override
+ public native void doAbort();
+
+ private native boolean doSetTimeout(int tech, int timeout);
+ @Override
+ public boolean setTimeout(int tech, int timeout) {
+ return doSetTimeout(tech, timeout);
+ }
+
+ private native int doGetTimeout(int tech);
+ @Override
+ public int getTimeout(int tech) {
+ return doGetTimeout(tech);
+ }
+
+
+ @Override
+ public boolean canMakeReadOnly(int ndefType) {
+ return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2);
+ }
+
+ @Override
+ public int getMaxTransceiveLength(int technology) {
+ switch (technology) {
+ case (TagTechnology.NFC_A):
+ case (TagTechnology.MIFARE_CLASSIC):
+ case (TagTechnology.MIFARE_ULTRALIGHT):
+ return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
+ case (TagTechnology.NFC_B):
+ /////////////////////////////////////////////////////////////////
+ // Broadcom: Since BCM2079x supports this, set NfcB max size.
+ //return 0; // PN544 does not support transceive of raw NfcB
+ return 253; // PN544 does not support transceive of raw NfcB
+ case (TagTechnology.NFC_V):
+ return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
+ case (TagTechnology.ISO_DEP):
+ /* The maximum length of a normal IsoDep frame consists of:
+ * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes
+ * such a frame is supported. Extended length frames however
+ * are not supported.
+ */
+ return 261; // Will be automatically split in two frames on the RF layer
+ case (TagTechnology.NFC_F):
+ return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC
+ default:
+ return 0;
+ }
+
+ }
+
+ private native void doSetP2pInitiatorModes(int modes);
+ @Override
+ public void setP2pInitiatorModes(int modes) {
+ doSetP2pInitiatorModes(modes);
+ }
+
+ private native void doSetP2pTargetModes(int modes);
+ @Override
+ public void setP2pTargetModes(int modes) {
+ doSetP2pTargetModes(modes);
+ }
+ @Override
+ public boolean getExtendedLengthApdusSupported() {
+ // TODO check BCM support
+ return false;
+ }
+
+ @Override
+ public boolean enablePN544Quirks() {
+ return false;
+ }
+
+ @Override
+ public byte[][] getWipeApdus() {
+ return EE_WIPE_APDUS;
+ }
+
+ @Override
+ public int getDefaultLlcpMiu() {
+ return DEFAULT_LLCP_MIU;
+ }
+
+ @Override
+ public int getDefaultLlcpRwSize() {
+ return DEFAULT_LLCP_RWSIZE;
+ }
+
+ private native String doDump();
+ @Override
+ public String dump() {
+ return doDump();
+ }
+
+ /**
+ * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered)
+ */
+ private void notifyNdefMessageListeners(NativeNfcTag tag) {
+ mListener.onRemoteEndpointDiscovered(tag);
+ }
+
+ /**
+ * Notifies transaction
+ */
+ private void notifyTargetDeselected() {
+ mListener.onCardEmulationDeselected();
+ }
+
+ /**
+ * Notifies transaction
+ */
+ private void notifyTransactionListeners(byte[] aid) {
+ mListener.onCardEmulationAidSelected(aid);
+ }
+
+ /**
+ * Notifies P2P Device detected, to activate LLCP link
+ */
+ private void notifyLlcpLinkActivation(NativeP2pDevice device) {
+ mListener.onLlcpLinkActivated(device);
+ }
+
+ /**
+ * Notifies P2P Device detected, to activate LLCP link
+ */
+ private void notifyLlcpLinkDeactivated(NativeP2pDevice device) {
+ mListener.onLlcpLinkDeactivated(device);
+ }
+
+ private void notifySeFieldActivated() {
+ mListener.onRemoteFieldActivated();
+ }
+
+ private void notifySeFieldDeactivated() {
+ mListener.onRemoteFieldDeactivated();
+ }
+
+ private void notifySeListenActivated() {
+ mListener.onSeListenActivated();
+ }
+
+ private void notifySeListenDeactivated() {
+ mListener.onSeListenDeactivated();
+ }
+
+ private void notifySeApduReceived(byte[] apdu) {
+ mListener.onSeApduReceived(apdu);
+ }
+
+ private void notifySeEmvCardRemoval() {
+ mListener.onSeEmvCardRemoval();
+ }
+
+ private void notifySeMifareAccess(byte[] block) {
+ mListener.onSeMifareAccess(block);
+ }
+
+}
diff --git a/nci/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java b/nci/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java
new file mode 100755
index 0000000..e2d91ec
--- /dev/null
+++ b/nci/src/com/android/nfc/dhimpl/NativeNfcSecureElement.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.nfc.dhimpl;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+
+/**
+ * Native interface to the NFC Secure Element functions
+ *
+ * {@hide}
+ */
+public class NativeNfcSecureElement {
+
+ static final String PREF_SE_WIRED = "se_wired";
+
+ private final Context mContext;
+
+ SharedPreferences mPrefs;
+ SharedPreferences.Editor mPrefsEditor;
+
+ public NativeNfcSecureElement(Context context) {
+ mContext = context;
+
+ mPrefs = mContext.getSharedPreferences(NativeNfcManager.PREF, Context.MODE_PRIVATE);
+ mPrefsEditor = mPrefs.edit();
+ }
+
+ private native int doNativeOpenSecureElementConnection();
+
+ public int doOpenSecureElementConnection() {
+ mPrefsEditor.putBoolean(PREF_SE_WIRED, true);
+ mPrefsEditor.apply();
+
+ return doNativeOpenSecureElementConnection();
+ }
+
+ private native boolean doNativeDisconnectSecureElementConnection(int handle);
+
+ public boolean doDisconnect(int handle) {
+ mPrefsEditor.putBoolean(PREF_SE_WIRED, false);
+ mPrefsEditor.apply();
+
+ return doNativeDisconnectSecureElementConnection(handle);
+ }
+
+ public native byte[] doTransceive(int handle, byte[] data);
+
+ public native int[] doGetTechList(int handle);
+
+ public native byte [] doGetUid(int handle);
+}
diff --git a/nci/src/com/android/nfc/dhimpl/NativeNfcTag.java b/nci/src/com/android/nfc/dhimpl/NativeNfcTag.java
new file mode 100755
index 0000000..eb8410f
--- /dev/null
+++ b/nci/src/com/android/nfc/dhimpl/NativeNfcTag.java
@@ -0,0 +1,811 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.nfc.dhimpl;
+
+import com.android.nfc.DeviceHost.TagEndpoint;
+
+import android.nfc.FormatException;
+import android.nfc.NdefMessage;
+import android.nfc.tech.IsoDep;
+import android.nfc.tech.MifareClassic;
+import android.nfc.tech.MifareUltralight;
+import android.nfc.tech.Ndef;
+import android.nfc.tech.NfcA;
+import android.nfc.tech.NfcB;
+import android.nfc.tech.NfcF;
+import android.nfc.tech.NfcV;
+import android.nfc.tech.TagTechnology;
+import android.os.Bundle;
+import android.util.Log;
+
+/**
+ * Native interface to the NFC tag functions
+ */
+public class NativeNfcTag implements TagEndpoint {
+ static final boolean DBG = true;
+
+ static final int STATUS_CODE_TARGET_LOST = 146;
+
+ private int[] mTechList;
+ private int[] mTechHandles;
+ private int[] mTechLibNfcTypes;
+ private Bundle[] mTechExtras;
+ private byte[][] mTechPollBytes;
+ private byte[][] mTechActBytes;
+ private byte[] mUid;
+
+ // mConnectedHandle stores the *real* libnfc handle
+ // that we're connected to.
+ private int mConnectedHandle;
+
+ // mConnectedTechIndex stores to which technology
+ // the upper layer stack is connected. Note that
+ // we may be connected to a libnfchandle without being
+ // connected to a technology - technology changes
+ // may occur runtime, whereas the underlying handle
+ // could stay present. Usually all technologies are on the
+ // same handle, with the exception of multi-protocol
+ // tags.
+ private int mConnectedTechIndex; // Index in mTechHandles
+
+ private final String TAG = "NativeNfcTag";
+
+ private boolean mIsPresent; // Whether the tag is known to be still present
+
+ private PresenceCheckWatchdog mWatchdog;
+ class PresenceCheckWatchdog extends Thread {
+
+ private int watchdogTimeout = 125;
+
+ private boolean isPresent = true;
+ private boolean isStopped = false;
+ private boolean isPaused = false;
+ private boolean doCheck = true;
+
+ public synchronized void pause() {
+ isPaused = true;
+ doCheck = false;
+ this.notifyAll();
+ }
+
+ public synchronized void doResume() {
+ isPaused = false;
+ // We don't want to resume presence checking immediately,
+ // but go through at least one more wait period.
+ doCheck = false;
+ this.notifyAll();
+ }
+
+ public synchronized void end() {
+ isStopped = true;
+ doCheck = false;
+ this.notifyAll();
+ }
+
+ public synchronized void setTimeout(int timeout) {
+ watchdogTimeout = timeout;
+ doCheck = false; // Do it only after we have waited "timeout" ms again
+ this.notifyAll();
+ }
+
+ @Override
+ public synchronized void run() {
+ if (DBG) Log.d(TAG, "Starting background presence check");
+ while (isPresent && !isStopped) {
+ try {
+ if (!isPaused) {
+ doCheck = true;
+ }
+ this.wait(watchdogTimeout);
+ if (doCheck) {
+ isPresent = doPresenceCheck();
+ } else {
+ // 1) We are paused, waiting for unpause
+ // 2) We just unpaused, do pres check in next iteration
+ // (after watchdogTimeout ms sleep)
+ // 3) We just set the timeout, wait for this timeout
+ // to expire once first.
+ // 4) We just stopped, exit loop anyway
+ }
+ } catch (InterruptedException e) {
+ // Activity detected, loop
+ }
+ }
+ mIsPresent = false;
+ // Restart the polling loop
+
+ Log.d(TAG, "Tag lost, restarting polling loop");
+ doDisconnect();
+ if (DBG) Log.d(TAG, "Stopping background presence check");
+ }
+ }
+
+ private native int doConnect(int handle);
+ public synchronized int connectWithStatus(int technology) {
+ if (mWatchdog != null) {
+ mWatchdog.pause();
+ }
+ int status = -1;
+ for (int i = 0; i < mTechList.length; i++) {
+ if (mTechList[i] == technology) {
+ // Get the handle and connect, if not already connected
+ if (mConnectedHandle != mTechHandles[i]) {
+ // We're not yet connected to this handle, there are
+ // a few scenario's here:
+ // 1) We are not connected to anything yet - allow
+ // 2) We are connected to a technology which has
+ // a different handle (multi-protocol tag); we support
+ // switching to that.
+ if (mConnectedHandle == -1) {
+ // Not connected yet
+ //status = doConnect(mTechHandles[i]);
+ status = doConnect(i);
+ } else {
+ // Connect to a tech with a different handle
+ Log.d(TAG,"Connect to a tech with a different handle");
+ //status = reconnectWithStatus(mTechHandles[i]);
+ status = reconnectWithStatus(i);
+ }
+ if (status == 0) {
+ mConnectedHandle = mTechHandles[i];
+ mConnectedTechIndex = i;
+ }
+ } else {
+ // 1) We are connected to a technology which has the same
+ // handle; we do not support connecting at a different
+ // level (libnfc auto-activates to the max level on
+ // any handle).
+ // 2) We are connecting to the ndef technology - always
+ // allowed.
+ if ((technology == TagTechnology.NDEF) ||
+ (technology == TagTechnology.NDEF_FORMATABLE)) {
+ // special case for NDEF, this will cause switch to ISO_DEP frame intf
+ i = 0;
+ // status = 0;
+ }
+ status = reconnectWithStatus(i);
+ /*
+ if ((technology != TagTechnology.ISO_DEP) &&
+ (hasTechOnHandle(TagTechnology.ISO_DEP, mTechHandles[i]))) {
+ // Don't allow to connect a -4 tag at a different level
+ // than IsoDep, as this is not supported by
+ // libNFC.
+ // revised for NFCA... do allow to connect a -4 tag at this level.
+ Log.d(TAG,"Connect to a tech with same different handle (rf intf change)");
+ status = reconnectWithStatus(i);
+ if (status == 0) {
+ mConnectedHandle = mTechHandles[i];
+ mConnectedTechIndex = i;
+ }
+ //status = 0;
+ } else {
+ status = 0;
+ }
+ */
+
+
+ if (status == 0) {
+ mConnectedTechIndex = i;
+ // Handle was already identical
+ }
+ }
+ break;
+ }
+ }
+ if (mWatchdog != null) {
+ mWatchdog.doResume();
+ }
+ return status;
+ }
+ @Override
+ public synchronized boolean connect(int technology) {
+ return connectWithStatus(technology) == 0;
+ }
+
+ @Override
+ public synchronized void startPresenceChecking() {
+ // Once we start presence checking, we allow the upper layers
+ // to know the tag is in the field.
+ mIsPresent = true;
+ if (mWatchdog == null) {
+ mWatchdog = new PresenceCheckWatchdog();
+ mWatchdog.start();
+ }
+ }
+
+ @Override
+ public synchronized boolean isPresent() {
+ // Returns whether the tag is still in the field to the best
+ // of our knowledge.
+ return mIsPresent;
+ }
+ native boolean doDisconnect();
+ @Override
+ public synchronized boolean disconnect() {
+ boolean result = false;
+
+ mIsPresent = false;
+ if (mWatchdog != null) {
+ // Watchdog has already disconnected or will do it
+ mWatchdog.end();
+ try {
+ mWatchdog.join();
+ } catch (InterruptedException e) {
+ // Should never happen.
+ }
+ mWatchdog = null;
+ result = true;
+ } else {
+ result = doDisconnect();
+ }
+
+ mConnectedTechIndex = -1;
+ mConnectedHandle = -1;
+ return result;
+ }
+
+ native int doReconnect();
+ public synchronized int reconnectWithStatus() {
+ if (mWatchdog != null) {
+ mWatchdog.pause();
+ }
+ int status = doReconnect();
+ if (mWatchdog != null) {
+ mWatchdog.doResume();
+ }
+ return status;
+ }
+ @Override
+ public synchronized boolean reconnect() {
+ return reconnectWithStatus() == 0;
+ }
+
+ native int doHandleReconnect(int handle);
+ public synchronized int reconnectWithStatus(int handle) {
+ if (mWatchdog != null) {
+ mWatchdog.pause();
+ }
+ int status = doHandleReconnect(handle);
+ if (mWatchdog != null) {
+ mWatchdog.doResume();
+ }
+ return status;
+ }
+
+ private native byte[] doTransceive(byte[] data, boolean raw, int[] returnCode);
+ @Override
+ public synchronized byte[] transceive(byte[] data, boolean raw, int[] returnCode) {
+ if (mWatchdog != null) {
+ mWatchdog.pause();
+ }
+ byte[] result = doTransceive(data, raw, returnCode);
+ if (mWatchdog != null) {
+ mWatchdog.doResume();
+ }
+ return result;
+ }
+
+ private native int doCheckNdef(int[] ndefinfo);
+ private synchronized int checkNdefWithStatus(int[] ndefinfo) {
+ if (mWatchdog != null) {
+ mWatchdog.pause();
+ }
+ int status = doCheckNdef(ndefinfo);
+ if (mWatchdog != null) {
+ mWatchdog.doResume();
+ }
+ return status;
+ }
+ @Override
+ public synchronized boolean checkNdef(int[] ndefinfo) {
+ return checkNdefWithStatus(ndefinfo) == 0;
+ }
+
+ private native byte[] doRead();
+ @Override
+ public synchronized byte[] readNdef() {
+ if (mWatchdog != null) {
+ mWatchdog.pause();
+ }
+ byte[] result = doRead();
+ if (mWatchdog != null) {
+ mWatchdog.doResume();
+ }
+ return result;
+ }
+
+ private native boolean doWrite(byte[] buf);
+ @Override
+ public synchronized boolean writeNdef(byte[] buf) {
+ if (mWatchdog != null) {
+ mWatchdog.pause();
+ }
+ boolean result = doWrite(buf);
+ if (mWatchdog != null) {
+ mWatchdog.doResume();
+ }
+ return result;
+ }
+
+ native boolean doPresenceCheck();
+ @Override
+ public synchronized boolean presenceCheck() {
+ if (mWatchdog != null) {
+ mWatchdog.pause();
+ }
+ boolean result = doPresenceCheck();
+ if (mWatchdog != null) {
+ mWatchdog.doResume();
+ }
+ return result;
+ }
+
+ native boolean doNdefFormat(byte[] key);
+ @Override
+ public synchronized boolean formatNdef(byte[] key) {
+ if (mWatchdog != null) {
+ mWatchdog.pause();
+ }
+ boolean result = doNdefFormat(key);
+ if (mWatchdog != null) {
+ mWatchdog.doResume();
+ }
+ return result;
+ }
+
+ native boolean doMakeReadonly(byte[] key);
+ @Override
+ public synchronized boolean makeReadOnly() {
+ if (mWatchdog != null) {
+ mWatchdog.pause();
+ }
+ boolean result;
+ if (hasTech(TagTechnology.MIFARE_CLASSIC)) {
+ result = doMakeReadonly(MifareClassic.KEY_DEFAULT);
+ } else {
+ // No key needed for other technologies
+ result = doMakeReadonly(new byte[] {});
+ }
+ if (mWatchdog != null) {
+ mWatchdog.doResume();
+ }
+ return result;
+ }
+
+ native boolean doIsIsoDepNdefFormatable(byte[] poll, byte[] act);
+ @Override
+ public synchronized boolean isNdefFormatable() {
+ // Let native code decide whether the currently activated tag
+ // is formatable. Although the name of the JNI function refers
+ // to ISO-DEP, the JNI function checks all tag types.
+ return doIsIsoDepNdefFormatable(mTechPollBytes[0],
+ mTechActBytes[0]);
+ }
+
+ @Override
+ public int getHandle() {
+ // This is just a handle for the clients; it can simply use the first
+ // technology handle we have.
+ if (mTechHandles.length > 0) {
+ return mTechHandles[0];
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ public byte[] getUid() {
+ return mUid;
+ }
+
+ @Override
+ public int[] getTechList() {
+ return mTechList;
+ }
+
+ private int getConnectedHandle() {
+ return mConnectedHandle;
+ }
+
+ private int getConnectedLibNfcType() {
+ if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechLibNfcTypes.length) {
+ return mTechLibNfcTypes[mConnectedTechIndex];
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ public int getConnectedTechnology() {
+ if (mConnectedTechIndex != -1 && mConnectedTechIndex < mTechList.length) {
+ return mTechList[mConnectedTechIndex];
+ } else {
+ return 0;
+ }
+ }
+ native int doGetNdefType(int libnfctype, int javatype);
+ private int getNdefType(int libnfctype, int javatype) {
+ return doGetNdefType(libnfctype, javatype);
+ }
+
+ private void addTechnology(int tech, int handle, int libnfctype) {
+ int[] mNewTechList = new int[mTechList.length + 1];
+ System.arraycopy(mTechList, 0, mNewTechList, 0, mTechList.length);
+ mNewTechList[mTechList.length] = tech;
+ mTechList = mNewTechList;
+
+ int[] mNewHandleList = new int[mTechHandles.length + 1];
+ System.arraycopy(mTechHandles, 0, mNewHandleList, 0, mTechHandles.length);
+ mNewHandleList[mTechHandles.length] = handle;
+ mTechHandles = mNewHandleList;
+
+ int[] mNewTypeList = new int[mTechLibNfcTypes.length + 1];
+ System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, mTechLibNfcTypes.length);
+ mNewTypeList[mTechLibNfcTypes.length] = libnfctype;
+ mTechLibNfcTypes = mNewTypeList;
+ }
+
+ @Override
+ public void removeTechnology(int tech) {
+ synchronized (this) {
+ int techIndex = getTechIndex(tech);
+ if (techIndex != -1) {
+ int[] mNewTechList = new int[mTechList.length - 1];
+ System.arraycopy(mTechList, 0, mNewTechList, 0, techIndex);
+ System.arraycopy(mTechList, techIndex + 1, mNewTechList, techIndex,
+ mTechList.length - techIndex - 1);
+ mTechList = mNewTechList;
+
+ int[] mNewHandleList = new int[mTechHandles.length - 1];
+ System.arraycopy(mTechHandles, 0, mNewHandleList, 0, techIndex);
+ System.arraycopy(mTechHandles, techIndex + 1, mNewTechList, techIndex,
+ mTechHandles.length - techIndex - 1);
+ mTechHandles = mNewHandleList;
+
+ int[] mNewTypeList = new int[mTechLibNfcTypes.length - 1];
+ System.arraycopy(mTechLibNfcTypes, 0, mNewTypeList, 0, techIndex);
+ System.arraycopy(mTechLibNfcTypes, techIndex + 1, mNewTypeList, techIndex,
+ mTechLibNfcTypes.length - techIndex - 1);
+ mTechLibNfcTypes = mNewTypeList;
+
+ //The technology must be removed from the mTechExtras array,
+ //just like the above arrays.
+ //Remove the specified element from the array,
+ //then shift the remaining elements by one.
+ if (mTechExtras != null)
+ {
+ Bundle[] mNewTechExtras = new Bundle[mTechExtras.length - 1];
+ System.arraycopy(mTechExtras, 0, mNewTechExtras, 0, techIndex);
+ System.arraycopy(mTechExtras, techIndex + 1, mNewTechExtras, techIndex,
+ mTechExtras.length - techIndex - 1);
+ mTechExtras = mNewTechExtras;
+ }
+ }
+ }
+ }
+
+ public void addNdefFormatableTechnology(int handle, int libnfcType) {
+ synchronized (this) {
+ addTechnology(TagTechnology.NDEF_FORMATABLE, handle, libnfcType);
+ }
+ }
+
+ // This method exists to "patch in" the ndef technologies,
+ // which is done inside Java instead of the native JNI code.
+ // To not create some nasty dependencies on the order on which things
+ // are called (most notably getTechExtras()), it needs some additional
+ // checking.
+ public void addNdefTechnology(NdefMessage msg, int handle, int libnfcType,
+ int javaType, int maxLength, int cardState) {
+ synchronized (this) {
+ addTechnology(TagTechnology.NDEF, handle, libnfcType);
+
+ Bundle extras = new Bundle();
+ extras.putParcelable(Ndef.EXTRA_NDEF_MSG, msg);
+ extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, maxLength);
+ extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, cardState);
+ extras.putInt(Ndef.EXTRA_NDEF_TYPE, getNdefType(libnfcType, javaType));
+
+ if (mTechExtras == null) {
+ // This will build the tech extra's for the first time,
+ // including a NULL ref for the NDEF tech we generated above.
+ Bundle[] builtTechExtras = getTechExtras();
+ builtTechExtras[builtTechExtras.length - 1] = extras;
+ }
+ else {
+ // Tech extras were built before, patch the NDEF one in
+ Bundle[] oldTechExtras = getTechExtras();
+ Bundle[] newTechExtras = new Bundle[oldTechExtras.length + 1];
+ System.arraycopy(oldTechExtras, 0, newTechExtras, 0, oldTechExtras.length);
+ newTechExtras[oldTechExtras.length] = extras;
+ mTechExtras = newTechExtras;
+ }
+
+
+ }
+ }
+
+ private int getTechIndex(int tech) {
+ int techIndex = -1;
+ for (int i = 0; i < mTechList.length; i++) {
+ if (mTechList[i] == tech) {
+ techIndex = i;
+ break;
+ }
+ }
+ return techIndex;
+ }
+
+ private boolean hasTech(int tech) {
+ boolean hasTech = false;
+ for (int i = 0; i < mTechList.length; i++) {
+ if (mTechList[i] == tech) {
+ hasTech = true;
+ break;
+ }
+ }
+ return hasTech;
+ }
+
+ private boolean hasTechOnHandle(int tech, int handle) {
+ boolean hasTech = false;
+ for (int i = 0; i < mTechList.length; i++) {
+ if (mTechList[i] == tech && mTechHandles[i] == handle) {
+ hasTech = true;
+ break;
+ }
+ }
+ return hasTech;
+
+ }
+
+ private boolean isUltralightC() {
+ /* Make a best-effort attempt at classifying ULTRALIGHT
+ * vs ULTRALIGHT-C (based on NXP's public AN1303).
+ * The memory layout is as follows:
+ * Page # BYTE1 BYTE2 BYTE3 BYTE4
+ * 2 INT1 INT2 LOCK LOCK
+ * 3 OTP OTP OTP OTP (NDEF CC if NDEF-formatted)
+ * 4 DATA DATA DATA DATA (version info if factory-state)
+ *
+ * Read four blocks from page 2, which will get us both
+ * the lock page, the OTP page and the version info.
+ */
+ boolean isUltralightC = false;
+ byte[] readCmd = { 0x30, 0x02 };
+ int[] retCode = new int[2];
+ byte[] respData = transceive(readCmd, false, retCode);
+ if (respData != null && respData.length == 16) {
+ // Check the lock bits (last 2 bytes in page2)
+ // and the OTP bytes (entire page 3)
+ if (respData[2] == 0 && respData[3] == 0 && respData[4] == 0 &&
+ respData[5] == 0 && respData[6] == 0 && respData[7] == 0) {
+ // Very likely to be a blank card, look at version info
+ // in page 4.
+ if ((respData[8] == (byte)0x02) && respData[9] == (byte)0x00) {
+ // This is Ultralight-C
+ isUltralightC = true;
+ } else {
+ // 0xFF 0xFF would indicate Ultralight, but we also use Ultralight
+ // as a fallback if it's anything else
+ isUltralightC = false;
+ }
+ } else {
+ // See if we can find the NDEF CC in the OTP page and if it's
+ // smaller than major version two
+ if (respData[4] == (byte)0xE1 && ((respData[5] & 0xff) < 0x20)) {
+ // OK, got NDEF. Technically we'd have to search for the
+ // NDEF TLV as well. However, this would add too much
+ // time for discovery and we can make already make a good guess
+ // with the data we have here. Byte 2 of the OTP page
+ // indicates the size of the tag - 0x06 is UL, anything
+ // above indicates UL-C.
+ if ((respData[6] & 0xff) > 0x06) {
+ isUltralightC = true;
+ }
+ } else {
+ // Fall back to ultralight
+ isUltralightC = false;
+ }
+ }
+ }
+ return isUltralightC;
+ }
+
+ @Override
+ public Bundle[] getTechExtras() {
+ synchronized (this) {
+ if (mTechExtras != null) return mTechExtras;
+ mTechExtras = new Bundle[mTechList.length];
+ for (int i = 0; i < mTechList.length; i++) {
+ Bundle extras = new Bundle();
+ switch (mTechList[i]) {
+ case TagTechnology.NFC_A: {
+ byte[] actBytes = mTechActBytes[i];
+ if ((actBytes != null) && (actBytes.length > 0)) {
+ extras.putShort(NfcA.EXTRA_SAK, (short) (actBytes[0] & (short) 0xFF));
+ } else {
+ // Unfortunately Jewel doesn't have act bytes,
+ // ignore this case.
+ }
+ extras.putByteArray(NfcA.EXTRA_ATQA, mTechPollBytes[i]);
+ break;
+ }
+
+ case TagTechnology.NFC_B: {
+ // What's returned from the PN544 is actually:
+ // 4 bytes app data
+ // 3 bytes prot info
+ byte[] appData = new byte[4];
+ byte[] protInfo = new byte[3];
+ if (mTechPollBytes[i].length >= 7) {
+ System.arraycopy(mTechPollBytes[i], 0, appData, 0, 4);
+ System.arraycopy(mTechPollBytes[i], 4, protInfo, 0, 3);
+
+ extras.putByteArray(NfcB.EXTRA_APPDATA, appData);
+ extras.putByteArray(NfcB.EXTRA_PROTINFO, protInfo);
+ }
+ break;
+ }
+
+ case TagTechnology.NFC_F: {
+ byte[] pmm = new byte[8];
+ byte[] sc = new byte[2];
+ if (mTechPollBytes[i].length >= 8) {
+ // At least pmm is present
+ System.arraycopy(mTechPollBytes[i], 0, pmm, 0, 8);
+ extras.putByteArray(NfcF.EXTRA_PMM, pmm);
+ }
+ if (mTechPollBytes[i].length == 10) {
+ System.arraycopy(mTechPollBytes[i], 8, sc, 0, 2);
+ extras.putByteArray(NfcF.EXTRA_SC, sc);
+ }
+ break;
+ }
+
+ case TagTechnology.ISO_DEP: {
+ if (hasTech(TagTechnology.NFC_A)) {
+ extras.putByteArray(IsoDep.EXTRA_HIST_BYTES, mTechActBytes[i]);
+ }
+ else {
+ extras.putByteArray(IsoDep.EXTRA_HI_LAYER_RESP, mTechActBytes[i]);
+ }
+ break;
+ }
+
+ case TagTechnology.NFC_V: {
+ // First byte response flags, second byte DSFID
+ if (mTechPollBytes[i] != null && mTechPollBytes[i].length >= 2) {
+ extras.putByte(NfcV.EXTRA_RESP_FLAGS, mTechPollBytes[i][0]);
+ extras.putByte(NfcV.EXTRA_DSFID, mTechPollBytes[i][1]);
+ }
+ break;
+ }
+
+ case TagTechnology.MIFARE_ULTRALIGHT: {
+ boolean isUlc = isUltralightC();
+ extras.putBoolean(MifareUltralight.EXTRA_IS_UL_C, isUlc);
+ break;
+ }
+
+ default: {
+ // Leave the entry in the array null
+ continue;
+ }
+ }
+ mTechExtras[i] = extras;
+ }
+ return mTechExtras;
+ }
+ }
+
+ @Override
+ public NdefMessage findAndReadNdef() {
+ // Try to find NDEF on any of the technologies.
+ int[] technologies = getTechList();
+ int[] handles = mTechHandles;
+ NdefMessage ndefMsg = null;
+ boolean foundFormattable = false;
+ int formattableHandle = 0;
+ int formattableLibNfcType = 0;
+ int status;
+
+ for (int techIndex = 0; techIndex < technologies.length; techIndex++) {
+ // have we seen this handle before?
+ for (int i = 0; i < techIndex; i++) {
+ if (handles[i] == handles[techIndex]) {
+ continue; // don't check duplicate handles
+ }
+ }
+
+ status = connectWithStatus(technologies[techIndex]);
+ if (status != 0) {
+ Log.d(TAG, "Connect Failed - status = "+ status);
+ if (status == STATUS_CODE_TARGET_LOST) {
+ break;
+ }
+ continue; // try next handle
+ }
+ // Check if this type is NDEF formatable
+ if (!foundFormattable) {
+ if (isNdefFormatable()) {
+ foundFormattable = true;
+ formattableHandle = getConnectedHandle();
+ formattableLibNfcType = getConnectedLibNfcType();
+ // We'll only add formattable tech if no ndef is
+ // found - this is because libNFC refuses to format
+ // an already NDEF formatted tag.
+ }
+ reconnect();
+ }
+
+ int[] ndefinfo = new int[2];
+ status = checkNdefWithStatus(ndefinfo);
+ if (status != 0) {
+ Log.d(TAG, "Check NDEF Failed - status = " + status);
+ if (status == STATUS_CODE_TARGET_LOST) {
+ break;
+ }
+ continue; // try next handle
+ }
+
+ // found our NDEF handle
+ boolean generateEmptyNdef = false;
+
+ int supportedNdefLength = ndefinfo[0];
+ int cardState = ndefinfo[1];
+ byte[] buff = readNdef();
+ if (buff != null) {
+ try {
+ ndefMsg = new NdefMessage(buff);
+ addNdefTechnology(ndefMsg,
+ getConnectedHandle(),
+ getConnectedLibNfcType(),
+ getConnectedTechnology(),
+ supportedNdefLength, cardState);
+ reconnect();
+ } catch (FormatException e) {
+ // Create an intent anyway, without NDEF messages
+ generateEmptyNdef = true;
+ }
+ } else {
+ generateEmptyNdef = true;
+ }
+
+ if (generateEmptyNdef) {
+ ndefMsg = null;
+ addNdefTechnology(null,
+ getConnectedHandle(),
+ getConnectedLibNfcType(),
+ getConnectedTechnology(),
+ supportedNdefLength, cardState);
+ reconnect();
+ }
+ break;
+ }
+
+ if (ndefMsg == null && foundFormattable) {
+ // Tag is not NDEF yet, and found a formattable target,
+ // so add formattable tech to tech list.
+ addNdefFormatableTechnology(
+ formattableHandle,
+ formattableLibNfcType);
+ }
+
+ return ndefMsg;
+ }
+}
diff --git a/nci/src/com/android/nfc/dhimpl/NativeP2pDevice.java b/nci/src/com/android/nfc/dhimpl/NativeP2pDevice.java
new file mode 100755
index 0000000..094f46a
--- /dev/null
+++ b/nci/src/com/android/nfc/dhimpl/NativeP2pDevice.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.nfc.dhimpl;
+
+import com.android.nfc.DeviceHost.NfcDepEndpoint;
+
+/**
+ * Native interface to the P2P Initiator functions
+ */
+public class NativeP2pDevice implements NfcDepEndpoint {
+
+ private int mHandle;
+
+ private int mMode;
+
+ private byte[] mGeneralBytes;
+
+ private native byte[] doReceive();
+ @Override
+ public byte[] receive() {
+ return doReceive();
+ }
+
+ private native boolean doSend(byte[] data);
+ @Override
+ public boolean send(byte[] data) {
+ return doSend(data);
+ }
+
+ private native boolean doConnect();
+ @Override
+ public boolean connect() {
+ return doConnect();
+ }
+
+ private native boolean doDisconnect();
+ @Override
+ public boolean disconnect() {
+ return doDisconnect();
+ }
+
+ public native byte[] doTransceive(byte[] data);
+ @Override
+ public byte[] transceive(byte[] data) {
+ return doTransceive(data);
+ }
+
+ @Override
+ public int getHandle() {
+ return mHandle;
+ }
+
+ @Override
+ public int getMode() {
+ return mMode;
+ }
+
+ @Override
+ public byte[] getGeneralBytes() {
+ return mGeneralBytes;
+ }
+
+}
diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java
index f969627..dc6ea7c 100755
--- a/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java
+++ b/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java
@@ -43,6 +43,25 @@ public class NativeNfcManager implements DeviceHost {
private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime";
private static final long FIRMWARE_MODTIME_DEFAULT = -1;
+ static final String DRIVER_NAME = "nxp";
+
+ static final int DEFAULT_LLCP_MIU = 128;
+ static final int DEFAULT_LLCP_RWSIZE = 1;
+
+ //TODO: dont hardcode this
+ private static final byte[][] EE_WIPE_APDUS = {
+ {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
+ {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00,
+ (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x20, (byte)0x10, (byte)0x00},
+ {(byte)0x80, (byte)0xe2, (byte)0x01, (byte)0x03, (byte)0x00},
+ {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
+ {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00,
+ (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x30, (byte)0x30, (byte)0x00},
+ {(byte)0x80, (byte)0xb4, (byte)0x00, (byte)0x00, (byte)0x00},
+ {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
+ };
+
+
static {
System.loadLibrary("nfc_jni");
}
@@ -144,6 +163,11 @@ public class NativeNfcManager implements DeviceHost {
}
@Override
+ public String getName() {
+ return DRIVER_NAME;
+ }
+
+ @Override
public native void enableDiscovery();
@Override
@@ -305,11 +329,32 @@ public class NativeNfcManager implements DeviceHost {
doSetP2pTargetModes(modes);
}
+ @Override
public boolean getExtendedLengthApdusSupported() {
// Not supported on the PN544
return false;
}
+ @Override
+ public boolean enablePN544Quirks() {
+ return true;
+ }
+
+ @Override
+ public byte[][] getWipeApdus() {
+ return EE_WIPE_APDUS;
+ }
+
+ @Override
+ public int getDefaultLlcpMiu() {
+ return DEFAULT_LLCP_MIU;
+ }
+
+ @Override
+ public int getDefaultLlcpRwSize() {
+ return DEFAULT_LLCP_RWSIZE;
+ }
+
private native String doDump();
@Override
public String dump() {
@@ -370,4 +415,5 @@ public class NativeNfcManager implements DeviceHost {
private void notifySeMifareAccess(byte[] block) {
mListener.onSeMifareAccess(block);
}
+
}
diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java
index eddde94..992e6d2 100755
--- a/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java
+++ b/nxp/src/com/android/nfc/dhimpl/NativeNfcTag.java
@@ -136,6 +136,10 @@ public class NativeNfcTag implements TagEndpoint {
private native int doConnect(int handle);
public synchronized int connectWithStatus(int technology) {
+ if (technology == TagTechnology.NFC_B) {
+ // Not supported by PN544
+ return -1;
+ }
if (mWatchdog != null) {
mWatchdog.pause();
}
@@ -785,6 +789,7 @@ public class NativeNfcTag implements TagEndpoint {
getConnectedLibNfcType(),
getConnectedTechnology(),
supportedNdefLength, cardState);
+ foundFormattable = false;
reconnect();
}
break;
diff --git a/src/com/android/nfc/DeviceHost.java b/src/com/android/nfc/DeviceHost.java
index 047e3d5..e514bb6 100644
--- a/src/com/android/nfc/DeviceHost.java
+++ b/src/com/android/nfc/DeviceHost.java
@@ -49,6 +49,16 @@ public interface DeviceHost {
public void onRemoteFieldDeactivated();
+ /**
+ * Notifies that the SE has been activated in listen mode
+ */
+ public void onSeListenActivated();
+
+ /**
+ * Notifies that the SE has been deactivated
+ */
+ public void onSeListenDeactivated();
+
public void onSeApduReceived(byte[] apdu);
public void onSeEmvCardRemoval();
@@ -175,6 +185,8 @@ public interface DeviceHost {
public boolean deinitialize();
+ public String getName();
+
public void enableDiscovery();
public void disableDiscovery();
@@ -216,5 +228,13 @@ public interface DeviceHost {
boolean getExtendedLengthApdusSupported();
+ boolean enablePN544Quirks();
+
+ byte[][] getWipeApdus();
+
+ int getDefaultLlcpMiu();
+
+ int getDefaultLlcpRwSize();
+
String dump();
}
diff --git a/src/com/android/nfc/FireflyRenderer.java b/src/com/android/nfc/FireflyRenderer.java
index 4ce58b4..40c931d 100644
--- a/src/com/android/nfc/FireflyRenderer.java
+++ b/src/com/android/nfc/FireflyRenderer.java
@@ -200,6 +200,7 @@ public class FireflyRenderer {
for (int i = 0; i < 3; i++) {
// Call eglSwapBuffers 3 times - this will allocate the necessary
// buffers, and make sure the animation looks smooth from the start.
+ mGL.glClear(GL10.GL_COLOR_BUFFER_BIT);
if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
Log.e(LOG_TAG, "Could not swap buffers");
mFinished = true;
diff --git a/src/com/android/nfc/NfcApplication.java b/src/com/android/nfc/NfcApplication.java
new file mode 100644
index 0000000..867b8bb
--- /dev/null
+++ b/src/com/android/nfc/NfcApplication.java
@@ -0,0 +1,24 @@
+package com.android.nfc;
+
+import android.app.Application;
+import android.os.UserHandle;
+import android.util.Log;
+
+public class NfcApplication extends Application {
+
+ public static final String TAG = "NfcApplication";
+ NfcService mNfcService;
+
+ public NfcApplication() {
+
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ if (UserHandle.myUserId() == 0) {
+ mNfcService = new NfcService(this);
+ }
+ }
+}
diff --git a/src/com/android/nfc/NfcDispatcher.java b/src/com/android/nfc/NfcDispatcher.java
index b3ab97c..1721d1a 100644
--- a/src/com/android/nfc/NfcDispatcher.java
+++ b/src/com/android/nfc/NfcDispatcher.java
@@ -20,6 +20,7 @@ import com.android.nfc.RegisteredComponentCache.ComponentInfo;
import com.android.nfc.handover.HandoverManager;
import android.app.Activity;
+import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.PendingIntent;
@@ -30,6 +31,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.nfc.NdefMessage;
@@ -38,6 +40,7 @@ import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.Ndef;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Log;
import java.io.FileDescriptor;
@@ -58,7 +61,6 @@ public class NfcDispatcher {
final Context mContext;
final IActivityManager mIActivityManager;
final RegisteredComponentCache mTechListFilters;
- final PackageManager mPackageManager;
final ContentResolver mContentResolver;
final HandoverManager mHandoverManager;
@@ -72,7 +74,6 @@ public class NfcDispatcher {
mIActivityManager = ActivityManagerNative.getDefault();
mTechListFilters = new RegisteredComponentCache(mContext,
NfcAdapter.ACTION_TECH_DISCOVERED, NfcAdapter.ACTION_TECH_DISCOVERED);
- mPackageManager = context.getPackageManager();
mContentResolver = context.getContentResolver();
mHandoverManager = handoverManager;
}
@@ -157,19 +158,21 @@ public class NfcDispatcher {
// is not available on Context. Instead, we query the PackageManager beforehand
// to determine if there is an Activity to handle this intent, and base the
// result of off that.
- List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
+ List<ResolveInfo> activities = packageManager.queryIntentActivitiesAsUser(intent, 0,
+ ActivityManager.getCurrentUser());
if (activities.size() > 0) {
- context.startActivity(rootIntent);
+ context.startActivityAsUser(rootIntent, UserHandle.CURRENT);
return true;
}
return false;
}
boolean tryStartActivity(Intent intentToStart) {
- List<ResolveInfo> activities = packageManager.queryIntentActivities(intentToStart, 0);
+ List<ResolveInfo> activities = packageManager.queryIntentActivitiesAsUser(
+ intentToStart, 0, ActivityManager.getCurrentUser());
if (activities.size() > 0) {
rootIntent.putExtra(NfcRootActivity.EXTRA_LAUNCH_INTENT, intentToStart);
- context.startActivity(rootIntent);
+ context.startActivityAsUser(rootIntent, UserHandle.CURRENT);
return true;
}
return false;
@@ -305,7 +308,10 @@ public class NfcDispatcher {
if (message == null) {
return false;
}
- dispatch.setNdefIntent();
+ Intent intent = dispatch.setNdefIntent();
+
+ // Bail out if the intent does not contain filterable NDEF data
+ if (intent == null) return false;
// Try to start AAR activity with matching filter
List<String> aarPackages = extractAarPackages(message);
@@ -320,7 +326,16 @@ public class NfcDispatcher {
// Try to perform regular launch of the first AAR
if (aarPackages.size() > 0) {
String firstPackage = aarPackages.get(0);
- Intent appLaunchIntent = mPackageManager.getLaunchIntentForPackage(firstPackage);
+ PackageManager pm;
+ try {
+ UserHandle currentUser = new UserHandle(ActivityManager.getCurrentUser());
+ pm = mContext.createPackageContextAsUser("android", 0,
+ currentUser).getPackageManager();
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Could not create user package context");
+ return false;
+ }
+ Intent appLaunchIntent = pm.getLaunchIntentForPackage(firstPackage);
if (appLaunchIntent != null && dispatch.tryStartActivity(appLaunchIntent)) {
if (DBG) Log.i(TAG, "matched AAR to application launch");
return true;
@@ -364,11 +379,20 @@ public class NfcDispatcher {
ArrayList<ResolveInfo> matches = new ArrayList<ResolveInfo>();
List<ComponentInfo> registered = mTechListFilters.getComponents();
+ PackageManager pm;
+ try {
+ UserHandle currentUser = new UserHandle(ActivityManager.getCurrentUser());
+ pm = mContext.createPackageContextAsUser("android", 0,
+ currentUser).getPackageManager();
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Could not create user package context");
+ return false;
+ }
// Check each registered activity to see if it matches
for (ComponentInfo info : registered) {
// Don't allow wild card matching
if (filterMatch(tagTechs, info.techs) &&
- isComponentEnabled(mPackageManager, info.resolveInfo)) {
+ isComponentEnabled(pm, info.resolveInfo)) {
// Add the activity as a match if it's not already in the list
if (!matches.contains(info.resolveInfo)) {
matches.add(info.resolveInfo);
diff --git a/src/com/android/nfc/NfcRootActivity.java b/src/com/android/nfc/NfcRootActivity.java
index 1325ead..cc216f2 100644
--- a/src/com/android/nfc/NfcRootActivity.java
+++ b/src/com/android/nfc/NfcRootActivity.java
@@ -17,9 +17,11 @@
package com.android.nfc;
import android.app.Activity;
+import android.app.ActivityManager;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.os.Bundle;
+import android.os.UserHandle;
public class NfcRootActivity extends Activity {
@@ -33,7 +35,7 @@ public class NfcRootActivity extends Activity {
final Intent launchIntent = intent.getParcelableExtra(EXTRA_LAUNCH_INTENT);
if (launchIntent != null) {
try {
- startActivity(launchIntent);
+ startActivityAsUser(launchIntent, UserHandle.CURRENT);
} catch (ActivityNotFoundException e) {
}
}
diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java
index 3e7a6b5..d63f84f 100755
--- a/src/com/android/nfc/NfcService.java
+++ b/src/com/android/nfc/NfcService.java
@@ -63,6 +63,7 @@ import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
@@ -75,7 +76,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.concurrent.ExecutionException;
-public class NfcService extends Application implements DeviceHostListener {
+public class NfcService implements DeviceHostListener {
private static final String ACTION_MASTER_CLEAR_NOTIFICATION = "android.intent.action.MASTER_CLEAR_NOTIFICATION";
static final boolean DBG = false;
@@ -101,8 +102,6 @@ public class NfcService extends Application implements DeviceHostListener {
static final String PREF_FIRST_BOOT = "first_boot";
static final String PREF_AIRPLANE_OVERRIDE = "airplane_override";
- static final boolean PN544_QUIRK_DISCONNECT_BEFORE_RECONFIGURE = true;
-
static final int MSG_NDEF_TAG = 0;
static final int MSG_CARD_EMULATION = 1;
static final int MSG_LLCP_LINK_ACTIVATION = 2;
@@ -114,6 +113,8 @@ public class NfcService extends Application implements DeviceHostListener {
static final int MSG_SE_APDU_RECEIVED = 10;
static final int MSG_SE_EMV_CARD_REMOVAL = 11;
static final int MSG_SE_MIFARE_ACCESS = 12;
+ static final int MSG_SE_LISTEN_ACTIVATED = 13;
+ static final int MSG_SE_LISTEN_DEACTIVATED = 14;
static final int TASK_ENABLE = 1;
static final int TASK_DISABLE = 2;
@@ -134,6 +135,15 @@ public class NfcService extends Application implements DeviceHostListener {
/** minimum screen state that enables NFC polling (discovery) */
static final int POLLING_MODE = SCREEN_STATE_ON_UNLOCKED;
+ // Time to wait for NFC controller to initialize before watchdog
+ // goes off. This time is chosen large, because firmware download
+ // may be a part of initialization.
+ static final int INIT_WATCHDOG_MS = 90000;
+
+ // Time to wait for routing to be applied before watchdog
+ // goes off
+ static final int ROUTING_WATCHDOG_MS = 10000;
+
// for use with playSound()
public static final int SOUND_START = 0;
public static final int SOUND_END = 1;
@@ -160,18 +170,10 @@ public class NfcService extends Application implements DeviceHostListener {
public static final String EXTRA_MIFARE_BLOCK =
"com.android.nfc_extras.extra.MIFARE_BLOCK";
- //TODO: dont hardcode this
- private static final byte[][] EE_WIPE_APDUS = {
- {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
- {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00,
- (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x20, (byte)0x10, (byte)0x00},
- {(byte)0x80, (byte)0xe2, (byte)0x01, (byte)0x03, (byte)0x00},
- {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
- {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00,
- (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x30, (byte)0x30, (byte)0x00},
- {(byte)0x80, (byte)0xb4, (byte)0x00, (byte)0x00, (byte)0x00},
- {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
- };
+ public static final String ACTION_SE_LISTEN_ACTIVATED =
+ "com.android.nfc_extras.action.SE_LISTEN_ACTIVATED";
+ public static final String ACTION_SE_LISTEN_DEACTIVATED =
+ "com.android.nfc_extras.action.SE_LISTEN_DEACTIVATED";
// NFC Execution Environment
// fields below are protected by this
@@ -184,6 +186,8 @@ public class NfcService extends Application implements DeviceHostListener {
// fields below are used in multiple threads and protected by synchronized(this)
final HashMap<Integer, Object> mObjectMap = new HashMap<Integer, Object>();
+ // mSePackages holds packages that accessed the SE, but only for the owner user,
+ // as SE access is not granted for non-owner users.
HashSet<String> mSePackages = new HashSet<String>();
int mScreenState;
boolean mIsNdefPushEnabled;
@@ -201,7 +205,9 @@ public class NfcService extends Application implements DeviceHostListener {
private DeviceHost mDeviceHost;
private SharedPreferences mPrefs;
private SharedPreferences.Editor mPrefsEditor;
- private PowerManager.WakeLock mWakeLock;
+ private PowerManager.WakeLock mRoutingWakeLock;
+ private PowerManager.WakeLock mEeWakeLock;
+
int mStartSound;
int mEndSound;
int mErrorSound;
@@ -233,6 +239,9 @@ public class NfcService extends Application implements DeviceHostListener {
throw new SecurityException(NfceeAccessControl.NFCEE_ACCESS_PATH +
" denies NFCEE access to " + pkg);
}
+ if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
+ throw new SecurityException("only the owner is allowed to call SE APIs");
+ }
}
public static NfcService getInstance() {
@@ -287,6 +296,17 @@ public class NfcService extends Application implements DeviceHostListener {
}
@Override
+ public void onSeListenActivated() {
+ sendMessage(NfcService.MSG_SE_LISTEN_ACTIVATED, null);
+ }
+
+ @Override
+ public void onSeListenDeactivated() {
+ sendMessage(NfcService.MSG_SE_LISTEN_DEACTIVATED, null);
+ }
+
+
+ @Override
public void onSeApduReceived(byte[] apdu) {
sendMessage(NfcService.MSG_SE_APDU_RECEIVED, apdu);
}
@@ -301,10 +321,7 @@ public class NfcService extends Application implements DeviceHostListener {
sendMessage(NfcService.MSG_SE_MIFARE_ACCESS, block);
}
- @Override
- public void onCreate() {
- super.onCreate();
-
+ public NfcService(Application nfcApplication) {
mNfcTagService = new TagService();
mNfcAdapter = new NfcAdapterService();
mExtrasService = new NfcAdapterExtrasService();
@@ -313,48 +330,60 @@ public class NfcService extends Application implements DeviceHostListener {
sService = this;
- mContext = this;
- mDeviceHost = new NativeNfcManager(this, this);
+ mContext = nfcApplication;
+ mDeviceHost = new NativeNfcManager(mContext, this);
HandoverManager handoverManager = new HandoverManager(mContext);
- mNfcDispatcher = new NfcDispatcher(this, handoverManager);
- mP2pLinkManager = new P2pLinkManager(mContext, handoverManager);
+ mNfcDispatcher = new NfcDispatcher(mContext, handoverManager);
+
+ mP2pLinkManager = new P2pLinkManager(mContext, handoverManager,
+ mDeviceHost.getDefaultLlcpMiu(), mDeviceHost.getDefaultLlcpRwSize());
mSecureElement = new NativeNfcSecureElement(mContext);
mEeRoutingState = ROUTE_OFF;
- mNfceeAccessControl = new NfceeAccessControl(this);
+ mNfceeAccessControl = new NfceeAccessControl(mContext);
- mPrefs = getSharedPreferences(PREF, Context.MODE_PRIVATE);
+ mPrefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
mPrefsEditor = mPrefs.edit();
mState = NfcAdapter.STATE_OFF;
mIsNdefPushEnabled = mPrefs.getBoolean(PREF_NDEF_PUSH_ON, NDEF_PUSH_ON_DEFAULT);
- mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
+ mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+
+ mRoutingWakeLock = mPowerManager.newWakeLock(
+ PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mRoutingWakeLock");
+ mEeWakeLock = mPowerManager.newWakeLock(
+ PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mEeWakeLock");
- mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "NfcService");
- mKeyguard = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
+ mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
mScreenState = checkScreenState();
ServiceManager.addService(SERVICE_NAME, mNfcAdapter);
+ // Intents only for owner
+ IntentFilter ownerFilter = new IntentFilter(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
+ ownerFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+ ownerFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+ ownerFilter.addAction(ACTION_MASTER_CLEAR_NOTIFICATION);
+
+ mContext.registerReceiver(mOwnerReceiver, ownerFilter);
+
+ ownerFilter = new IntentFilter();
+ ownerFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ ownerFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ ownerFilter.addDataScheme("package");
+
+ mContext.registerReceiver(mOwnerReceiver, ownerFilter);
+
+ // Intents for all users
IntentFilter filter = new IntentFilter(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
- filter.addAction(ACTION_MASTER_CLEAR_NOTIFICATION);
filter.addAction(Intent.ACTION_USER_PRESENT);
- filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
- filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
registerForAirplaneMode(filter);
- registerReceiver(mReceiver, filter);
-
- filter = new IntentFilter();
- filter.addAction(Intent.ACTION_PACKAGE_ADDED);
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- filter.addDataScheme("package");
-
- registerReceiver(mReceiver, filter);
+ mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, null);
updatePackageCache();
@@ -365,9 +394,9 @@ public class NfcService extends Application implements DeviceHostListener {
synchronized(this) {
if (mSoundPool == null) {
mSoundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0);
- mStartSound = mSoundPool.load(this, R.raw.start, 1);
- mEndSound = mSoundPool.load(this, R.raw.end, 1);
- mErrorSound = mSoundPool.load(this, R.raw.error, 1);
+ mStartSound = mSoundPool.load(mContext, R.raw.start, 1);
+ mEndSound = mSoundPool.load(mContext, R.raw.end, 1);
+ mErrorSound = mSoundPool.load(mContext, R.raw.error, 1);
}
}
}
@@ -399,8 +428,8 @@ public class NfcService extends Application implements DeviceHostListener {
}
void updatePackageCache() {
- PackageManager pm = getPackageManager();
- List<PackageInfo> packages = pm.getInstalledPackages(0);
+ PackageManager pm = mContext.getPackageManager();
+ List<PackageInfo> packages = pm.getInstalledPackages(0, UserHandle.USER_OWNER);
synchronized (this) {
mInstalledPackages = packages;
}
@@ -416,6 +445,37 @@ public class NfcService extends Application implements DeviceHostListener {
}
}
+ int doOpenSecureElementConnection() {
+ mEeWakeLock.acquire();
+ try {
+ return mSecureElement.doOpenSecureElementConnection();
+ } finally {
+ mEeWakeLock.release();
+ }
+ }
+
+ byte[] doTransceive(int handle, byte[] cmd) {
+ mEeWakeLock.acquire();
+ try {
+ return doTransceiveNoLock(handle, cmd);
+ } finally {
+ mEeWakeLock.release();
+ }
+ }
+
+ byte[] doTransceiveNoLock(int handle, byte[] cmd) {
+ return mSecureElement.doTransceive(handle, cmd);
+ }
+
+ void doDisconnect(int handle) {
+ mEeWakeLock.acquire();
+ try {
+ mSecureElement.doDisconnect(handle);
+ } finally {
+ mEeWakeLock.release();
+ }
+ }
+
/**
* Manages tasks that involve turning on/off the NFC controller.
*
@@ -512,11 +572,21 @@ public class NfcService extends Application implements DeviceHostListener {
Log.i(TAG, "Enabling NFC");
updateState(NfcAdapter.STATE_TURNING_ON);
-
- if (!mDeviceHost.initialize()) {
- Log.w(TAG, "Error enabling NFC");
- updateState(NfcAdapter.STATE_OFF);
- return false;
+ WatchDogThread watchDog = new WatchDogThread("enableInternal", INIT_WATCHDOG_MS);
+ watchDog.start();
+ try {
+ mRoutingWakeLock.acquire();
+ try {
+ if (!mDeviceHost.initialize()) {
+ Log.w(TAG, "Error enabling NFC");
+ updateState(NfcAdapter.STATE_OFF);
+ return false;
+ }
+ } finally {
+ mRoutingWakeLock.release();
+ }
+ } finally {
+ watchDog.cancel();
}
synchronized(NfcService.this) {
@@ -549,7 +619,7 @@ public class NfcService extends Application implements DeviceHostListener {
* Implemented with a new thread (instead of a Handler or AsyncTask),
* because the UI Thread and AsyncTask thread-pools can also get hung
* when the NFC controller stops responding */
- WatchDogThread watchDog = new WatchDogThread();
+ WatchDogThread watchDog = new WatchDogThread("disableInternal", ROUTING_WATCHDOG_MS);
watchDog.start();
mP2pLinkManager.enableDisable(false, false);
@@ -566,7 +636,6 @@ public class NfcService extends Application implements DeviceHostListener {
// A convenient way to stop the watchdog properly consists of
// disconnecting the tag. The polling loop shall be stopped before
// to avoid the tag being discovered again.
- applyRouting(true);
maybeDisconnectTarget();
mNfcDispatcher.setForegroundDispatch(null, null, null);
@@ -585,41 +654,64 @@ public class NfcService extends Application implements DeviceHostListener {
void executeEeWipe() {
// TODO: read SE reset list from /system/etc
- byte[][]apdus = EE_WIPE_APDUS;
+ byte[][]apdus = mDeviceHost.getWipeApdus();
+
+ if (apdus == null) {
+ Log.d(TAG, "No wipe APDUs found");
+ return;
+ }
boolean tempEnable = mState == NfcAdapter.STATE_OFF;
- if (tempEnable) {
- if (!enableInternal()) {
+ // Hold a wake-lock over the entire wipe procedure
+ mEeWakeLock.acquire();
+ try {
+ if (tempEnable && !enableInternal()) {
Log.w(TAG, "Could not enable NFC to wipe NFC-EE");
return;
}
- }
- Log.i(TAG, "Executing SE wipe");
- int handle = mSecureElement.doOpenSecureElementConnection();
- if (handle == 0) {
- Log.w(TAG, "Could not open the secure element");
- if (tempEnable) {
- disableInternal();
- }
- return;
- }
-
- mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 10000);
+ try {
+ // NFC enabled
+ int handle = 0;
+ try {
+ Log.i(TAG, "Executing SE wipe");
+ handle = doOpenSecureElementConnection();
+ if (handle == 0) {
+ Log.w(TAG, "Could not open the secure element");
+ return;
+ }
+ // TODO: remove this hack
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ // Ignore
+ }
- for (byte[] cmd : apdus) {
- byte[] resp = mSecureElement.doTransceive(handle, cmd);
- if (resp == null) {
- Log.w(TAG, "Transceive failed, could not wipe NFC-EE");
- break;
+ mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 10000);
+ try {
+ for (byte[] cmd : apdus) {
+ byte[] resp = doTransceiveNoLock(handle, cmd);
+ if (resp == null) {
+ Log.w(TAG, "Transceive failed, could not wipe NFC-EE");
+ break;
+ }
+ }
+ } finally {
+ mDeviceHost.resetTimeouts();
+ }
+ } finally {
+ if (handle != 0) {
+ doDisconnect(handle);
+ }
+ }
+ } finally {
+ if (tempEnable) {
+ disableInternal();
+ }
}
+ } finally {
+ mEeWakeLock.release();
}
-
- mDeviceHost.resetTimeouts();
- mSecureElement.doDisconnect(handle);
-
- if (tempEnable) {
- disableInternal();
- }
+ Log.i(TAG, "SE wipe done");
}
void updateState(int newState) {
@@ -631,7 +723,7 @@ public class NfcService extends Application implements DeviceHostListener {
Intent intent = new Intent(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
intent.putExtra(NfcAdapter.EXTRA_ADAPTER_STATE, mState);
- mContext.sendBroadcast(intent);
+ mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
}
}
}
@@ -663,12 +755,6 @@ public class NfcService extends Application implements DeviceHostListener {
}
}
- @Override
- public void onTerminate() {
- super.onTerminate();
- // NFC application is persistent, it should not be destroyed by framework
- Log.wtf(TAG, "NFC service is under attack!");
- }
final class NfcAdapterService extends INfcAdapter.Stub {
@Override
@@ -870,10 +956,6 @@ public class NfcService extends Application implements DeviceHostListener {
return ErrorCodes.ERROR_DISCONNECT;
}
- if (technology == TagTechnology.NFC_B) {
- return ErrorCodes.ERROR_NOT_SUPPORTED;
- }
-
// Note that on most tags, all technologies are behind a single
// handle. This means that the connect at the lower levels
// will do nothing, as the tag is already connected to that handle.
@@ -1201,7 +1283,7 @@ public class NfcService extends Application implements DeviceHostListener {
binder.unlinkToDeath(mOpenEe, 0);
mDeviceHost.resetTimeouts();
- mSecureElement.doDisconnect(mOpenEe.handle);
+ doDisconnect(mOpenEe.handle);
mOpenEe = null;
applyRouting(true);
@@ -1244,11 +1326,11 @@ public class NfcService extends Application implements DeviceHostListener {
throw new IOException("NFC EE already open");
}
- int handle = mSecureElement.doOpenSecureElementConnection();
+ int handle = doOpenSecureElementConnection();
if (handle == 0) {
throw new IOException("NFC EE failed to open");
}
- mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 10000);
+ mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 30000);
mOpenEe = new OpenSecureElement(getCallingPid(), handle, b);
try {
@@ -1259,7 +1341,7 @@ public class NfcService extends Application implements DeviceHostListener {
// Add the calling package to the list of packages that have accessed
// the secure element.
- for (String packageName : getPackageManager().getPackagesForUid(getCallingUid())) {
+ for (String packageName : mContext.getPackageManager().getPackagesForUid(getCallingUid())) {
mSePackages.add(packageName);
}
}
@@ -1308,7 +1390,7 @@ public class NfcService extends Application implements DeviceHostListener {
}
}
- return mSecureElement.doTransceive(mOpenEe.handle, data);
+ return doTransceive(mOpenEe.handle, data);
}
@Override
@@ -1321,13 +1403,28 @@ public class NfcService extends Application implements DeviceHostListener {
public void setCardEmulationRoute(String pkg, int route) throws RemoteException {
NfcService.this.enforceNfceeAdminPerm(pkg);
mEeRoutingState = route;
- applyRouting(true);
+ ApplyRoutingTask applyRoutingTask = new ApplyRoutingTask();
+ applyRoutingTask.execute();
+ try {
+ // Block until route is set
+ applyRoutingTask.get();
+ } catch (ExecutionException e) {
+ Log.e(TAG, "failed to set card emulation mode");
+ } catch (InterruptedException e) {
+ Log.e(TAG, "failed to set card emulation mode");
+ }
}
@Override
public void authenticate(String pkg, byte[] token) throws RemoteException {
NfcService.this.enforceNfceeAdminPerm(pkg);
}
+
+ @Override
+ public String getDriverName(String pkg) throws RemoteException {
+ NfcService.this.enforceNfceeAdminPerm(pkg);
+ return mDeviceHost.getName();
+ }
}
/** resources kept while secure element is open */
@@ -1376,19 +1473,27 @@ public class NfcService extends Application implements DeviceHostListener {
class WatchDogThread extends Thread {
boolean mWatchDogCanceled = false;
+ final int mTimeout;
+
+ public WatchDogThread(String threadName, int timeout) {
+ super(threadName);
+ mTimeout = timeout;
+ }
+
@Override
public void run() {
boolean slept = false;
while (!slept) {
try {
- Thread.sleep(10000);
+ Thread.sleep(mTimeout);
slept = true;
} catch (InterruptedException e) { }
}
synchronized (this) {
if (!mWatchDogCanceled) {
// Trigger watch-dog
- Log.e(TAG, "Watch dog triggered");
+ Log.e(TAG, "Watchdog fired: name=" + getName() + " threadId=" +
+ getId() + " timeout=" + mTimeout);
mDeviceHost.doAbort();
}
}
@@ -1407,12 +1512,12 @@ public class NfcService extends Application implements DeviceHostListener {
// PN544 cannot be reconfigured while EE is open
return;
}
- WatchDogThread watchDog = new WatchDogThread();
+ WatchDogThread watchDog = new WatchDogThread("applyRouting", ROUTING_WATCHDOG_MS);
try {
watchDog.start();
- if (PN544_QUIRK_DISCONNECT_BEFORE_RECONFIGURE && mScreenState == SCREEN_STATE_OFF) {
+ if (mDeviceHost.enablePN544Quirks() && mScreenState == SCREEN_STATE_OFF) {
/* TODO undo this after the LLCP stack is fixed.
* Use a different sequence when turning the screen off to
* workaround race conditions in pn544 libnfc. The race occurs
@@ -1704,6 +1809,22 @@ public class NfcService extends Application implements DeviceHostListener {
break;
}
+ case MSG_SE_LISTEN_ACTIVATED: {
+ if (DBG) Log.d(TAG, "SE LISTEN MODE ACTIVATED");
+ Intent listenModeActivated = new Intent();
+ listenModeActivated.setAction(ACTION_SE_LISTEN_ACTIVATED);
+ sendSeBroadcast(listenModeActivated);
+ break;
+ }
+
+ case MSG_SE_LISTEN_DEACTIVATED: {
+ if (DBG) Log.d(TAG, "SE LISTEN MODE DEACTIVATED");
+ Intent listenModeDeactivated = new Intent();
+ listenModeDeactivated.setAction(ACTION_SE_LISTEN_DEACTIVATED);
+ sendSeBroadcast(listenModeDeactivated);
+ break;
+ }
+
default:
Log.e(TAG, "Unknown message received");
break;
@@ -1808,52 +1929,22 @@ public class NfcService extends Application implements DeviceHostListener {
}
mScreenState = params[0].intValue();
- boolean needWakelock = mScreenState == SCREEN_STATE_OFF;
- if (needWakelock) {
- mWakeLock.acquire();
- }
- applyRouting(false);
- if (needWakelock) {
- mWakeLock.release();
+ mRoutingWakeLock.acquire();
+ try {
+ applyRouting(false);
+ } finally {
+ mRoutingWakeLock.release();
}
return null;
}
}
}
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ private final BroadcastReceiver mOwnerReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- if (action.equals(
- NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION)) {
- // Perform applyRouting() in AsyncTask to serialize blocking calls
- new ApplyRoutingTask().execute();
- } else if (action.equals(Intent.ACTION_SCREEN_ON)
- || action.equals(Intent.ACTION_SCREEN_OFF)
- || action.equals(Intent.ACTION_USER_PRESENT)) {
- // Perform applyRouting() in AsyncTask to serialize blocking calls
- int screenState = SCREEN_STATE_OFF;
- if (action.equals(Intent.ACTION_SCREEN_OFF)) {
- screenState = SCREEN_STATE_OFF;
- } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
- screenState = mKeyguard.isKeyguardLocked() ?
- SCREEN_STATE_ON_LOCKED : SCREEN_STATE_ON_UNLOCKED;
- } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
- screenState = SCREEN_STATE_ON_UNLOCKED;
- }
- new ApplyRoutingTask().execute(Integer.valueOf(screenState));
- } else if (action.equals(ACTION_MASTER_CLEAR_NOTIFICATION)) {
- EnableDisableTask eeWipeTask = new EnableDisableTask();
- eeWipeTask.execute(TASK_EE_WIPE);
- try {
- eeWipeTask.get(); // blocks until EE wipe is complete
- } catch (ExecutionException e) {
- Log.w(TAG, "failed to wipe NFC-EE");
- } catch (InterruptedException e) {
- Log.w(TAG, "failed to wipe NFC-EE");
- }
- } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED) ||
+ if (action.equals(Intent.ACTION_PACKAGE_REMOVED) ||
action.equals(Intent.ACTION_PACKAGE_ADDED) ||
action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE) ||
action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
@@ -1877,6 +1968,42 @@ public class NfcService extends Application implements DeviceHostListener {
}
}
}
+ } else if (action.equals(ACTION_MASTER_CLEAR_NOTIFICATION)) {
+ EnableDisableTask eeWipeTask = new EnableDisableTask();
+ eeWipeTask.execute(TASK_EE_WIPE);
+ try {
+ eeWipeTask.get(); // blocks until EE wipe is complete
+ } catch (ExecutionException e) {
+ Log.w(TAG, "failed to wipe NFC-EE");
+ } catch (InterruptedException e) {
+ Log.w(TAG, "failed to wipe NFC-EE");
+ }
+ }
+ }
+ };
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(
+ NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION)) {
+ // Perform applyRouting() in AsyncTask to serialize blocking calls
+ new ApplyRoutingTask().execute();
+ } else if (action.equals(Intent.ACTION_SCREEN_ON)
+ || action.equals(Intent.ACTION_SCREEN_OFF)
+ || action.equals(Intent.ACTION_USER_PRESENT)) {
+ // Perform applyRouting() in AsyncTask to serialize blocking calls
+ int screenState = SCREEN_STATE_OFF;
+ if (action.equals(Intent.ACTION_SCREEN_OFF)) {
+ screenState = SCREEN_STATE_OFF;
+ } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
+ screenState = mKeyguard.isKeyguardLocked() ?
+ SCREEN_STATE_ON_LOCKED : SCREEN_STATE_ON_UNLOCKED;
+ } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
+ screenState = SCREEN_STATE_ON_UNLOCKED;
+ }
+ new ApplyRoutingTask().execute(Integer.valueOf(screenState));
} else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
boolean isAirplaneModeOn = intent.getBooleanExtra("state", false);
// Query the airplane mode from Settings.System just to make sure that
diff --git a/src/com/android/nfc/P2pLinkManager.java b/src/com/android/nfc/P2pLinkManager.java
index 253ddaf..9b23f65 100755
--- a/src/com/android/nfc/P2pLinkManager.java
+++ b/src/com/android/nfc/P2pLinkManager.java
@@ -167,6 +167,9 @@ public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callba
final Handler mHandler;
final HandoverManager mHandoverManager;
+ final int mDefaultMiu;
+ final int mDefaultRwSize;
+
// Locked on NdefP2pManager.this
int mLinkState;
int mSendState; // valid during LINK_STATE_UP or LINK_STATE_DEBOUNCE
@@ -179,9 +182,10 @@ public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callba
SharedPreferences mPrefs;
boolean mFirstBeam;
- public P2pLinkManager(Context context, HandoverManager handoverManager) {
+ public P2pLinkManager(Context context, HandoverManager handoverManager, int defaultMiu,
+ int defaultRwSize) {
mNdefPushServer = new NdefPushServer(NDEFPUSH_SAP, mNppCallback);
- mDefaultSnepServer = new SnepServer(mDefaultSnepCallback);
+ mDefaultSnepServer = new SnepServer(mDefaultSnepCallback, defaultMiu, defaultRwSize);
mHandoverServer = new HandoverServer(HANDOVER_SAP, handoverManager, mHandoverCallback);
if (ECHOSERVER_ENABLED) {
@@ -201,6 +205,8 @@ public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callba
mPrefs = context.getSharedPreferences(NfcService.PREF, Context.MODE_PRIVATE);
mFirstBeam = mPrefs.getBoolean(NfcService.PREF_FIRST_BEAM, true);
mHandoverManager = handoverManager;
+ mDefaultMiu = defaultMiu;
+ mDefaultRwSize = defaultRwSize;
}
/**
@@ -417,11 +423,11 @@ public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callba
long time = SystemClock.elapsedRealtime();
-
try {
if (DBG) Log.d(TAG, "Sending ndef via SNEP");
- int snepResult = doSnepProtocol(mHandoverManager, m, uris);
+ int snepResult = doSnepProtocol(mHandoverManager, m, uris,
+ mDefaultMiu, mDefaultRwSize);
switch (snepResult) {
case SNEP_HANDOVER_UNSUPPORTED:
@@ -461,8 +467,8 @@ public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callba
}
static int doSnepProtocol(HandoverManager handoverManager,
- NdefMessage msg, Uri[] uris) throws IOException {
- SnepClient snepClient = new SnepClient();
+ NdefMessage msg, Uri[] uris, int miu, int rwSize) throws IOException {
+ SnepClient snepClient = new SnepClient(miu, rwSize);
try {
snepClient.connect();
} catch (IOException e) {
diff --git a/src/com/android/nfc/RegisteredComponentCache.java b/src/com/android/nfc/RegisteredComponentCache.java
index 1bac283..5da2cd4 100644
--- a/src/com/android/nfc/RegisteredComponentCache.java
+++ b/src/com/android/nfc/RegisteredComponentCache.java
@@ -19,6 +19,7 @@ package com.android.nfc;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -29,6 +30,7 @@ import android.content.pm.ResolveInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
+import android.os.UserHandle;
import android.util.Log;
import java.io.IOException;
@@ -69,12 +71,16 @@ public class RegisteredComponentCache {
intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
intentFilter.addDataScheme("package");
- mContext.registerReceiver(receiver, intentFilter);
+ mContext.registerReceiverAsUser(receiver, UserHandle.ALL, intentFilter, null, null);
// Register for events related to sdcard installation.
IntentFilter sdFilter = new IntentFilter();
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
- mContext.registerReceiver(receiver, sdFilter);
+ mContext.registerReceiverAsUser(receiver, UserHandle.ALL, sdFilter, null, null);
+ // Generate a new list upon switching users as well
+ IntentFilter userFilter = new IntentFilter();
+ userFilter.addAction(Intent.ACTION_USER_SWITCHED);
+ mContext.registerReceiverAsUser(receiver, UserHandle.ALL, userFilter, null, null);
}
public static class ComponentInfo {
@@ -137,13 +143,21 @@ public class RegisteredComponentCache {
}
void generateComponentsList() {
- PackageManager pm = mContext.getPackageManager();
+ PackageManager pm;
+ try {
+ UserHandle currentUser = new UserHandle(ActivityManager.getCurrentUser());
+ pm = mContext.createPackageContextAsUser("android", 0,
+ currentUser).getPackageManager();
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Could not create user package context");
+ return;
+ }
ArrayList<ComponentInfo> components = new ArrayList<ComponentInfo>();
- List<ResolveInfo> resolveInfos = pm.queryIntentActivities(new Intent(mAction),
- PackageManager.GET_META_DATA);
+ List<ResolveInfo> resolveInfos = pm.queryIntentActivitiesAsUser(new Intent(mAction),
+ PackageManager.GET_META_DATA, ActivityManager.getCurrentUser());
for (ResolveInfo resolveInfo : resolveInfos) {
try {
- parseComponentInfo(resolveInfo, components);
+ parseComponentInfo(pm, resolveInfo, components);
} catch (XmlPullParserException e) {
Log.w(TAG, "Unable to load component info " + resolveInfo.toString(), e);
} catch (IOException e) {
@@ -158,10 +172,9 @@ public class RegisteredComponentCache {
}
}
- void parseComponentInfo(ResolveInfo info, ArrayList<ComponentInfo> components)
- throws XmlPullParserException, IOException {
+ void parseComponentInfo(PackageManager pm, ResolveInfo info,
+ ArrayList<ComponentInfo> components) throws XmlPullParserException, IOException {
ActivityInfo ai = info.activityInfo;
- PackageManager pm = mContext.getPackageManager();
XmlResourceParser parser = null;
try {
diff --git a/src/com/android/nfc/SendUi.java b/src/com/android/nfc/SendUi.java
index 23602c9..5b5c234 100644
--- a/src/com/android/nfc/SendUi.java
+++ b/src/com/android/nfc/SendUi.java
@@ -183,7 +183,7 @@ public class SendUi implements Animator.AnimatorListener, View.OnTouchListener,
// We're only allowed to use hardware acceleration if
// isHighEndGfx() returns true - otherwise, we're too limited
// on resources to do it.
- mHardwareAccelerated = ActivityManager.isHighEndGfx(mDisplay);
+ mHardwareAccelerated = ActivityManager.isHighEndGfx();
int hwAccelerationFlags = mHardwareAccelerated ?
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED : 0;
@@ -194,6 +194,8 @@ public class SendUi implements Animator.AnimatorListener, View.OnTouchListener,
| hwAccelerationFlags
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
PixelFormat.OPAQUE);
+ mWindowLayoutParams.privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
mWindowLayoutParams.token = new Binder();
mFrameCounterAnimator = new TimeAnimator();
@@ -443,6 +445,9 @@ public class SendUi implements Animator.AnimatorListener, View.OnTouchListener,
// Navbar has different sizes, depending on orientation
final int navBarHeight = hasNavBar ? mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.navigation_bar_height) : 0;
+ final int navBarHeightLandscape = hasNavBar ? mContext.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.navigation_bar_height_landscape) : 0;
+
final int navBarWidth = hasNavBar ? mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.navigation_bar_width) : 0;
@@ -483,13 +488,20 @@ public class SendUi implements Animator.AnimatorListener, View.OnTouchListener,
int newTop = statusBarHeight;
int newWidth = bitmap.getWidth();
int newHeight = bitmap.getHeight();
+ float smallestWidth = (float)Math.min(newWidth, newHeight);
+ float smallestWidthDp = smallestWidth / (mDisplayMetrics.densityDpi / 160f);
if (bitmap.getWidth() < bitmap.getHeight()) {
// Portrait mode: status bar is at the top, navbar bottom, width unchanged
newHeight = bitmap.getHeight() - statusBarHeight - navBarHeight;
} else {
- // Landscape mode: status bar is at the top, navbar right
- newHeight = bitmap.getHeight() - statusBarHeight;
- newWidth = bitmap.getWidth() - navBarWidth;
+ // Landscape mode: status bar is at the top
+ // Navbar: bottom on >599dp width devices, otherwise to the side
+ if (smallestWidthDp > 599) {
+ newHeight = bitmap.getHeight() - statusBarHeight - navBarHeightLandscape;
+ } else {
+ newHeight = bitmap.getHeight() - statusBarHeight;
+ newWidth = bitmap.getWidth() - navBarWidth;
+ }
}
bitmap = Bitmap.createBitmap(bitmap, newLeft, newTop, newWidth, newHeight);
diff --git a/src/com/android/nfc/handover/BluetoothHeadsetHandover.java b/src/com/android/nfc/handover/BluetoothHeadsetHandover.java
index 7974dfa..1377160 100644
--- a/src/com/android/nfc/handover/BluetoothHeadsetHandover.java
+++ b/src/com/android/nfc/handover/BluetoothHeadsetHandover.java
@@ -16,6 +16,7 @@
package com.android.nfc.handover;
+import android.app.ActivityManager;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
@@ -28,6 +29,7 @@ import android.content.IntentFilter;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.UserHandle;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.Toast;
@@ -44,9 +46,8 @@ import com.android.nfc.R;
* designed to be re-used after the sequence has completed or timed out.
* Subsequent NFC interactions should use new objects.
*
- * TODO: UI review
*/
-public class BluetoothHeadsetHandover {
+public class BluetoothHeadsetHandover implements BluetoothProfile.ServiceListener {
static final String TAG = HandoverManager.TAG;
static final boolean DBG = HandoverManager.DBG;
@@ -57,28 +58,33 @@ public class BluetoothHeadsetHandover {
static final int STATE_INIT = 0;
static final int STATE_TURNING_ON = 1;
- static final int STATE_WAITING_FOR_BOND_CONFIRMATION = 2;
- static final int STATE_BONDING = 3;
- static final int STATE_CONNECTING = 4;
- static final int STATE_DISCONNECTING = 5;
- static final int STATE_COMPLETE = 6;
+ static final int STATE_WAITING_FOR_PROXIES = 2;
+ static final int STATE_INIT_COMPLETE = 3;
+ static final int STATE_WAITING_FOR_BOND_CONFIRMATION = 4;
+ static final int STATE_BONDING = 5;
+ static final int STATE_CONNECTING = 6;
+ static final int STATE_DISCONNECTING = 7;
+ static final int STATE_COMPLETE = 8;
static final int RESULT_PENDING = 0;
static final int RESULT_CONNECTED = 1;
static final int RESULT_DISCONNECTED = 2;
+ static final int ACTION_INIT = 0;
static final int ACTION_DISCONNECT = 1;
static final int ACTION_CONNECT = 2;
static final int MSG_TIMEOUT = 1;
+ static final int MSG_NEXT_STEP = 2;
final Context mContext;
final BluetoothDevice mDevice;
final String mName;
final HandoverPowerManager mHandoverPowerManager;
- final BluetoothA2dp mA2dp;
- final BluetoothHeadset mHeadset;
final Callback mCallback;
+ final BluetoothAdapter mBluetoothAdapter;
+
+ final Object mLock = new Object();
// only used on main thread
int mAction;
@@ -86,21 +92,24 @@ public class BluetoothHeadsetHandover {
int mHfpResult; // used only in STATE_CONNECTING and STATE_DISCONNETING
int mA2dpResult; // used only in STATE_CONNECTING and STATE_DISCONNETING
+ // protected by mLock
+ BluetoothA2dp mA2dp;
+ BluetoothHeadset mHeadset;
+
public interface Callback {
public void onBluetoothHeadsetHandoverComplete(boolean connected);
}
public BluetoothHeadsetHandover(Context context, BluetoothDevice device, String name,
- HandoverPowerManager powerManager, BluetoothA2dp a2dp, BluetoothHeadset headset,
- Callback callback) {
+ HandoverPowerManager powerManager, Callback callback) {
checkMainThread(); // mHandler must get get constructed on Main Thread for toasts to work
mContext = context;
mDevice = device;
mName = name;
mHandoverPowerManager = powerManager;
- mA2dp = a2dp;
- mHeadset = headset;
mCallback = callback;
+ mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+
mState = STATE_INIT;
}
@@ -111,6 +120,7 @@ public class BluetoothHeadsetHandover {
public void start() {
checkMainThread();
if (mState != STATE_INIT) return;
+ if (mBluetoothAdapter == null) return;
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
@@ -122,15 +132,8 @@ public class BluetoothHeadsetHandover {
mContext.registerReceiver(mReceiver, filter);
- if (mA2dp.getConnectedDevices().contains(mDevice) ||
- mHeadset.getConnectedDevices().contains(mDevice)) {
- Log.i(TAG, "ACTION_DISCONNECT addr=" + mDevice + " name=" + mName);
- mAction = ACTION_DISCONNECT;
- } else {
- Log.i(TAG, "ACTION_CONNECT addr=" + mDevice + " name=" + mName);
- mAction = ACTION_CONNECT;
- }
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_TIMEOUT), TIMEOUT_MS);
+ mAction = ACTION_INIT;
nextStep();
}
@@ -138,35 +141,83 @@ public class BluetoothHeadsetHandover {
* Called to execute next step in state machine
*/
void nextStep() {
- if (mAction == ACTION_CONNECT) {
+ if (mAction == ACTION_INIT) {
+ nextStepInit();
+ } else if (mAction == ACTION_CONNECT) {
nextStepConnect();
} else {
nextStepDisconnect();
}
}
- void nextStepDisconnect() {
+ /*
+ * Enables bluetooth and gets the profile proxies
+ */
+ void nextStepInit() {
switch (mState) {
case STATE_INIT:
- mState = STATE_DISCONNECTING;
- if (mHeadset.getConnectionState(mDevice) != BluetoothProfile.STATE_DISCONNECTED) {
- mHfpResult = RESULT_PENDING;
- mHeadset.disconnect(mDevice);
- } else {
- mHfpResult = RESULT_DISCONNECTED;
- }
- if (mA2dp.getConnectionState(mDevice) != BluetoothProfile.STATE_DISCONNECTED) {
- mA2dpResult = RESULT_PENDING;
- mA2dp.disconnect(mDevice);
- } else {
- mA2dpResult = RESULT_DISCONNECTED;
+ if (!mHandoverPowerManager.isBluetoothEnabled()) {
+ if (mHandoverPowerManager.enableBluetooth()) {
+ // Bluetooth is being enabled
+ mState = STATE_TURNING_ON;
+ } else {
+ toast(mContext.getString(R.string.failed_to_enable_bt));
+ complete(false);
+ }
+ break;
}
- if (mA2dpResult == RESULT_PENDING || mHfpResult == RESULT_PENDING) {
- toast(mContext.getString(R.string.disconnecting_headset ) + " " +
- mName + "...");
+ // fall-through
+ case STATE_TURNING_ON:
+ if (mA2dp == null || mHeadset == null) {
+ mState = STATE_WAITING_FOR_PROXIES;
+ if (!getProfileProxys()) {
+ complete(false);
+ }
break;
}
// fall-through
+ case STATE_WAITING_FOR_PROXIES:
+ mState = STATE_INIT_COMPLETE;
+ // Check connected devices and see if we need to disconnect
+ synchronized(mLock) {
+ if (mA2dp.getConnectedDevices().contains(mDevice) ||
+ mHeadset.getConnectedDevices().contains(mDevice)) {
+ Log.i(TAG, "ACTION_DISCONNECT addr=" + mDevice + " name=" + mName);
+ mAction = ACTION_DISCONNECT;
+ } else {
+ Log.i(TAG, "ACTION_CONNECT addr=" + mDevice + " name=" + mName);
+ mAction = ACTION_CONNECT;
+ }
+ }
+ nextStep();
+ }
+
+ }
+
+ void nextStepDisconnect() {
+ switch (mState) {
+ case STATE_INIT_COMPLETE:
+ mState = STATE_DISCONNECTING;
+ synchronized (mLock) {
+ if (mHeadset.getConnectionState(mDevice) != BluetoothProfile.STATE_DISCONNECTED) {
+ mHfpResult = RESULT_PENDING;
+ mHeadset.disconnect(mDevice);
+ } else {
+ mHfpResult = RESULT_DISCONNECTED;
+ }
+ if (mA2dp.getConnectionState(mDevice) != BluetoothProfile.STATE_DISCONNECTED) {
+ mA2dpResult = RESULT_PENDING;
+ mA2dp.disconnect(mDevice);
+ } else {
+ mA2dpResult = RESULT_DISCONNECTED;
+ }
+ if (mA2dpResult == RESULT_PENDING || mHfpResult == RESULT_PENDING) {
+ toast(mContext.getString(R.string.disconnecting_headset ) + " " +
+ mName + "...");
+ break;
+ }
+ }
+ // fall-through
case STATE_DISCONNECTING:
if (mA2dpResult == RESULT_PENDING || mHfpResult == RESULT_PENDING) {
// still disconnecting
@@ -178,26 +229,26 @@ public class BluetoothHeadsetHandover {
complete(false);
break;
}
+
+ }
+
+ boolean getProfileProxys() {
+ if(!mBluetoothAdapter.getProfileProxy(mContext, this, BluetoothProfile.HEADSET))
+ return false;
+
+ if(!mBluetoothAdapter.getProfileProxy(mContext, this, BluetoothProfile.A2DP))
+ return false;
+
+ return true;
}
void nextStepConnect() {
switch (mState) {
- case STATE_INIT:
- if (!mHandoverPowerManager.isBluetoothEnabled()) {
- if (mHandoverPowerManager.enableBluetooth()) {
- // Bluetooth is being enabled
- mState = STATE_TURNING_ON;
- } else {
- toast(mContext.getString(R.string.failed_to_enable_bt));
- complete(false);
- }
- break;
- }
- // fall-through
- case STATE_TURNING_ON:
+ case STATE_INIT_COMPLETE:
if (mDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
requestPairConfirmation();
mState = STATE_WAITING_FOR_BOND_CONFIRMATION;
+
break;
}
// fall-through
@@ -211,21 +262,23 @@ public class BluetoothHeadsetHandover {
// Bluetooth Profile service will correctly serialize
// HFP then A2DP connect
mState = STATE_CONNECTING;
- if (mHeadset.getConnectionState(mDevice) != BluetoothProfile.STATE_CONNECTED) {
- mHfpResult = RESULT_PENDING;
- mHeadset.connect(mDevice);
- } else {
- mHfpResult = RESULT_CONNECTED;
- }
- if (mA2dp.getConnectionState(mDevice) != BluetoothProfile.STATE_CONNECTED) {
- mA2dpResult = RESULT_PENDING;
- mA2dp.connect(mDevice);
- } else {
- mA2dpResult = RESULT_CONNECTED;
- }
- if (mA2dpResult == RESULT_PENDING || mHfpResult == RESULT_PENDING) {
- toast(mContext.getString(R.string.connecting_headset) + " " + mName + "...");
- break;
+ synchronized (mLock) {
+ if (mHeadset.getConnectionState(mDevice) != BluetoothProfile.STATE_CONNECTED) {
+ mHfpResult = RESULT_PENDING;
+ mHeadset.connect(mDevice);
+ } else {
+ mHfpResult = RESULT_CONNECTED;
+ }
+ if (mA2dp.getConnectionState(mDevice) != BluetoothProfile.STATE_CONNECTED) {
+ mA2dpResult = RESULT_PENDING;
+ mA2dp.connect(mDevice);
+ } else {
+ mA2dpResult = RESULT_CONNECTED;
+ }
+ if (mA2dpResult == RESULT_PENDING || mHfpResult == RESULT_PENDING) {
+ toast(mContext.getString(R.string.connecting_headset) + " " + mName + "...");
+ break;
+ }
}
// fall-through
case STATE_CONNECTING:
@@ -260,7 +313,7 @@ public class BluetoothHeadsetHandover {
if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action) && mState == STATE_TURNING_ON) {
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
if (state == BluetoothAdapter.STATE_ON) {
- nextStepConnect();
+ nextStep();
} else if (state == BluetoothAdapter.STATE_OFF) {
toast(mContext.getString(R.string.failed_to_enable_bt));
complete(false);
@@ -313,6 +366,16 @@ public class BluetoothHeadsetHandover {
mState = STATE_COMPLETE;
mContext.unregisterReceiver(mReceiver);
mHandler.removeMessages(MSG_TIMEOUT);
+ synchronized (mLock) {
+ if (mA2dp != null) {
+ mBluetoothAdapter.closeProfileProxy(BluetoothProfile.A2DP, mA2dp);
+ }
+ if (mHeadset != null) {
+ mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mHeadset);
+ }
+ mA2dp = null;
+ mHeadset = null;
+ }
mCallback.onBluetoothHeadsetHandoverComplete(connected);
}
@@ -324,10 +387,10 @@ public class BluetoothHeadsetHandover {
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN,
KeyEvent.KEYCODE_MEDIA_PLAY));
- mContext.sendOrderedBroadcast(intent, null);
+ mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null, null, null, 0, null, null);
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP,
KeyEvent.KEYCODE_MEDIA_PLAY));
- mContext.sendOrderedBroadcast(intent, null);
+ mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null, null, null, 0, null, null);
}
void requestPairConfirmation() {
@@ -336,7 +399,7 @@ public class BluetoothHeadsetHandover {
dialogIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
- mContext.startActivity(dialogIntent);
+ mContext.startActivityAsUser(dialogIntent, new UserHandle(UserHandle.USER_CURRENT));
}
final Handler mHandler = new Handler() {
@@ -348,6 +411,9 @@ public class BluetoothHeadsetHandover {
Log.i(TAG, "Timeout completing BT handover");
complete(false);
break;
+ case MSG_NEXT_STEP:
+ nextStep();
+ break;
}
}
};
@@ -364,4 +430,29 @@ public class BluetoothHeadsetHandover {
throw new IllegalThreadStateException("must be called on main thread");
}
}
+
+ @Override
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ synchronized (mLock) {
+ switch (profile) {
+ case BluetoothProfile.HEADSET:
+ mHeadset = (BluetoothHeadset) proxy;
+ if (mA2dp != null) {
+ mHandler.sendEmptyMessage(MSG_NEXT_STEP);
+ }
+ break;
+ case BluetoothProfile.A2DP:
+ mA2dp = (BluetoothA2dp) proxy;
+ if (mHeadset != null) {
+ mHandler.sendEmptyMessage(MSG_NEXT_STEP);
+ }
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(int profile) {
+ // We can ignore these
+ }
}
diff --git a/src/com/android/nfc/handover/HandoverManager.java b/src/com/android/nfc/handover/HandoverManager.java
index f77f780..e7e807d 100644
--- a/src/com/android/nfc/handover/HandoverManager.java
+++ b/src/com/android/nfc/handover/HandoverManager.java
@@ -33,11 +33,8 @@ import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Notification.Builder;
-import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHeadset;
-import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -52,6 +49,7 @@ import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.util.Log;
import android.util.Pair;
@@ -62,8 +60,7 @@ import com.android.nfc.R;
/**
* Manages handover of NFC to other technologies.
*/
-public class HandoverManager implements BluetoothProfile.ServiceListener,
- BluetoothHeadsetHandover.Callback {
+public class HandoverManager implements BluetoothHeadsetHandover.Callback {
static final String TAG = "NfcHandover";
static final boolean DBG = true;
@@ -142,8 +139,6 @@ public class HandoverManager implements BluetoothProfile.ServiceListener,
// Variables below synchronized on HandoverManager.this
final HashMap<Pair<String, Boolean>, HandoverTransfer> mTransfers;
- BluetoothHeadset mBluetoothHeadset;
- BluetoothA2dp mBluetoothA2dp;
BluetoothHeadsetHandover mBluetoothHeadsetHandover;
boolean mBluetoothHeadsetConnected;
@@ -390,7 +385,8 @@ public class HandoverManager implements BluetoothProfile.ServiceListener,
notBuilder.setContentText(mContext.getString(R.string.beam_touch_to_view));
Intent viewIntent = buildViewIntent();
- PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, viewIntent, 0);
+ PendingIntent contentIntent = PendingIntent.getActivityAsUser(
+ mContext, 0, viewIntent, 0, null, UserHandle.CURRENT);
notBuilder.setContentIntent(contentIntent);
@@ -410,7 +406,8 @@ public class HandoverManager implements BluetoothProfile.ServiceListener,
return;
}
- mNotificationManager.notify(mNotificationId, notBuilder.build());
+ mNotificationManager.notifyAsUser(null, mNotificationId, notBuilder.build(),
+ UserHandle.CURRENT);
}
synchronized void updateStateAndNotification(int newState) {
@@ -537,7 +534,7 @@ public class HandoverManager implements BluetoothProfile.ServiceListener,
Uri uri = mediaUri != null ? mediaUri :
Uri.parse(ContentResolver.SCHEME_FILE + "://" + filePath);
viewIntent.setDataAndTypeAndNormalize(uri, mimeTypes.get(filePath));
-
+ viewIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
return viewIntent;
}
@@ -612,10 +609,6 @@ public class HandoverManager implements BluetoothProfile.ServiceListener,
public HandoverManager(Context context) {
mContext = context;
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
- if (mBluetoothAdapter != null) {
- mBluetoothAdapter.getProfileProxy(mContext, this, BluetoothProfile.HEADSET);
- mBluetoothAdapter.getProfileProxy(mContext, this, BluetoothProfile.A2DP);
- }
mNotificationManager = (NotificationManager) mContext.getSystemService(
Context.NOTIFICATION_SERVICE);
@@ -792,9 +785,7 @@ public class HandoverManager implements BluetoothProfile.ServiceListener,
if (!handover.valid) return true;
synchronized (HandoverManager.this) {
- if (mBluetoothAdapter == null ||
- mBluetoothA2dp == null ||
- mBluetoothHeadset == null) {
+ if (mBluetoothAdapter == null) {
if (DBG) Log.d(TAG, "BT handover, but BT not available");
return true;
}
@@ -803,7 +794,7 @@ public class HandoverManager implements BluetoothProfile.ServiceListener,
return true;
}
mBluetoothHeadsetHandover = new BluetoothHeadsetHandover(mContext, handover.device,
- handover.name, mHandoverPowerManager, mBluetoothA2dp, mBluetoothHeadset, this);
+ handover.name, mHandoverPowerManager, this);
mBluetoothHeadsetHandover.start();
}
return true;
@@ -983,34 +974,6 @@ public class HandoverManager implements BluetoothProfile.ServiceListener,
}
@Override
- public void onServiceConnected(int profile, BluetoothProfile proxy) {
- synchronized (HandoverManager.this) {
- switch (profile) {
- case BluetoothProfile.HEADSET:
- mBluetoothHeadset = (BluetoothHeadset) proxy;
- break;
- case BluetoothProfile.A2DP:
- mBluetoothA2dp = (BluetoothA2dp) proxy;
- break;
- }
- }
- }
-
- @Override
- public void onServiceDisconnected(int profile) {
- synchronized (HandoverManager.this) {
- switch (profile) {
- case BluetoothProfile.HEADSET:
- mBluetoothHeadset = null;
- break;
- case BluetoothProfile.A2DP:
- mBluetoothA2dp = null;
- break;
- }
- }
- }
-
- @Override
public void onBluetoothHeadsetHandoverComplete(boolean connected) {
synchronized (HandoverManager.this) {
mBluetoothHeadsetHandover = null;
diff --git a/src/com/android/nfc/ndefpush/NdefPushServer.java b/src/com/android/nfc/ndefpush/NdefPushServer.java
index ca58a67..bf92c17 100755
--- a/src/com/android/nfc/ndefpush/NdefPushServer.java
+++ b/src/com/android/nfc/ndefpush/NdefPushServer.java
@@ -117,28 +117,49 @@ public class NdefPushServer {
/** Server class, used to listen for incoming connection request */
class ServerThread extends Thread {
+ // Variables below synchronized on NdefPushServer.this
boolean mRunning = true;
LlcpServerSocket mServerSocket;
@Override
public void run() {
- while (mRunning) {
+ boolean threadRunning;
+ synchronized (NdefPushServer.this) {
+ threadRunning = mRunning;
+ }
+ while (threadRunning) {
if (DBG) Log.d(TAG, "about create LLCP service socket");
try {
- mServerSocket = mService.createLlcpServerSocket(mSap, SERVICE_NAME,
- MIU, 1, 1024);
+ synchronized (NdefPushServer.this) {
+ mServerSocket = mService.createLlcpServerSocket(mSap, SERVICE_NAME,
+ MIU, 1, 1024);
+ }
if (mServerSocket == null) {
if (DBG) Log.d(TAG, "failed to create LLCP service socket");
return;
}
if (DBG) Log.d(TAG, "created LLCP service socket");
- while (mRunning) {
+ synchronized (NdefPushServer.this) {
+ threadRunning = mRunning;
+ }
+
+ while (threadRunning) {
+ LlcpServerSocket serverSocket;
+ synchronized (NdefPushServer.this) {
+ serverSocket = mServerSocket;
+ }
+ if (serverSocket == null) return;
+
if (DBG) Log.d(TAG, "about to accept");
- LlcpSocket communicationSocket = mServerSocket.accept();
+ LlcpSocket communicationSocket = serverSocket.accept();
if (DBG) Log.d(TAG, "accept returned " + communicationSocket);
if (communicationSocket != null) {
new ConnectionThread(communicationSocket).start();
}
+
+ synchronized (NdefPushServer.this) {
+ threadRunning = mRunning;
+ }
}
if (DBG) Log.d(TAG, "stop running");
} catch (LlcpException e) {
@@ -146,28 +167,36 @@ public class NdefPushServer {
} catch (IOException e) {
Log.e(TAG, "IO error", e);
} finally {
- if (mServerSocket != null) {
- if (DBG) Log.d(TAG, "about to close");
- try {
- mServerSocket.close();
- } catch (IOException e) {
- // ignore
+ synchronized (NdefPushServer.this) {
+ if (mServerSocket != null) {
+ if (DBG) Log.d(TAG, "about to close");
+ try {
+ mServerSocket.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ mServerSocket = null;
}
- mServerSocket = null;
}
}
+
+ synchronized (NdefPushServer.this) {
+ threadRunning = mRunning;
+ }
}
}
public void shutdown() {
- mRunning = false;
- if (mServerSocket != null) {
- try {
- mServerSocket.close();
- } catch (IOException e) {
- // ignore
+ synchronized (NdefPushServer.this) {
+ mRunning = false;
+ if (mServerSocket != null) {
+ try {
+ mServerSocket.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ mServerSocket = null;
}
- mServerSocket = null;
}
}
}
diff --git a/src/com/android/nfc/snep/SnepClient.java b/src/com/android/nfc/snep/SnepClient.java
index 8dca6ae..fae8143 100644
--- a/src/com/android/nfc/snep/SnepClient.java
+++ b/src/com/android/nfc/snep/SnepClient.java
@@ -29,7 +29,8 @@ public final class SnepClient {
private static final String TAG = "SnepClient";
private static final boolean DBG = false;
private static final int DEFAULT_ACCEPTABLE_LENGTH = 100*1024;
- private static final int MIU = 128;
+ private static final int DEFAULT_MIU = 128;
+ private static final int DEFAULT_RWSIZE = 1;
SnepMessenger mMessenger = null;
private final Object mTransmissionLock = new Object();
@@ -38,6 +39,8 @@ public final class SnepClient {
private int mState = DISCONNECTED;
private final int mAcceptableLength;
private final int mFragmentLength;
+ private final int mMiu;
+ private final int mRwSize;
private static final int DISCONNECTED = 0;
private static final int CONNECTING = 1;
@@ -48,6 +51,8 @@ public final class SnepClient {
mPort = SnepServer.DEFAULT_PORT;
mAcceptableLength = DEFAULT_ACCEPTABLE_LENGTH;
mFragmentLength = -1;
+ mMiu = DEFAULT_MIU;
+ mRwSize = DEFAULT_RWSIZE;
}
public SnepClient(String serviceName) {
@@ -55,6 +60,17 @@ public final class SnepClient {
mPort = -1;
mAcceptableLength = DEFAULT_ACCEPTABLE_LENGTH;
mFragmentLength = -1;
+ mMiu = DEFAULT_MIU;
+ mRwSize = DEFAULT_RWSIZE;
+ }
+
+ public SnepClient(int miu, int rwSize) {
+ mServiceName = SnepServer.DEFAULT_SERVICE_NAME;
+ mPort = SnepServer.DEFAULT_PORT;
+ mAcceptableLength = DEFAULT_ACCEPTABLE_LENGTH;
+ mFragmentLength = -1;
+ mMiu = miu;
+ mRwSize = rwSize;
}
SnepClient(String serviceName, int fragmentLength) {
@@ -62,6 +78,8 @@ public final class SnepClient {
mPort = -1;
mAcceptableLength = DEFAULT_ACCEPTABLE_LENGTH;
mFragmentLength = fragmentLength;
+ mMiu = DEFAULT_MIU;
+ mRwSize = DEFAULT_RWSIZE;
}
SnepClient(String serviceName, int acceptableLength, int fragmentLength) {
@@ -69,6 +87,8 @@ public final class SnepClient {
mPort = -1;
mAcceptableLength = acceptableLength;
mFragmentLength = fragmentLength;
+ mMiu = DEFAULT_MIU;
+ mRwSize = DEFAULT_RWSIZE;
}
public void put(NdefMessage msg) throws IOException {
@@ -122,7 +142,7 @@ public final class SnepClient {
try {
if (DBG) Log.d(TAG, "about to create socket");
// Connect to the snep server on the remote side
- socket = NfcService.getInstance().createLlcpSocket(0, MIU, 1, 1024);
+ socket = NfcService.getInstance().createLlcpSocket(0, mMiu, mRwSize, 1024);
if (socket == null) {
throw new IOException("Could not connect to socket.");
}
diff --git a/src/com/android/nfc/snep/SnepServer.java b/src/com/android/nfc/snep/SnepServer.java
index 84bb673..aa7da48 100644
--- a/src/com/android/nfc/snep/SnepServer.java
+++ b/src/com/android/nfc/snep/SnepServer.java
@@ -34,9 +34,10 @@ import java.io.IOException;
public final class SnepServer {
private static final String TAG = "SnepServer";
private static final boolean DBG = false;
+ private static final int DEFAULT_MIU = 248;
+ private static final int DEFAULT_RW_SIZE = 1;
public static final int DEFAULT_PORT = 4;
- private static final int MIU = 248;
public static final String DEFAULT_SERVICE_NAME = "urn:nfc:sn:snep";
@@ -44,6 +45,8 @@ public final class SnepServer {
final String mServiceName;
final int mServiceSap;
final int mFragmentLength;
+ final int mMiu;
+ final int mRwSize;
/** Protected by 'this', null when stopped, non-null when running */
ServerThread mServerThread = null;
@@ -59,6 +62,8 @@ public final class SnepServer {
mServiceName = DEFAULT_SERVICE_NAME;
mServiceSap = DEFAULT_PORT;
mFragmentLength = -1;
+ mMiu = DEFAULT_MIU;
+ mRwSize = DEFAULT_RW_SIZE;
}
public SnepServer(String serviceName, int serviceSap, Callback callback) {
@@ -66,6 +71,17 @@ public final class SnepServer {
mServiceName = serviceName;
mServiceSap = serviceSap;
mFragmentLength = -1;
+ mMiu = DEFAULT_MIU;
+ mRwSize = DEFAULT_RW_SIZE;
+ }
+
+ public SnepServer(Callback callback, int miu, int rwSize) {
+ mCallback = callback;
+ mServiceName = DEFAULT_SERVICE_NAME;
+ mServiceSap = DEFAULT_PORT;
+ mFragmentLength = -1;
+ mMiu = miu;
+ mRwSize = rwSize;
}
SnepServer(String serviceName, int serviceSap, int fragmentLength, Callback callback) {
@@ -73,6 +89,8 @@ public final class SnepServer {
mServiceName = serviceName;
mServiceSap = serviceSap;
mFragmentLength = fragmentLength;
+ mMiu = DEFAULT_MIU;
+ mRwSize = DEFAULT_RW_SIZE;
}
/** Connection class, used to handle incoming connections */
@@ -168,7 +186,7 @@ public final class SnepServer {
try {
synchronized (SnepServer.this) {
mServerSocket = NfcService.getInstance().createLlcpServerSocket(mServiceSap,
- mServiceName, MIU, 1, 1024);
+ mServiceName, mMiu, mRwSize, 1024);
}
if (mServerSocket == null) {
if (DBG) Log.d(TAG, "failed to create LLCP service socket");