Merge "Allow foreground override in provision mode."
diff --git a/nci/jni/Android.mk b/nci/jni/Android.mk
index 1e33ca6..e386861 100644
--- a/nci/jni/Android.mk
+++ b/nci/jni/Android.mk
@@ -10,7 +10,7 @@
LOCAL_CFLAGS += -DNCI_VERSION=$(NCI_VERSION) -O0 -g
endif
-LOCAL_CFLAGS += -Wall -Wextra
+LOCAL_CFLAGS += -Wall -Wextra -Wno-unused-parameter -Werror
LOCAL_SRC_FILES := $(call all-subdir-cpp-files) $(call all-subdir-c-files)
diff --git a/nci/jni/NativeLlcpConnectionlessSocket.cpp b/nci/jni/NativeLlcpConnectionlessSocket.cpp
index fb0b96d..b877acb 100644
--- a/nci/jni/NativeLlcpConnectionlessSocket.cpp
+++ b/nci/jni/NativeLlcpConnectionlessSocket.cpp
@@ -74,7 +74,7 @@
}
size_t byte_count = bytes.size();
- ALOGD("NFA_P2pSendUI: len = %d", byte_count);
+ ALOGD("NFA_P2pSendUI: len = %zu", byte_count);
UINT8* raw_ptr = const_cast<UINT8*>(reinterpret_cast<const UINT8*>(&bytes[0])); // TODO: API bug; NFA_P2pSendUI should take const*!
tNFA_STATUS status = NFA_P2pSendUI((tNFA_HANDLE) handle, nsap, byte_count, raw_ptr);
diff --git a/nci/jni/NativeNfcManager.cpp b/nci/jni/NativeNfcManager.cpp
index e42ddb5..4f0b427 100755
--- a/nci/jni/NativeNfcManager.cpp
+++ b/nci/jni/NativeNfcManager.cpp
@@ -109,10 +109,6 @@
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()
@@ -128,6 +124,8 @@
static bool sP2pEnabled = false;
static bool sP2pActive = false; // whether p2p was last active
static bool sAbortConnlessWait = false;
+static jint sLfT3tMax = 0;
+
#define CONFIG_UPDATE_TECH_MASK (1 << 1)
#define DEFAULT_TECH_MASK (NFA_TECHNOLOGY_MASK_A \
| NFA_TECHNOLOGY_MASK_B \
@@ -575,13 +573,13 @@
"notifyLlcpLinkFirstPacketReceived", "(Lcom/android/nfc/dhimpl/NativeP2pDevice;)V");
gCachedNfcManagerNotifyHostEmuActivated = e->GetMethodID(cls.get(),
- "notifyHostEmuActivated", "()V");
+ "notifyHostEmuActivated", "(I)V");
gCachedNfcManagerNotifyHostEmuData = e->GetMethodID(cls.get(),
- "notifyHostEmuData", "([B)V");
+ "notifyHostEmuData", "(I[B)V");
gCachedNfcManagerNotifyHostEmuDeactivated = e->GetMethodID(cls.get(),
- "notifyHostEmuDeactivated", "()V");
+ "notifyHostEmuDeactivated", "(I)V");
gCachedNfcManagerNotifyRfFieldActivated = e->GetMethodID(cls.get(),
"notifyRfFieldActivated", "()V");
@@ -830,6 +828,74 @@
/*******************************************************************************
**
+** Function: nfcManager_doRegisterT3tIdentifier
+**
+** Description: Registers LF_T3T_IDENTIFIER for NFC-F.
+** e: JVM environment.
+** o: Java object.
+** t3tIdentifier: LF_T3T_IDENTIFIER value (10 or 18 bytes)
+**
+** Returns: Handle retrieve from RoutingManager.
+**
+*******************************************************************************/
+static jint nfcManager_doRegisterT3tIdentifier(JNIEnv* e, jobject, jbyteArray t3tIdentifier)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+
+ ScopedByteArrayRO bytes(e, t3tIdentifier);
+ uint8_t* buf = const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(&bytes[0]));
+ size_t bufLen = bytes.size();
+ int handle = RoutingManager::getInstance().registerT3tIdentifier(buf, bufLen);
+
+ ALOGD ("%s: handle=%d", __FUNCTION__, handle);
+ ALOGD ("%s: exit", __FUNCTION__);
+
+ return handle;
+}
+
+/*******************************************************************************
+**
+** Function: nfcManager_doDeregisterT3tIdentifier
+**
+** Description: Deregisters LF_T3T_IDENTIFIER for NFC-F.
+** e: JVM environment.
+** o: Java object.
+** handle: Handle retrieve from libnfc-nci.
+**
+** Returns: None
+**
+*******************************************************************************/
+static void nfcManager_doDeregisterT3tIdentifier(JNIEnv*, jobject, jint handle)
+{
+ ALOGD ("%s: enter; handle=%d", __FUNCTION__, handle);
+
+ RoutingManager::getInstance().deregisterT3tIdentifier(handle);
+
+ ALOGD ("%s: exit", __FUNCTION__);
+}
+
+/*******************************************************************************
+**
+** Function: nfcManager_getLfT3tMax
+**
+** Description: Returns LF_T3T_MAX value.
+** e: JVM environment.
+** o: Java object.
+**
+** Returns: LF_T3T_MAX value.
+**
+*******************************************************************************/
+static jint nfcManager_getLfT3tMax(JNIEnv*, jobject)
+{
+ ALOGD ("%s: enter", __FUNCTION__);
+ ALOGD ("LF_T3T_MAX=%d", sLfT3tMax);
+ ALOGD ("%s: exit", __FUNCTION__);
+
+ return sLfT3tMax;
+}
+
+/*******************************************************************************
+**
** Function: nfcManager_doInitialize
**
** Description: Turn on NFC.
@@ -915,6 +981,21 @@
NFA_SetRfDiscoveryDuration(nat->discovery_duration);
+ // get LF_T3T_MAX
+ {
+ SyncEventGuard guard (sNfaGetConfigEvent);
+ tNFA_PMID configParam[1] = {NCI_PARAM_ID_LF_T3T_MAX};
+ stat = NFA_GetConfig(1, configParam);
+ if (stat == NFA_STATUS_OK)
+ {
+ sNfaGetConfigEvent.wait ();
+ if (sCurrentConfigLen >= 4 || sConfig[1] == NCI_PARAM_ID_LF_T3T_MAX) {
+ ALOGD("%s: lfT3tMax=%d", __FUNCTION__, sConfig[3]);
+ sLfT3tMax = sConfig[3];
+ }
+ }
+ }
+
// Do custom NFCA startup configuration.
doStartupConfig();
goto TheEnd;
@@ -972,8 +1053,6 @@
return;
}
- tNFA_STATUS stat = NFA_STATUS_OK;
-
PowerSwitch::getInstance ().setLevel (PowerSwitch::FULL_POWER);
if (sRfEnabled) {
@@ -1271,6 +1350,7 @@
sIsDisabling = false;
sP2pEnabled = false;
gActivated = false;
+ sLfT3tMax = 0;
{
//unblock NFA_EnablePolling() and NFA_DisablePolling()
@@ -1650,6 +1730,15 @@
{"commitRouting", "()Z",
(void*) nfcManager_commitRouting},
+ {"doRegisterT3tIdentifier", "([B)I",
+ (void*) nfcManager_doRegisterT3tIdentifier},
+
+ {"doDeregisterT3tIdentifier", "(I)V",
+ (void*) nfcManager_doDeregisterT3tIdentifier},
+
+ {"getLfT3tMax", "()I",
+ (void*) nfcManager_getLfT3tMax},
+
{"doEnableDiscovery", "(IZZZZZ)V",
(void*) nfcManager_enableDiscovery},
diff --git a/nci/jni/NativeNfcTag.cpp b/nci/jni/NativeNfcTag.cpp
index a25c3d7..5ebc561 100755
--- a/nci/jni/NativeNfcTag.cpp
+++ b/nci/jni/NativeNfcTag.cpp
@@ -994,7 +994,7 @@
break;
}
- ALOGD ("%s: response %d bytes", __FUNCTION__, sRxDataBuffer.size());
+ ALOGD ("%s: response %zu bytes", __FUNCTION__, sRxDataBuffer.size());
if ((natTag.getProtocol () == NFA_PROTOCOL_T2T) &&
natTag.isT2tNackResponse (sRxDataBuffer.data(), sRxDataBuffer.size()))
diff --git a/nci/jni/PeerToPeer.cpp b/nci/jni/PeerToPeer.cpp
index da4cf30..8074f69 100644
--- a/nci/jni/PeerToPeer.cpp
+++ b/nci/jni/PeerToPeer.cpp
@@ -1709,7 +1709,7 @@
if (maxInfoUnit > (int)LLCP_MIU)
{
- ALOGD ("%s: overriding the miu passed by the app(%d) with stack miu(%d)", fn, maxInfoUnit, LLCP_MIU);
+ ALOGD ("%s: overriding the miu passed by the app(%d) with stack miu(%zu)", fn, maxInfoUnit, LLCP_MIU);
maxInfoUnit = LLCP_MIU;
}
diff --git a/nci/jni/RouteDataSet.cpp b/nci/jni/RouteDataSet.cpp
index 9935d88..bb259b3 100644
--- a/nci/jni/RouteDataSet.cpp
+++ b/nci/jni/RouteDataSet.cpp
@@ -140,7 +140,7 @@
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());
+ ALOGD ("%s: default db size=%zu; sec elem db size=%zu", fn, mDefaultRouteDatabase.size(), mSecElemRouteDatabase.size());
Database::iterator it;
for (it = mDefaultRouteDatabase.begin(); it != mDefaultRouteDatabase.end(); it++)
@@ -266,7 +266,7 @@
actualWritten = fwrite (routesXml, sizeof(char), strlen(routesXml), fh);
retval = actualWritten == strlen(routesXml);
fclose (fh);
- ALOGD ("%s: wrote %u bytes", fn, actualWritten);
+ ALOGD ("%s: wrote %zu bytes", fn, actualWritten);
if (retval == false)
ALOGE ("%s: error during write", fn);
@@ -313,7 +313,7 @@
routesXml.append (buffer, actual);
}
fclose (fh);
- ALOGD ("%s: read %u bytes", fn, routesXml.length());
+ ALOGD ("%s: read %zu bytes", fn, routesXml.length());
return true;
}
diff --git a/nci/jni/RoutingManager.cpp b/nci/jni/RoutingManager.cpp
old mode 100644
new mode 100755
index c0827ca..6a8a452
--- a/nci/jni/RoutingManager.cpp
+++ b/nci/jni/RoutingManager.cpp
@@ -54,6 +54,13 @@
else
mActiveSe = 0x00;
+ // Get the active SE for Nfc-F
+ if (GetNumValue("ACTIVE_SE_NFCF", &num, sizeof(num)))
+ mActiveSeNfcF = num;
+ else
+ mActiveSeNfcF = 0x00;
+ ALOGD("%s: Active SE for Nfc-F is 0x%02X", fn, mActiveSeNfcF);
+
// Get the "default" route
if (GetNumValue("DEFAULT_ISODEP_ROUTE", &num, sizeof(num)))
mDefaultEe = num;
@@ -61,6 +68,13 @@
mDefaultEe = 0x00;
ALOGD("%s: default route is 0x%02X", fn, mDefaultEe);
+ // Get the "default" route for Nfc-F
+ if (GetNumValue("DEFAULT_NFCF_ROUTE", &num, sizeof(num)))
+ mDefaultEeNfcF = num;
+ else
+ mDefaultEeNfcF = 0x00;
+ ALOGD("%s: default route for Nfc-F is 0x%02X", fn, mDefaultEeNfcF);
+
// Get the default "off-host" route. This is hard-coded at the Java layer
// but we can override it here to avoid forcing Java changes.
if (GetNumValue("DEFAULT_OFFHOST_ROUTE", &num, sizeof(num)))
@@ -78,6 +92,8 @@
memset (&mEeInfo, 0, sizeof(mEeInfo));
mReceivedEeInfo = false;
mSeTechMask = 0x00;
+
+ mNfcFOnDhHandle = NFA_HANDLE_INVALID;
}
RoutingManager::~RoutingManager ()
@@ -105,7 +121,9 @@
mRxDataBuffer.clear ();
- if (mActiveSe != 0) {
+ if ((mActiveSe != 0) || (mActiveSeNfcF != 0))
+ {
+ ALOGD ("%s: Technology Routing (NfcASe:0x%02x, NfcFSe:0x%02x)", fn, mActiveSe, mActiveSeNfcF);
{
// Wait for EE info if needed
SyncEventGuard guard (mEeInfoEvent);
@@ -115,31 +133,46 @@
mEeInfoEvent.wait();
}
}
+
+ ALOGD ("%s: Number of EE is %d", fn, mEeInfo.num_ee);
for (UINT8 i = 0; i < mEeInfo.num_ee; i++)
{
- ALOGD ("%s EE[%u] Handle: 0x%04x techA: 0x%02x techB: 0x%02x techF: 0x%02x techBprime: 0x%02x",
- fn, i, mEeInfo.ee_disc_info[i].ee_handle,
- mEeInfo.ee_disc_info[i].la_protocol,
- mEeInfo.ee_disc_info[i].lb_protocol,
- mEeInfo.ee_disc_info[i].lf_protocol,
- mEeInfo.ee_disc_info[i].lbp_protocol);
- if (mEeInfo.ee_disc_info[i].ee_handle == (mActiveSe | NFA_HANDLE_GROUP_EE))
- {
- if (mEeInfo.ee_disc_info[i].la_protocol != 0) mSeTechMask |= NFA_TECHNOLOGY_MASK_A;
+ tNFA_HANDLE eeHandle = mEeInfo.ee_disc_info[i].ee_handle;
+ tNFA_TECHNOLOGY_MASK seTechMask = 0;
- if (mSeTechMask != 0x00)
- {
- ALOGD("Configuring tech mask 0x%02x on EE 0x%04x", mSeTechMask, mEeInfo.ee_disc_info[i].ee_handle);
- nfaStat = NFA_CeConfigureUiccListenTech(mEeInfo.ee_disc_info[i].ee_handle, mSeTechMask);
- if (nfaStat != NFA_STATUS_OK)
- ALOGE ("Failed to configure UICC listen technologies.");
- // Set technology routes to UICC if it's there
- nfaStat = NFA_EeSetDefaultTechRouting(mEeInfo.ee_disc_info[i].ee_handle, mSeTechMask, mSeTechMask,
- mSeTechMask);
- if (nfaStat != NFA_STATUS_OK)
- ALOGE ("Failed to configure UICC technology routing.");
- }
- }
+ ALOGD ("%s EE[%u] Handle: 0x%04x techA: 0x%02x techB: 0x%02x techF: 0x%02x techBprime: 0x%02x",
+ fn, i, eeHandle,
+ mEeInfo.ee_disc_info[i].la_protocol,
+ mEeInfo.ee_disc_info[i].lb_protocol,
+ mEeInfo.ee_disc_info[i].lf_protocol,
+ mEeInfo.ee_disc_info[i].lbp_protocol);
+ if ((mActiveSe != 0) && (eeHandle == (mActiveSe | NFA_HANDLE_GROUP_EE)))
+ {
+ if (mEeInfo.ee_disc_info[i].la_protocol != 0)
+ seTechMask |= NFA_TECHNOLOGY_MASK_A;
+ }
+ if ((mActiveSeNfcF != 0) && (eeHandle == (mActiveSeNfcF | NFA_HANDLE_GROUP_EE)))
+ {
+ if (mEeInfo.ee_disc_info[i].lf_protocol != 0)
+ seTechMask |= NFA_TECHNOLOGY_MASK_F;
+ }
+
+ ALOGD ("%s: seTechMask[%u]=0x%02x", fn, i, seTechMask);
+ if (seTechMask != 0x00)
+ {
+ ALOGD("Configuring tech mask 0x%02x on EE 0x%04x", seTechMask, eeHandle);
+
+ nfaStat = NFA_CeConfigureUiccListenTech(eeHandle, seTechMask);
+ if (nfaStat != NFA_STATUS_OK)
+ ALOGE ("Failed to configure UICC listen technologies.");
+
+ // Set technology routes to UICC if it's there
+ nfaStat = NFA_EeSetDefaultTechRouting(eeHandle, seTechMask, seTechMask, seTechMask);
+ if (nfaStat != NFA_STATUS_OK)
+ ALOGE ("Failed to configure UICC technology routing.");
+
+ mSeTechMask |= seTechMask;
+ }
}
}
@@ -165,51 +198,130 @@
void RoutingManager::enableRoutingToHost()
{
tNFA_STATUS nfaStat;
+ tNFA_TECHNOLOGY_MASK techMask;
+ tNFA_PROTOCOL_MASK protoMask;
+ SyncEventGuard guard (mRoutingEvent);
+ // Set default routing at one time when the NFCEE IDs for Nfc-A and Nfc-F are same
+ if (mDefaultEe == mDefaultEeNfcF)
{
- SyncEventGuard guard (mRoutingEvent);
-
- // Route Nfc-A to host if we don't have a SE
- if (mSeTechMask == 0)
+ // Route Nfc-A/Nfc-F to host if we don't have a SE
+ techMask = (mSeTechMask ^ (NFA_TECHNOLOGY_MASK_A | NFA_TECHNOLOGY_MASK_F));
+ if (techMask != 0)
{
- nfaStat = NFA_EeSetDefaultTechRouting (mDefaultEe, NFA_TECHNOLOGY_MASK_A, 0, 0);
+ nfaStat = NFA_EeSetDefaultTechRouting (mDefaultEe, techMask, 0, 0);
if (nfaStat == NFA_STATUS_OK)
mRoutingEvent.wait ();
else
- ALOGE ("Fail to set default tech routing");
+ ALOGE ("Fail to set default tech routing for Nfc-A/Nfc-F");
}
-
- // Default routing for IsoDep protocol
- nfaStat = NFA_EeSetDefaultProtoRouting(mDefaultEe, NFA_PROTOCOL_MASK_ISO_DEP, 0, 0);
+ // Default routing for IsoDep and T3T protocol
+ protoMask = (NFA_PROTOCOL_MASK_ISO_DEP | NFA_PROTOCOL_MASK_T3T);
+ nfaStat = NFA_EeSetDefaultProtoRouting(mDefaultEe, protoMask, 0, 0);
if (nfaStat == NFA_STATUS_OK)
mRoutingEvent.wait ();
else
- ALOGE ("Fail to set default proto routing");
+ ALOGE ("Fail to set default proto routing for IsoDep and T3T");
+ }
+ else
+ {
+ // Route Nfc-A to host if we don't have a SE
+ techMask = NFA_TECHNOLOGY_MASK_A;
+ if ((mSeTechMask & NFA_TECHNOLOGY_MASK_A) == 0)
+ {
+ nfaStat = NFA_EeSetDefaultTechRouting (mDefaultEe, techMask, 0, 0);
+ if (nfaStat == NFA_STATUS_OK)
+ mRoutingEvent.wait ();
+ else
+ ALOGE ("Fail to set default tech routing for Nfc-A");
+ }
+ // Default routing for IsoDep protocol
+ protoMask = NFA_PROTOCOL_MASK_ISO_DEP;
+ nfaStat = NFA_EeSetDefaultProtoRouting(mDefaultEe, protoMask, 0, 0);
+ if (nfaStat == NFA_STATUS_OK)
+ mRoutingEvent.wait ();
+ else
+ ALOGE ("Fail to set default proto routing for IsoDep");
+
+ // Route Nfc-F to host if we don't have a SE
+ techMask = NFA_TECHNOLOGY_MASK_F;
+ if ((mSeTechMask & NFA_TECHNOLOGY_MASK_F) == 0)
+ {
+ nfaStat = NFA_EeSetDefaultTechRouting (mDefaultEeNfcF, techMask, 0, 0);
+ if (nfaStat == NFA_STATUS_OK)
+ mRoutingEvent.wait ();
+ else
+ ALOGE ("Fail to set default tech routing for Nfc-F");
+ }
+ // Default routing for T3T protocol
+ protoMask = NFA_PROTOCOL_MASK_T3T;
+ nfaStat = NFA_EeSetDefaultProtoRouting(mDefaultEeNfcF, protoMask, 0, 0);
+ if (nfaStat == NFA_STATUS_OK)
+ mRoutingEvent.wait ();
+ else
+ ALOGE ("Fail to set default proto routing for T3T");
}
}
void RoutingManager::disableRoutingToHost()
{
tNFA_STATUS nfaStat;
+ tNFA_TECHNOLOGY_MASK techMask;
+ SyncEventGuard guard (mRoutingEvent);
+ // Set default routing at one time when the NFCEE IDs for Nfc-A and Nfc-F are same
+ if (mDefaultEe == mDefaultEeNfcF)
{
- SyncEventGuard guard (mRoutingEvent);
- // Default routing for NFC-A technology if we don't have a SE
- if (mSeTechMask == 0)
+ // Default routing for Nfc-A/Nfc-F technology if we don't have a SE
+ techMask = (mSeTechMask ^ (NFA_TECHNOLOGY_MASK_A | NFA_TECHNOLOGY_MASK_F));
+ if (techMask != 0)
{
nfaStat = NFA_EeSetDefaultTechRouting (mDefaultEe, 0, 0, 0);
if (nfaStat == NFA_STATUS_OK)
mRoutingEvent.wait ();
else
- ALOGE ("Fail to set default tech routing");
+ ALOGE ("Fail to set default tech routing for Nfc-A/Nfc-F");
}
-
+ // Default routing for IsoDep and T3T protocol
+ nfaStat = NFA_EeSetDefaultProtoRouting(mDefaultEe, 0, 0, 0);
+ if (nfaStat == NFA_STATUS_OK)
+ mRoutingEvent.wait ();
+ else
+ ALOGE ("Fail to set default proto routing for IsoDep and T3T");
+ }
+ else
+ {
+ // Default routing for Nfc-A technology if we don't have a SE
+ if ((mSeTechMask & NFA_TECHNOLOGY_MASK_A) == 0)
+ {
+ nfaStat = NFA_EeSetDefaultTechRouting (mDefaultEe, 0, 0, 0);
+ if (nfaStat == NFA_STATUS_OK)
+ mRoutingEvent.wait ();
+ else
+ ALOGE ("Fail to set default tech routing for Nfc-A");
+ }
// Default routing for IsoDep protocol
nfaStat = NFA_EeSetDefaultProtoRouting(mDefaultEe, 0, 0, 0);
if (nfaStat == NFA_STATUS_OK)
mRoutingEvent.wait ();
else
- ALOGE ("Fail to set default proto routing");
+ ALOGE ("Fail to set default proto routing for IsoDep");
+
+ // Default routing for Nfc-F technology if we don't have a SE
+ if ((mSeTechMask & NFA_TECHNOLOGY_MASK_F) == 0)
+ {
+ nfaStat = NFA_EeSetDefaultTechRouting (mDefaultEeNfcF, 0, 0, 0);
+ if (nfaStat == NFA_STATUS_OK)
+ mRoutingEvent.wait ();
+ else
+ ALOGE ("Fail to set default tech routing for Nfc-F");
+ }
+ // Default routing for T3T protocol
+ nfaStat = NFA_EeSetDefaultProtoRouting(mDefaultEeNfcF, 0, 0, 0);
+ if (nfaStat == NFA_STATUS_OK)
+ mRoutingEvent.wait ();
+ else
+ ALOGE ("Fail to set default proto routing for T3T");
}
}
@@ -303,7 +415,7 @@
}
}
-void RoutingManager::notifyActivated ()
+void RoutingManager::notifyActivated (UINT8 technology)
{
JNIEnv* e = NULL;
ScopedAttach attach(mNativeData->vm, &e);
@@ -313,7 +425,7 @@
return;
}
- e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifyHostEmuActivated);
+ e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifyHostEmuActivated, (int)technology);
if (e->ExceptionCheck())
{
e->ExceptionClear();
@@ -321,7 +433,7 @@
}
}
-void RoutingManager::notifyDeactivated ()
+void RoutingManager::notifyDeactivated (UINT8 technology)
{
mRxDataBuffer.clear();
JNIEnv* e = NULL;
@@ -332,7 +444,7 @@
return;
}
- e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifyHostEmuDeactivated);
+ e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifyHostEmuDeactivated, (int)technology);
if (e->ExceptionCheck())
{
e->ExceptionClear();
@@ -340,7 +452,7 @@
}
}
-void RoutingManager::handleData (const UINT8* data, UINT32 dataLen, tNFA_STATUS status)
+void RoutingManager::handleData (UINT8 technology, const UINT8* data, UINT32 dataLen, tNFA_STATUS status)
{
if (dataLen <= 0)
{
@@ -389,7 +501,8 @@
goto TheEnd;
}
- e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifyHostEmuData, dataJavaArray.get());
+ e->CallVoidMethod (mNativeData->manager, android::gCachedNfcManagerNotifyHostEmuData,
+ (int)technology, dataJavaArray.get());
if (e->ExceptionCheck())
{
e->ExceptionClear();
@@ -424,7 +537,7 @@
case NFA_CE_ACTIVATED_EVT:
{
- routingManager.notifyActivated();
+ routingManager.notifyActivated(NFA_TECHNOLOGY_MASK_A);
}
break;
@@ -432,7 +545,7 @@
case NFA_CE_DEACTIVATED_EVT:
{
ALOGD("%s: NFA_DEACTIVATED_EVT, NFA_CE_DEACTIVATED_EVT", fn);
- routingManager.notifyDeactivated();
+ routingManager.notifyDeactivated(NFA_TECHNOLOGY_MASK_A);
SyncEventGuard g (gDeactivatedEvent);
gActivated = false; //guard this variable from multi-threaded access
gDeactivatedEvent.notifyOne ();
@@ -443,7 +556,7 @@
{
tNFA_CE_DATA& ce_data = eventData->ce_data;
ALOGD("%s: NFA_CE_DATA_EVT; stat=0x%X; h=0x%X; data len=%u", fn, ce_data.status, ce_data.handle, ce_data.len);
- getInstance().handleData(ce_data.p_data, ce_data.len, ce_data.status);
+ getInstance().handleData(NFA_TECHNOLOGY_MASK_A, ce_data.p_data, ce_data.len, ce_data.status);
}
break;
}
@@ -568,6 +681,113 @@
}
}
+int RoutingManager::registerT3tIdentifier(UINT8* t3tId, UINT8 t3tIdLen)
+{
+ static const char fn [] = "RoutingManager::registerT3tIdentifier";
+
+ ALOGD ("%s: Start to register NFC-F system on DH", fn);
+
+ if (t3tIdLen != (2 + NCI_RF_F_UID_LEN))
+ {
+ ALOGE ("%s: Invalid length of T3T Identifier", fn);
+ return NFA_HANDLE_INVALID;
+ }
+
+ SyncEventGuard guard (mRoutingEvent);
+ mNfcFOnDhHandle = NFA_HANDLE_INVALID;
+
+ int systemCode;
+ UINT8 nfcid2[NCI_RF_F_UID_LEN];
+
+ systemCode = (((int)t3tId[0] << 8) | ((int)t3tId[1] << 0));
+ memcpy(nfcid2, t3tId + 2, NCI_RF_F_UID_LEN);
+
+ tNFA_STATUS nfaStat = NFA_CeRegisterFelicaSystemCodeOnDH (systemCode, nfcid2, nfcFCeCallback);
+ if (nfaStat == NFA_STATUS_OK)
+ {
+ mRoutingEvent.wait ();
+ }
+ else
+ {
+ ALOGE ("%s: Fail to register NFC-F system on DH", fn);
+ return NFA_HANDLE_INVALID;
+ }
+
+ ALOGD ("%s: Succeed to register NFC-F system on DH", fn);
+
+ return mNfcFOnDhHandle;
+}
+
+void RoutingManager::deregisterT3tIdentifier(int handle)
+{
+ static const char fn [] = "RoutingManager::deregisterT3tIdentifier";
+
+ ALOGD ("%s: Start to deregister NFC-F system on DH", fn);
+
+ SyncEventGuard guard (mRoutingEvent);
+ tNFA_STATUS nfaStat = NFA_CeDeregisterFelicaSystemCodeOnDH (handle);
+ if (nfaStat == NFA_STATUS_OK)
+ {
+ mRoutingEvent.wait ();
+ ALOGD ("%s: Succeeded in deregistering NFC-F system on DH", fn);
+ }
+ else
+ {
+ ALOGE ("%s: Fail to deregister NFC-F system on DH", fn);
+ }
+}
+
+void RoutingManager::nfcFCeCallback (UINT8 event, tNFA_CONN_EVT_DATA* eventData)
+{
+ static const char fn [] = "RoutingManager::nfcFCeCallback";
+ RoutingManager& routingManager = RoutingManager::getInstance();
+
+ ALOGD("%s: 0x%x", __FUNCTION__, event);
+
+ switch (event)
+ {
+ case NFA_CE_REGISTERED_EVT:
+ {
+ ALOGD ("%s: registerd event notified", fn);
+ routingManager.mNfcFOnDhHandle = eventData->ce_registered.handle;
+ SyncEventGuard guard(routingManager.mRoutingEvent);
+ routingManager.mRoutingEvent.notifyOne();
+ }
+ break;
+ case NFA_CE_DEREGISTERED_EVT:
+ {
+ ALOGD ("%s: deregisterd event notified", fn);
+ SyncEventGuard guard(routingManager.mRoutingEvent);
+ routingManager.mRoutingEvent.notifyOne();
+ }
+ break;
+ case NFA_CE_ACTIVATED_EVT:
+ {
+ ALOGD ("%s: activated event notified", fn);
+ routingManager.notifyActivated(NFA_TECHNOLOGY_MASK_F);
+ }
+ break;
+ case NFA_CE_DEACTIVATED_EVT:
+ {
+ ALOGD ("%s: deactivated event notified", fn);
+ routingManager.notifyDeactivated(NFA_TECHNOLOGY_MASK_F);
+ }
+ break;
+ case NFA_CE_DATA_EVT:
+ {
+ ALOGD ("%s: data event notified", fn);
+ tNFA_CE_DATA& ce_data = eventData->ce_data;
+ routingManager.handleData(NFA_TECHNOLOGY_MASK_F, ce_data.p_data, ce_data.len, ce_data.status);
+ }
+ break;
+ default:
+ {
+ ALOGE ("%s: unknown event=%u ????", fn, event);
+ }
+ break;
+ }
+}
+
int RoutingManager::registerJniFunctions (JNIEnv* e)
{
static const char fn [] = "RoutingManager::registerJniFunctions";
diff --git a/nci/jni/RoutingManager.h b/nci/jni/RoutingManager.h
old mode 100644
new mode 100755
index ea04066..f6d4639
--- a/nci/jni/RoutingManager.h
+++ b/nci/jni/RoutingManager.h
@@ -38,6 +38,8 @@
bool addAidRouting(const UINT8* aid, UINT8 aidLen, int route);
bool removeAidRouting(const UINT8* aid, UINT8 aidLen);
bool commitRouting();
+ int registerT3tIdentifier(UINT8* t3tId, UINT8 t3tIdLen);
+ void deregisterT3tIdentifier(int handle);
void onNfccShutdown();
int registerJniFunctions (JNIEnv* e);
private:
@@ -46,9 +48,9 @@
RoutingManager(const RoutingManager&);
RoutingManager& operator=(const RoutingManager&);
- void handleData (const UINT8* data, UINT32 dataLen, tNFA_STATUS status);
- void notifyActivated ();
- void notifyDeactivated ();
+ void handleData (UINT8 technology, const UINT8* data, UINT32 dataLen, tNFA_STATUS status);
+ void notifyActivated (UINT8 technology);
+ void notifyDeactivated (UINT8 technology);
// See AidRoutingManager.java for corresponding
// AID_MATCHING_ constants
@@ -62,6 +64,8 @@
static void nfaEeCallback (tNFA_EE_EVT event, tNFA_EE_CBACK_DATA* eventData);
static void stackCallback (UINT8 event, tNFA_CONN_EVT_DATA* eventData);
+ static void nfcFCeCallback (UINT8 event, tNFA_CONN_EVT_DATA* eventData);
+
static int com_android_nfc_cardemulation_doGetDefaultRouteDestination (JNIEnv* e);
static int com_android_nfc_cardemulation_doGetDefaultOffHostRouteDestination (JNIEnv* e);
static int com_android_nfc_cardemulation_doGetAidMatchingMode (JNIEnv* e);
@@ -71,9 +75,12 @@
// Fields below are final after initialize()
nfc_jni_native_data* mNativeData;
int mDefaultEe;
+ int mDefaultEeNfcF;
int mOffHostEe;
int mActiveSe;
+ int mActiveSeNfcF;
int mAidMatchingMode;
+ int mNfcFOnDhHandle;
bool mReceivedEeInfo;
tNFA_EE_DISCOVER_REQ mEeInfo;
tNFA_TECHNOLOGY_MASK mSeTechMask;
diff --git a/nci/jni/extns/pn54x/src/mifare/phFriNfc_MifareStdMap.c b/nci/jni/extns/pn54x/src/mifare/phFriNfc_MifareStdMap.c
index a2291fc..66da24b 100755
--- a/nci/jni/extns/pn54x/src/mifare/phFriNfc_MifareStdMap.c
+++ b/nci/jni/extns/pn54x/src/mifare/phFriNfc_MifareStdMap.c
@@ -2796,8 +2796,8 @@
+ PH_FRINFC_MIFARESTD_VAL2):
PH_FRINFC_MIFARESTD_VAL0);
- if(( NdefMap->SendRecvBuf[TempLength] ==
- PH_FRINFC_MIFARESTD_VAL0))
+ if(NdefMap->SendRecvBuf[TempLength] ==
+ PH_FRINFC_MIFARESTD_VAL0)
{
Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
NFCSTATUS_INVALID_PARAMETER);
@@ -3687,8 +3687,8 @@
{
NdefMap->StdMifareContainer.NFCforumSectFlag =
(((NdefMap->StdMifareContainer.currentBlock == 64) &&
- (NdefMap->CardType == PH_FRINFC_NDEFMAP_MIFARE_STD_4K_CARD)||
- (NdefMap->CardType == PH_FRINFC_NDEFMAP_MIFARE_STD_2K_CARD))?
+ ((NdefMap->CardType == PH_FRINFC_NDEFMAP_MIFARE_STD_4K_CARD) ||
+ (NdefMap->CardType == PH_FRINFC_NDEFMAP_MIFARE_STD_2K_CARD))) ?
NdefMap->StdMifareContainer.NFCforumSectFlag:
PH_FRINFC_MIFARESTD_FLAG1);
}
diff --git a/nci/jni/extns/pn54x/src/mifare/phNxpExtns_MifareStd.c b/nci/jni/extns/pn54x/src/mifare/phNxpExtns_MifareStd.c
index c0c3bc1..6f58e08 100755
--- a/nci/jni/extns/pn54x/src/mifare/phNxpExtns_MifareStd.c
+++ b/nci/jni/extns/pn54x/src/mifare/phNxpExtns_MifareStd.c
@@ -1124,7 +1124,7 @@
else if( ((p_data[0] == phNfc_eMifareTransfer) || (p_data[0] == phNfc_eMifareRestore)) && (len == 2) )
{
NdefMap->Cmd.MfCmd = p_data[0];
- if ((p_data[0] == phNfc_eMifareRestore))
+ if (p_data[0] == phNfc_eMifareRestore)
{
EXTNS_SetCallBackFlag(FALSE);
gphNxpExtns_Context.RawWriteCallBack = TRUE;
@@ -2101,7 +2101,7 @@
status = phLibNfc_SendIncDecCmd(pTransceiveInfo, &tNciTranscvInfo, Cmd.MfCmd);
}
- else if( (Cmd.MfCmd == phNfc_eMifareRestore ) )
+ else if(Cmd.MfCmd == phNfc_eMifareRestore)
{
pTransceiveInfo->addr = SendRecvBuf[i++];
length = SendLength - i;
@@ -2116,7 +2116,7 @@
}
else if ((Cmd.MfCmd == phNfc_eMifareRaw) || (Cmd.MfCmd == phNfc_eMifareTransfer ))
{
- pTransceiveInfo->cmd.MfCmd = phNciNfc_eT2TRaw;
+ pTransceiveInfo->cmd.MfCmd = (phNfc_eMifareCmdList_t) phNciNfc_eT2TRaw;
memcpy(pTransceiveInfo->sSendData.buffer, SendRecvBuf, length);
pTransceiveInfo->sSendData.length = length;
pTransceiveInfo->sRecvData.length = MAX_BUFF_SIZE;
diff --git a/nci/jni/extns/pn54x/src/phNxpExtns.c b/nci/jni/extns/pn54x/src/phNxpExtns.c
index f39342c..478e5f4 100755
--- a/nci/jni/extns/pn54x/src/phNxpExtns.c
+++ b/nci/jni/extns/pn54x/src/phNxpExtns.c
@@ -627,6 +627,8 @@
if (sem_timedwait (&gAuthCmdBuf.semPresenceCheck, &ts))
{
ALOGE ("%s: failed to wait (errno=0x%08x)", __FUNCTION__, errno);
+ sem_destroy (&gAuthCmdBuf.semPresenceCheck);
+ gAuthCmdBuf.auth_sent = FALSE;
return NFCSTATUS_FAILED;
}
if (sem_destroy (&gAuthCmdBuf.semPresenceCheck))
diff --git a/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java b/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java
index 99ee5d5..1ea5b2a 100755
--- a/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java
+++ b/nci/src/com/android/nfc/dhimpl/NativeNfcManager.java
@@ -26,6 +26,10 @@
import com.android.nfc.LlcpException;
import com.android.nfc.NfcDiscoveryParameters;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.HashMap;
+
/**
* Native interface to the NFC Manager functions
*/
@@ -42,13 +46,14 @@
System.loadLibrary("nfc_nci_jni");
}
-
/* Native structure */
private long mNative;
private final DeviceHostListener mListener;
private final Context mContext;
+ private final Object mLock = new Object();
+ private final HashMap<Integer, byte[]> mT3tIdentifiers = new HashMap<Integer, byte[]>();
public NativeNfcManager(Context context, DeviceHostListener listener) {
mListener = listener;
@@ -98,6 +103,46 @@
@Override
public native boolean commitRouting();
+ public native int doRegisterT3tIdentifier(byte[] t3tIdentifier);
+
+ @Override
+ public void registerT3tIdentifier(byte[] t3tIdentifier) {
+ synchronized (mLock) {
+ int handle = doRegisterT3tIdentifier(t3tIdentifier);
+ if (handle != 0xffff) {
+ mT3tIdentifiers.put(Integer.valueOf(handle), t3tIdentifier);
+ }
+ }
+ }
+
+ public native void doDeregisterT3tIdentifier(int handle);
+
+ @Override
+ public void deregisterT3tIdentifier(byte[] t3tIdentifier) {
+ synchronized (mLock) {
+ Iterator<Integer> it = mT3tIdentifiers.keySet().iterator();
+ while (it.hasNext()) {
+ int handle = it.next().intValue();
+ byte[] value = mT3tIdentifiers.get(handle);
+ if (Arrays.equals(value, t3tIdentifier)) {
+ doDeregisterT3tIdentifier(handle);
+ mT3tIdentifiers.remove(handle);
+ break;
+ }
+ }
+ }
+ }
+
+ @Override
+ public void clearT3tIdentifiersCache() {
+ synchronized (mLock) {
+ mT3tIdentifiers.clear();
+ }
+ }
+
+ @Override
+ public native int getLfT3tMax();
+
private native void doEnableDiscovery(int techMask,
boolean enableLowPowerPolling,
boolean enableReaderMode,
@@ -326,16 +371,16 @@
mListener.onLlcpFirstPacketReceived(device);
}
- private void notifyHostEmuActivated() {
- mListener.onHostCardEmulationActivated();
+ private void notifyHostEmuActivated(int technology) {
+ mListener.onHostCardEmulationActivated(technology);
}
- private void notifyHostEmuData(byte[] data) {
- mListener.onHostCardEmulationData(data);
+ private void notifyHostEmuData(int technology, byte[] data) {
+ mListener.onHostCardEmulationData(technology, data);
}
- private void notifyHostEmuDeactivated() {
- mListener.onHostCardEmulationDeactivated();
+ private void notifyHostEmuDeactivated(int technology) {
+ mListener.onHostCardEmulationDeactivated(technology);
}
private void notifyRfFieldActivated() {
diff --git a/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java b/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java
index 805e1ea..60a08a2 100755
--- a/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java
+++ b/nxp/src/com/android/nfc/dhimpl/NativeNfcManager.java
@@ -135,29 +135,45 @@
}
@Override
- public boolean sendRawFrame(byte[] data)
- {
+ public boolean sendRawFrame(byte[] data) {
return false;
}
@Override
- public boolean routeAid(byte[] aid, int route)
- {
+ public boolean routeAid(byte[] aid, int route) {
return false;
}
@Override
- public boolean unrouteAid(byte[] aid)
- {
+ public boolean unrouteAid(byte[] aid) {
return false;
}
@Override
- public boolean commitRouting()
- {
+ public boolean commitRouting() {
return false;
}
+ @Override
+ public void registerT3tIdentifier(byte[] t3tIdentifier) {
+ return;
+ }
+
+ @Override
+ public void deregisterT3tIdentifier(byte[] t3tIdentifier) {
+ return;
+ }
+
+ @Override
+ public void clearT3tIdentifiersCache() {
+ return;
+ }
+
+ @Override
+ public int getLfT3tMax() {
+ return 0;
+ }
+
private native void doEnableDiscovery(int techMask,
boolean enableLowPowerPolling,
boolean enableReaderMode,
@@ -375,6 +391,18 @@
mListener.onLlcpLinkDeactivated(device);
}
+ private void notifyHostEmuActivated(int technology) {
+ mListener.onHostCardEmulationActivated(technology);
+ }
+
+ private void notifyHostEmuData(int technology, byte[] data) {
+ mListener.onHostCardEmulationData(technology, data);
+ }
+
+ private void notifyHostEmuDeactivated(int technology) {
+ mListener.onHostCardEmulationDeactivated(technology);
+ }
+
private void notifyRfFieldActivated() {
mListener.onRemoteFieldActivated();
}
diff --git a/res/values-az-rAZ/provisioning.xml b/res/values-az-rAZ/provisioning.xml
new file mode 100644
index 0000000..676cad9
--- /dev/null
+++ b/res/values-az-rAZ/provisioning.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2013 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.
+ -->
+
+<!-- NFC resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string-array name="provisioning_mime_types">
+ <item msgid="3675637130021393293">"application/com.android.managedprovisioning"</item>
+ <item msgid="9182300251635024136">"application/com.android.managedprovisioning.v2"</item>
+ </string-array>
+</resources>
diff --git a/res/values-az-rAZ/strings.xml b/res/values-az-rAZ/strings.xml
index b1071ae..0fc6031 100644
--- a/res/values-az-rAZ/strings.xml
+++ b/res/values-az-rAZ/strings.xml
@@ -18,15 +18,32 @@
<string name="beam_touch_to_view" msgid="7853129156831642630">"Görüntüləmək üçün toxunun"</string>
<string name="beam_handover_not_supported" msgid="4083165921751489015">"Qəbul edənin cihazı beam vasitəsilə böyük fayl ötürülməsini dəstəkləmir."</string>
<string name="beam_try_again" msgid="3364677301009783455">"Cihazları yenidən bir yerə gətir"</string>
- <string name="connecting_headset" msgid="3929250919225573008">"Qoşulur..."</string>
- <string name="connected_headset" msgid="4047751837023241955">"Qoşulu"</string>
- <string name="connect_headset_failed" msgid="7500801585498094863">"Qoşula bilmədi"</string>
- <string name="disconnecting_headset" msgid="868262189044372780">"Əlaqə kəsilir"</string>
- <string name="disconnected_headset" msgid="4066109452701733916">"Əlaqə kəsilib"</string>
- <string name="pairing_headset" msgid="6443461444755646137">"Qoşalama"</string>
- <string name="pairing_headset_failed" msgid="6509629663883514688">"Qoşalaya bilmədi"</string>
+ <string name="beam_busy" msgid="5253335587620612576">"Beam hazırda məşğuldur. Əvvəlki ötürmə tamamlandıqda yenidən cəhd edin."</string>
+ <string name="device" msgid="4459621591392478151">"cihaz"</string>
+ <string name="connecting_peripheral" msgid="1296182660525660935">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazına qoşulur"</string>
+ <string name="connected_peripheral" msgid="20748648543160091">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazına qoşulub"</string>
+ <string name="connect_peripheral_failed" msgid="7925702596242839275">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazına qoşula bilmədi"</string>
+ <string name="disconnecting_peripheral" msgid="1443699384809097200">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazından ayrılır"</string>
+ <string name="disconnected_peripheral" msgid="4470578100296504366">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazından ayrıldı"</string>
+ <string name="pairing_peripheral" msgid="6983626861540899365">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> cütləşir"</string>
+ <string name="pairing_peripheral_failed" msgid="6087643307743264679">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ilə cütləşə bilmir"</string>
<string name="failed_to_enable_bt" msgid="7229153323594758077">"Bluetooth aktiv edilə bilmədi"</string>
<string name="confirm_pairing" msgid="4112568077038265363">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> Bluetooth cihazını qoşalamaq istədiyinizdən əminsiniz?"</string>
<string name="pair_yes" msgid="3525614878559994448">"Bəli"</string>
<string name="pair_no" msgid="5022308368904055020">"Xeyr"</string>
+ <string name="tap_again_to_pay" msgid="5754988005412859897">"<xliff:g id="APP">%1$s</xliff:g> Tətbiqi ilə ödəmək üçün yenidən tıklayın"</string>
+ <string name="tap_again_to_complete" msgid="5423640945118279123">"<xliff:g id="APP">%1$s</xliff:g> Tətbiqi ilə tamamlamaq üçün tıklayın"</string>
+ <string name="transaction_failure" msgid="7828102078637936513">"Bu əməliyyat <xliff:g id="APP">%1$s</xliff:g> tətbiqi ilə tamamlana bilməz."</string>
+ <string name="could_not_use_app" msgid="8137587876138569083">"<xliff:g id="APP">%1$s</xliff:g> Tətbiqi istifadə edə bilmədi."</string>
+ <string name="pay_with" msgid="5531545488795798945">"İlə ödə"</string>
+ <string name="complete_with" msgid="6797459104103012992">"İlə tamamla"</string>
+ <string name="default_pay_app_removed" msgid="4108250545457437360">"Tıkla və ödə üçün tərcih etdiyiniz xidmət silindi. Digərisi seçilsin?"</string>
+ <string name="ask_nfc_tap" msgid="2925239870458286340">"Tamamlamaq üçün digər cihaza tıklayın"</string>
+ <string name="wifi_connect" msgid="6250727951843550671">"Qoşul"</string>
+ <string name="status_unable_to_connect" msgid="9183908200295307657">"Şəbəkəyə qoşulmaq mümkün deyil"</string>
+ <string name="status_wifi_connected" msgid="5893022897732105739">"Qoşuldu"</string>
+ <string name="title_connect_to_network" msgid="2474034615817280146">"Şəbəkəyə qoşulun"</string>
+ <string name="prompt_connect_to_network" msgid="8511683573657516114">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> şəbəkəsinə birləşdirilsin?"</string>
+ <string name="beam_requires_nfc_enabled" msgid="2800366967218600534">"Android Beam aktivləşmək üçün NFC tələb edir. Aktivləşdirmək istəyirsiniz?"</string>
+ <string name="android_beam" msgid="1666446406999492763">"Android Beam"</string>
</resources>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 2a58467..ce34a07 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -25,10 +25,10 @@
<string name="connect_peripheral_failed" msgid="7925702596242839275">"No s\'ha pogut connectar <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="disconnecting_peripheral" msgid="1443699384809097200">"S\'està desconnectant <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="disconnected_peripheral" msgid="4470578100296504366">"S\'ha desconnectat <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
- <string name="pairing_peripheral" msgid="6983626861540899365">"S\'està emparellant <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
- <string name="pairing_peripheral_failed" msgid="6087643307743264679">"No s\'ha pogut emparellar <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="pairing_peripheral" msgid="6983626861540899365">"S\'està vinculant <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="pairing_peripheral_failed" msgid="6087643307743264679">"No s\'ha pogut vincular <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="failed_to_enable_bt" msgid="7229153323594758077">"No es pot activar el Bluetooth"</string>
- <string name="confirm_pairing" msgid="4112568077038265363">"Estàs segur que vols emparellar el dispositiu Bluetooth <xliff:g id="DEVICE_NAME">%1$s</xliff:g>?"</string>
+ <string name="confirm_pairing" msgid="4112568077038265363">"Estàs segur que vols vincular el dispositiu Bluetooth <xliff:g id="DEVICE_NAME">%1$s</xliff:g>?"</string>
<string name="pair_yes" msgid="3525614878559994448">"Sí"</string>
<string name="pair_no" msgid="5022308368904055020">"No"</string>
<string name="tap_again_to_pay" msgid="5754988005412859897">"Torna a tocar per pagar amb <xliff:g id="APP">%1$s</xliff:g>"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 0b35ed8..430c162 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -37,7 +37,7 @@
<string name="could_not_use_app" msgid="8137587876138569083">"Aplikaci <xliff:g id="APP">%1$s</xliff:g> nelze použít."</string>
<string name="pay_with" msgid="5531545488795798945">"Platební metoda"</string>
<string name="complete_with" msgid="6797459104103012992">"Dokončit pomocí"</string>
- <string name="default_pay_app_removed" msgid="4108250545457437360">"Preferovaná služba pro platbu mobilem byla odstraněna. Chcete vybrat jinou?"</string>
+ <string name="default_pay_app_removed" msgid="4108250545457437360">"Preferovaná služba pro platbu dotykem telefonu byla odstraněna. Chcete vybrat jinou?"</string>
<string name="ask_nfc_tap" msgid="2925239870458286340">"Akci dokončíte tím, že se zařízením dotknete jiného zařízení"</string>
<string name="wifi_connect" msgid="6250727951843550671">"Připojit"</string>
<string name="status_unable_to_connect" msgid="9183908200295307657">"K síti se nelze připojit."</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index beb17b7..2d0821e 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -6,7 +6,7 @@
<string name="inbound_me_profile_title" msgid="6146013785225412693">"Kontakt per NFC erhalten"</string>
<string name="inbound_me_profile_text" msgid="2342757196108092923">"Zum Hinzufügen dieser Person als Kontakt tippen"</string>
<string name="outbound_me_profile_title" msgid="2523625031572784769">"NFC-Interaktion abgeschlossen"</string>
- <string name="outbound_me_profile_text" msgid="5594998841143667989">"Zum Weitergeben Ihrer Kontaktinformationen an diese Person tippen"</string>
+ <string name="outbound_me_profile_text" msgid="5594998841143667989">"Zum Weitergeben deiner Kontaktinformationen an diese Person tippen"</string>
<string name="accessibility_nfc_enabled" msgid="7796246979948787735">"NFC aktiviert"</string>
<string name="touch" msgid="4727218133711188355">"Zum Beamen berühren"</string>
<string name="beam_progress" msgid="7453634884807323920">"Beam wird empfangen..."</string>
@@ -18,7 +18,7 @@
<string name="beam_touch_to_view" msgid="7853129156831642630">"Zum Anzeigen berühren"</string>
<string name="beam_handover_not_supported" msgid="4083165921751489015">"Das Gerät des Empfängers unterstützt die Übertragung großer Dateien durch Beamen nicht."</string>
<string name="beam_try_again" msgid="3364677301009783455">"Geräte erneut nebeneinander platzieren"</string>
- <string name="beam_busy" msgid="5253335587620612576">"Android Beam ist momentan ausgelastet. Bitte versuchen Sie es erneut, wenn die vorherige Übertragung abgeschlossen ist."</string>
+ <string name="beam_busy" msgid="5253335587620612576">"Android Beam ist momentan ausgelastet. Bitte versuche es erneut, wenn die vorherige Übertragung abgeschlossen ist."</string>
<string name="device" msgid="4459621591392478151">"Gerät"</string>
<string name="connecting_peripheral" msgid="1296182660525660935">"Verbindung zu <xliff:g id="DEVICE_NAME">%1$s</xliff:g> wird hergestellt"</string>
<string name="connected_peripheral" msgid="20748648543160091">"Mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> verbunden"</string>
@@ -28,22 +28,22 @@
<string name="pairing_peripheral" msgid="6983626861540899365">"Pairing mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> wird durchgeführt"</string>
<string name="pairing_peripheral_failed" msgid="6087643307743264679">"Pairing mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> nicht möglich"</string>
<string name="failed_to_enable_bt" msgid="7229153323594758077">"Bluetooth konnte nicht aktiviert werden."</string>
- <string name="confirm_pairing" msgid="4112568077038265363">"Möchten Sie das Bluetooth-Gerät <xliff:g id="DEVICE_NAME">%1$s</xliff:g> wirklich koppeln?"</string>
+ <string name="confirm_pairing" msgid="4112568077038265363">"Möchtest du das Bluetooth-Gerät <xliff:g id="DEVICE_NAME">%1$s</xliff:g> wirklich koppeln?"</string>
<string name="pair_yes" msgid="3525614878559994448">"Ja"</string>
<string name="pair_no" msgid="5022308368904055020">"Nein"</string>
- <string name="tap_again_to_pay" msgid="5754988005412859897">"Halten Sie Ihr Gerät erneut ans Terminal, um mit <xliff:g id="APP">%1$s</xliff:g> zu bezahlen."</string>
- <string name="tap_again_to_complete" msgid="5423640945118279123">"Halten Sie Ihr Gerät erneut ans Terminal, um den Vorgang mit <xliff:g id="APP">%1$s</xliff:g> durchzuführen."</string>
+ <string name="tap_again_to_pay" msgid="5754988005412859897">"Halte dein Gerät erneut ans Terminal, um mit <xliff:g id="APP">%1$s</xliff:g> zu bezahlen."</string>
+ <string name="tap_again_to_complete" msgid="5423640945118279123">"Halte dein Gerät erneut ans Terminal, um den Vorgang mit <xliff:g id="APP">%1$s</xliff:g> durchzuführen."</string>
<string name="transaction_failure" msgid="7828102078637936513">"Diese Transaktion konnte nicht mit <xliff:g id="APP">%1$s</xliff:g> durchgeführt werden."</string>
<string name="could_not_use_app" msgid="8137587876138569083">"Fehler bei der Verwendung von <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="pay_with" msgid="5531545488795798945">"Zahlen mit"</string>
<string name="complete_with" msgid="6797459104103012992">"Durchführen mit"</string>
- <string name="default_pay_app_removed" msgid="4108250545457437360">"Der von Ihnen bevorzugte Dienst für das mobile Bezahlen wurde entfernt. Möchten Sie einen anderen auswählen?"</string>
+ <string name="default_pay_app_removed" msgid="4108250545457437360">"Der von dir bevorzugte Dienst für das mobile Bezahlen wurde entfernt. Möchtest du einen anderen auswählen?"</string>
<string name="ask_nfc_tap" msgid="2925239870458286340">"Zum Abschluss auf ein anderes Gerät tippen"</string>
<string name="wifi_connect" msgid="6250727951843550671">"Verbinden"</string>
<string name="status_unable_to_connect" msgid="9183908200295307657">"Verbindung zum Netzwerk konnte nicht hergestellt werden."</string>
<string name="status_wifi_connected" msgid="5893022897732105739">"Verbunden"</string>
<string name="title_connect_to_network" msgid="2474034615817280146">"Mit Netzwerk verbinden"</string>
<string name="prompt_connect_to_network" msgid="8511683573657516114">"Verbindung zum Netzwerk <xliff:g id="NETWORK_SSID">%1$s</xliff:g> herstellen?"</string>
- <string name="beam_requires_nfc_enabled" msgid="2800366967218600534">"Android Beam erfordert zur Aktivierung die Nahfeldkommunikation (NFC). Möchten Sie sie aktivieren?"</string>
+ <string name="beam_requires_nfc_enabled" msgid="2800366967218600534">"Android Beam erfordert zur Aktivierung die Nahfeldkommunikation (NFC). Möchtest du sie aktivieren?"</string>
<string name="android_beam" msgid="1666446406999492763">"Android Beam"</string>
</resources>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index a3fe0e7..e995f4b 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -26,11 +26,11 @@
<string name="disconnecting_peripheral" msgid="1443699384809097200">"در حال قطع ارتباط <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="disconnected_peripheral" msgid="4470578100296504366">"ارتباط <xliff:g id="DEVICE_NAME">%1$s</xliff:g> قطع شد"</string>
<string name="pairing_peripheral" msgid="6983626861540899365">"در حال مرتبطسازی <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
- <string name="pairing_peripheral_failed" msgid="6087643307743264679">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> مرتبط نشد"</string>
+ <string name="pairing_peripheral_failed" msgid="6087643307743264679">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> مرتبطسازی نشد"</string>
<string name="failed_to_enable_bt" msgid="7229153323594758077">"فعال کردن بلوتوث امکانپذیر نیست"</string>
- <string name="confirm_pairing" msgid="4112568077038265363">"آیا مطمئن هستید که میخواهید دستگاه بلوتوث <xliff:g id="DEVICE_NAME">%1$s</xliff:g> را جفت کنید؟"</string>
+ <string name="confirm_pairing" msgid="4112568077038265363">"آیا مطمئنید که میخواهید با دستگاه بلوتوث <xliff:g id="DEVICE_NAME">%1$s</xliff:g> مرتبطسازی کنید؟"</string>
<string name="pair_yes" msgid="3525614878559994448">"بله"</string>
- <string name="pair_no" msgid="5022308368904055020">"خیر"</string>
+ <string name="pair_no" msgid="5022308368904055020">"نه"</string>
<string name="tap_again_to_pay" msgid="5754988005412859897">"برای پرداخت با <xliff:g id="APP">%1$s</xliff:g>، دوباره ضربه بزنید"</string>
<string name="tap_again_to_complete" msgid="5423640945118279123">"برای تکمیل از طریق <xliff:g id="APP">%1$s</xliff:g>، دوباره ضربه بزنید"</string>
<string name="transaction_failure" msgid="7828102078637936513">"این تراکنش با <xliff:g id="APP">%1$s</xliff:g> تکمیل نشد."</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 382cf20..88d193a 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -37,7 +37,7 @@
<string name="could_not_use_app" msgid="8137587876138569083">"<xliff:g id="APP">%1$s</xliff:g>を使用できませんでした。"</string>
<string name="pay_with" msgid="5531545488795798945">"お支払い:"</string>
<string name="complete_with" msgid="6797459104103012992">"完了:"</string>
- <string name="default_pay_app_removed" msgid="4108250545457437360">"「タップしてお支払い」用のサービスが削除されました。別のサービスを選択しますか?"</string>
+ <string name="default_pay_app_removed" msgid="4108250545457437360">"「タップ&ペイ」用のサービスが削除されました。別のサービスを選択しますか?"</string>
<string name="ask_nfc_tap" msgid="2925239870458286340">"完了するには別の端末をタップしてください"</string>
<string name="wifi_connect" msgid="6250727951843550671">"接続"</string>
<string name="status_unable_to_connect" msgid="9183908200295307657">"ネットワークに接続できません"</string>
diff --git a/res/values-ml-rIN/strings.xml b/res/values-ml-rIN/strings.xml
index d9bb0a5..6b9a83b 100644
--- a/res/values-ml-rIN/strings.xml
+++ b/res/values-ml-rIN/strings.xml
@@ -37,7 +37,7 @@
<string name="could_not_use_app" msgid="8137587876138569083">"<xliff:g id="APP">%1$s</xliff:g> ഉപയോഗിക്കാനായില്ല."</string>
<string name="pay_with" msgid="5531545488795798945">"ഇതുപയോഗിച്ച് പണമടയ്ക്കുക"</string>
<string name="complete_with" msgid="6797459104103012992">"ഇതുപയോഗിച്ച് പൂർത്തിയാക്കുക"</string>
- <string name="default_pay_app_removed" msgid="4108250545457437360">"ടാപ്പുചെയ്ത് പണമടയ്ക്കുക എന്നതിനായി നിങ്ങൾ തിരഞ്ഞെടുത്ത സേവനം നീക്കംചെയ്തു. മറ്റൊന്ന് തിരഞ്ഞെടുക്കണോ?"</string>
+ <string name="default_pay_app_removed" msgid="4108250545457437360">"\'മൊബൈൽ തൊടീച്ച് പണമടയ്ക്കുക\' എന്നതിനായി നിങ്ങൾ തിരഞ്ഞെടുത്ത സേവനം നീക്കംചെയ്തു. മറ്റൊന്ന് തിരഞ്ഞെടുക്കണോ?"</string>
<string name="ask_nfc_tap" msgid="2925239870458286340">"പൂർത്തിയാക്കുന്നതിന് മറ്റൊരു ഉപകരണം ടാപ്പുചെയ്യുക"</string>
<string name="wifi_connect" msgid="6250727951843550671">"കണക്റ്റുചെയ്യുക"</string>
<string name="status_unable_to_connect" msgid="9183908200295307657">"നെറ്റ്വർക്കിലേക്ക് കണക്റ്റുചെയ്യാനായില്ല"</string>
diff --git a/res/values-mr-rIN/strings.xml b/res/values-mr-rIN/strings.xml
index f63cf04..0863e32 100644
--- a/res/values-mr-rIN/strings.xml
+++ b/res/values-mr-rIN/strings.xml
@@ -27,8 +27,8 @@
<string name="disconnected_peripheral" msgid="4470578100296504366">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> डिस्कनेक्ट केले"</string>
<string name="pairing_peripheral" msgid="6983626861540899365">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> जोडणी करीत आहे"</string>
<string name="pairing_peripheral_failed" msgid="6087643307743264679">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> जोडणे शक्य झाले नाही"</string>
- <string name="failed_to_enable_bt" msgid="7229153323594758077">"ब सक्षम करू शकलो नाही"</string>
- <string name="confirm_pairing" msgid="4112568077038265363">"आपण <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ब डिव्हाइस जोडू इच्छिता याची आपल्याला खात्री आहे?"</string>
+ <string name="failed_to_enable_bt" msgid="7229153323594758077">"ब्लूटुथ सक्षम करू शकलो नाही"</string>
+ <string name="confirm_pairing" msgid="4112568077038265363">"आपण <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ब्लूटुथ डिव्हाइस जोडू इच्छिता याची आपल्याला खात्री आहे?"</string>
<string name="pair_yes" msgid="3525614878559994448">"होय"</string>
<string name="pair_no" msgid="5022308368904055020">"नाही"</string>
<string name="tap_again_to_pay" msgid="5754988005412859897">"<xliff:g id="APP">%1$s</xliff:g> सह देय देण्यासाठी पुन्हा टॅप करा"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index cea1dd0..e262688 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -27,7 +27,7 @@
<string name="disconnected_peripheral" msgid="4470578100296504366">"Frakoblet <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="pairing_peripheral" msgid="6983626861540899365">"Sammenkobler <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="pairing_peripheral_failed" msgid="6087643307743264679">"Kunne ikke sammenkoble <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
- <string name="failed_to_enable_bt" msgid="7229153323594758077">"Kunne ikke aktivere Bluetooth"</string>
+ <string name="failed_to_enable_bt" msgid="7229153323594758077">"Kunne ikke slå på Bluetooth"</string>
<string name="confirm_pairing" msgid="4112568077038265363">"Er du sikker på at koble til Bluetooth-enheten <xliff:g id="DEVICE_NAME">%1$s</xliff:g>?"</string>
<string name="pair_yes" msgid="3525614878559994448">"Ja"</string>
<string name="pair_no" msgid="5022308368904055020">"Nei"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 11b2c8f..6822046 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -6,7 +6,7 @@
<string name="inbound_me_profile_title" msgid="6146013785225412693">"Contact ontvangen via NFC"</string>
<string name="inbound_me_profile_text" msgid="2342757196108092923">"Raak aan om deze persoon toe te voegen als contact."</string>
<string name="outbound_me_profile_title" msgid="2523625031572784769">"NFC-interactie voltooid"</string>
- <string name="outbound_me_profile_text" msgid="5594998841143667989">"Raak aan om deze persoon uw contactgegevens te geven."</string>
+ <string name="outbound_me_profile_text" msgid="5594998841143667989">"Raak aan om deze persoon je contactgegevens te geven."</string>
<string name="accessibility_nfc_enabled" msgid="7796246979948787735">"NFC ingeschakeld."</string>
<string name="touch" msgid="4727218133711188355">"Tikken om uit te zenden"</string>
<string name="beam_progress" msgid="7453634884807323920">"Inkomende beam..."</string>
@@ -28,7 +28,7 @@
<string name="pairing_peripheral" msgid="6983626861540899365">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> koppelen"</string>
<string name="pairing_peripheral_failed" msgid="6087643307743264679">"Kan <xliff:g id="DEVICE_NAME">%1$s</xliff:g> niet koppelen"</string>
<string name="failed_to_enable_bt" msgid="7229153323594758077">"Kan Bluetooth niet inschakelen"</string>
- <string name="confirm_pairing" msgid="4112568077038265363">"Weet u zeker dat u het Bluetooth-apparaat <xliff:g id="DEVICE_NAME">%1$s</xliff:g> wilt koppelen?"</string>
+ <string name="confirm_pairing" msgid="4112568077038265363">"Weet je zeker dat je het Bluetooth-apparaat <xliff:g id="DEVICE_NAME">%1$s</xliff:g> wilt koppelen?"</string>
<string name="pair_yes" msgid="3525614878559994448">"Ja"</string>
<string name="pair_no" msgid="5022308368904055020">"Nee"</string>
<string name="tap_again_to_pay" msgid="5754988005412859897">"Tik nogmaals om te betalen met <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -37,13 +37,13 @@
<string name="could_not_use_app" msgid="8137587876138569083">"Kan <xliff:g id="APP">%1$s</xliff:g> niet gebruiken."</string>
<string name="pay_with" msgid="5531545488795798945">"Betalen met"</string>
<string name="complete_with" msgid="6797459104103012992">"Voltooien met"</string>
- <string name="default_pay_app_removed" msgid="4108250545457437360">"Uw voorkeursservice voor tikken en betalen is verwijderd. Een andere app kiezen?"</string>
+ <string name="default_pay_app_removed" msgid="4108250545457437360">"Je voorkeursservice voor tikken en betalen is verwijderd. Een andere app kiezen?"</string>
<string name="ask_nfc_tap" msgid="2925239870458286340">"Tik op een ander apparaat om te voltooien"</string>
<string name="wifi_connect" msgid="6250727951843550671">"Verbinding maken"</string>
<string name="status_unable_to_connect" msgid="9183908200295307657">"Kan geen verbinding maken met het netwerk"</string>
<string name="status_wifi_connected" msgid="5893022897732105739">"Verbonden"</string>
<string name="title_connect_to_network" msgid="2474034615817280146">"Verbinding maken met netwerk"</string>
<string name="prompt_connect_to_network" msgid="8511683573657516114">"Verbinding maken met netwerk <xliff:g id="NETWORK_SSID">%1$s</xliff:g>?"</string>
- <string name="beam_requires_nfc_enabled" msgid="2800366967218600534">"NFC moet zijn ingeschakeld voor Android Beam. Wilt u dit inschakelen?"</string>
+ <string name="beam_requires_nfc_enabled" msgid="2800366967218600534">"NFC moet zijn ingeschakeld voor Android Beam. Wil je dit inschakelen?"</string>
<string name="android_beam" msgid="1666446406999492763">"Android Beam"</string>
</resources>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 0f7a5d8..b720f77 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -4,19 +4,19 @@
<string name="app_name" msgid="78565911793142902">"Serviciul NFC"</string>
<string name="nfcUserLabel" msgid="7708535817084357357">"NFC"</string>
<string name="inbound_me_profile_title" msgid="6146013785225412693">"Persoană din agendă primită prin NFC"</string>
- <string name="inbound_me_profile_text" msgid="2342757196108092923">"Atingeţi pentru a adăuga această persoană în Agendă."</string>
- <string name="outbound_me_profile_title" msgid="2523625031572784769">"Interacţiune NFC completă"</string>
- <string name="outbound_me_profile_text" msgid="5594998841143667989">"Atingeţi pentru a oferi acestei persoane datele dvs. de contact"</string>
+ <string name="inbound_me_profile_text" msgid="2342757196108092923">"Atingeți pentru a adăuga această persoană în Agendă."</string>
+ <string name="outbound_me_profile_title" msgid="2523625031572784769">"Interacțiune NFC completă"</string>
+ <string name="outbound_me_profile_text" msgid="5594998841143667989">"Atingeți pentru a oferi acestei persoane datele dvs. de contact"</string>
<string name="accessibility_nfc_enabled" msgid="7796246979948787735">"NFC activat."</string>
- <string name="touch" msgid="4727218133711188355">"Atingeţi pentru transmitere"</string>
+ <string name="touch" msgid="4727218133711188355">"Atingeți pentru transmitere"</string>
<string name="beam_progress" msgid="7453634884807323920">"Transmitere primită..."</string>
<string name="beam_outgoing" msgid="4679536649779123495">"Se transmite..."</string>
<string name="beam_complete" msgid="477026736424637435">"Transmitere încheiată"</string>
<string name="beam_failed" msgid="5116241718189888630">"Transmiterea nu este finalizată"</string>
<string name="beam_canceled" msgid="5425192751826544741">"Transmitere anulată"</string>
<string name="cancel" msgid="61873902552555096">"Anulați"</string>
- <string name="beam_touch_to_view" msgid="7853129156831642630">"Atingeţi pentru a afişa"</string>
- <string name="beam_handover_not_supported" msgid="4083165921751489015">"Dispozitivul destinatarului nu acceptă transferul fişierelor mari prin fascicul."</string>
+ <string name="beam_touch_to_view" msgid="7853129156831642630">"Atingeți pentru a afișa"</string>
+ <string name="beam_handover_not_supported" msgid="4083165921751489015">"Dispozitivul destinatarului nu acceptă transferul fișierelor mari prin fascicul."</string>
<string name="beam_try_again" msgid="3364677301009783455">"Apropiați dispozitivele din nou"</string>
<string name="beam_busy" msgid="5253335587620612576">"Beam este ocupat. Încercați după finalizarea transferului anterior."</string>
<string name="device" msgid="4459621591392478151">"dispozitiv"</string>
@@ -27,8 +27,8 @@
<string name="disconnected_peripheral" msgid="4470578100296504366">"S-a deconectat <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="pairing_peripheral" msgid="6983626861540899365">"Se asociază <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
<string name="pairing_peripheral_failed" msgid="6087643307743264679">"Nu s-a putut asocia <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
- <string name="failed_to_enable_bt" msgid="7229153323594758077">"Activarea Bluetooth a eşuat"</string>
- <string name="confirm_pairing" msgid="4112568077038265363">"Sigur doriţi să împerecheaţi dispozitivul Bluetooth <xliff:g id="DEVICE_NAME">%1$s</xliff:g>?"</string>
+ <string name="failed_to_enable_bt" msgid="7229153323594758077">"Activarea Bluetooth a eșuat"</string>
+ <string name="confirm_pairing" msgid="4112568077038265363">"Sigur doriți să împerecheați dispozitivul Bluetooth <xliff:g id="DEVICE_NAME">%1$s</xliff:g>?"</string>
<string name="pair_yes" msgid="3525614878559994448">"Da"</string>
<string name="pair_no" msgid="5022308368904055020">"Nu"</string>
<string name="tap_again_to_pay" msgid="5754988005412859897">"Atingeți din nou pentru a plăti cu <xliff:g id="APP">%1$s</xliff:g>"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index ea338e9..f69fe21 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -38,7 +38,7 @@
<string name="pay_with" msgid="5531545488795798945">"Способ оплаты"</string>
<string name="complete_with" msgid="6797459104103012992">"Использовать"</string>
<string name="default_pay_app_removed" msgid="4108250545457437360">"Вы удалили приложение для бесконтактной оплаты, используемое по умолчанию. Выбрать другое?"</string>
- <string name="ask_nfc_tap" msgid="2925239870458286340">"Нажмите на экран другого устройства, чтобы передать данные"</string>
+ <string name="ask_nfc_tap" msgid="2925239870458286340">"Коснитесь другого устройства, чтобы передать данные"</string>
<string name="wifi_connect" msgid="6250727951843550671">"Подключиться"</string>
<string name="status_unable_to_connect" msgid="9183908200295307657">"Не удалось подключиться к сети"</string>
<string name="status_wifi_connected" msgid="5893022897732105739">"Соединение установлено"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 3c33636..07d6eed 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -31,14 +31,14 @@
<string name="confirm_pairing" msgid="4112568077038265363">"您確定要與藍牙裝置「<xliff:g id="DEVICE_NAME">%1$s</xliff:g>」配對嗎?"</string>
<string name="pair_yes" msgid="3525614878559994448">"是"</string>
<string name="pair_no" msgid="5022308368904055020">"否"</string>
- <string name="tap_again_to_pay" msgid="5754988005412859897">"再輕按一下即可使用「<xliff:g id="APP">%1$s</xliff:g>」付款"</string>
- <string name="tap_again_to_complete" msgid="5423640945118279123">"再輕按一下即可使用「<xliff:g id="APP">%1$s</xliff:g>」完成付款"</string>
+ <string name="tap_again_to_pay" msgid="5754988005412859897">"再輕觸一下即可使用「<xliff:g id="APP">%1$s</xliff:g>」付款"</string>
+ <string name="tap_again_to_complete" msgid="5423640945118279123">"再輕觸一下即可使用「<xliff:g id="APP">%1$s</xliff:g>」完成付款"</string>
<string name="transaction_failure" msgid="7828102078637936513">"無法使用「<xliff:g id="APP">%1$s</xliff:g>」完成這項交易作業。"</string>
<string name="could_not_use_app" msgid="8137587876138569083">"無法使用「<xliff:g id="APP">%1$s</xliff:g>」。"</string>
<string name="pay_with" msgid="5531545488795798945">"使用以下應用程式完成付款:"</string>
<string name="complete_with" msgid="6797459104103012992">"使用以下應用程式完成操作:"</string>
<string name="default_pay_app_removed" msgid="4108250545457437360">"您偏好的感應付款服務已遭移除,要選擇其他服務嗎?"</string>
- <string name="ask_nfc_tap" msgid="2925239870458286340">"輕按另一個裝置即可完成"</string>
+ <string name="ask_nfc_tap" msgid="2925239870458286340">"輕觸另一個裝置即可完成"</string>
<string name="wifi_connect" msgid="6250727951843550671">"連線"</string>
<string name="status_unable_to_connect" msgid="9183908200295307657">"無法連線至網路"</string>
<string name="status_wifi_connected" msgid="5893022897732105739">"已連線"</string>
diff --git a/src/com/android/nfc/BeamShareActivity.java b/src/com/android/nfc/BeamShareActivity.java
index cff601c..76629b8 100644
--- a/src/com/android/nfc/BeamShareActivity.java
+++ b/src/com/android/nfc/BeamShareActivity.java
@@ -143,7 +143,13 @@
ClipData.Item item = clipData.getItemAt(i);
// First try to get an Uri
Uri uri = item.getUri();
- String plainText = item.coerceToText(this).toString();
+ String plainText = null;
+ try {
+ plainText = item.coerceToText(this).toString();
+ } catch (IllegalStateException e) {
+ if (DBG) Log.d(TAG, e.getMessage());
+ continue;
+ }
if (uri != null) {
if (DBG) Log.d(TAG, "Found uri in ClipData.");
tryUri(uri);
diff --git a/src/com/android/nfc/DeviceHost.java b/src/com/android/nfc/DeviceHost.java
index 21d720e..a123dde 100644
--- a/src/com/android/nfc/DeviceHost.java
+++ b/src/com/android/nfc/DeviceHost.java
@@ -28,9 +28,9 @@
/**
*/
- public void onHostCardEmulationActivated();
- public void onHostCardEmulationData(byte[] data);
- public void onHostCardEmulationDeactivated();
+ public void onHostCardEmulationActivated(int technology);
+ public void onHostCardEmulationData(int technology, byte[] data);
+ public void onHostCardEmulationDeactivated(int technology);
/**
* Notifies P2P Device detected, to activate LLCP link
@@ -189,6 +189,14 @@
public boolean commitRouting();
+ public void registerT3tIdentifier(byte[] t3tIdentifier);
+
+ public void deregisterT3tIdentifier(byte[] t3tIdentifier);
+
+ public void clearT3tIdentifiersCache();
+
+ public int getLfT3tMax();
+
public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn)
throws LlcpException;
diff --git a/src/com/android/nfc/NfcDispatcher.java b/src/com/android/nfc/NfcDispatcher.java
index 912b897..531d322 100644
--- a/src/com/android/nfc/NfcDispatcher.java
+++ b/src/com/android/nfc/NfcDispatcher.java
@@ -592,6 +592,9 @@
intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_DEVICE, handover.device);
intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_NAME, handover.name);
intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_TRANSPORT, handover.transport);
+ if (handover.oobData != null) {
+ intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_OOB_DATA, handover.oobData);
+ }
mContext.startServiceAsUser(intent, UserHandle.CURRENT);
return true;
diff --git a/src/com/android/nfc/NfcService.java b/src/com/android/nfc/NfcService.java
index 08779aa..ca99c16 100755
--- a/src/com/android/nfc/NfcService.java
+++ b/src/com/android/nfc/NfcService.java
@@ -42,6 +42,7 @@
import android.nfc.INfcAdapter;
import android.nfc.INfcAdapterExtras;
import android.nfc.INfcCardEmulation;
+import android.nfc.INfcFCardEmulation;
import android.nfc.INfcTag;
import android.nfc.INfcUnlockHandler;
import android.nfc.NdefMessage;
@@ -79,6 +80,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.HashMap;
@@ -114,6 +116,8 @@
static final int MSG_RF_FIELD_ACTIVATED = 9;
static final int MSG_RF_FIELD_DEACTIVATED = 10;
static final int MSG_RESUME_POLLING = 11;
+ static final int MSG_REGISTER_T3T_IDENTIFIER = 12;
+ static final int MSG_DEREGISTER_T3T_IDENTIFIER = 13;
static final long MAX_POLLING_PAUSE_TIMEOUT = 40000;
@@ -210,6 +214,7 @@
NfcAdapterService mNfcAdapter;
boolean mIsDebugBuild;
boolean mIsHceCapable;
+ boolean mIsHceFCapable;
boolean mPollingPaused;
private NfcDispatcher mNfcDispatcher;
@@ -238,23 +243,23 @@
* Notifies transaction
*/
@Override
- public void onHostCardEmulationActivated() {
+ public void onHostCardEmulationActivated(int technology) {
if (mCardEmulationManager != null) {
- mCardEmulationManager.onHostCardEmulationActivated();
+ mCardEmulationManager.onHostCardEmulationActivated(technology);
}
}
@Override
- public void onHostCardEmulationData(byte[] data) {
+ public void onHostCardEmulationData(int technology, byte[] data) {
if (mCardEmulationManager != null) {
- mCardEmulationManager.onHostCardEmulationData(data);
+ mCardEmulationManager.onHostCardEmulationData(technology, data);
}
}
@Override
- public void onHostCardEmulationDeactivated() {
+ public void onHostCardEmulationDeactivated(int technology) {
if (mCardEmulationManager != null) {
- mCardEmulationManager.onHostCardEmulationDeactivated();
+ mCardEmulationManager.onHostCardEmulationDeactivated(technology);
}
}
@@ -379,7 +384,11 @@
updatePackageCache();
PackageManager pm = mContext.getPackageManager();
- mIsHceCapable = pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION);
+ mIsHceCapable =
+ pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION) ||
+ pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF);
+ mIsHceFCapable =
+ pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF);
if (mIsHceCapable) {
mCardEmulationManager = new CardEmulationManager(mContext);
}
@@ -876,6 +885,15 @@
}
@Override
+ public INfcFCardEmulation getNfcFCardEmulationInterface() {
+ if (mIsHceFCapable) {
+ return mCardEmulationManager.getNfcFCardEmulationInterface();
+ } else {
+ return null;
+ }
+ }
+
+ @Override
public int getState() throws RemoteException {
synchronized (NfcService.this) {
return mState;
@@ -905,6 +923,10 @@
public void setReaderMode(IBinder binder, IAppCallback callback, int flags, Bundle extras)
throws RemoteException {
synchronized (NfcService.this) {
+ if (!isNfcEnabled()) {
+ Log.e(TAG, "setReaderMode() called while NFC is not enabled.");
+ return;
+ }
if (flags != 0) {
try {
mReaderModeParams = new ReaderModeParams();
@@ -1603,6 +1625,41 @@
sendMessage(MSG_UNROUTE_AID, aid);
}
+ private byte[] getT3tIdentifierBytes(String systemCode, String nfcId2) {
+ ByteBuffer buffer = ByteBuffer.allocate(2 + 8);
+ buffer.put(hexStringToBytes(systemCode));
+ buffer.put(hexStringToBytes(nfcId2));
+
+ byte[] t3tIdBytes = new byte[buffer.position()];
+ buffer.position(0);
+ buffer.get(t3tIdBytes);
+
+ return t3tIdBytes;
+ }
+
+ public void registerT3tIdentifier(String systemCode, String nfcId2) {
+ Log.d(TAG, "request to register LF_T3T_IDENTIFIER");
+
+ byte[] t3tIdentifier = getT3tIdentifierBytes(systemCode, nfcId2);
+ sendMessage(MSG_REGISTER_T3T_IDENTIFIER, t3tIdentifier);
+ }
+
+ public void deregisterT3tIdentifier(String systemCode, String nfcId2) {
+ Log.d(TAG, "request to deregister LF_T3T_IDENTIFIER");
+
+ byte[] t3tIdentifier = getT3tIdentifierBytes(systemCode, nfcId2);
+ sendMessage(MSG_DEREGISTER_T3T_IDENTIFIER, t3tIdentifier);
+ }
+
+ public void clearT3tIdentifiersCache() {
+ Log.d(TAG, "clear T3t Identifiers Cache");
+ mDeviceHost.clearT3tIdentifiersCache();
+ }
+
+ public int getLfT3tMax() {
+ return mDeviceHost.getLfT3tMax();
+ }
+
public void commitRouting() {
mHandler.sendEmptyMessage(MSG_COMMIT_ROUTING);
}
@@ -1634,6 +1691,30 @@
mDeviceHost.unrouteAid(hexStringToBytes(aid));
break;
}
+ case MSG_REGISTER_T3T_IDENTIFIER: {
+ Log.d(TAG, "message to register LF_T3T_IDENTIFIER");
+ mDeviceHost.disableDiscovery();
+
+ byte[] t3tIdentifier = (byte[]) msg.obj;
+ mDeviceHost.registerT3tIdentifier(t3tIdentifier);
+
+ NfcDiscoveryParameters params = computeDiscoveryParameters(mScreenState);
+ boolean shouldRestart = mCurrentDiscoveryParameters.shouldEnableDiscovery();
+ mDeviceHost.enableDiscovery(params, shouldRestart);
+ break;
+ }
+ case MSG_DEREGISTER_T3T_IDENTIFIER: {
+ Log.d(TAG, "message to deregister LF_T3T_IDENTIFIER");
+ mDeviceHost.disableDiscovery();
+
+ byte[] t3tIdentifier = (byte[]) msg.obj;
+ mDeviceHost.deregisterT3tIdentifier(t3tIdentifier);
+
+ NfcDiscoveryParameters params = computeDiscoveryParameters(mScreenState);
+ boolean shouldRestart = mCurrentDiscoveryParameters.shouldEnableDiscovery();
+ mDeviceHost.enableDiscovery(params, shouldRestart);
+ break;
+ }
case MSG_INVOKE_BEAM: {
mP2pLinkManager.onManualBeamInvoke((BeamShareData)msg.obj);
break;
diff --git a/src/com/android/nfc/cardemulation/CardEmulationManager.java b/src/com/android/nfc/cardemulation/CardEmulationManager.java
index f34522a..73ed881 100644
--- a/src/com/android/nfc/cardemulation/CardEmulationManager.java
+++ b/src/com/android/nfc/cardemulation/CardEmulationManager.java
@@ -23,9 +23,12 @@
import android.content.Context;
import android.content.Intent;
import android.nfc.INfcCardEmulation;
+import android.nfc.INfcFCardEmulation;
import android.nfc.cardemulation.AidGroup;
import android.nfc.cardemulation.ApduServiceInfo;
+import android.nfc.cardemulation.NfcFServiceInfo;
import android.nfc.cardemulation.CardEmulation;
+import android.nfc.cardemulation.NfcFCardEmulation;
import android.os.Binder;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -33,57 +36,100 @@
import android.util.Log;
import com.android.nfc.NfcPermissions;
+import com.android.nfc.NfcService;
import com.android.nfc.cardemulation.RegisteredServicesCache;
+import com.android.nfc.cardemulation.RegisteredNfcFServicesCache;
/**
* CardEmulationManager is the central entity
* responsible for delegating to individual components
* implementing card emulation:
* - RegisteredServicesCache keeping track of HCE and SE services on the device
+ * - RegisteredNfcFServicesCache keeping track of HCE-F services on the device
* - RegisteredAidCache keeping track of AIDs registered by those services and manages
* the routing table in the NFCC.
+ * - RegisteredT3tIdentifiersCache keeping track of T3T Identifier registered by
+ * those services and manages the routing table in the NFCC.
* - HostEmulationManager handles incoming APDUs for the host and forwards to HCE
* services as necessary.
+ * - HostNfcFEmulationManager handles incoming NFC-F packets for the host and
+ * forwards to HCE-F services as necessary.
*/
public class CardEmulationManager implements RegisteredServicesCache.Callback,
- PreferredServices.Callback {
+ RegisteredNfcFServicesCache.Callback, PreferredServices.Callback,
+ EnabledNfcFServices.Callback {
static final String TAG = "CardEmulationManager";
static final boolean DBG = false;
+ static final int NFC_HCE_APDU = 0x01;
+ static final int NFC_HCE_NFCF = 0x04;
+
final RegisteredAidCache mAidCache;
+ final RegisteredT3tIdentifiersCache mT3tIdentifiersCache;
final RegisteredServicesCache mServiceCache;
+ final RegisteredNfcFServicesCache mNfcFServicesCache;
final HostEmulationManager mHostEmulationManager;
+ final HostNfcFEmulationManager mHostNfcFEmulationManager;
final PreferredServices mPreferredServices;
+ final EnabledNfcFServices mEnabledNfcFServices;
final Context mContext;
final CardEmulationInterface mCardEmulationInterface;
+ final NfcFCardEmulationInterface mNfcFCardEmulationInterface;
public CardEmulationManager(Context context) {
mContext = context;
mCardEmulationInterface = new CardEmulationInterface();
+ mNfcFCardEmulationInterface = new NfcFCardEmulationInterface();
mAidCache = new RegisteredAidCache(context);
+ mT3tIdentifiersCache = new RegisteredT3tIdentifiersCache(context);
mHostEmulationManager = new HostEmulationManager(context, mAidCache);
+ mHostNfcFEmulationManager = new HostNfcFEmulationManager(context, mT3tIdentifiersCache);
mServiceCache = new RegisteredServicesCache(context, this);
+ mNfcFServicesCache = new RegisteredNfcFServicesCache(context, this);
mPreferredServices = new PreferredServices(context, mServiceCache, mAidCache, this);
-
+ mEnabledNfcFServices = new EnabledNfcFServices(
+ context, mNfcFServicesCache, mT3tIdentifiersCache, this);
mServiceCache.initialize();
+ mNfcFServicesCache.initialize();
}
public INfcCardEmulation getNfcCardEmulationInterface() {
return mCardEmulationInterface;
}
- public void onHostCardEmulationActivated() {
- mHostEmulationManager.onHostEmulationActivated();
- mPreferredServices.onHostEmulationActivated();
+ public INfcFCardEmulation getNfcFCardEmulationInterface() {
+ return mNfcFCardEmulationInterface;
}
- public void onHostCardEmulationData(byte[] data) {
- mHostEmulationManager.onHostEmulationData(data);
+
+ public void onHostCardEmulationActivated(int technology) {
+ if (technology == NFC_HCE_APDU) {
+ mHostEmulationManager.onHostEmulationActivated();
+ mPreferredServices.onHostEmulationActivated();
+ } else if (technology == NFC_HCE_NFCF) {
+ mHostNfcFEmulationManager.onHostEmulationActivated();
+ mNfcFServicesCache.onHostEmulationActivated();
+ mEnabledNfcFServices.onHostEmulationActivated();
+ }
}
- public void onHostCardEmulationDeactivated() {
- mHostEmulationManager.onHostEmulationDeactivated();
- mPreferredServices.onHostEmulationDeactivated();
+ public void onHostCardEmulationData(int technology, byte[] data) {
+ if (technology == NFC_HCE_APDU) {
+ mHostEmulationManager.onHostEmulationData(data);
+ } else if (technology == NFC_HCE_NFCF) {
+ mHostNfcFEmulationManager.onHostEmulationData(data);
+ }
+ }
+
+ public void onHostCardEmulationDeactivated(int technology) {
+ if (technology == NFC_HCE_APDU) {
+ mHostEmulationManager.onHostEmulationDeactivated();
+ mPreferredServices.onHostEmulationDeactivated();
+ } else if (technology == NFC_HCE_NFCF) {
+ mHostNfcFEmulationManager.onHostEmulationDeactivated();
+ mNfcFServicesCache.onHostEmulationDeactivated();
+ mEnabledNfcFServices.onHostEmulationDeactivated();
+ }
}
public void onOffHostAidSelected() {
@@ -91,23 +137,42 @@
}
public void onUserSwitched(int userId) {
+ // for HCE
mServiceCache.invalidateCache(userId);
mPreferredServices.onUserSwitched(userId);
+ // for HCE-F
+ mHostNfcFEmulationManager.onUserSwitched();
+ mT3tIdentifiersCache.onUserSwitched();
+ mEnabledNfcFServices.onUserSwitched(userId);
+ mNfcFServicesCache.invalidateCache(userId);
}
public void onNfcEnabled() {
+ // for HCE
mAidCache.onNfcEnabled();
+ // for HCE-F
+ mT3tIdentifiersCache.onNfcEnabled();
}
public void onNfcDisabled() {
+ // for HCE
mAidCache.onNfcDisabled();
+ // for HCE-F
+ mHostNfcFEmulationManager.onNfcDisabled();
+ mNfcFServicesCache.onNfcDisabled();
+ mT3tIdentifiersCache.onNfcDisabled();
+ mEnabledNfcFServices.onNfcDisabled();
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
mServiceCache.dump(fd, pw, args);
+ mNfcFServicesCache.dump(fd, pw ,args);
mPreferredServices.dump(fd, pw, args);
+ mEnabledNfcFServices.dump(fd, pw, args);
mAidCache.dump(fd, pw, args);
+ mT3tIdentifiersCache.dump(fd, pw, args);
mHostEmulationManager.dump(fd, pw, args);
+ mHostNfcFEmulationManager.dump(fd, pw, args);
}
@Override
@@ -120,6 +185,14 @@
mPreferredServices.onServicesUpdated();
}
+ @Override
+ public void onNfcFServicesUpdated(int userId, List<NfcFServiceInfo> services) {
+ // Update the T3T identifier cache
+ mT3tIdentifiersCache.onServicesUpdated(userId, services);
+ // Update the enabled services list
+ mEnabledNfcFServices.onServicesUpdated();
+ }
+
void verifyDefaults(int userId, List<ApduServiceInfo> services) {
ComponentName defaultPaymentService =
getDefaultServiceForCategory(userId, CardEmulation.CATEGORY_PAYMENT, false);
@@ -247,6 +320,20 @@
return mServiceCache.hasService(userId, service);
}
+ boolean isNfcFServiceInstalled(int userId, ComponentName service) {
+ boolean serviceFound = mNfcFServicesCache.hasService(userId, service);
+ if (!serviceFound) {
+ // If we don't know about this service yet, it may have just been enabled
+ // using PackageManager.setComponentEnabledSetting(). The PackageManager
+ // broadcasts are delayed by 10 seconds in that scenario, which causes
+ // calls to our APIs referencing that service to fail.
+ // Hence, update the cache in case we don't know about the service.
+ if (DBG) Log.d(TAG, "Didn't find passed in service, invalidating cache.");
+ mNfcFServicesCache.invalidateCache(userId);
+ }
+ return mNfcFServicesCache.hasService(userId, service);
+ }
+
/**
* Returns whether a service in this package is preferred,
* either because it's the default payment app or it's running
@@ -257,10 +344,8 @@
}
/**
- * This class implements the application-facing APIs
- * and are called from binder. All calls must be
- * permission-checked.
- *
+ * This class implements the application-facing APIs and are called
+ * from binder. All calls must be permission-checked.
*/
final class CardEmulationInterface extends INfcCardEmulation.Stub {
@Override
@@ -370,7 +455,6 @@
NfcPermissions.enforceUserPermissions(mContext);
return mPreferredServices.unregisteredPreferredForegroundService(
Binder.getCallingUid());
-
}
@Override
@@ -379,6 +463,106 @@
}
}
+ /**
+ * This class implements the application-facing APIs and are called
+ * from binder. All calls must be permission-checked.
+ */
+ final class NfcFCardEmulationInterface extends INfcFCardEmulation.Stub {
+ @Override
+ public String getSystemCodeForService(int userId, ComponentName service)
+ throws RemoteException {
+ NfcPermissions.validateUserId(userId);
+ NfcPermissions.enforceUserPermissions(mContext);
+ if (!isNfcFServiceInstalled(userId, service)) {
+ return null;
+ }
+ return mNfcFServicesCache.getSystemCodeForService(
+ userId, Binder.getCallingUid(), service);
+ }
+
+ @Override
+ public boolean registerSystemCodeForService(int userId, ComponentName service,
+ String systemCode)
+ throws RemoteException {
+ NfcPermissions.validateUserId(userId);
+ NfcPermissions.enforceUserPermissions(mContext);
+ if (!isNfcFServiceInstalled(userId, service)) {
+ return false;
+ }
+ return mNfcFServicesCache.registerSystemCodeForService(
+ userId, Binder.getCallingUid(), service, systemCode);
+ }
+
+ @Override
+ public boolean removeSystemCodeForService(int userId, ComponentName service)
+ throws RemoteException {
+ NfcPermissions.validateUserId(userId);
+ NfcPermissions.enforceUserPermissions(mContext);
+ if (!isNfcFServiceInstalled(userId, service)) {
+ return false;
+ }
+ return mNfcFServicesCache.removeSystemCodeForService(
+ userId, Binder.getCallingUid(), service);
+ }
+
+ @Override
+ public String getNfcid2ForService(int userId, ComponentName service)
+ throws RemoteException {
+ NfcPermissions.validateUserId(userId);
+ NfcPermissions.enforceUserPermissions(mContext);
+ if (!isNfcFServiceInstalled(userId, service)) {
+ return null;
+ }
+ return mNfcFServicesCache.getNfcid2ForService(
+ userId, Binder.getCallingUid(), service);
+ }
+
+ @Override
+ public boolean setNfcid2ForService(int userId,
+ ComponentName service, String nfcid2) throws RemoteException {
+ NfcPermissions.validateUserId(userId);
+ NfcPermissions.enforceUserPermissions(mContext);
+ if (!isNfcFServiceInstalled(userId, service)) {
+ return false;
+ }
+ return mNfcFServicesCache.setNfcid2ForService(
+ userId, Binder.getCallingUid(), service, nfcid2);
+ }
+
+ @Override
+ public boolean enableNfcFForegroundService(ComponentName service)
+ throws RemoteException {
+ NfcPermissions.enforceUserPermissions(mContext);
+ if (isNfcFServiceInstalled(UserHandle.getCallingUserId(), service)) {
+ return mEnabledNfcFServices.registerEnabledForegroundService(service,
+ Binder.getCallingUid());
+ }
+ return false;
+ }
+
+ @Override
+ public boolean disableNfcFForegroundService() throws RemoteException {
+ NfcPermissions.enforceUserPermissions(mContext);
+ return mEnabledNfcFServices.unregisteredEnabledForegroundService(
+ Binder.getCallingUid());
+ }
+
+ @Override
+ public List<NfcFServiceInfo> getNfcFServices(int userId)
+ throws RemoteException {
+ NfcPermissions.validateUserId(userId);
+ NfcPermissions.enforceUserPermissions(mContext);
+ return mNfcFServicesCache.getServices(userId);
+ }
+
+ @Override
+ public int getMaxNumOfRegisterableSystemCodes()
+ throws RemoteException {
+ NfcPermissions.enforceUserPermissions(mContext);
+ return NfcService.getInstance().getLfT3tMax();
+ }
+ }
+
@Override
public void onPreferredPaymentServiceChanged(ComponentName service) {
mAidCache.onPreferredPaymentServiceChanged(service);
@@ -389,5 +573,11 @@
public void onPreferredForegroundServiceChanged(ComponentName service) {
mAidCache.onPreferredForegroundServiceChanged(service);
mHostEmulationManager.onPreferredForegroundServiceChanged(service);
- };
+ }
+
+ @Override
+ public void onEnabledForegroundNfcFServiceChanged(ComponentName service) {
+ mT3tIdentifiersCache.onEnabledForegroundNfcFServiceChanged(service);
+ mHostNfcFEmulationManager.onEnabledForegroundNfcFServiceChanged(service);
+ }
}
diff --git a/src/com/android/nfc/cardemulation/EnabledNfcFServices.java b/src/com/android/nfc/cardemulation/EnabledNfcFServices.java
new file mode 100644
index 0000000..1d2acb5
--- /dev/null
+++ b/src/com/android/nfc/cardemulation/EnabledNfcFServices.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2015 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.cardemulation;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+import com.android.nfc.ForegroundUtils;
+
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.nfc.cardemulation.NfcFServiceInfo;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
+
+public class EnabledNfcFServices implements com.android.nfc.ForegroundUtils.Callback {
+ static final String TAG = "EnabledNfcFCardEmulationServices";
+ static final boolean DBG = false;
+
+ final Context mContext;
+ final RegisteredNfcFServicesCache mNfcFServiceCache;
+ final RegisteredT3tIdentifiersCache mT3tIdentifiersCache;
+ final Callback mCallback;
+ final ForegroundUtils mForegroundUtils = ForegroundUtils.getInstance();
+ final Handler mHandler = new Handler(Looper.getMainLooper());
+
+ final Object mLock = new Object();
+ // Variables below synchronized on mLock
+ ComponentName mForegroundComponent = null; // The computed enabled foreground component
+ ComponentName mForegroundRequested = null; // The component requested to be enabled by fg app
+ int mForegroundUid = -1; // The UID of the fg app, or -1 if fg app didn't request
+
+ boolean mComputeFgRequested = false;
+ boolean mActivated = false;
+
+ public interface Callback {
+ void onEnabledForegroundNfcFServiceChanged(ComponentName service);
+ }
+
+ public EnabledNfcFServices(Context context,
+ RegisteredNfcFServicesCache nfcFServiceCache,
+ RegisteredT3tIdentifiersCache t3tIdentifiersCache, Callback callback) {
+ if (DBG) Log.d(TAG, "EnabledNfcFServices");
+ mContext = context;
+ mNfcFServiceCache = nfcFServiceCache;
+ mT3tIdentifiersCache = t3tIdentifiersCache;
+ mCallback = callback;
+ }
+
+ void computeEnabledForegroundService() {
+ if (DBG) Log.d(TAG, "computeEnabledForegroundService");
+ ComponentName foregroundRequested = null;
+ boolean changed = false;
+ synchronized (mLock) {
+ if (mActivated) {
+ Log.d(TAG, "configuration will be postponed until deactivation");
+ mComputeFgRequested = true;
+ return;
+ }
+ mComputeFgRequested = false;
+ foregroundRequested = mForegroundRequested;
+ if (mForegroundRequested != null &&
+ (mForegroundComponent == null ||
+ !mForegroundRequested.equals(mForegroundComponent))) {
+ mForegroundComponent = mForegroundRequested;
+ changed = true;
+ } else if (mForegroundRequested == null && mForegroundComponent != null){
+ mForegroundComponent = mForegroundRequested;
+ changed = true;
+ }
+ }
+ // Notify if anything changed
+ if (changed) {
+ mCallback.onEnabledForegroundNfcFServiceChanged(foregroundRequested);
+ }
+ }
+
+ public void onServicesUpdated() {
+ if (DBG) Log.d(TAG, "onServicesUpdated");
+ // If enabled foreground service is set, remove it
+ boolean changed = false;
+ synchronized (mLock) {
+ if (mForegroundComponent != null) {
+ Log.d(TAG, "Removing foreground enabled service because of service update.");
+ mForegroundRequested = null;
+ mForegroundUid = -1;
+ changed = true;
+ }
+ }
+ if (changed) {
+ computeEnabledForegroundService();
+ }
+ }
+
+ public boolean registerEnabledForegroundService(ComponentName service, int callingUid) {
+ if (DBG) Log.d(TAG, "registerEnabledForegroundService");
+ boolean success = false;
+ synchronized (mLock) {
+ NfcFServiceInfo serviceInfo = mNfcFServiceCache.getService(
+ ActivityManager.getCurrentUser(), service);
+ if (serviceInfo == null) {
+ return false;
+ } else {
+ if (serviceInfo.getSystemCode().equalsIgnoreCase("NULL") ||
+ serviceInfo.getNfcid2().equalsIgnoreCase("NULL")) {
+ return false;
+ }
+ }
+ if (service.equals(mForegroundRequested)) {
+ Log.e(TAG, "The servcie is already requested to the foreground service.");
+ return true;
+ }
+ if (mForegroundUtils.registerUidToBackgroundCallback(this, callingUid)) {
+ mForegroundRequested = service;
+ mForegroundUid = callingUid;
+ success = true;
+ } else {
+ Log.e(TAG, "Calling UID is not in the foreground, ignorning!");
+ }
+ }
+ if (success) {
+ computeEnabledForegroundService();
+ }
+ return success;
+ }
+
+ boolean unregisterForegroundService(int uid) {
+ if (DBG) Log.d(TAG, "unregisterForegroundService");
+ boolean success = false;
+ synchronized (mLock) {
+ if (mForegroundUid == uid) {
+ mForegroundRequested = null;
+ mForegroundUid = -1;
+ success = true;
+ } // else, other UID in foreground
+ }
+ if (success) {
+ computeEnabledForegroundService();
+ }
+ return success;
+ }
+
+ public boolean unregisteredEnabledForegroundService(int callingUid) {
+ if (DBG) Log.d(TAG, "unregisterEnabledForegroundService");
+ // Verify the calling UID is in the foreground
+ if (mForegroundUtils.isInForeground(callingUid)) {
+ return unregisterForegroundService(callingUid);
+ } else {
+ Log.e(TAG, "Calling UID is not in the foreground, ignorning!");
+ return false;
+ }
+ }
+
+ @Override
+ public void onUidToBackground(int uid) {
+ if (DBG) Log.d(TAG, "onUidToBackground");
+ unregisterForegroundService(uid);
+ }
+
+ public void onHostEmulationActivated() {
+ if (DBG) Log.d(TAG, "onHostEmulationActivated");
+ synchronized (mLock) {
+ mActivated = true;
+ }
+ }
+
+ public void onHostEmulationDeactivated() {
+ if (DBG) Log.d(TAG, "onHostEmulationDeactivated");
+ boolean needComputeFg = false;
+ synchronized (mLock) {
+ mActivated = false;
+ if (mComputeFgRequested) {
+ needComputeFg = true;
+ }
+ }
+ if (needComputeFg) {
+ Log.d(TAG, "do postponed configuration");
+ computeEnabledForegroundService();
+ }
+ }
+
+ public void onNfcDisabled() {
+ synchronized (mLock) {
+ mForegroundComponent = null;
+ mForegroundRequested = null;
+ mActivated = false;
+ mComputeFgRequested = false;
+ mForegroundUid = -1;
+ }
+ }
+
+ public void onUserSwitched(int userId) {
+ synchronized (mLock) {
+ mForegroundComponent = null;
+ mForegroundRequested = null;
+ mActivated = false;
+ mComputeFgRequested = false;
+ mForegroundUid = -1;
+ }
+ }
+
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ }
+}
diff --git a/src/com/android/nfc/cardemulation/HostNfcFEmulationManager.java b/src/com/android/nfc/cardemulation/HostNfcFEmulationManager.java
new file mode 100644
index 0000000..db61a06
--- /dev/null
+++ b/src/com/android/nfc/cardemulation/HostNfcFEmulationManager.java
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2015 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.cardemulation;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.nfc.cardemulation.NfcFServiceInfo;
+import android.nfc.cardemulation.HostNfcFService;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+
+import com.android.nfc.NfcService;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+public class HostNfcFEmulationManager {
+ static final String TAG = "HostNfcFEmulationManager";
+ static final boolean DBG = false;
+
+ static final int STATE_IDLE = 0;
+ static final int STATE_W4_SERVICE = 1;
+ static final int STATE_XFER = 2;
+
+ /** NFCID2 length */
+ static final int NFCID2_LENGTH = 8;
+
+ /** Minimum NFC-F packets including length, command code and NFCID2 */
+ static final int MINIMUM_NFCF_PACKET_LENGTH = 10;
+
+ final Context mContext;
+ final RegisteredT3tIdentifiersCache mT3tIdentifiersCache;
+ final Messenger mMessenger = new Messenger (new MessageHandler());
+ final Object mLock;
+
+ // All variables below protected by mLock
+ ComponentName mEnabledFgServiceName;
+
+ Messenger mService;
+ boolean mServiceBound;
+ ComponentName mServiceName;
+
+ // mActiveService denotes the service interface
+ // that is the current active one, until a new packet
+ // comes in that may be resolved to a different service.
+ // On deactivation, mActiveService stops being valid.
+ Messenger mActiveService;
+ ComponentName mActiveServiceName;
+
+ int mState;
+ byte[] mPendingPacket;
+
+ public HostNfcFEmulationManager(Context context,
+ RegisteredT3tIdentifiersCache t3tIdentifiersCache) {
+ mContext = context;
+ mLock = new Object();
+ mEnabledFgServiceName = null;
+ mT3tIdentifiersCache = t3tIdentifiersCache;
+ mState = STATE_IDLE;
+ }
+
+ public void onEnabledForegroundNfcFServiceChanged(ComponentName service) {
+ synchronized (mLock) {
+ mEnabledFgServiceName = service;
+ if (service == null) {
+ sendDeactivateToActiveServiceLocked(HostNfcFService.DEACTIVATION_LINK_LOSS);
+ unbindServiceIfNeededLocked();
+ }
+ }
+ }
+
+ public void onHostEmulationActivated() {
+ if (DBG) Log.d(TAG, "notifyHostEmulationActivated");
+ }
+
+ public void onHostEmulationData(byte[] data) {
+ if (DBG) Log.d(TAG, "notifyHostEmulationData");
+ String nfcid2 = findNfcid2(data);
+ ComponentName resolvedServiceName = null;
+ synchronized (mLock) {
+ if (nfcid2 != null) {
+ NfcFServiceInfo resolvedService = mT3tIdentifiersCache.resolveNfcid2(nfcid2);
+ if (resolvedService != null) {
+ resolvedServiceName = resolvedService.getComponent();
+ }
+ }
+ if (resolvedServiceName == null) {
+ if (mActiveServiceName == null) {
+ return;
+ }
+ resolvedServiceName = mActiveServiceName;
+ }
+ // Check if resolvedService is actually currently enabled
+ if (mEnabledFgServiceName == null ||
+ !mEnabledFgServiceName.equals(resolvedServiceName)) {
+ return;
+ }
+ if (DBG) Log.d(TAG, "resolvedServiceName: " + resolvedServiceName.toString() +
+ "mState: " + String.valueOf(mState));
+ switch (mState) {
+ case STATE_IDLE:
+ Messenger existingService = bindServiceIfNeededLocked(resolvedServiceName);
+ if (existingService != null) {
+ Log.d(TAG, "Binding to existing service");
+ mState = STATE_XFER;
+ sendDataToServiceLocked(existingService, data);
+ } else {
+ // Waiting for service to be bound
+ Log.d(TAG, "Waiting for new service.");
+ // Queue packet to be used
+ mPendingPacket = data;
+ mState = STATE_W4_SERVICE;
+ }
+ break;
+ case STATE_W4_SERVICE:
+ Log.d(TAG, "Unexpected packet in STATE_W4_SERVICE");
+ break;
+ case STATE_XFER:
+ // Regular packet data
+ sendDataToServiceLocked(mActiveService, data);
+ break;
+ }
+ }
+ }
+
+ public void onHostEmulationDeactivated() {
+ if (DBG) Log.d(TAG, "notifyHostEmulationDeactivated");
+ synchronized (mLock) {
+ sendDeactivateToActiveServiceLocked(HostNfcFService.DEACTIVATION_LINK_LOSS);
+ mActiveService = null;
+ mActiveServiceName = null;
+ unbindServiceIfNeededLocked();
+ mState = STATE_IDLE;
+ }
+ }
+
+ public void onNfcDisabled() {
+ synchronized (mLock) {
+ sendDeactivateToActiveServiceLocked(HostNfcFService.DEACTIVATION_LINK_LOSS);
+ mEnabledFgServiceName = null;
+ mActiveService = null;
+ mActiveServiceName = null;
+ unbindServiceIfNeededLocked();
+ mState = STATE_IDLE;
+ }
+ }
+
+ public void onUserSwitched() {
+ synchronized (mLock) {
+ sendDeactivateToActiveServiceLocked(HostNfcFService.DEACTIVATION_LINK_LOSS);
+ mEnabledFgServiceName = null;
+ mActiveService = null;
+ mActiveServiceName = null;
+ unbindServiceIfNeededLocked();
+ mState = STATE_IDLE;
+ }
+ }
+
+ void sendDataToServiceLocked(Messenger service, byte[] data) {
+ if (DBG) Log.d(TAG, "sendDataToServiceLocked");
+ if (DBG) {
+ Log.d(TAG, "service: " +
+ (service != null ? service.toString() : "null"));
+ Log.d(TAG, "mActiveService: " +
+ (mActiveService != null ? mActiveService.toString() : "null"));
+ }
+ if (service != mActiveService) {
+ sendDeactivateToActiveServiceLocked(HostNfcFService.DEACTIVATION_LINK_LOSS);
+ mActiveService = service;
+ mActiveServiceName = mServiceName;
+ }
+ Message msg = Message.obtain(null, HostNfcFService.MSG_COMMAND_PACKET);
+ Bundle dataBundle = new Bundle();
+ dataBundle.putByteArray("data", data);
+ msg.setData(dataBundle);
+ msg.replyTo = mMessenger;
+ try {
+ Log.d(TAG, "Sending data to service");
+ if (DBG) Log.d(TAG, "data: " + getByteDump(data));
+ mActiveService.send(msg);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Remote service has died, dropping packet");
+ }
+ }
+
+ void sendDeactivateToActiveServiceLocked(int reason) {
+ if (DBG) Log.d(TAG, "sendDeactivateToActiveServiceLocked");
+ if (mActiveService == null) return;
+ Message msg = Message.obtain(null, HostNfcFService.MSG_DEACTIVATED);
+ msg.arg1 = reason;
+ try {
+ mActiveService.send(msg);
+ } catch (RemoteException e) {
+ // Don't care
+ }
+ }
+
+ Messenger bindServiceIfNeededLocked(ComponentName service) {
+ if (DBG) Log.d(TAG, "bindServiceIfNeededLocked");
+ if (mServiceBound && mServiceName.equals(service)) {
+ Log.d(TAG, "Service already bound.");
+ return mService;
+ } else {
+ Log.d(TAG, "Binding to service " + service);
+ unbindServiceIfNeededLocked();
+ Intent bindIntent = new Intent(HostNfcFService.SERVICE_INTERFACE);
+ bindIntent.setComponent(service);
+ if (mContext.bindServiceAsUser(bindIntent, mConnection,
+ Context.BIND_AUTO_CREATE, UserHandle.CURRENT)) {
+ } else {
+ Log.e(TAG, "Could not bind service.");
+ }
+ return null;
+ }
+ }
+
+ void unbindServiceIfNeededLocked() {
+ if (DBG) Log.d(TAG, "unbindServiceIfNeededLocked");
+ if (mServiceBound) {
+ Log.d(TAG, "Unbinding from service " + mServiceName);
+ mContext.unbindService(mConnection);
+ mServiceBound = false;
+ mService = null;
+ mServiceName = null;
+ }
+ }
+
+ String findNfcid2(byte[] data) {
+ if (DBG) Log.d(TAG, "findNfcid2");
+ if (data == null || data.length < MINIMUM_NFCF_PACKET_LENGTH) {
+ if (DBG) Log.d(TAG, "Data size too small");
+ return null;
+ }
+ int nfcid2Offset = 2;
+ return bytesToString(data, nfcid2Offset, NFCID2_LENGTH);
+ }
+
+ private ServiceConnection mConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ synchronized (mLock) {
+ mService = new Messenger(service);
+ mServiceBound = true;
+ mServiceName = name;
+ Log.d(TAG, "Service bound");
+ mState = STATE_XFER;
+ // Send pending packet
+ if (mPendingPacket != null) {
+ sendDataToServiceLocked(mService, mPendingPacket);
+ mPendingPacket = null;
+ }
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ synchronized (mLock) {
+ Log.d(TAG, "Service unbound");
+ mService = null;
+ mServiceBound = false;
+ mServiceName = null;
+ }
+ }
+ };
+
+ class MessageHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ synchronized(mLock) {
+ if (mActiveService == null) {
+ Log.d(TAG, "Dropping service response message; service no longer active.");
+ return;
+ } else if (!msg.replyTo.getBinder().equals(mActiveService.getBinder())) {
+ Log.d(TAG, "Dropping service response message; service no longer bound.");
+ return;
+ }
+ }
+ if (msg.what == HostNfcFService.MSG_RESPONSE_PACKET) {
+ Bundle dataBundle = msg.getData();
+ if (dataBundle == null) {
+ return;
+ }
+ byte[] data = dataBundle.getByteArray("data");
+ if (data == null) {
+ return;
+ }
+ if (data.length == 0) {
+ Log.e(TAG, "Invalid response packet");
+ return;
+ }
+ if (data.length != (data[0] & 0xff)) {
+ Log.e(TAG, "Invalid response packet");
+ return;
+ }
+ int state;
+ synchronized(mLock) {
+ state = mState;
+ }
+ if (state == STATE_XFER) {
+ Log.d(TAG, "Sending data");
+ if (DBG) Log.d(TAG, "data:" + getByteDump(data));
+ NfcService.getInstance().sendData(data);
+ } else {
+ Log.d(TAG, "Dropping data, wrong state " + Integer.toString(state));
+ }
+ }
+ }
+ }
+
+ static String bytesToString(byte[] bytes, int offset, int length) {
+ final char[] hexChars = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+ char[] chars = new char[length * 2];
+ int byteValue;
+ for (int j = 0; j < length; j++) {
+ byteValue = bytes[offset + j] & 0xFF;
+ chars[j * 2] = hexChars[byteValue >>> 4];
+ chars[j * 2 + 1] = hexChars[byteValue & 0x0F];
+ }
+ return new String(chars);
+ }
+
+ private String getByteDump(final byte[] cmd) {
+ StringBuffer str = new StringBuffer("");
+ int letters = 8;
+ int i = 0;
+
+ if (cmd == null) {
+ str.append(" null\n");
+ return str.toString();
+ }
+
+ for (; i < cmd.length; i++) {
+ str.append(String.format(" %02X", cmd[i]));
+ if ((i % letters == letters - 1) || (i + 1 == cmd.length)) {
+ str.append("\n");
+ }
+ }
+
+ return str.toString();
+ }
+
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("Bound services: ");
+ if (mServiceBound) {
+ pw.println(" service: " + mServiceName);
+ }
+ }
+}
diff --git a/src/com/android/nfc/cardemulation/RegisteredNfcFServicesCache.java b/src/com/android/nfc/cardemulation/RegisteredNfcFServicesCache.java
new file mode 100644
index 0000000..cf188aa
--- /dev/null
+++ b/src/com/android/nfc/cardemulation/RegisteredNfcFServicesCache.java
@@ -0,0 +1,719 @@
+/*
+ * Copyright (C) 2015 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.cardemulation;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.nfc.cardemulation.NfcFServiceInfo;
+import android.nfc.cardemulation.NfcFCardEmulation;
+import android.nfc.cardemulation.HostNfcFService;
+import android.os.UserHandle;
+import android.util.AtomicFile;
+import android.util.Log;
+import android.util.SparseArray;
+import android.util.Xml;
+
+import com.android.internal.util.FastXmlSerializer;
+import com.google.android.collect.Maps;
+
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
+
+public class RegisteredNfcFServicesCache {
+ static final String XML_INDENT_OUTPUT_FEATURE = "http://xmlpull.org/v1/doc/features.html#indent-output";
+ static final String TAG = "RegisteredNfcFServicesCache";
+ static final boolean DBG = false;
+
+ final Context mContext;
+ final AtomicReference<BroadcastReceiver> mReceiver;
+
+ final Object mLock = new Object();
+ // All variables below synchronized on mLock
+
+ // mUserServices holds the card emulation services that are running for each user
+ final SparseArray<UserServices> mUserServices = new SparseArray<UserServices>();
+ final Callback mCallback;
+ final AtomicFile mDynamicSystemCodeNfcid2File;
+ boolean mActivated = false;
+
+ public interface Callback {
+ void onNfcFServicesUpdated(int userId, final List<NfcFServiceInfo> services);
+ };
+
+ static class DynamicSystemCode {
+ public final int uid;
+ public final String systemCode;
+
+ DynamicSystemCode(int uid, String systemCode) {
+ this.uid = uid;
+ this.systemCode = systemCode;
+ }
+ };
+
+ static class DynamicNfcid2 {
+ public final int uid;
+ public final String nfcid2;
+
+ DynamicNfcid2(int uid, String nfcid2) {
+ this.uid = uid;
+ this.nfcid2 = nfcid2;
+ }
+ };
+
+ private static class UserServices {
+ /**
+ * All services that have registered
+ */
+ final HashMap<ComponentName, NfcFServiceInfo> services =
+ Maps.newHashMap(); // Re-built at run-time
+ final HashMap<ComponentName, DynamicSystemCode> dynamicSystemCode =
+ Maps.newHashMap(); // In memory cache of dynamic System Code store
+ final HashMap<ComponentName, DynamicNfcid2> dynamicNfcid2 =
+ Maps.newHashMap(); // In memory cache of dynamic NFCID2 store
+ };
+
+ private UserServices findOrCreateUserLocked(int userId) {
+ UserServices userServices = mUserServices.get(userId);
+ if (userServices == null) {
+ userServices = new UserServices();
+ mUserServices.put(userId, userServices);
+ }
+ return userServices;
+ }
+
+ public RegisteredNfcFServicesCache(Context context, Callback callback) {
+ mContext = context;
+ mCallback = callback;
+
+ final BroadcastReceiver receiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ String action = intent.getAction();
+ if (DBG) Log.d(TAG, "Intent action: " + action);
+ if (uid != -1) {
+ boolean replaced = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false) &&
+ (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
+ Intent.ACTION_PACKAGE_REMOVED.equals(action));
+ if (!replaced) {
+ int currentUser = ActivityManager.getCurrentUser();
+ if (currentUser == UserHandle.getUserId(uid)) {
+ invalidateCache(UserHandle.getUserId(uid));
+ } else {
+ // Cache will automatically be updated on user switch
+ }
+ } else {
+ if (DBG) Log.d(TAG,
+ "Ignoring package intent due to package being replaced.");
+ }
+ }
+ }
+ };
+ mReceiver = new AtomicReference<BroadcastReceiver>(receiver);
+
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+ intentFilter.addAction(Intent.ACTION_PACKAGE_FIRST_LAUNCH);
+ intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
+ intentFilter.addDataScheme("package");
+ mContext.registerReceiverAsUser(mReceiver.get(), UserHandle.ALL, intentFilter, null, null);
+
+ // Register for events related to sdcard operations
+ IntentFilter sdFilter = new IntentFilter();
+ sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+ sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+ mContext.registerReceiverAsUser(mReceiver.get(), UserHandle.ALL, sdFilter, null, null);
+
+ File dataDir = mContext.getFilesDir();
+ mDynamicSystemCodeNfcid2File =
+ new AtomicFile(new File(dataDir, "dynamic_systemcode_nfcid2.xml"));
+ }
+
+ void initialize() {
+ synchronized (mLock) {
+ readDynamicSystemCodeNfcid2Locked();
+ }
+ invalidateCache(ActivityManager.getCurrentUser());
+ }
+
+ void dump(ArrayList<NfcFServiceInfo> services) {
+ for (NfcFServiceInfo service : services) {
+ Log.d(TAG, service.toString());
+ }
+ }
+
+ boolean containsServiceLocked(ArrayList<NfcFServiceInfo> services,
+ ComponentName componentName) {
+ for (NfcFServiceInfo service : services) {
+ if (service.getComponent().equals(componentName)) return true;
+ }
+ return false;
+ }
+
+ public boolean hasService(int userId, ComponentName componentName) {
+ return getService(userId, componentName) != null;
+ }
+
+ public NfcFServiceInfo getService(int userId, ComponentName componentName) {
+ synchronized (mLock) {
+ UserServices userServices = findOrCreateUserLocked(userId);
+ return userServices.services.get(componentName);
+ }
+ }
+
+ public List<NfcFServiceInfo> getServices(int userId) {
+ final ArrayList<NfcFServiceInfo> services = new ArrayList<NfcFServiceInfo>();
+ synchronized (mLock) {
+ UserServices userServices = findOrCreateUserLocked(userId);
+ services.addAll(userServices.services.values());
+ }
+ return services;
+ }
+
+ ArrayList<NfcFServiceInfo> getInstalledServices(int userId) {
+ if (DBG) Log.d(TAG, "getInstalledServices");
+ PackageManager pm;
+ try {
+ pm = mContext.createPackageContextAsUser("android", 0,
+ new UserHandle(userId)).getPackageManager();
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Could not create user package context");
+ return null;
+ }
+
+ ArrayList<NfcFServiceInfo> validServices = new ArrayList<NfcFServiceInfo>();
+
+ List<ResolveInfo> resolvedServices = pm.queryIntentServicesAsUser(
+ new Intent(HostNfcFService.SERVICE_INTERFACE),
+ PackageManager.GET_META_DATA, userId);
+
+ for (ResolveInfo resolvedService : resolvedServices) {
+ try {
+ ServiceInfo si = resolvedService.serviceInfo;
+ ComponentName componentName = new ComponentName(si.packageName, si.name);
+ // Check if the package holds the NFC permission
+ if (pm.checkPermission(android.Manifest.permission.NFC, si.packageName) !=
+ PackageManager.PERMISSION_GRANTED) {
+ Log.e(TAG, "Skipping NfcF service " + componentName +
+ ": it does not require the permission " +
+ android.Manifest.permission.NFC);
+ continue;
+ }
+ if (!android.Manifest.permission.BIND_NFC_SERVICE.equals(
+ si.permission)) {
+ Log.e(TAG, "Skipping NfcF service " + componentName +
+ ": it does not require the permission " +
+ android.Manifest.permission.BIND_NFC_SERVICE);
+ continue;
+ }
+ NfcFServiceInfo service = new NfcFServiceInfo(pm, resolvedService);
+ if (service != null) {
+ validServices.add(service);
+ }
+ } catch (XmlPullParserException e) {
+ Log.w(TAG, "Unable to load component info " + resolvedService.toString(), e);
+ } catch (IOException e) {
+ Log.w(TAG, "Unable to load component info " + resolvedService.toString(), e);
+ }
+ }
+
+ return validServices;
+ }
+
+ public void invalidateCache(int userId) {
+ if (DBG) Log.d(TAG, "invalidateCache");
+ final ArrayList<NfcFServiceInfo> validServices = getInstalledServices(userId);
+ if (validServices == null) {
+ return;
+ }
+ ArrayList<NfcFServiceInfo> newServices = null;
+ synchronized (mLock) {
+ UserServices userServices = findOrCreateUserLocked(userId);
+
+ // Check update
+ ArrayList<NfcFServiceInfo> cachedServices =
+ new ArrayList<NfcFServiceInfo>(userServices.services.values());
+ ArrayList<NfcFServiceInfo> toBeAdded = new ArrayList<NfcFServiceInfo>();
+ ArrayList<NfcFServiceInfo> toBeRemoved = new ArrayList<NfcFServiceInfo>();
+ boolean matched = false;
+ for (NfcFServiceInfo validService : validServices) {
+ for (NfcFServiceInfo cachedService : cachedServices) {
+ if (validService.equals(cachedService)) {
+ matched = true;
+ break;
+ }
+ }
+ if (!matched) {
+ toBeAdded.add(validService);
+ }
+ matched = false;
+ }
+ for (NfcFServiceInfo cachedService : cachedServices) {
+ for (NfcFServiceInfo validService : validServices) {
+ if (cachedService.equals(validService)) {
+ matched = true;
+ break;
+ }
+ }
+ if (!matched) {
+ toBeRemoved.add(cachedService);
+ }
+ matched = false;
+ }
+ if (toBeAdded.size() == 0 && toBeRemoved.size() == 0) {
+ Log.d(TAG, "Service unchanged, not updating");
+ return;
+ }
+
+ // Update cache
+ for (NfcFServiceInfo service : toBeAdded) {
+ userServices.services.put(service.getComponent(), service);
+ if (DBG) Log.d(TAG, "Added service: " + service.getComponent());
+ }
+ for (NfcFServiceInfo service : toBeRemoved) {
+ userServices.services.remove(service.getComponent());
+ if (DBG) Log.d(TAG, "Removed service: " + service.getComponent());
+ }
+ // Apply dynamic System Code mappings
+ ArrayList<ComponentName> toBeRemovedDynamicSystemCode =
+ new ArrayList<ComponentName>();
+ for (Map.Entry<ComponentName, DynamicSystemCode> entry :
+ userServices.dynamicSystemCode.entrySet()) {
+ // Verify component / uid match
+ ComponentName componentName = entry.getKey();
+ DynamicSystemCode dynamicSystemCode = entry.getValue();
+ NfcFServiceInfo service = userServices.services.get(componentName);
+ if (service == null || (service.getUid() != dynamicSystemCode.uid)) {
+ toBeRemovedDynamicSystemCode.add(componentName);
+ continue;
+ } else {
+ service.setOrReplaceDynamicSystemCode(dynamicSystemCode.systemCode);
+ }
+ }
+ // Apply dynamic NFCID2 mappings
+ ArrayList<ComponentName> toBeRemovedDynamicNfcid2 =
+ new ArrayList<ComponentName>();
+ for (Map.Entry<ComponentName, DynamicNfcid2> entry :
+ userServices.dynamicNfcid2.entrySet()) {
+ // Verify component / uid match
+ ComponentName componentName = entry.getKey();
+ DynamicNfcid2 dynamicNfcid2 = entry.getValue();
+ NfcFServiceInfo service = userServices.services.get(componentName);
+ if (service == null || (service.getUid() != dynamicNfcid2.uid)) {
+ toBeRemovedDynamicNfcid2.add(componentName);
+ continue;
+ } else {
+ service.setOrReplaceDynamicNfcid2(dynamicNfcid2.nfcid2);
+ }
+ }
+ for (ComponentName removedComponent : toBeRemovedDynamicSystemCode) {
+ Log.d(TAG, "Removing dynamic System Code registered by " +
+ removedComponent);
+ userServices.dynamicSystemCode.remove(removedComponent);
+ }
+ for (ComponentName removedComponent : toBeRemovedDynamicNfcid2) {
+ Log.d(TAG, "Removing dynamic NFCID2 registered by " +
+ removedComponent);
+ userServices.dynamicNfcid2.remove(removedComponent);
+ }
+ // Assign a NFCID2 for services requesting a random NFCID2, then apply
+ boolean nfcid2Assigned = false;
+ for (Map.Entry<ComponentName, NfcFServiceInfo> entry :
+ userServices.services.entrySet()) {
+ NfcFServiceInfo service = entry.getValue();
+ if (service.getNfcid2().equalsIgnoreCase("RANDOM")) {
+ String randomNfcid2 = generateRandomNfcid2();
+ service.setOrReplaceDynamicNfcid2(randomNfcid2);
+ DynamicNfcid2 dynamicNfcid2 =
+ new DynamicNfcid2(service.getUid(), randomNfcid2);
+ userServices.dynamicNfcid2.put(entry.getKey(), dynamicNfcid2);
+ nfcid2Assigned = true;
+ }
+ }
+
+ // Persist to filesystem
+ if (toBeRemovedDynamicSystemCode.size() > 0 ||
+ toBeRemovedDynamicNfcid2.size() > 0 ||
+ nfcid2Assigned) {
+ writeDynamicSystemCodeNfcid2Locked();
+ }
+
+ newServices = new ArrayList<NfcFServiceInfo>(userServices.services.values());
+ }
+ mCallback.onNfcFServicesUpdated(userId, Collections.unmodifiableList(newServices));
+ if (DBG) dump(newServices);
+ }
+
+ private void readDynamicSystemCodeNfcid2Locked() {
+ if (DBG) Log.d(TAG, "readDynamicSystemCodeNfcid2Locked");
+ FileInputStream fis = null;
+ try {
+ if (!mDynamicSystemCodeNfcid2File.getBaseFile().exists()) {
+ Log.d(TAG, "Dynamic System Code, NFCID2 file does not exist.");
+ return;
+ }
+ fis = mDynamicSystemCodeNfcid2File.openRead();
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(fis, null);
+ int eventType = parser.getEventType();
+ while (eventType != XmlPullParser.START_TAG &&
+ eventType != XmlPullParser.END_DOCUMENT) {
+ eventType = parser.next();
+ }
+ String tagName = parser.getName();
+ if ("services".equals(tagName)) {
+ ComponentName componentName = null;
+ int currentUid = -1;
+ String systemCode = null;
+ String nfcid2 = null;
+ String description = null;
+ while (eventType != XmlPullParser.END_DOCUMENT) {
+ tagName = parser.getName();
+ if (eventType == XmlPullParser.START_TAG) {
+ if ("service".equals(tagName) && parser.getDepth() == 2) {
+ String compString =
+ parser.getAttributeValue(null, "component");
+ String uidString =
+ parser.getAttributeValue(null, "uid");
+ String systemCodeString =
+ parser.getAttributeValue(null, "system-code");
+ String descriptionString =
+ parser.getAttributeValue(null, "description");
+ String nfcid2String =
+ parser.getAttributeValue(null, "nfcid2");
+ if (compString == null || uidString == null) {
+ Log.e(TAG, "Invalid service attributes");
+ } else {
+ try {
+ componentName = ComponentName.unflattenFromString(compString);
+ currentUid = Integer.parseInt(uidString);
+ systemCode = systemCodeString;
+ description = descriptionString;
+ nfcid2 = nfcid2String;
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "Could not parse service uid");
+ }
+ }
+ }
+ } else if (eventType == XmlPullParser.END_TAG) {
+ if ("service".equals(tagName)) {
+ // See if we have a valid service
+ if (componentName != null && currentUid >= 0) {
+ final int userId = UserHandle.getUserId(currentUid);
+ UserServices userServices = findOrCreateUserLocked(userId);
+ if (systemCode != null) {
+ DynamicSystemCode dynamicSystemCode =
+ new DynamicSystemCode(currentUid, systemCode);
+ userServices.dynamicSystemCode.put(
+ componentName, dynamicSystemCode);
+ }
+ if (nfcid2 != null) {
+ DynamicNfcid2 dynamicNfcid2 =
+ new DynamicNfcid2(currentUid, nfcid2);
+ userServices.dynamicNfcid2.put(
+ componentName, dynamicNfcid2);
+ }
+ }
+ componentName = null;
+ currentUid = -1;
+ systemCode = null;
+ description = null;
+ nfcid2 = null;
+ }
+ }
+ eventType = parser.next();
+ };
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Could not parse dynamic System Code, NFCID2 file, trashing.");
+ mDynamicSystemCodeNfcid2File.delete();
+ } finally {
+ if (fis != null) {
+ try {
+ fis.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+
+ private boolean writeDynamicSystemCodeNfcid2Locked() {
+ if (DBG) Log.d(TAG, "writeDynamicSystemCodeNfcid2Locked");
+ FileOutputStream fos = null;
+ try {
+ fos = mDynamicSystemCodeNfcid2File.startWrite();
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(fos, "utf-8");
+ out.startDocument(null, true);
+ out.setFeature(XML_INDENT_OUTPUT_FEATURE, true);
+ out.startTag(null, "services");
+ for (int i = 0; i < mUserServices.size(); i++) {
+ final UserServices userServices = mUserServices.valueAt(i);
+ for (Map.Entry<ComponentName, DynamicSystemCode> entry :
+ userServices.dynamicSystemCode.entrySet()) {
+ out.startTag(null, "service");
+ out.attribute(null, "component", entry.getKey().flattenToString());
+ out.attribute(null, "uid", Integer.toString(entry.getValue().uid));
+ out.attribute(null, "system-code", entry.getValue().systemCode);
+ if (userServices.dynamicNfcid2.containsKey(entry.getKey())) {
+ out.attribute(null, "nfcid2",
+ userServices.dynamicNfcid2.get(entry.getKey()).nfcid2);
+ }
+ out.endTag(null, "service");
+ }
+ for (Map.Entry<ComponentName, DynamicNfcid2> entry :
+ userServices.dynamicNfcid2.entrySet()) {
+ if (!userServices.dynamicSystemCode.containsKey(entry.getKey())) {
+ out.startTag(null, "service");
+ out.attribute(null, "component", entry.getKey().flattenToString());
+ out.attribute(null, "uid", Integer.toString(entry.getValue().uid));
+ out.attribute(null, "nfcid2", entry.getValue().nfcid2);
+ out.endTag(null, "service");
+ }
+ }
+ }
+ out.endTag(null, "services");
+ out.endDocument();
+ mDynamicSystemCodeNfcid2File.finishWrite(fos);
+ return true;
+ } catch (Exception e) {
+ Log.e(TAG, "Error writing dynamic System Code, NFCID2", e);
+ if (fos != null) {
+ mDynamicSystemCodeNfcid2File.failWrite(fos);
+ }
+ return false;
+ }
+ }
+
+ public boolean registerSystemCodeForService(int userId, int uid,
+ ComponentName componentName, String systemCode) {
+ if (DBG) Log.d(TAG, "registerSystemCodeForService");
+ ArrayList<NfcFServiceInfo> newServices = null;
+ boolean success;
+ synchronized (mLock) {
+ if (mActivated) {
+ Log.d(TAG, "failed to register System Code during activation");
+ return false;
+ }
+ UserServices userServices = findOrCreateUserLocked(userId);
+ // Check if we can find this service
+ NfcFServiceInfo service = getService(userId, componentName);
+ if (service == null) {
+ Log.e(TAG, "Service " + componentName + " does not exist.");
+ return false;
+ }
+ if (service.getUid() != uid) {
+ // This is probably a good indication something is wrong here.
+ // Either newer service installed with different uid (but then
+ // we should have known about it), or somebody calling us from
+ // a different uid.
+ Log.e(TAG, "UID mismatch.");
+ return false;
+ }
+ if (!systemCode.equalsIgnoreCase("NULL") &&
+ !NfcFCardEmulation.isValidSystemCode(systemCode)) {
+ Log.e(TAG, "System Code " + systemCode + " is not a valid System Code");
+ return false;
+ }
+ // Apply dynamic System Code mappings
+ systemCode = systemCode.toUpperCase();
+ DynamicSystemCode oldDynamicSystemCode =
+ userServices.dynamicSystemCode.get(componentName);
+ DynamicSystemCode dynamicSystemCode = new DynamicSystemCode(uid, systemCode);
+ userServices.dynamicSystemCode.put(componentName, dynamicSystemCode);
+ success = writeDynamicSystemCodeNfcid2Locked();
+ if (success) {
+ service.setOrReplaceDynamicSystemCode(systemCode);
+ newServices = new ArrayList<NfcFServiceInfo>(userServices.services.values());
+ } else {
+ Log.e(TAG, "Failed to persist System Code.");
+ // Undo registration
+ if (oldDynamicSystemCode == null) {
+ userServices.dynamicSystemCode.remove(componentName);
+ } else {
+ userServices.dynamicSystemCode.put(componentName, oldDynamicSystemCode);
+ }
+ }
+ }
+ if (success) {
+ // Make callback without the lock held
+ mCallback.onNfcFServicesUpdated(userId, newServices);
+ }
+ return success;
+ }
+
+ public String getSystemCodeForService(int userId, int uid, ComponentName componentName) {
+ if (DBG) Log.d(TAG, "getSystemCodeForService");
+ NfcFServiceInfo service = getService(userId, componentName);
+ if (service != null) {
+ if (service.getUid() != uid) {
+ Log.e(TAG, "UID mismatch");
+ return null;
+ }
+ return service.getSystemCode();
+ } else {
+ Log.e(TAG, "Could not find service " + componentName);
+ return null;
+ }
+ }
+
+ public boolean removeSystemCodeForService(int userId, int uid, ComponentName componentName) {
+ if (DBG) Log.d(TAG, "removeSystemCodeForService");
+ return registerSystemCodeForService(userId, uid, componentName, "NULL");
+ }
+
+ public boolean setNfcid2ForService(int userId, int uid,
+ ComponentName componentName, String nfcid2) {
+ if (DBG) Log.d(TAG, "setNfcid2ForService");
+ ArrayList<NfcFServiceInfo> newServices = null;
+ boolean success;
+ synchronized (mLock) {
+ if (mActivated) {
+ Log.d(TAG, "failed to set NFCID2 during activation");
+ return false;
+ }
+ UserServices userServices = findOrCreateUserLocked(userId);
+ // Check if we can find this service
+ NfcFServiceInfo service = getService(userId, componentName);
+ if (service == null) {
+ Log.e(TAG, "Service " + componentName + " does not exist.");
+ return false;
+ }
+ if (service.getUid() != uid) {
+ // This is probably a good indication something is wrong here.
+ // Either newer service installed with different uid (but then
+ // we should have known about it), or somebody calling us from
+ // a different uid.
+ Log.e(TAG, "UID mismatch.");
+ return false;
+ }
+ if (!NfcFCardEmulation.isValidNfcid2(nfcid2)) {
+ Log.e(TAG, "NFCID2 " + nfcid2 + " is not a valid NFCID2");
+ return false;
+ }
+ // Apply dynamic NFCID2 mappings
+ nfcid2 = nfcid2.toUpperCase();
+ DynamicNfcid2 oldDynamicNfcid2 = userServices.dynamicNfcid2.get(componentName);
+ DynamicNfcid2 dynamicNfcid2 = new DynamicNfcid2(uid, nfcid2);
+ userServices.dynamicNfcid2.put(componentName, dynamicNfcid2);
+ success = writeDynamicSystemCodeNfcid2Locked();
+ if (success) {
+ service.setOrReplaceDynamicNfcid2(nfcid2);
+ newServices = new ArrayList<NfcFServiceInfo>(userServices.services.values());
+ } else {
+ Log.e(TAG, "Failed to persist NFCID2.");
+ // Undo registration
+ if (oldDynamicNfcid2 == null) {
+ userServices.dynamicNfcid2.remove(componentName);
+ } else {
+ userServices.dynamicNfcid2.put(componentName, oldDynamicNfcid2);
+ }
+ }
+ }
+ if (success) {
+ // Make callback without the lock held
+ mCallback.onNfcFServicesUpdated(userId, newServices);
+ }
+ return success;
+ }
+
+ public String getNfcid2ForService(int userId, int uid, ComponentName componentName) {
+ if (DBG) Log.d(TAG, "getNfcid2ForService");
+ NfcFServiceInfo service = getService(userId, componentName);
+ if (service != null) {
+ if (service.getUid() != uid) {
+ Log.e(TAG, "UID mismatch");
+ return null;
+ }
+ return service.getNfcid2();
+ } else {
+ Log.e(TAG, "Could not find service " + componentName);
+ return null;
+ }
+ }
+
+ public void onHostEmulationActivated() {
+ if (DBG) Log.d(TAG, "onHostEmulationActivated");
+ synchronized (mLock) {
+ mActivated = true;
+ }
+ }
+
+ public void onHostEmulationDeactivated() {
+ if (DBG) Log.d(TAG, "onHostEmulationDeactivated");
+ synchronized (mLock) {
+ mActivated = false;
+ }
+ }
+
+ public void onNfcDisabled() {
+ synchronized (mLock) {
+ mActivated = false;
+ }
+ }
+
+ private String generateRandomNfcid2() {
+ long min = 0L;
+ long max = 0xFFFFFFFFFFFFL;
+
+ long randomNfcid2 = (long)Math.floor(Math.random() * (max-min+1)) + min;
+ return String.format("02FE%02X%02X%02X%02X%02X%02X",
+ (randomNfcid2 >>> 8 * 5) & 0xFF, (randomNfcid2 >>> 8 * 4) & 0xFF,
+ (randomNfcid2 >>> 8 * 3) & 0xFF, (randomNfcid2 >>> 8 * 2) & 0xFF,
+ (randomNfcid2 >>> 8 * 1) & 0xFF, (randomNfcid2 >>> 8 * 0) & 0xFF);
+ }
+
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("Registered HCE services for current user: ");
+ synchronized (mLock) {
+ UserServices userServices = findOrCreateUserLocked(ActivityManager.getCurrentUser());
+ for (NfcFServiceInfo service : userServices.services.values()) {
+ service.dump(fd, pw, args);
+ pw.println("");
+ }
+ pw.println("");
+ }
+ }
+
+}
diff --git a/src/com/android/nfc/cardemulation/RegisteredT3tIdentifiersCache.java b/src/com/android/nfc/cardemulation/RegisteredT3tIdentifiersCache.java
new file mode 100644
index 0000000..47408a8
--- /dev/null
+++ b/src/com/android/nfc/cardemulation/RegisteredT3tIdentifiersCache.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2015 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.cardemulation;
+
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.nfc.cardemulation.NfcFServiceInfo;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+
+public class RegisteredT3tIdentifiersCache {
+ static final String TAG = "RegisteredT3tIdentifiersCache";
+
+ static final boolean DBG = false;
+
+ // All NFC-F services that have registered
+ List<NfcFServiceInfo> mServices = new ArrayList<NfcFServiceInfo>();
+
+ final HashMap<String, NfcFServiceInfo> mForegroundT3tIdentifiersCache =
+ new HashMap<String, NfcFServiceInfo>();
+
+ ComponentName mEnabledForegroundService;
+
+ final class T3tIdentifier {
+ public final String systemCode;
+ public final String nfcid2;
+
+ T3tIdentifier(String systemCode, String nfcid2) {
+ this.systemCode = systemCode;
+ this.nfcid2 = nfcid2;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ T3tIdentifier that = (T3tIdentifier) o;
+ if (!systemCode.equalsIgnoreCase(that.systemCode)) return false;
+ if (!nfcid2.equalsIgnoreCase(that.nfcid2)) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = systemCode.hashCode();
+ result = 31 * result + nfcid2.hashCode();
+ return result;
+ }
+ }
+
+ final Context mContext;
+ final SystemCodeRoutingManager mRoutingManager;
+
+ final Object mLock = new Object();
+
+ boolean mNfcEnabled = false;
+
+ public RegisteredT3tIdentifiersCache(Context context) {
+ Log.d(TAG, "RegisteredT3tIdentifiersCache");
+ mContext = context;
+ mRoutingManager = new SystemCodeRoutingManager();
+ }
+
+ public NfcFServiceInfo resolveNfcid2(String nfcid2) {
+ synchronized (mLock) {
+ if (DBG) Log.d(TAG, "resolveNfcid2: resolving NFCID " + nfcid2);
+ NfcFServiceInfo resolveInfo;
+ resolveInfo = mForegroundT3tIdentifiersCache.get(nfcid2);
+ Log.d(TAG,
+ "Resolved to: " + (resolveInfo == null ? "null" : resolveInfo.toString()));
+ return resolveInfo;
+ }
+ }
+
+ void generateForegroundT3tIdentifiersCacheLocked() {
+ if (DBG) Log.d(TAG, "generateForegroundT3tIdentifiersCacheLocked");
+ mForegroundT3tIdentifiersCache.clear();
+ if (mEnabledForegroundService != null) {
+ for (NfcFServiceInfo service : mServices) {
+ if (mEnabledForegroundService.equals(service.getComponent())) {
+ if (!service.getSystemCode().equalsIgnoreCase("NULL") &&
+ !service.getNfcid2().equalsIgnoreCase("NULL")) {
+ mForegroundT3tIdentifiersCache.put(service.getNfcid2(), service);
+ }
+ break;
+ }
+ }
+ }
+
+ if (DBG) {
+ Log.d(TAG, "mForegroundT3tIdentifiersCache: size=" +
+ mForegroundT3tIdentifiersCache.size());
+ for (Map.Entry<String, NfcFServiceInfo> entry :
+ mForegroundT3tIdentifiersCache.entrySet()) {
+ Log.d(TAG, " " + entry.getKey() +
+ "/" + entry.getValue().getComponent().toString());
+ }
+ }
+
+ updateRoutingLocked();
+ }
+
+ void updateRoutingLocked() {
+ if (DBG) Log.d(TAG, "updateRoutingLocked");
+ if (!mNfcEnabled) {
+ Log.d(TAG, "Not updating routing table because NFC is off.");
+ return;
+ }
+ List<T3tIdentifier> t3tIdentifiers = new ArrayList<T3tIdentifier>();
+ Iterator<Map.Entry<String, NfcFServiceInfo>> it;
+ // Register foreground service
+ it = mForegroundT3tIdentifiersCache.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<String, NfcFServiceInfo> entry =
+ (Map.Entry<String, NfcFServiceInfo>) it.next();
+ t3tIdentifiers.add(new T3tIdentifier(
+ entry.getValue().getSystemCode(), entry.getValue().getNfcid2()));
+ }
+ mRoutingManager.configureRouting(t3tIdentifiers);
+ }
+
+ public void onServicesUpdated(int userId, List<NfcFServiceInfo> services) {
+ if (DBG) Log.d(TAG, "onServicesUpdated");
+ synchronized (mLock) {
+ if (ActivityManager.getCurrentUser() == userId) {
+ // Rebuild our internal data-structures
+ mServices = services;
+ } else {
+ Log.d(TAG, "Ignoring update because it's not for the current user.");
+ }
+ }
+ }
+
+ public void onEnabledForegroundNfcFServiceChanged(ComponentName component) {
+ if (DBG) Log.d(TAG, "Enabled foreground service changed.");
+ synchronized (mLock) {
+ if (component != null) {
+ if (mEnabledForegroundService != null) {
+ return;
+ }
+ mEnabledForegroundService = component;
+ } else {
+ if (mEnabledForegroundService == null) {
+ return;
+ }
+ mEnabledForegroundService = null;
+ }
+ generateForegroundT3tIdentifiersCacheLocked();
+ }
+ }
+
+ public void onNfcEnabled() {
+ synchronized (mLock) {
+ mNfcEnabled = true;
+ }
+ }
+
+ public void onNfcDisabled() {
+ synchronized (mLock) {
+ mNfcEnabled = false;
+ mForegroundT3tIdentifiersCache.clear();
+ mEnabledForegroundService = null;
+ }
+ mRoutingManager.onNfccRoutingTableCleared();
+ }
+
+ public void onUserSwitched() {
+ synchronized (mLock) {
+ mForegroundT3tIdentifiersCache.clear();
+ updateRoutingLocked();
+ mEnabledForegroundService = null;
+ }
+ }
+
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println(" T3T Identifier cache entries: ");
+ for (Map.Entry<String, NfcFServiceInfo> entry : mForegroundT3tIdentifiersCache.entrySet()) {
+ pw.println(" NFCID2: " + entry.getKey());
+ pw.println(" NfcFServiceInfo: ");
+ entry.getValue().dump(fd, pw, args);
+ }
+ pw.println("");
+ mRoutingManager.dump(fd, pw, args);
+ pw.println("");
+ }
+}
diff --git a/src/com/android/nfc/cardemulation/SystemCodeRoutingManager.java b/src/com/android/nfc/cardemulation/SystemCodeRoutingManager.java
new file mode 100644
index 0000000..3067573
--- /dev/null
+++ b/src/com/android/nfc/cardemulation/SystemCodeRoutingManager.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2015 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.cardemulation;
+
+import android.util.Log;
+
+import com.android.nfc.NfcService;
+import com.android.nfc.cardemulation.RegisteredT3tIdentifiersCache.T3tIdentifier;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+public class SystemCodeRoutingManager {
+ static final String TAG = "SystemCodeRoutingManager";
+
+ static final boolean DBG = false;
+
+ final Object mLock = new Object();
+
+ List<T3tIdentifier> mConfiguredT3tIdentifiers =
+ new ArrayList<T3tIdentifier>();
+
+ public boolean configureRouting(List<T3tIdentifier> t3tIdentifiers) {
+ if (DBG) Log.d(TAG, "configureRouting");
+ List<T3tIdentifier> toBeAdded = new ArrayList<T3tIdentifier>();
+ List<T3tIdentifier> toBeRemoved = new ArrayList<T3tIdentifier>();
+ synchronized (mLock) {
+ for (T3tIdentifier t3tIdentifier : t3tIdentifiers) {
+ if (!mConfiguredT3tIdentifiers.contains(t3tIdentifier)) {
+ toBeAdded.add(t3tIdentifier);
+ }
+ }
+ for (T3tIdentifier t3tIdentifier : mConfiguredT3tIdentifiers) {
+ if (!t3tIdentifiers.contains(t3tIdentifier)) {
+ toBeRemoved.add(t3tIdentifier);
+ }
+ }
+ if (toBeAdded.size() <= 0 && toBeRemoved.size() <= 0) {
+ Log.d(TAG, "Routing table unchanged, not updating");
+ return false;
+ }
+ // Update internal structures
+ for (T3tIdentifier t3tIdentifier : toBeRemoved) {
+ if (DBG) Log.d(TAG, "deregisterNfcFSystemCodeonDh:");
+ NfcService.getInstance().deregisterT3tIdentifier(
+ t3tIdentifier.systemCode, t3tIdentifier.nfcid2);
+ }
+ for (T3tIdentifier t3tIdentifier : toBeAdded) {
+ if (DBG) Log.d(TAG, "registerNfcFSystemCodeonDh:");
+ NfcService.getInstance().registerT3tIdentifier(
+ t3tIdentifier.systemCode, t3tIdentifier.nfcid2);
+ }
+ if (DBG) {
+ Log.d(TAG, "(Before) mConfiguredT3tIdentifiers: size=" +
+ mConfiguredT3tIdentifiers.size());
+ for (T3tIdentifier t3tIdentifier : mConfiguredT3tIdentifiers) {
+ Log.d(TAG, " " + t3tIdentifier.systemCode +
+ "/" + t3tIdentifier.nfcid2);
+ }
+ Log.d(TAG, "(After) mConfiguredT3tIdentifiers: size=" +
+ t3tIdentifiers.size());
+ for (T3tIdentifier t3tIdentifier : t3tIdentifiers) {
+ Log.d(TAG, " " + t3tIdentifier.systemCode +
+ "/" + t3tIdentifier.nfcid2);
+ }
+ }
+ mConfiguredT3tIdentifiers = t3tIdentifiers;
+ }
+
+ // And finally commit the routing
+ NfcService.getInstance().commitRouting();
+
+ return true;
+ }
+
+ /**
+ * This notifies that the SystemCode routing table in the controller
+ * has been cleared (usually due to NFC being turned off).
+ */
+ public void onNfccRoutingTableCleared() {
+ // The routing table in the controller was cleared
+ // To stay in sync, clear our own tables.
+ synchronized (mLock) {
+ if (DBG) Log.d(TAG, "onNfccRoutingTableCleared");
+ NfcService.getInstance().clearT3tIdentifiersCache();
+ mConfiguredT3tIdentifiers.clear();
+ }
+ }
+
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("Routing table:");
+ synchronized (mLock) {
+ for (T3tIdentifier t3tIdentifier : mConfiguredT3tIdentifiers) {
+ pw.println(" " + t3tIdentifier.systemCode +
+ "/" + t3tIdentifier.nfcid2);
+ }
+ }
+ }
+}
diff --git a/src/com/android/nfc/handover/BluetoothPeripheralHandover.java b/src/com/android/nfc/handover/BluetoothPeripheralHandover.java
index 10400be..b43961b 100644
--- a/src/com/android/nfc/handover/BluetoothPeripheralHandover.java
+++ b/src/com/android/nfc/handover/BluetoothPeripheralHandover.java
@@ -22,6 +22,7 @@
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothInputDevice;
import android.bluetooth.BluetoothProfile;
+import android.bluetooth.OobData;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -94,6 +95,7 @@
int mHfpResult; // used only in STATE_CONNECTING and STATE_DISCONNETING
int mA2dpResult; // used only in STATE_CONNECTING and STATE_DISCONNETING
int mHidResult;
+ OobData mOobData;
// protected by mLock
BluetoothA2dp mA2dp;
@@ -105,12 +107,13 @@
}
public BluetoothPeripheralHandover(Context context, BluetoothDevice device, String name,
- int transport, Callback callback) {
+ int transport, OobData oobData, Callback callback) {
checkMainThread(); // mHandler must get get constructed on Main Thread for toasts to work
mContext = context;
mDevice = device;
mName = name;
mTransport = transport;
+ mOobData = oobData;
mCallback = callback;
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
@@ -389,9 +392,14 @@
void startBonding() {
mState = STATE_BONDING;
toast(getToastString(R.string.pairing_peripheral));
- if (!mDevice.createBond(mTransport)) {
- toast(getToastString(R.string.pairing_peripheral_failed));
- complete(false);
+ if (mOobData != null) {
+ if (!mDevice.createBondOutOfBand(mTransport, mOobData)) {
+ toast(getToastString(R.string.pairing_peripheral_failed));
+ complete(false);
+ }
+ } else if (!mDevice.createBond(mTransport)) {
+ toast(getToastString(R.string.pairing_peripheral_failed));
+ complete(false);
}
}
diff --git a/src/com/android/nfc/handover/HandoverDataParser.java b/src/com/android/nfc/handover/HandoverDataParser.java
index 691488f..eb77aaa 100644
--- a/src/com/android/nfc/handover/HandoverDataParser.java
+++ b/src/com/android/nfc/handover/HandoverDataParser.java
@@ -26,6 +26,7 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.OobData;
import android.content.Context;
import android.content.Intent;
import android.nfc.FormatException;
@@ -59,8 +60,12 @@
private static final int BT_HANDOVER_TYPE_LE_ROLE = 0x1C;
private static final int BT_HANDOVER_TYPE_LONG_LOCAL_NAME = 0x09;
private static final int BT_HANDOVER_TYPE_SHORT_LOCAL_NAME = 0x08;
+ private static final int BT_HANDOVER_TYPE_SECURITY_MANAGER_TK = 0x10;
+
public static final int BT_HANDOVER_LE_ROLE_CENTRAL_ONLY = 0x01;
+ public static final int SECURITY_MANAGER_TK_SIZE = 16;
+
private final BluetoothAdapter mBluetoothAdapter;
private final Object mLock = new Object();
@@ -74,6 +79,7 @@
public String name;
public boolean carrierActivating = false;
public int transport = BluetoothDevice.TRANSPORT_AUTO;
+ public OobData oobData;
}
public static class IncomingHandoverData {
@@ -408,7 +414,6 @@
try {
while (payload.remaining() > 0) {
- byte[] nameBytes;
int len = payload.get();
int type = payload.get();
switch (type) {
@@ -427,10 +432,30 @@
}
break;
case BT_HANDOVER_TYPE_LONG_LOCAL_NAME:
- nameBytes = new byte[len - 1];
+ byte[] nameBytes = new byte[len - 1];
payload.get(nameBytes);
result.name = new String(nameBytes, StandardCharsets.UTF_8);
break;
+ case BT_HANDOVER_TYPE_SECURITY_MANAGER_TK:
+ if (len-1 != SECURITY_MANAGER_TK_SIZE) {
+ Log.i(TAG, "BT OOB: invalid size of SM TK, should be " +
+ SECURITY_MANAGER_TK_SIZE + " bytes.");
+ break;
+ }
+
+ byte[] reversedTK = new byte[len - 1];
+ payload.get(reversedTK);
+
+ byte[] securityManagerTK = new byte[len - 1];
+
+ //TK in AD is in reverse order
+ for (int i = 0; i < reversedTK.length; i++) {
+ securityManagerTK[i] = reversedTK[securityManagerTK.length - 1 - i];
+ }
+
+ result.oobData = new OobData();
+ result.oobData.setSecurityManagerTk(securityManagerTK);
+ break;
default:
payload.position(payload.position() + len - 1);
break;
diff --git a/src/com/android/nfc/handover/PeripheralHandoverService.java b/src/com/android/nfc/handover/PeripheralHandoverService.java
index 6c30244..95bf0d6 100644
--- a/src/com/android/nfc/handover/PeripheralHandoverService.java
+++ b/src/com/android/nfc/handover/PeripheralHandoverService.java
@@ -19,6 +19,7 @@
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.OobData;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -46,6 +47,7 @@
public static final String EXTRA_PERIPHERAL_DEVICE = "device";
public static final String EXTRA_PERIPHERAL_NAME = "headsetname";
public static final String EXTRA_PERIPHERAL_TRANSPORT = "transporttype";
+ public static final String EXTRA_PERIPHERAL_OOB_DATA = "oobdata";
// Amount of time to pause polling when connecting to peripherals
private static final int PAUSE_POLLING_TIMEOUT_MS = 35000;
@@ -157,9 +159,10 @@
BluetoothDevice device = msgData.getParcelable(EXTRA_PERIPHERAL_DEVICE);
String name = msgData.getString(EXTRA_PERIPHERAL_NAME);
int transport = msgData.getInt(EXTRA_PERIPHERAL_TRANSPORT);
+ OobData oobData = msgData.getParcelable(EXTRA_PERIPHERAL_OOB_DATA);
mBluetoothPeripheralHandover = new BluetoothPeripheralHandover(
- this, device, name, transport, this);
+ this, device, name, transport, oobData, this);
if (transport == BluetoothDevice.TRANSPORT_LE) {
mHandler.sendMessageDelayed(