Snapshot 1a6bcf3cca90fedfbad33c1cdd6d05af5774fc01

Change-Id: I3ccb25bf7cde2c22f52260cae0e9957517e6bb5f
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_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 @@
 
 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 @@
     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 @@
     }
 
     @Override
+    public String getName() {
+        return DRIVER_NAME;
+    }
+
+    @Override
     public native void enableDiscovery();
 
     @Override
@@ -305,11 +329,32 @@
         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 @@
     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 @@
 
     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 @@
                         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 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 boolean deinitialize();
 
+    public String getName();
+
     public void enableDiscovery();
 
     public void disableDiscovery();
@@ -216,5 +228,13 @@
 
     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 @@
             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.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.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.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 @@
     final Context mContext;
     final IActivityManager mIActivityManager;
     final RegisteredComponentCache mTechListFilters;
-    final PackageManager mPackageManager;
     final ContentResolver mContentResolver;
     final HandoverManager mHandoverManager;
 
@@ -72,7 +74,6 @@
         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 @@
             // 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 @@
         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 @@
         // 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 @@
         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 @@
             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.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.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 @@
     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 @@
     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 @@
     /** 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 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 @@
 
     // 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 @@
     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 @@
             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 @@
     }
 
     @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 @@
         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 @@
 
         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);
 
-        mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "NfcService");
-        mKeyguard = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
+        mRoutingWakeLock = mPowerManager.newWakeLock(
+            PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mRoutingWakeLock");
+        mEeWakeLock = mPowerManager.newWakeLock(
+            PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mEeWakeLock");
+
+        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 @@
         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 @@
     }
 
     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 @@
         }
     }
 
+    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 @@
             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 @@
              * 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 @@
             // 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 @@
 
         void executeEeWipe() {
             // TODO: read SE reset list from /system/etc
-            byte[][]apdus = EE_WIPE_APDUS;
+            byte[][]apdus = mDeviceHost.getWipeApdus();
 
-            boolean tempEnable = mState == NfcAdapter.STATE_OFF;
-            if (tempEnable) {
-                if (!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();
-                }
+            if (apdus == null) {
+                Log.d(TAG, "No wipe APDUs found");
                 return;
             }
 
-            mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 10000);
-
-            for (byte[] cmd : apdus) {
-                byte[] resp = mSecureElement.doTransceive(handle, cmd);
-                if (resp == null) {
-                    Log.w(TAG, "Transceive failed, could not wipe NFC-EE");
-                    break;
+            boolean tempEnable = mState == NfcAdapter.STATE_OFF;
+            // 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;
                 }
-            }
+                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
+                        }
 
-            mDeviceHost.resetTimeouts();
-            mSecureElement.doDisconnect(handle);
-
-            if (tempEnable) {
-                disableInternal();
+                        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();
             }
+            Log.i(TAG, "SE wipe done");
         }
 
         void updateState(int newState) {
@@ -631,7 +723,7 @@
                 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 @@
         }
     }
 
-    @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 @@
                 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 @@
 
             binder.unlinkToDeath(mOpenEe, 0);
             mDeviceHost.resetTimeouts();
-            mSecureElement.doDisconnect(mOpenEe.handle);
+            doDisconnect(mOpenEe.handle);
             mOpenEe = null;
 
             applyRouting(true);
@@ -1244,11 +1326,11 @@
                     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 @@
 
                 // 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 @@
                 }
             }
 
-            return mSecureElement.doTransceive(mOpenEe.handle, data);
+            return doTransceive(mOpenEe.handle, data);
         }
 
         @Override
@@ -1321,13 +1403,28 @@
         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 @@
 
     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 @@
                 // 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 @@
                     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 @@
                 }
                 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 @@
                         }
                     }
                 }
+            } 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 @@
     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 @@
     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 @@
         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 @@
 
             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 @@
     }
 
     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 @@
 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.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 @@
         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 @@
     }
 
     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 @@
         }
     }
 
-    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 @@
         // 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 @@
                 | 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 @@
         // 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 @@
         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.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 @@
  * 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 @@
 
     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 @@
     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 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 @@
 
         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,49 +141,19 @@
      * 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() {
-        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 (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
-                    break;
-                }
-                if (mA2dpResult == RESULT_DISCONNECTED && mHfpResult == RESULT_DISCONNECTED) {
-                    toast(mContext.getString(R.string.disconnected_headset) + " " + mName);
-                }
-                complete(false);
-                break;
-        }
-    }
-
-    void nextStepConnect() {
+    /*
+     * Enables bluetooth and gets the profile proxies
+     */
+    void nextStepInit() {
         switch (mState) {
             case STATE_INIT:
                 if (!mHandoverPowerManager.isBluetoothEnabled()) {
@@ -195,9 +168,87 @@
                 }
                 // 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
+                    break;
+                }
+                if (mA2dpResult == RESULT_DISCONNECTED && mHfpResult == RESULT_DISCONNECTED) {
+                    toast(mContext.getString(R.string.disconnected_headset) + " " + mName);
+                }
+                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_COMPLETE:
                 if (mDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
                     requestPairConfirmation();
                     mState = STATE_WAITING_FOR_BOND_CONFIRMATION;
+
                     break;
                 }
                 // fall-through
@@ -211,21 +262,23 @@
                 // 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 @@
         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 @@
         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 @@
         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 @@
 
         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 @@
                     Log.i(TAG, "Timeout completing BT handover");
                     complete(false);
                     break;
+                case MSG_NEXT_STEP:
+                    nextStep();
+                    break;
             }
         }
     };
@@ -364,4 +430,29 @@
             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.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.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 @@
 /**
  * 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 @@
     // 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 @@
                 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 @@
                 return;
             }
 
-            mNotificationManager.notify(mNotificationId, notBuilder.build());
+            mNotificationManager.notifyAsUser(null, mNotificationId, notBuilder.build(),
+                    UserHandle.CURRENT);
         }
 
         synchronized void updateStateAndNotification(int newState) {
@@ -537,7 +534,7 @@
             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 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 @@
         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 @@
                 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 @@
     }
 
     @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 @@
 
     /** 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 @@
                 } 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 @@
     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 @@
     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 @@
         mPort = SnepServer.DEFAULT_PORT;
         mAcceptableLength = DEFAULT_ACCEPTABLE_LENGTH;
         mFragmentLength = -1;
+        mMiu = DEFAULT_MIU;
+        mRwSize = DEFAULT_RWSIZE;
     }
 
     public SnepClient(String serviceName) {
@@ -55,6 +60,17 @@
         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 @@
         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 @@
         mPort = -1;
         mAcceptableLength = acceptableLength;
         mFragmentLength = fragmentLength;
+        mMiu = DEFAULT_MIU;
+        mRwSize = DEFAULT_RWSIZE;
     }
 
     public void put(NdefMessage msg) throws IOException {
@@ -122,7 +142,7 @@
         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 @@
 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 @@
     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 @@
         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 @@
         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 @@
         mServiceName = serviceName;
         mServiceSap = serviceSap;
         mFragmentLength = fragmentLength;
+        mMiu = DEFAULT_MIU;
+        mRwSize = DEFAULT_RW_SIZE;
     }
 
     /** Connection class, used to handle incoming connections */
@@ -168,7 +186,7 @@
                 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");