diff options
author | Nick Pelly <npelly@google.com> | 2010-09-23 16:12:11 -0700 |
---|---|---|
committer | Nick Pelly <npelly@google.com> | 2010-09-28 22:36:27 -0700 |
commit | 038cabe0247ee46df62f9363f1a303bc5b9c1028 (patch) | |
tree | 11c6037442f85e0e7adad870ba9d8092323b6bf0 | |
parent | d6877fa4971710150de20453bf4ba54dca863429 (diff) | |
download | frameworks_base-038cabe0247ee46df62f9363f1a303bc5b9c1028.zip frameworks_base-038cabe0247ee46df62f9363f1a303bc5b9c1028.tar.gz frameworks_base-038cabe0247ee46df62f9363f1a303bc5b9c1028.tar.bz2 |
NFC integration
Source: Trusted_NFC_Device_Host_AA03.01e02_google.zip code drop (23-Sep-2010)
Conflicts:
core/java/android/app/ApplicationContext.java
core/java/android/provider/Settings.java
core/jni/Android.mk
core/jni/AndroidRuntime.cpp
core/res/AndroidManifest.xml
include/utils/Asset.h
Change-Id: I62c92f4c79f5ee65126c97602f6bc1c15794e573
Signed-off-by: Nick Pelly <npelly@google.com>
44 files changed, 6762 insertions, 1 deletions
@@ -159,6 +159,14 @@ LOCAL_SRC_FILES += \ core/java/com/android/internal/view/IInputMethodClient.aidl \ core/java/com/android/internal/view/IInputMethodManager.aidl \ core/java/com/android/internal/view/IInputMethodSession.aidl \ + core/java/com/trustedlogic/trustednfc/android/ILlcpConnectionlessSocket.aidl \ + core/java/com/trustedlogic/trustednfc/android/ILlcpServiceSocket.aidl \ + core/java/com/trustedlogic/trustednfc/android/ILlcpSocket.aidl \ + core/java/com/trustedlogic/trustednfc/android/INdefTag.aidl \ + core/java/com/trustedlogic/trustednfc/android/INfcManager.aidl \ + core/java/com/trustedlogic/trustednfc/android/INfcTag.aidl \ + core/java/com/trustedlogic/trustednfc/android/IP2pInitiator.aidl \ + core/java/com/trustedlogic/trustednfc/android/IP2pTarget.aidl \ location/java/android/location/IGeocodeProvider.aidl \ location/java/android/location/IGpsStatusListener.aidl \ location/java/android/location/IGpsStatusProvider.aidl \ diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index c01516f..e93e684 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -102,6 +102,8 @@ import android.view.inputmethod.InputMethodManager; import android.accounts.AccountManager; import android.accounts.IAccountManager; import android.app.admin.DevicePolicyManager; +import com.trustedlogic.trustednfc.android.NfcManager; +import com.trustedlogic.trustednfc.android.INfcManager; import com.android.internal.os.IDropBoxManagerService; @@ -171,6 +173,7 @@ class ContextImpl extends Context { private static ThrottleManager sThrottleManager; private static WifiManager sWifiManager; private static LocationManager sLocationManager; + private static NfcManager sNfcManager; private static final HashMap<String, SharedPreferencesImpl> sSharedPrefs = new HashMap<String, SharedPreferencesImpl>(); @@ -969,6 +972,8 @@ class ContextImpl extends Context { return getClipboardManager(); } else if (WALLPAPER_SERVICE.equals(name)) { return getWallpaperManager(); + } else if (NFC_SERVICE.equals(name)) { + return getNfcManager(); } else if (DROPBOX_SERVICE.equals(name)) { return getDropBoxManager(); } else if (DEVICE_POLICY_SERVICE.equals(name)) { @@ -1204,6 +1209,21 @@ class ContextImpl extends Context { return mDownloadManager; } + private NfcManager getNfcManager() + { + synchronized (sSync) { + if (sNfcManager == null) { + IBinder b = ServiceManager.getService(NFC_SERVICE); + if (b == null) { + return null; + } + INfcManager service = INfcManager.Stub.asInterface(b); + sNfcManager = new NfcManager(service, mMainThread.getHandler()); + } + } + return sNfcManager; + } + @Override public int checkPermission(String permission, int pid, int uid) { if (permission == null) { diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 0dd2e4a..693be21 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -1555,6 +1555,16 @@ public abstract class Context { public static final String SIP_SERVICE = "sip"; /** + * Use with {@link #getSystemService} to retrieve an + * {@link com.trustedlogic.trustednfc.android.INfcManager.INfcManager} for + * accessing NFC methods. + * + * @see #getSystemService + * @hide + */ + public static final String NFC_SERVICE = "nfc"; + + /** * Determine whether the given permission is allowed for a particular * process and user ID running in the system. * diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 1dd2420..90cd840 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -1640,6 +1640,86 @@ public final class Settings { public static final String NOTIFICATION_LIGHT_PULSE = "notification_light_pulse"; /** + * Whether nfc is enabled/disabled + * 0=disabled. 1=enabled. + * @hide + */ + public static final String NFC_ON = "nfc_on"; + + /** + * Whether nfc secure element is enabled/disabled + * 0=disabled. 1=enabled. + * @hide + */ + public static final String NFC_SECURE_ELEMENT_ON = "nfc_secure_element_on"; + + /** + * Whether nfc secure element is enabled/disabled + * 0=disabled. 1=enabled. + * @hide + */ + public static final String NFC_SECURE_ELEMENT_ID = "nfc_secure_element_id"; + + /** + * LLCP LTO value + * @hide + */ + public static final String NFC_LLCP_LTO = "nfc_llcp_lto"; + + /** + * LLCP MIU value + * @hide + */ + public static final String NFC_LLCP_MIU = "nfc_llcp_miu"; + + /** + * LLCP WKS value + * @hide + */ + public static final String NFC_LLCP_WKS = "nfc_llcp_wks"; + + /** + * LLCP OPT value + * @hide + */ + public static final String NFC_LLCP_OPT = "nfc_llcp_opt"; + + /** + * NFC Discovery Reader A + * 0=disabled. 1=enabled. + * @hide + */ + public static final String NFC_DISCOVERY_A = "nfc_discovery_a"; + + /** + * NFC Discovery Reader B + * 0=disabled. 1=enabled. + * @hide + */ + public static final String NFC_DISCOVERY_B = "nfc_discovery_b"; + + /** + * NFC Discovery Reader Felica + * 0=disabled. 1=enabled. + * @hide + */ + public static final String NFC_DISCOVERY_F = "nfc_discovery_felica"; + + /** + * NFC Discovery Reader 15693 + * 0=disabled. 1=enabled. + * @hide + */ + public static final String NFC_DISCOVERY_15693 = "nfc_discovery_15693"; + + /** + * NFC Discovery NFCIP + * 0=disabled. 1=enabled. + * @hide + */ + public static final String NFC_DISCOVERY_NFCIP = "nfc_discovery_nfcip"; + + /** * Show pointer location on screen? * 0 = no * 1 = yes @@ -1804,7 +1884,19 @@ public final class Settings { SHOW_WEB_SUGGESTIONS, NOTIFICATION_LIGHT_PULSE, SIP_CALL_OPTIONS, - SIP_RECEIVE_CALLS + SIP_RECEIVE_CALLS, + NFC_ON, + NFC_SECURE_ELEMENT_ON, + NFC_SECURE_ELEMENT_ID, + NFC_LLCP_LTO, + NFC_LLCP_MIU, + NFC_LLCP_WKS, + NFC_LLCP_OPT, + NFC_DISCOVERY_A, + NFC_DISCOVERY_B, + NFC_DISCOVERY_F, + NFC_DISCOVERY_15693, + NFC_DISCOVERY_NFCIP, }; // Settings moved to Settings.Secure diff --git a/core/java/com/trustedlogic/trustednfc/android/ILlcpConnectionlessSocket.aidl b/core/java/com/trustedlogic/trustednfc/android/ILlcpConnectionlessSocket.aidl new file mode 100644 index 0000000..35746ad --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/ILlcpConnectionlessSocket.aidl @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.trustedlogic.trustednfc.android; + +import com.trustedlogic.trustednfc.android.LlcpPacket; + +/** + * TODO + * + * {@hide} + */ +interface ILlcpConnectionlessSocket +{ + + void close(int nativeHandle); + int getSap(int nativeHandle); + LlcpPacket receiveFrom(int nativeHandle); + int sendTo(int nativeHandle, in LlcpPacket packet); + +}
\ No newline at end of file diff --git a/core/java/com/trustedlogic/trustednfc/android/ILlcpServiceSocket.aidl b/core/java/com/trustedlogic/trustednfc/android/ILlcpServiceSocket.aidl new file mode 100644 index 0000000..5eb1f3c --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/ILlcpServiceSocket.aidl @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.trustedlogic.trustednfc.android; + +/** + * TODO + * + * {@hide} + */ +interface ILlcpServiceSocket +{ + + int accept(int nativeHandle); + void close(int nativeHandle); + int getAcceptTimeout(int nativeHandle); + void setAcceptTimeout(int nativeHandle, int timeout); + +}
\ No newline at end of file diff --git a/core/java/com/trustedlogic/trustednfc/android/ILlcpSocket.aidl b/core/java/com/trustedlogic/trustednfc/android/ILlcpSocket.aidl new file mode 100644 index 0000000..e9169d8 --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/ILlcpSocket.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.trustedlogic.trustednfc.android; + +/** + * TODO + * + * {@hide} + */ +interface ILlcpSocket +{ + + int close(int nativeHandle); + int connect(int nativeHandle, int sap); + int connectByName(int nativeHandle, String sn); + int getConnectTimeout(int nativeHandle); + int getLocalSap(int nativeHandle); + int getLocalSocketMiu(int nativeHandle); + int getLocalSocketRw(int nativeHandle); + int getRemoteSocketMiu(int nativeHandle); + int getRemoteSocketRw(int nativeHandle); + int receive(int nativeHandle, out byte[] receiveBuffer); + int send(int nativeHandle, in byte[] data); + void setConnectTimeout(int nativeHandle, int timeout); + +} + diff --git a/core/java/com/trustedlogic/trustednfc/android/INdefTag.aidl b/core/java/com/trustedlogic/trustednfc/android/INdefTag.aidl new file mode 100644 index 0000000..1f8d1a4 --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/INdefTag.aidl @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.trustedlogic.trustednfc.android; + +import com.trustedlogic.trustednfc.android.NdefMessage; + +/** + * TODO + * + * {@hide} + */ +interface INdefTag +{ + + NdefMessage read(int nativeHandle); + boolean write(int nativeHandle, in NdefMessage msg); + +}
\ No newline at end of file diff --git a/core/java/com/trustedlogic/trustednfc/android/INfcManager.aidl b/core/java/com/trustedlogic/trustednfc/android/INfcManager.aidl new file mode 100644 index 0000000..ce36ab2 --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/INfcManager.aidl @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.trustedlogic.trustednfc.android; + +import com.trustedlogic.trustednfc.android.ILlcpSocket; +import com.trustedlogic.trustednfc.android.ILlcpServiceSocket; +import com.trustedlogic.trustednfc.android.ILlcpConnectionlessSocket; +import com.trustedlogic.trustednfc.android.INfcTag; +import com.trustedlogic.trustednfc.android.IP2pTarget; +import com.trustedlogic.trustednfc.android.IP2pInitiator; + + +/** + * Interface that allows controlling NFC activity. + * + * {@hide} + */ +interface INfcManager +{ + + ILlcpSocket getLlcpInterface(); + ILlcpConnectionlessSocket getLlcpConnectionlessInterface(); + ILlcpServiceSocket getLlcpServiceInterface(); + INfcTag getNfcTagInterface(); + IP2pTarget getP2pTargetInterface(); + IP2pInitiator getP2pInitiatorInterface(); + + void cancel(); + int createLlcpConnectionlessSocket(int sap); + int createLlcpServiceSocket(int sap, String sn, int miu, int rw, int linearBufferLength); + int createLlcpSocket(int sap, int miu, int rw, int linearBufferLength); + int deselectSecureElement(); + boolean disable(); + boolean enable(); + int getOpenTimeout(); + String getProperties(String param); + int[] getSecureElementList(); + int getSelectedSecureElement(); + boolean isEnabled(); + int openP2pConnection(); + int openTagConnection(); + int selectSecureElement(int seId); + void setOpenTimeout(int timeout); + int setProperties(String param, String value); + +} + diff --git a/core/java/com/trustedlogic/trustednfc/android/INfcTag.aidl b/core/java/com/trustedlogic/trustednfc/android/INfcTag.aidl new file mode 100644 index 0000000..79543c4 --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/INfcTag.aidl @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.trustedlogic.trustednfc.android; + +import com.trustedlogic.trustednfc.android.NdefMessage; + +/** + * TODO + * + * {@hide} + */ +interface INfcTag +{ + + int close(int nativeHandle); + int connect(int nativeHandle); + String getType(int nativeHandle); + byte[] getUid(int nativeHandle); + boolean isNdef(int nativeHandle); + byte[] transceive(int nativeHandle, in byte[] data); + + NdefMessage read(int nativeHandle); + boolean write(int nativeHandle, in NdefMessage msg); +}
\ No newline at end of file diff --git a/core/java/com/trustedlogic/trustednfc/android/IP2pInitiator.aidl b/core/java/com/trustedlogic/trustednfc/android/IP2pInitiator.aidl new file mode 100644 index 0000000..96819ae --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/IP2pInitiator.aidl @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.trustedlogic.trustednfc.android; + +/** + * TODO + * + * {@hide} + */ +interface IP2pInitiator +{ + + byte[] getGeneralBytes(int nativeHandle); + int getMode(int nativeHandle); + byte[] receive(int nativeHandle); + boolean send(int nativeHandle, in byte[] data); + +}
\ No newline at end of file diff --git a/core/java/com/trustedlogic/trustednfc/android/IP2pTarget.aidl b/core/java/com/trustedlogic/trustednfc/android/IP2pTarget.aidl new file mode 100644 index 0000000..8dcdf18 --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/IP2pTarget.aidl @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.trustedlogic.trustednfc.android; + +/** + * TODO + * + * {@hide} + */ +interface IP2pTarget +{ + + byte[] getGeneralBytes(int nativeHandle); + int getMode(int nativeHandle); + int connect(int nativeHandle); + boolean disconnect(int nativeHandle); + byte[] transceive(int nativeHandle, in byte[] data); + +}
\ No newline at end of file diff --git a/core/java/com/trustedlogic/trustednfc/android/LlcpConnectionlessSocket.java b/core/java/com/trustedlogic/trustednfc/android/LlcpConnectionlessSocket.java new file mode 100644 index 0000000..0270626 --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/LlcpConnectionlessSocket.java @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * File : LlcpConnectionLessSocket.java + * Original-Author : Trusted Logic S.A. (Daniel Tomas) + * Created : 18-02-2010 + */ + +package com.trustedlogic.trustednfc.android; + +import java.io.IOException; + +import com.trustedlogic.trustednfc.android.internal.ErrorCodes; + +import android.os.RemoteException; +import android.util.Log; + +/** + * LlcpConnectionlessSocket represents a LLCP Connectionless object to be used + * in a connectionless communication + * + * @since AA02.01 + * @hide + */ +public class LlcpConnectionlessSocket { + + + private static final String TAG = "LlcpConnectionlessSocket"; + + /** + * The handle returned by the NFC service and used to identify the LLCP connectionless socket in + * every call of this class. + * + * @hide + */ + protected int mHandle; + + + /** + * The entry point for LLCP Connectionless socket operations. + * + * @hide + */ + protected ILlcpConnectionlessSocket mService; + + + /** + * Internal constructor for the LlcpConnectionlessSocket class. + * + * @param service The entry point to the Nfc Service for LLCP Connectionless socket class. + * @param handle The handle returned by the NFC service and used to identify + * the socket in subsequent calls. + * @hide + */ + LlcpConnectionlessSocket(ILlcpConnectionlessSocket service, int handle) { + this.mService = service; + this.mHandle = handle; + } + + /** + * Send data to a specific LLCP Connectionless client + * + * @param packet Service Access Point number related to a LLCP + * Connectionless client and a data buffer to send + * @throws IOException if the LLCP link has been lost or deactivated. + * @since AA02.01 + */ + public void sendTo(LlcpPacket packet) throws IOException { + try { + int result = mService.sendTo(mHandle, packet); + // Handle potential errors + if (ErrorCodes.isError(result)) { + throw new IOException(); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in sendTo(): ", e); + } + } + + /** + * Receive data from a LLCP Connectionless client + * + * @return data data received from a specific LLCP Connectionless client + * @throws IOException if the LLCP link has been lost or deactivated. + * @see LlcpPacket + * @since AA02.01 + */ + public LlcpPacket receiveFrom() throws IOException { + try { + LlcpPacket packet = mService.receiveFrom(mHandle); + if (packet != null) { + return packet; + }else{ + // Handle potential errors + throw new IOException(); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in receiveFrom(): ", e); + } + return null; + } + + /** + * Close the created Connectionless socket. + * + * @since AA02.01 + */ + public void close() { + try { + mService.close(mHandle); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in close(): ", e); + } + } + + /** + * Returns the local Service Access Point number of the socket + * + * @return sap + * @since AA02.01 + */ + public int getSap() { + int sap = 0; + + try { + sap = mService.getSap(mHandle); + + } catch (RemoteException e) { + + e.printStackTrace(); + } + return sap; + } +} diff --git a/core/java/com/trustedlogic/trustednfc/android/LlcpException.java b/core/java/com/trustedlogic/trustednfc/android/LlcpException.java new file mode 100644 index 0000000..1e2e2da --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/LlcpException.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * File : LLCPException.java + * Original-Author : Trusted Logic S.A. (Daniel Tomas) + * Created : 24-02-2010 + */ + +package com.trustedlogic.trustednfc.android; + +/** + * Generic exception thrown in case something unexpected happened during a + * LLCP communication. + * + * @since AA02.01 + * @hide + */ +public class LlcpException extends Exception { + /** + * Constructs a new LlcpException with the current stack trace and the + * specified detail message. + * + * @param s the detail message for this exception. + */ + public LlcpException(String s) { + super(s); + } +} diff --git a/core/java/com/trustedlogic/trustednfc/android/LlcpPacket.aidl b/core/java/com/trustedlogic/trustednfc/android/LlcpPacket.aidl new file mode 100644 index 0000000..297a1fe --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/LlcpPacket.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.trustedlogic.trustednfc.android; + +parcelable LlcpPacket; diff --git a/core/java/com/trustedlogic/trustednfc/android/LlcpPacket.java b/core/java/com/trustedlogic/trustednfc/android/LlcpPacket.java new file mode 100644 index 0000000..af79023 --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/LlcpPacket.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * File : LLCPPacket.java + * Original-Author : Trusted Logic S.A. (Daniel Tomas) + * Created : 25-02-2010 + */ + +package com.trustedlogic.trustednfc.android; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Represents a LLCP packet received in a LLCP Connectionless communication; + * + * @since AA02.01 + * @hide + */ +public class LlcpPacket implements Parcelable { + + private int mRemoteSap; + + private byte[] mDataBuffer; + + /** + * Creator class, needed when implementing from Parcelable + * {@hide} + */ + public static final Parcelable.Creator<LlcpPacket> CREATOR = new Parcelable.Creator<LlcpPacket>() { + public LlcpPacket createFromParcel(Parcel in) { + // Remote SAP + short sap = (short)in.readInt(); + + // Data Buffer + int dataLength = in.readInt(); + byte[] data = new byte[dataLength]; + in.readByteArray(data); + + return new LlcpPacket(sap, data); + } + + public LlcpPacket[] newArray(int size) { + return new LlcpPacket[size]; + } + }; + + + /** + * Creates a LlcpPacket to be sent to a remote Service Access Point number + * (SAP) + * + * @param sap Remote Service Access Point number + * @param data Data buffer + * @since AA02.01 + */ + public LlcpPacket(int sap, byte[] data) { + mRemoteSap = sap; + mDataBuffer = data; + } + + /** + * @hide + */ + public LlcpPacket() { + } + + /** + * Returns the remote Service Access Point number + * + * @return remoteSap + * @since AA02.01 + */ + public int getRemoteSap() { + return mRemoteSap; + } + + /** + * Returns the data buffer + * + * @return data + * @since AA02.01 + */ + public byte[] getDataBuffer() { + return mDataBuffer; + } + + /** + * (Parcelable) Describe the parcel + * {@hide} + */ + public int describeContents() { + return 0; + } + + /** + * (Parcelable) Convert current object to a Parcel + * {@hide} + */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mRemoteSap); + dest.writeInt(mDataBuffer.length); + dest.writeByteArray(mDataBuffer); + } +} diff --git a/core/java/com/trustedlogic/trustednfc/android/LlcpServiceSocket.java b/core/java/com/trustedlogic/trustednfc/android/LlcpServiceSocket.java new file mode 100644 index 0000000..a152ecb1 --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/LlcpServiceSocket.java @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * File : LLCPServerSocket.java + * Original-Author : Trusted Logic S.A. (Daniel Tomas) + * Created : 18-02-2010 + */ + +package com.trustedlogic.trustednfc.android; + +import java.io.IOException; + +import com.trustedlogic.trustednfc.android.internal.ErrorCodes; + +import android.os.RemoteException; +import android.util.Log; + +/** + * LlcpServiceSocket represents a LLCP Service to be used in a + * Connection-oriented communication + * + * @since AA02.01 + * @hide + */ +public class LlcpServiceSocket { + + private static final String TAG = "LlcpServiceSocket"; + + /** + * The handle returned by the NFC service and used to identify the LLCP + * Service socket in every call of this class. + * + * @hide + */ + protected int mHandle; + + /** + * The entry point for LLCP Service socket operations. + * + * @hide + */ + protected ILlcpServiceSocket mService; + + private ILlcpSocket mLlcpSocketService; + + static LlcpException convertErrorToLlcpException(int errorCode) { + return convertErrorToLlcpException(errorCode, null); + } + + static LlcpException convertErrorToLlcpException(int errorCode, + String message) { + if (message == null) { + message = ""; + } else { + message = " (" + message + ")"; + } + + switch (errorCode) { + case ErrorCodes.ERROR_SOCKET_CREATION: + return new LlcpException( + "Error during the creation of an Llcp socket" + message); + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + return new LlcpException("Not enough ressources are available" + + message); + default: + return new LlcpException("Unkown error code " + errorCode + message); + } + } + + /** + * Internal constructor for the LlcpServiceSocket class. + * + * @param service + * The entry point to the Nfc Service for LlcpServiceSocket + * class. + * @param handle + * The handle returned by the NFC service and used to identify + * the socket in subsequent calls. + * @hide + */ + LlcpServiceSocket(ILlcpServiceSocket service, ILlcpSocket socketService, int handle) { + this.mService = service; + this.mHandle = handle; + this.mLlcpSocketService = socketService; + } + + /** + * Wait for incomming connection request from a LLCP client and accept this + * request + * + * @return socket object to be used to communicate with a LLCP client + * + * @throws IOException + * if the llcp link is lost or deactivated + * @throws LlcpException + * if not enough ressources are available + * + * @see LlcpSocket + * @since AA02.01 + */ + public LlcpSocket accept() throws IOException, LlcpException { + + try { + int handle = mService.accept(mHandle); + // Handle potential errors + if (ErrorCodes.isError(handle)) { + if (handle == ErrorCodes.ERROR_IO) { + throw new IOException(); + } else { + throw convertErrorToLlcpException(handle); + } + } + + // Build the public LlcpSocket object + return new LlcpSocket(mLlcpSocketService, handle); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in accept(): ", e); + return null; + } + + } + + /** + * Set the timeout for the accept request + * + * @param timeout + * value of the timeout for the accept request + * @since AA02.01 + */ + public void setAcceptTimeout(int timeout) { + try { + mService.setAcceptTimeout(mHandle, timeout); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in setAcceptTimeout(): ", e); + } + } + + /** + * Get the timeout value of the accept request + * + * @return mTimeout + * @since AA02.01 + */ + public int getAcceptTimeout() { + try { + return mService.getAcceptTimeout(mHandle); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in getAcceptTimeout(): ", e); + return 0; + } + } + + /** + * Close the created Llcp Service socket + * + * @since AA02.01 + */ + public void close() { + try { + mService.close(mHandle); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in close(): ", e); + } + } + +} diff --git a/core/java/com/trustedlogic/trustednfc/android/LlcpSocket.java b/core/java/com/trustedlogic/trustednfc/android/LlcpSocket.java new file mode 100644 index 0000000..e47160c --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/LlcpSocket.java @@ -0,0 +1,344 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * File : LlcpClientSocket.java + * Original-Author : Trusted Logic S.A. (Daniel Tomas) + * Created : 18-02-2010 + */ + +package com.trustedlogic.trustednfc.android; + +import java.io.IOException; + +import com.trustedlogic.trustednfc.android.internal.ErrorCodes; + +import android.os.RemoteException; +import android.util.Log; + +/** + * LlcpClientSocket represents a LLCP Connection-Oriented client to be used in a + * connection-oriented communication + * + * @since AA02.01 + * @hide + */ +public class LlcpSocket { + + private static final String TAG = "LlcpSocket"; + + /** + * The handle returned by the NFC service and used to identify the LLCP + * socket in every call of this class. + * + * @hide + */ + protected int mHandle; + + /** + * The entry point for LLCP socket operations. + * + * @hide + */ + protected ILlcpSocket mService; + + static LlcpException convertErrorToLlcpException(int errorCode) { + return convertErrorToLlcpException(errorCode, null); + } + + static LlcpException convertErrorToLlcpException(int errorCode, + String message) { + if (message == null) { + message = ""; + } else { + message = " (" + message + ")"; + } + + switch (errorCode) { + case ErrorCodes.ERROR_SOCKET_CREATION: + return new LlcpException( + "Error during the creation of an Llcp socket" + message); + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + return new LlcpException("Not enough ressources are available" + + message); + case ErrorCodes.ERROR_SOCKET_NOT_CONNECTED: + return new LlcpException("Socket not connected to an Llcp Service" + + message); + default: + return new LlcpException("Unkown error code " + errorCode + message); + } + } + + /** + * Internal constructor for the LlcpSocket class. + * + * @param service + * The entry point to the Nfc Service for LlcpServiceSocket + * class. + * @param handle + * The handle returned by the NFC service and used to identify + * the socket in subsequent calls. + * @hide + */ + LlcpSocket(ILlcpSocket service, int handle) { + this.mService = service; + this.mHandle = handle; + } + + /** + * Connect request to a specific LLCP Service by its SAP. + * + * @param sap + * Service Access Point number of the LLCP Service + * @throws IOException + * if the LLCP has been lost or deactivated. + * @throws LlcpException + * if the connection request is rejected by the remote LLCP + * Service + * @since AA02.01 + */ + public void connect(int sap) throws IOException, LlcpException { + try { + int result = mService.connect(mHandle, sap); + // Handle potential errors + if (ErrorCodes.isError(result)) { + if (result == ErrorCodes.ERROR_IO) { + throw new IOException(); + } else { + throw convertErrorToLlcpException(result); + } + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in accept(): ", e); + } + } + + /** + * Connect request to a specific LLCP Service by its Service Name. + * + * @param sn + * Service Name of the LLCP Service + * @throws IOException + * if the LLCP has been lost or deactivated. + * @throws LlcpException + * if the connection request is rejected by the remote LLCP + * Service + * @since AA02.01 + */ + public void connect(String sn) throws IOException, LlcpException { + try { + int result = mService.connectByName(mHandle, sn); + // Handle potential errors + if (ErrorCodes.isError(result)) { + if (result == ErrorCodes.ERROR_IO) { + throw new IOException(); + } else { + throw convertErrorToLlcpException(result); + } + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in accept(): ", e); + } + } + + /** + * Set the timeout for the connect request + * + * @param timeout + * timeout value for the connect request + * @since AA02.01 + */ + public void setConnectTimeout(int timeout) { + try { + mService.setConnectTimeout(mHandle, timeout); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in setConnectTimeout(): ", e); + } + } + + /** + * Get the timeout value of the connect request + * + * @return mTimeout + * @since AA02.01 + */ + public int getConnectTimeout() { + try { + return mService.getConnectTimeout(mHandle); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in getConnectTimeout(): ", e); + return 0; + } + } + + /** + * Disconnect request to the connected LLCP socket and close the created + * socket. + * + * @throws IOException + * if the LLCP has been lost or deactivated. + * @since AA02.01 + */ + public void close() throws IOException { + try { + int result = mService.close(mHandle); + // Handle potential errors + if (ErrorCodes.isError(result)) { + throw new IOException(); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in close(): ", e); + } + } + + /** + * Send data to the connected LLCP Socket. + * + * @throws IOException + * if the LLCP has been lost or deactivated. + * @since AA02.01 + */ + public void send(byte[] data) throws IOException { + try { + int result = mService.send(mHandle, data); + // Handle potential errors + if (ErrorCodes.isError(result)) { + throw new IOException(); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in send(): ", e); + } + } + + /** + * Receive data from the connected LLCP socket + * + * @param receiveBuffer + * a buffer for the received data + * @return length length of the data received + * @throws IOException + * if the LLCP has been lost or deactivated. + * @since AA02.01 + */ + public int receive(byte[] receiveBuffer) throws IOException { + int receivedLength = 0; + try { + receivedLength = mService.receive(mHandle, receiveBuffer); + if(receivedLength == 0){ + throw new IOException(); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in send(): ", e); + } + + return receivedLength; + } + + /** + * Returns the local Service Access Point number of the socket + * + * @return localSap + * @since AA02.01 + */ + public int getLocalSap() { + try { + return mService.getLocalSap(mHandle); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in getLocalSap(): ", e); + return 0; + } + } + + /** + * Returns the local Maximum Information Unit(MIU) of the socket + * + * @return miu + * @since AA02.01 + */ + public int getLocalSocketMiu() { + try { + return mService.getLocalSocketMiu(mHandle); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in getLocalSocketMiu(): ", e); + return 0; + } + } + + /** + * Returns the local Receive Window(RW) of the socket + * + * @return rw + * @since AA02.01 + */ + public int getLocalSocketRw() { + try { + return mService.getLocalSocketRw(mHandle); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in getLocalSocketRw(): ", e); + return 0; + } + } + + /** + * Returns the remote Maximum Information Unit(MIU) of the socket. + * <p> + * This method must be called when the socket is in CONNECTED_STATE + * + * @return remoteMiu + * @throws LlcpException + * if the LlcpClientSocket is not in a CONNECTED_STATE + * @since AA02.01 + */ + public int getRemoteSocketMiu() throws LlcpException { + try { + int result = mService.getRemoteSocketMiu(mHandle); + if(result != ErrorCodes.ERROR_SOCKET_NOT_CONNECTED){ + return result; + }else{ + throw convertErrorToLlcpException(result); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in getRemoteSocketMiu(): ", e); + return 0; + } + } + + /** + * Returns the remote Receive Window(RW) of the connected remote socket. + * <p> + * This method must be called when the socket is in CONNECTED_STATE + * + * @return rw + * @throws LlcpException + * if the LlcpClientSocket is not in a CONNECTED_STATE + * @since AA02.01 + */ + public int getRemoteSocketRw() throws LlcpException { + try { + int result = mService.getRemoteSocketRw(mHandle); + if( result != ErrorCodes.ERROR_SOCKET_NOT_CONNECTED){ + return result; + }else{ + throw convertErrorToLlcpException(result); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in getRemoteSocketRw(): ", e); + return 0; + } + } + + +} diff --git a/core/java/com/trustedlogic/trustednfc/android/NdefMessage.aidl b/core/java/com/trustedlogic/trustednfc/android/NdefMessage.aidl new file mode 100644 index 0000000..e60f4e8 --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/NdefMessage.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.trustedlogic.trustednfc.android; + +parcelable NdefMessage; diff --git a/core/java/com/trustedlogic/trustednfc/android/NdefMessage.java b/core/java/com/trustedlogic/trustednfc/android/NdefMessage.java new file mode 100644 index 0000000..f03b604 --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/NdefMessage.java @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * File : NDEFMessage.java + * Original-Author : Trusted Logic S.A. (Jeremie Corbier) + * Created : 05-10-2009 + */ + +package com.trustedlogic.trustednfc.android; + +import java.util.LinkedList; +import java.util.ListIterator; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Represents an NDEF message as specified by the <a + * href="http://www.nfc-forum.org/">NFC Forum</a>. + * + * @see NdefRecord + * + * @since AA01.04 + * @hide + */ +public class NdefMessage implements Parcelable { + /* Flag values */ + private static final int FLAG_MB = 0x80; + private static final int FLAG_ME = 0x40; + private static final int FLAG_CF = 0x20; + private static final int FLAG_SR = 0x10; + private static final int FLAG_IL = 0x08; + + /** + * Array of {@link NdefRecord} composing this message. + */ + private NdefRecord[] mRecords; + + /** + * Builds an NDEF message. + * + * @param data raw NDEF message data + * + * @throws NFCException + */ + public NdefMessage(byte[] data) throws NfcException { + if (parseNdefMessage(data) == -1) + throw new NfcException("Error while parsing NDEF message"); + } + + /** + * Builds an NDEF message. + * + * @param records + * an array of already created NDEF records + */ + public NdefMessage(NdefRecord[] records) { + mRecords = new NdefRecord[records.length]; + + System.arraycopy(records, 0, mRecords, 0, records.length); + } + + /** + * Returns the NDEF message as a byte array. + * + * @return the message as a byte array + */ + public byte[] toByteArray() { + if ((mRecords == null) || (mRecords.length == 0)) + return null; + + byte[] msg = {}; + + for (int i = 0; i < mRecords.length; i++) { + byte[] record = mRecords[i].toByteArray(); + byte[] tmp = new byte[msg.length + record.length]; + + /* Make sure the Message Begin flag is set only for the first record */ + if (i == 0) + record[0] |= FLAG_MB; + else + record[0] &= ~FLAG_MB; + + /* Make sure the Message End flag is set only for the last record */ + if (i == (mRecords.length - 1)) + record[0] |= FLAG_ME; + else + record[0] &= ~FLAG_ME; + + System.arraycopy(msg, 0, tmp, 0, msg.length); + System.arraycopy(record, 0, tmp, msg.length, record.length); + + msg = tmp; + } + + return msg; + } + + /** + * Returns an array of {@link NdefRecord} composing this message. + * + * @return mRecords + * + * @since AA02.01 + */ + public NdefRecord[] getRecords(){ + return mRecords; + } + + private native int parseNdefMessage(byte[] data); + + /** + * (Parcelable) Describe the parcel + * {@hide} + */ + public int describeContents() { + return 0; + } + + /** + * (Parcelable) Convert current object to a Parcel + * {@hide} + */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mRecords.length); + dest.writeTypedArray(mRecords, 0); + } + + /** + * Creator class, needed when implementing from Parcelable + * {@hide} + */ + public static final Parcelable.Creator<NdefMessage> CREATOR = new Parcelable.Creator<NdefMessage>() { + public NdefMessage createFromParcel(Parcel in) { + int recordsLength = in.readInt(); + NdefRecord[] records = new NdefRecord[recordsLength]; + in.readTypedArray(records, NdefRecord.CREATOR); + return new NdefMessage(records); + } + + public NdefMessage[] newArray(int size) { + return new NdefMessage[size]; + } + }; + +} diff --git a/core/java/com/trustedlogic/trustednfc/android/NdefRecord.aidl b/core/java/com/trustedlogic/trustednfc/android/NdefRecord.aidl new file mode 100644 index 0000000..9d95174 --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/NdefRecord.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.trustedlogic.trustednfc.android; + +parcelable NdefRecord; diff --git a/core/java/com/trustedlogic/trustednfc/android/NdefRecord.java b/core/java/com/trustedlogic/trustednfc/android/NdefRecord.java new file mode 100644 index 0000000..a0257fe --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/NdefRecord.java @@ -0,0 +1,293 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * File : NdefRecord.java + * Original-Author : Trusted Logic S.A. (Jeremie Corbier) + * Created : 05-10-2009 + */ + +package com.trustedlogic.trustednfc.android; + +import android.location.Location; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * An NDEF record as specified by the <a href="http://www.nfc-forum.org/">NFC + * Forum</a>. + * + * @see NdefMessage + * + * @since AA01.04 + * @hide + */ +public class NdefRecord implements Parcelable { + + /** + * Type Name Format - Empty record + */ + public static final short TNF_EMPTY = 0x0; + + /** + * Type Name Format - NFC Forum-defined type + */ + public static final short TNF_WELL_KNOWN_TYPE = 0x1; + + /** + * Type Name Format - RFC2045 MIME type + */ + public static final short TNF_MIME_MEDIA_TYPE = 0x2; + + /** + * Type Name Format - Absolute URI + */ + public static final short TNF_ABSOLUTE_URI = 0x3; + + /** + * Type Name Format - User-defined type + */ + public static final short TNF_EXTERNAL_TYPE = 0x4; + + /** + * Type Name Format - Unknown type + */ + public static final short TNF_UNKNOWN = 0x5; + + /** + * Type Name Format - Unchanged. This TNF is used for chunked records, so + * that middle records inherits from the first record's type. + */ + public static final short TNF_UNCHANGED = 0x6; + + /** + * NFC Forum-defined Type - Smart Poster + */ + public static final byte[] TYPE_SMART_POSTER = { 0x53, 0x70 }; + + /** + * NFC Forum-defined Type - Text + */ + public static final byte[] TYPE_TEXT = { 0x54 }; + + /** + * NFC Forum-defined Type - URI + */ + public static final byte[] TYPE_URI = { 0x55 }; + + /** + * NFC Forum-defined Global Type - Connection Handover Request + */ + public static final byte[] TYPE_HANDOVER_REQUEST = { 0x48, 0x72 }; + + /** + * NFC Forum-defined Global Type - Connection Handover Select + */ + public static final byte[] TYPE_HANDOVER_SELECT = { 0x48, 0x73 }; + + /** + * NFC Forum-defined Global Type - Connection Handover Carrier + */ + public static final byte[] TYPE_HANDOVER_CARRIER = { 0x48, 0x63 }; + + /** + * NFC Forum-defined Local Type - Alternative Carrier + */ + public static final byte[] TYPE_ALTERNATIVE_CARRIER = { 0x61, 0x63 }; + + /* Flag values */ + private static final int FLAG_MB = 0x80; + private static final int FLAG_ME = 0x40; + private static final int FLAG_CF = 0x20; + private static final int FLAG_SR = 0x10; + private static final int FLAG_IL = 0x08; + + /** + * Record Flags + */ + private short mFlags = 0; + + /** + * Record Type Name Format + */ + private short mTnf = 0; + + /** + * Record Type + */ + private byte[] mType = null; + + /** + * Record Identifier + */ + private byte[] mId = null; + + /** + * Record Payload + */ + private byte[] mPayload = null; + + /** + * Creates an NdefRecord given its Type Name Format, its type, its id and + * its. + * + * @param tnf + * Type Name Format + * @param type + * record type + * @param id + * record id (optional, can be null) + * @param data + * record payload + */ + public NdefRecord(short tnf, byte[] type, byte[] id, byte[] data) { + + /* generate flag */ + mFlags = FLAG_MB | FLAG_ME; + + /* Determine if it is a short record */ + if(data.length < 0xFF) + { + mFlags |= FLAG_SR; + } + + /* Determine if an id is present */ + if(id.length != 0) + { + mFlags |= FLAG_IL; + } + + mTnf = tnf; + mType = (byte[]) type.clone(); + mId = (byte[]) id.clone(); + mPayload = (byte[]) data.clone(); + } + + /** + * Appends data to the record's payload. + * + * @param data + * Data to be added to the record. + */ + public void appendPayload(byte[] data) { + byte[] newPayload = new byte[mPayload.length + data.length]; + + System.arraycopy(mPayload, 0, newPayload, 0, mPayload.length); + System.arraycopy(data, 0, newPayload, mPayload.length, data.length); + + mPayload = newPayload; + } + + /** + * Returns record as a byte array. + * + * @return record as a byte array. + */ + public byte[] toByteArray() { + return generate(mFlags, mTnf, mType, mId, mPayload); + } + + private native byte[] generate(short flags, short tnf, byte[] type, + byte[] id, byte[] data); + + /** + * (Parcelable) Describe the parcel + * {@hide} + */ + public int describeContents() { + return 0; + } + + /** + * (Parcelable) Convert current object to a Parcel + * {@hide} + */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mTnf); + dest.writeInt(mType.length); + dest.writeByteArray(mType); + dest.writeInt(mId.length); + dest.writeByteArray(mId); + dest.writeInt(mPayload.length); + dest.writeByteArray(mPayload); + } + + /** + * Creator class, needed when implementing from Parcelable + * {@hide} + */ + public static final Parcelable.Creator<NdefRecord> CREATOR = new Parcelable.Creator<NdefRecord>() { + public NdefRecord createFromParcel(Parcel in) { + // TNF + short tnf = (short)in.readInt(); + // Type + int typeLength = in.readInt(); + byte[] type = new byte[typeLength]; + in.readByteArray(type); + // ID + int idLength = in.readInt(); + byte[] id = new byte[idLength]; + in.readByteArray(id); + // Payload + int payloadLength = in.readInt(); + byte[] payload = new byte[payloadLength]; + in.readByteArray(payload); + + return new NdefRecord(tnf, type, id, payload); + } + + public NdefRecord[] newArray(int size) { + return new NdefRecord[size]; + } + }; + + /** + * Returns record TNF + * + * @return mTnf + */ + public int getTnf(){ + return mTnf; + } + + /** + * Returns record TYPE + * + * @return mType + */ + public byte[] getType(){ + return mType; + } + + /** + * Returns record ID + * + * @return mId + */ + public byte[] getId(){ + return mId; + } + + /** + * Returns record Payload + * + * @return mPayload + */ + public byte[] getPayload(){ + return mPayload; + } + +} diff --git a/core/java/com/trustedlogic/trustednfc/android/NdefTag.java b/core/java/com/trustedlogic/trustednfc/android/NdefTag.java new file mode 100644 index 0000000..1d99241 --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/NdefTag.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * File : NDEFTag.java + * Original-Author : Trusted Logic S.A. (Jeremie Corbier) + * Created : 04-12-2009 + */ + +package com.trustedlogic.trustednfc.android; + +import java.io.IOException; + +import android.os.RemoteException; +import android.util.Log; + +/** + * NdefTag represents tags complying with the NFC Forum's NFC Data Exchange + * Format. + * + * @since AA01.04 + * @hide + */ +public class NdefTag extends NfcTag { + + private static final String TAG = "NdefTag"; + + + public NdefTag(NfcTag tag){ + super(tag.mService,tag.mHandle); + this.isConnected = tag.isConnected; + this.isClosed = tag.isClosed; + tag.isClosed = false; + } + + /** + * Internal constructor for the NfcNdefTag class. + * + * @param service The entry point to the Nfc Service for NfcNdefTag class. + * @param handle The handle returned by the NFC service and used to identify + * the tag in subsequent calls. + * @hide + */ + NdefTag(INfcTag service, int handle) { + super(service, handle); + } + + /** + * Read NDEF data from an NDEF tag. + * + * @return the NDEF message read from the tag. + * @throws NfcException if the tag is not NDEF-formatted. + * @throws IOException if the target has been lost or the connection has + * been closed. + * @see NdefMessage + */ + public NdefMessage read() throws NfcException, IOException { + // Check state + checkState(); + + //Check if the tag is Ndef compliant + if(isNdef != true){ + isNdef = isNdef(); + if(isNdef != true) { + throw new NfcException("Tag is not NDEF compliant"); + } + } + + // Perform transceive + try { + NdefMessage msg = mService.read(mHandle); + if (msg == null) { + throw new IOException("NDEF read failed"); + } + return msg; + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in read(): ", e); + return null; + } + } + + /** + * Write NDEF data to an NDEF-compliant tag. + * + * @param msg NDEF message to be written to the tag. + * @throws NfcException if the tag is not NDEF formatted. + * @throws IOException if the target has been lost or the connection has + * been closed. + * @see NdefMessage + */ + public void write(NdefMessage msg) throws NfcException, IOException { + // Check state + checkState(); + + //Check if the tag is Ndef compliant + if(isNdef != true){ + isNdef = isNdef(); + if(isNdef != true) { + throw new NfcException("Tag is not NDEF compliant"); + } + } + + // Perform transceive + try { + boolean isSuccess = mService.write(mHandle, msg); + if (!isSuccess) { + throw new IOException("NDEF write failed"); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in write(): ", e); + } + } +} diff --git a/core/java/com/trustedlogic/trustednfc/android/NfcException.java b/core/java/com/trustedlogic/trustednfc/android/NfcException.java new file mode 100644 index 0000000..2497c15 --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/NfcException.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * File : NFCException.java + * Original-Author : Trusted Logic S.A. (Jeremie Corbier) + * Created : 26-08-2009 + */ + +package com.trustedlogic.trustednfc.android; + +/** + * Generic exception thrown in case something unexpected happened during the + * NFCManager operations. + * + * @since AA01.04 + * @hide + */ +public class NfcException extends Exception { + /** + * Constructs a new NfcException with the current stack trace and the + * specified detail message. + * + * @param s the detail message for this exception. + */ + public NfcException(String s) { + super(s); + } +} diff --git a/core/java/com/trustedlogic/trustednfc/android/NfcManager.java b/core/java/com/trustedlogic/trustednfc/android/NfcManager.java new file mode 100644 index 0000000..98ab5bf --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/NfcManager.java @@ -0,0 +1,656 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * File : NfcManager.java + * Original-Author : Trusted Logic S.A. (Jeremie Corbier) + * Created : 26-08-2009 + */ + +package com.trustedlogic.trustednfc.android; + +import java.io.IOException; + +import com.trustedlogic.trustednfc.android.internal.ErrorCodes; + +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.media.MiniThumbFile; +import android.os.Handler; +import android.os.RemoteException; +import android.util.Log; + +//import android.util.Log; + +/** + * This class provides the primary API for managing all aspects of NFC. Get an + * instance of this class by calling + * Context.getSystemService(Context.NFC_SERVICE). + * @hide + */ +public final class NfcManager { + /** + * Tag Reader Discovery mode + */ + private static final int DISCOVERY_MODE_TAG_READER = 0; + + /** + * NFC-IP1 Peer-to-Peer mode Enables the manager to act as a peer in an + * NFC-IP1 communication. Implementations should not assume that the + * controller will end up behaving as an NFC-IP1 target or initiator and + * should handle both cases, depending on the type of the remote peer type. + */ + private static final int DISCOVERY_MODE_NFCIP1 = 1; + + /** + * Card Emulation mode Enables the manager to act as an NFC tag. Provided + * that a Secure Element (an UICC for instance) is connected to the NFC + * controller through its SWP interface, it can be exposed to the outside + * NFC world and be addressed by external readers the same way they would + * with a tag. + * <p> + * Which Secure Element is exposed is implementation-dependent. + * + * @since AA01.04 + */ + private static final int DISCOVERY_MODE_CARD_EMULATION = 2; + + /** + * Used as Parcelable extra field in + * {@link com.trustedlogic.trustednfc.android.NfcManager#NDEF_TAG_DISCOVERED_ACTION} + * . It contains the NDEF message read from the NDEF tag discovered. + */ + public static final String NDEF_MESSAGE_EXTRA = "com.trustedlogic.trustednfc.android.extra.NDEF_MESSAGE"; + + /** + * Broadcast Action: a NDEF tag has been discovered. + * <p> + * Always contains the extra field + * {@link com.trustedlogic.trustednfc.android.NfcManager#NDEF_MESSAGE_EXTRA}. + * <p class="note"> + * <strong>Note:</strong> Requires the NFC_NOTIFY permission. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String NDEF_TAG_DISCOVERED_ACTION = "com.trustedlogic.trustednfc.android.action.NDEF_TAG_DISCOVERED"; + + /** + * Used as byte array extra field in + * {@link com.trustedlogic.trustednfc.android.NfcManager#TRANSACTION_DETECTED_ACTION} + * . It contains the AID of the applet concerned by the transaction. + */ + public static final String AID_EXTRA = "com.trustedlogic.trustednfc.android.extra.AID"; + + /** + * Broadcast Action: a transaction with a secure element has been detected. + * <p> + * Always contains the extra field + * {@link com.trustedlogic.trustednfc.android.NfcManager#AID_EXTRA} + * <p class="note"> + * <strong>Note:</strong> Requires the NFC_NOTIFY permission + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String TRANSACTION_DETECTED_ACTION = "com.trustedlogic.trustednfc.android.action.TRANSACTION_DETECTED"; + + /** + * LLCP link status: The LLCP link is activated. + * + * @since AA02.01 + */ + public static final int LLCP_LINK_STATE_ACTIVATED = 0; + + /** + * LLCP link status: The LLCP link is deactivated. + * + * @since AA02.01 + */ + public static final int LLCP_LINK_STATE_DEACTIVATED = 1; + + /** + * Used as int extra field in + * {@link com.trustedlogic.trustednfc.android.NfcManager#LLCP_LINK_STATE_CHANGED_ACTION} + * . It contains the new state of the LLCP link. + */ + public static final String LLCP_LINK_STATE_CHANGED_EXTRA = "com.trustedlogic.trustednfc.android.extra.LLCP_LINK_STATE"; + + /** + * Broadcast Action: the LLCP link state changed. + * <p> + * Always contains the extra field + * {@link com.trustedlogic.trustednfc.android.NfcManager#LLCP_LINK_STATE_CHANGED_EXTRA}. + * <p class="note"> + * <strong>Note:</strong> Requires the NFC_LLCP permission. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String LLCP_LINK_STATE_CHANGED_ACTION = "com.trustedlogic.trustednfc.android.action.LLCP_LINK_STATE_CHANGED"; + + private static final String TAG = "NfcManager"; + + private Handler mHandler; + + private INfcManager mService; + + private INfcTag mNfcTagService; + + private IP2pTarget mP2pTargetService; + + private IP2pInitiator mP2pInitiatorService; + + private ILlcpSocket mLlcpSocketService; + + private ILlcpConnectionlessSocket mLlcpConnectionlessSocketService; + + private ILlcpServiceSocket mLlcpServiceSocketService; + + static NfcException convertErrorToNfcException(int errorCode) { + return convertErrorToNfcException(errorCode, null); + } + + static NfcException convertErrorToNfcException(int errorCode, String message) { + if (message == null) { + message = ""; + } else { + message = " (" + message + ")"; + } + + switch (errorCode) { + case ErrorCodes.ERROR_BUSY: + return new NfcException("Another operation is already pending" + message); + case ErrorCodes.ERROR_CANCELLED: + return new NfcException("Operation cancelled" + message); + case ErrorCodes.ERROR_TIMEOUT: + return new NfcException("Operation timed out" + message); + case ErrorCodes.ERROR_SOCKET_CREATION: + return new NfcException("Error during the creation of an Llcp socket:" + message); + case ErrorCodes.ERROR_SAP_USED: + return new NfcException("Error SAP already used:" + message); + case ErrorCodes.ERROR_SERVICE_NAME_USED: + return new NfcException("Error Service Name already used:" + message); + case ErrorCodes.ERROR_SOCKET_OPTIONS: + return new NfcException("Error Socket options:" + message); + case ErrorCodes.ERROR_INVALID_PARAM: + return new NfcException("Error Set Properties: invalid param" + message); + case ErrorCodes.ERROR_NFC_ON: + return new NfcException("Error Set Properties : NFC is ON" + message); + case ErrorCodes.ERROR_NOT_INITIALIZED: + return new NfcException("NFC is not running " + message); + case ErrorCodes.ERROR_SE_ALREADY_SELECTED: + return new NfcException("Secure Element already connected" + message); + case ErrorCodes.ERROR_NO_SE_CONNECTED: + return new NfcException("No Secure Element connected" + message); + case ErrorCodes.ERROR_SE_CONNECTED: + return new NfcException("A secure Element is already connected" + message); + default: + return new NfcException("Unkown error code " + errorCode + message); + } + } + + /** + * @hide + */ + public NfcManager(INfcManager service, Handler handler) { + mService = service; + mHandler = handler; + try { + mNfcTagService = mService.getNfcTagInterface(); + mP2pInitiatorService = mService.getP2pInitiatorInterface(); + mP2pTargetService = mService.getP2pTargetInterface(); + mLlcpServiceSocketService = mService.getLlcpServiceInterface(); + mLlcpConnectionlessSocketService = mService.getLlcpConnectionlessInterface(); + mLlcpSocketService = mService.getLlcpInterface(); + } catch (RemoteException e) { + mLlcpSocketService = null; + mNfcTagService = null; + mP2pInitiatorService = null; + mP2pTargetService = null; + mLlcpConnectionlessSocketService = null; + mLlcpServiceSocketService = null; + } + } + + /** + * Return the status of the NFC feature + * + * @return mIsNfcEnabled + * @since AA02.01 + */ + public boolean isEnabled() { + try { + return mService.isEnabled(); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in isEnabled(): ", e); + return false; + } + } + + /** + * Enable the NFC Feature + * <p class="note"> + * <strong>Note:</strong> Requires the NFC_ADMIN permission + * + * @throws NfcException if the enable failed + * @since AA02.01 + */ + public void enable() throws NfcException { + try { + boolean isSuccess = mService.enable(); + if (isSuccess == false) { + throw new NfcException("NFC Service failed to enable"); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in enable(): ", e); + } + } + + /** + * Disable the NFC feature + * <p class="note"> + * <strong>Note:</strong> Requires the NFC_ADMIN permission + * + * @throws NfcException if the disable failed + * @since AA02.01 + */ + public void disable() throws NfcException { + try { + boolean isSuccess = mService.disable(); + if (isSuccess == false) { + throw new NfcException("NFC Service failed to disable"); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in disable(): ", e); + } + } + + /** + * Get the list of the identifiers of the Secure Elements detected + * by the NFC controller. + * + * @return list a list of Secure Element identifiers. + * @see #getSelectedSecureElement + * @see #selectSecureElement(int) + * @see #deselectSecureElement + * @since AA02.01 + */ + public int[] getSecureElementList() { + try { + return mService.getSecureElementList(); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in getSecureElementList(): ", e); + return null; + } + } + + /** + * Get the identifier of the currently selected secure element. + * + * @return id identifier of the currently selected Secure Element. 0 if none. + * @see #getSecureElementList + * @see #selectSecureElement(int) + * @see #deselectSecureElement + * @since AA02.01 + */ + public int getSelectedSecureElement() { + try { + return mService.getSelectedSecureElement(); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in getSelectedSecureElement(): ", e); + return -1; + } + } + + /** + * Select a specific Secure Element by its identifier. + * <p class="note"> + * <strong>Note:</strong> Requires the NFC_ADMIN permission + * + * @throws NfcException if a or this secure element is already selected + * @see #getSecureElementList + * @see #getSelectedSecureElement + * @see #deselectSecureElement + * @since AA02.01 + */ + public void selectSecureElement(int seId) throws NfcException { + try { + int status = mService.selectSecureElement(seId); + if(status != ErrorCodes.SUCCESS){ + throw convertErrorToNfcException(status); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in selectSecureElement(): ", e); + } + } + + /** + * Deselect the currently selected Secure Element + * <p class="note"> + * <strong>Note:</strong> Requires the NFC_ADMIN permission + * + * @throws NfcException if no secure Element is selected + * @see #getSecureElementList + * @see #getSelectedSecureElement + * @see #selectSecureElement(int) + * @since AA02.01 + */ + public void deselectSecureElement() throws NfcException { + try { + int status = mService.deselectSecureElement(); + if(status != ErrorCodes.SUCCESS){ + throw convertErrorToNfcException(status); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in deselectSecureElement(): ", e); + } + } + + /** + * Open a connection with a remote NFC peer + * + * This method does not return while no remote NFC peer enters the field. + * <p class="note"> + * <strong>Note:</strong> Requires the NFC_RAW permission + * + * @return P2pDevice object to be used to communicate with the detected + * peer. + * @throws IOException if the target has been lost or the connection has + * been closed. + * @throws NfcException if an open is already started + * @see P2pDevice + * @see #getOpenTimeout + * @see #setOpenTimeout(int) + * @see #cancel + * @since AA02.01 + */ + public P2pDevice openP2pConnection() throws IOException, NfcException { + try { + int handle = mService.openP2pConnection(); + // Handle potential errors + if (ErrorCodes.isError(handle)) { + if (handle == ErrorCodes.ERROR_IO) { + throw new IOException(); + } else { + throw convertErrorToNfcException(handle); + } + } + // Build the public NfcTag object, depending on its type + if (mP2pTargetService.getMode(handle) == P2pDevice.MODE_P2P_TARGET) { + return new P2pTarget(mP2pTargetService, handle); + } else { + return new P2pInitiator(mP2pInitiatorService, handle); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in openTagConnection(): ", e); + return null; + } + } + + /** + * Open a connection with a tag + * + * This method does not return while no tag enters the field. + * <p class="note"> + * <strong>Note:</strong> Requires the NFC_RAW permission + * + * @return tag object to be use to communicate with the detected NfcTag. + * @throws IOException if the target has been lost or the connection has + * been closed. + * @throws NfcException if an open is already started + * @see NfcTag + * @see #getOpenTimeout + * @see #setOpenTimeout(int) + * @see #cancel + * @since AA02.01 + */ + public NfcTag openTagConnection() throws IOException, NfcException { + try { + int handle = mService.openTagConnection(); + // Handle potential errors + if (ErrorCodes.isError(handle)) { + if (handle == ErrorCodes.ERROR_IO) { + throw new IOException(); + } else { + throw convertErrorToNfcException(handle); + } + } + // Build the public NfcTag object + return new NfcTag(mNfcTagService, handle); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in openTagConnection(): ", e); + return null; + } + } + + /** + * Set the timeout for open requests + * <p class="note"> + * <strong>Note:</strong> Requires the NFC_RAW permission + * + * @param timeout value of the timeout for open request + * @see #openP2pConnection + * @see #openTagConnection + * @see #getOpenTimeout + * @since AA02.01 + */ + public void setOpenTimeout(int timeout) { + try { + mService.setOpenTimeout(timeout); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in setOpenTimeout(): ", e); + } + } + + /** + * Get the timeout value of open requests + * + * @return mTimeout + * @see #setOpenTimeout(int) + * @since AA02.01 + */ + public int getOpenTimeout() { + try { + return mService.getOpenTimeout(); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in getOpenTimeout(): ", e); + return 0; + } + } + + /** + * Cancel an openTagConnection or an openP2pConnection started + * <p class="note"> + * <strong>Note:</strong> Requires the NFC_RAW permission + * + * @see #openP2pConnection + * @see #openTagConnection + * @since AA02.01 + */ + public void cancel() { + try { + mService.cancel(); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in cancel(): ", e); + } + } + + /** + * Creates a connectionless socket for a LLCP link and set its Service + * Access Point number (SAP) + * <p class="note"> + * <strong>Note:</strong> Requires the NFC_LLCP permission + * + * @param sap Service Access Point number related to the created + * Connectionless socket. + * @return LlcpConnectionlessSocket object to be used in a LLCP + * Connectionless communication. + * @throws IOException if the socket creation failed + * @throws NfcException if socket ressources are insufficicent + * @see LlcpConnectionlessSocket + * @since AA02.01 + */ + public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int sap) throws IOException, + NfcException { + + try { + int handle = mService.createLlcpConnectionlessSocket(sap); + // Handle potential errors + if (ErrorCodes.isError(handle)) { + if (handle == ErrorCodes.ERROR_IO) { + throw new IOException(); + } else { + throw convertErrorToNfcException(handle); + } + } + + // Build the public LlcpConnectionLess object + return new LlcpConnectionlessSocket(mLlcpConnectionlessSocketService, handle); + + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in createLlcpConnectionlessSocket(): ", e); + return null; + } + } + + /** + * Creates a LlcpServiceSocket for a LLCP link, set its Service Access Point + * number (SAP). + * <p> + * During a LLCP communication, the LlcpServiceSocket will create LlcpSocket + * to communicate with incoming LLCP clients. For that, a server socket need + * to have some informations as a working buffer length in order to handle + * incoming data and some options to define the LLCP communication. + * <p class="note"> + * <strong>Note:</strong> Requires the NFC_LLCP permission + * + * @param sap + * @param sn Service Name of the LlcpServiceSocket + * @param miu Maximum Information Unit (MIU) for a LlcpSocket created by the + * LlcpServiceSocket + * @param rw Receive Window (RW) for a LlcpSocket created by the + * LlcpServiceSocket + * @param linearBufferLength size of the memory space needed to handle + * incoming data for every LlcpSocket created. + * @return LlcpServiceSocket object to be used as a LLCP Service in a + * connection oriented communication. + * @throws IOException if the socket creation failed + * @throws NfcException if socket ressources are insufficicent + * @see LlcpServiceSocket + * @since AA02.01 + */ + public LlcpServiceSocket createLlcpServiceSocket(int sap, String sn, int miu, int rw, + int linearBufferLength) throws IOException, NfcException { + try { + int handle = mService.createLlcpServiceSocket(sap, sn, miu, rw, linearBufferLength); + // Handle potential errors + if (ErrorCodes.isError(handle)) { + if (handle == ErrorCodes.ERROR_IO) { + throw new IOException(); + } else { + throw convertErrorToNfcException(handle); + } + } + + // Build the public LlcpServiceSocket object + return new LlcpServiceSocket(mLlcpServiceSocketService, mLlcpSocketService, handle); + + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in createLlcpServiceSocket(): ", e); + return null; + } + } + + /** + * Creates a LlcpSocket for a LLCP link with a specific Service Access Point + * number (SAP) + * <p> + * A LlcpSocket need to have a linear buffer in order to handle incoming + * data. This linear buffer will be used to store incoming data as a stream. + * Data will be readable later. + * <p class="note"> + * <strong>Note:</strong> Requires the NFC_LLCP permission + * + * @param sap Service Access Point number for the created socket + * @param miu Maximum Information Unit (MIU) of the communication socket + * @param rw Receive Window (RW) of the communication socket + * @param linearBufferLength size of the memory space needed to handle + * incoming data with this socket + * @throws IOException if the socket creation failed + * @throws NfcException if socket ressources are insufficicent + * @see LlcpSocket + * @since AA02.01 + */ + public LlcpSocket createLlcpSocket(int sap, int miu, int rw, int linearBufferLength) + throws IOException, NfcException { + try { + int handle = mService.createLlcpSocket(sap, miu, rw, linearBufferLength); + // Handle potential errors + if (ErrorCodes.isError(handle)) { + if (handle == ErrorCodes.ERROR_IO) { + throw new IOException(); + } else { + throw convertErrorToNfcException(handle); + } + } + // Build the public LlcpSocket object + return new LlcpSocket(mLlcpSocketService, handle); + + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in createLlcpSocket(): ", e); + return null; + } + } + + /** + * Set different parameters like the NCIP General bytes, the LLCP link + * parameters and all tag discovery parameters. + * <p class="note"> + * <strong>Note:</strong> Requires the NFC_ADMIN permission + * + * @param param parameter to be updated with a new value + * @param value new value of the parameter + * @throws NfcException if incorrect parameters of NFC is ON + * @since AA02.01 + */ + public void setProperties(String param, String value) throws NfcException { + try { + int result = mService.setProperties(param, value); + // Handle potential errors + if (ErrorCodes.isError(result)) { + throw convertErrorToNfcException(result); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in setProperties(): ", e); + } + } + + /** + * Get the value of different parameters like the NCFIP General bytes, the + * LLCP link parameters and all tag discovery parameters. + * + * @param param parameter to be updated + * @return String value of the requested parameter + * @throws RemoteException + * @since AA02.01 + */ + public String getProperties(String param) { + String value; + try { + value = mService.getProperties(param); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in getProperties(): ", e); + return null; + } + return value; + } + +} diff --git a/core/java/com/trustedlogic/trustednfc/android/NfcTag.java b/core/java/com/trustedlogic/trustednfc/android/NfcTag.java new file mode 100644 index 0000000..798c7e4 --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/NfcTag.java @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * File : NFCTag.java + * Original-Author : Trusted Logic S.A. (Daniel Tomas) + * Created : 26-02-2010 + */ + +package com.trustedlogic.trustednfc.android; + +import java.io.IOException; + +import android.os.RemoteException; +import android.util.Log; + +import com.trustedlogic.trustednfc.android.internal.ErrorCodes; + +/** + * This class represents tags with no known formatting. One can use the method + * {@link #isNdef()} to determine if the tag can store NDEF-formatted messages. + * <p> + * + * <pre class="prettyprint"> + * if (tag.isNdef()) { + * NdefTag ndefTag = (NdefTag) tag; + * NdefMessage msg = ndefTag.read(); + * } + * </pre> + * + * @since AA01.04 + * @see NdefMessage + * @hide + */ +public class NfcTag { + + private static final String TAG = "NfcTag"; + + /** + * The handle returned by the NFC service and used to identify the tag in + * every call of this class. + * + * @hide + */ + protected int mHandle; + + /** + * The entry point for tag operations. + * + * @hide + */ + protected INfcTag mService; + + /** + * Flag set when the object is closed and thus not usable any more. + * + * @hide + */ + protected boolean isClosed = false; + + /** + * Flag set when the tag is connected. + * + * @hide + */ + protected boolean isConnected = false; + + /** + * Flag set when a check NDEF is performed. + * + * @hide + */ + protected boolean isNdef = false; + + /** + * Check if tag is still opened. + * + * @return data sent by the P2pInitiator. + * @throws NfcException if accessing a closed target. + * + * @hide + */ + public void checkState() throws NfcException { + if (isClosed) { + throw new NfcException("Tag has been closed."); + } + if (!isConnected) { + throw new NfcException("Tag is not connected."); + } + } + + /** + * Internal constructor for the NfcTag class. + * + * @param service The entry point to the Nfc Service for NfcTag class. + * @param handle The handle returned by the NFC service and used to identify + * the tag in subsequent calls. + * @hide + */ + NfcTag(INfcTag service, int handle) { + this.mService = service; + this.mHandle = handle; + } + + /** + * Connects to the tag. This shall be called prior to any other operation on + * the tag. + * + * @throws IOException if the tag has been lost or the connection has been + * closed. + * @throws nfcException if the tag is already in connected state. + */ + public void connect() throws NfcException, IOException { + // Check state + if (isClosed) { + throw new NfcException("Tag has been closed."); + } + if (isConnected) { + throw new NfcException("Already connected"); + } + + // Perform connect + try { + int result = mService.connect(mHandle); + if (ErrorCodes.isError(result)) { + if (result == ErrorCodes.ERROR_IO) { + throw new IOException("Failed to connect"); + } + else { + throw NfcManager.convertErrorToNfcException(result); + } + } + isConnected = true; + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in connect(): ", e); + } + } + + /** + * Disconnects from the tag. This must be called so that other targets can + * be discovered. It restarts the NFC discovery loop. + * + * @throws NfcException if the tag is already in disconnected state or not connected + */ + public void close() throws NfcException { + // Check state + checkState(); + + try { + mService.close(mHandle); + isClosed = true; + isConnected = false; + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in close(): ", e); + } + } + + /** + * Exchanges raw data with the tag, whatever the tag type. + * + * To exchange APDUs with a ISO14443-4-compliant tag, the data parameter + * must be filled with the C-APDU (CLA, INS, P1, P2 [, ...]). The returned + * data consists of the R-APDU ([...,] SW1, SW2). + * + * @param data data to be sent to the tag + * @return data sent in response by the tag + * @throws IOException if the tag has been lost or the connection has been + * closed. + * @throws NfcException in case of failure within the stack + */ + public byte[] transceive(byte[] data) throws IOException, NfcException { + // Check state + checkState(); + + // Perform transceive + try { + byte[] response = mService.transceive(mHandle, data); + if (response == null) { + throw new IOException("Transceive failed"); + } + return response; + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in transceive(): ", e); + return null; + } + } + + /** + * Checks whether tag is NDEF-compliant or not. + * + * @return true if the tag is NDEF-compliant, false otherwise + * @throws NfcException in case an error occurred when trying to determine + * whether the tag is NDEF-compliant + */ + public boolean isNdef() throws NfcException { + // Check state + checkState(); + + // Perform Check Ndef + try { + isNdef = mService.isNdef(mHandle); + return isNdef; + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in isNdef(): ", e); + return false; + } + } + + /** + * Returns target type. constants. + * + * @return tag type. + */ + public String getType() { + try { + return mService.getType(mHandle); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in getType(): ", e); + return null; + } + } + + /** + * Returns target UID. + * + * @return tag UID. + */ + public byte[] getUid() { + try { + return mService.getUid(mHandle); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in getType(): ", e); + return null; + } + } + +} diff --git a/core/java/com/trustedlogic/trustednfc/android/P2pDevice.java b/core/java/com/trustedlogic/trustednfc/android/P2pDevice.java new file mode 100644 index 0000000..65800f2 --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/P2pDevice.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * File : P2PDevice.java + * Original-Author : Trusted Logic S.A. (Daniel Tomas) + * Created : 26-02-2010 + */ + +package com.trustedlogic.trustednfc.android; + +import java.io.IOException; + +/** + * P2pDevice is the abstract base class for all supported P2P targets the + * NfcManager can handle. + * @hide + */ +public abstract class P2pDevice { + + /** + * Peer-to-Peer Target. + */ + public static final short MODE_P2P_TARGET = 0x00; + + /** + * Peer-to-Peer Initiator. + */ + public static final short MODE_P2P_INITIATOR = 0x01; + + /** + * Invalid target type. + */ + public static final short MODE_INVALID = 0xff; + + /** + * Target handle, used by native calls. + * @hide + */ + protected int mHandle; + + /** + * Flag set when the object is closed and thus not usable any more. + * @hide + */ + protected boolean isClosed = false; + + /** + * Prevent default constructor to be public. + * @hide + */ + protected P2pDevice() { + } + + /** + * Returns the remote NFC-IP1 General Bytes. + * + * @return remote general bytes + * @throws IOException + */ + public byte[] getGeneralBytes() throws IOException { + // Should not be called directly (use subclasses overridden method instead) + return null; + } + + /** + * Returns target type. The value returned can be one of the TYPE_* + * constants. + * + * @return target type. + */ + public int getMode() { + // Should not be called directly (use subclasses overridden method instead) + return MODE_INVALID; + } +} diff --git a/core/java/com/trustedlogic/trustednfc/android/P2pInitiator.java b/core/java/com/trustedlogic/trustednfc/android/P2pInitiator.java new file mode 100644 index 0000000..0f28ae0 --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/P2pInitiator.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * File : P2PInitiator.java + * Original-Author : Trusted Logic S.A. (Daniel Tomas) + */ + +package com.trustedlogic.trustednfc.android; + +import java.io.IOException; + +import com.trustedlogic.trustednfc.android.internal.ErrorCodes; + +import android.os.RemoteException; +import android.util.Log; + +/** + * P2pInitiator represents the initiator in an NFC-IP1 peer-to-peer + * communication. + * + * @see P2pTarget + * @since AA02.01 + * @hide + */ +public class P2pInitiator extends P2pDevice { + + private static final String TAG = "P2pInitiator"; + + /** + * The entry point for P2P tag operations. + * @hide + */ + private IP2pInitiator mService; + + /** + * Internal constructor for the P2pInitiator class. + * + * @param handle The handle returned by the NFC service and used to identify + * the tag in subsequent calls. + * + * @hide + */ + P2pInitiator(IP2pInitiator service, int handle) { + this.mService = service; + this.mHandle = handle; + } + + /** + * Receives data from a P2pInitiator. + * + * @return data sent by the P2pInitiator. + * @throws IOException if the target has been lost or if the connection has + * been closed. + */ + public byte[] receive() throws IOException { + try { + byte[] result = mService.receive(mHandle); + if (result == null) { + throw new IOException("Tag has been lost"); + } + return result; + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in receive(): ", e); + return null; + } + } + + /** + * Sends data to a P2pInitiator. + * + * @param data data to be sent to the P2pInitiator. + * @throws IOException if the target has been lost or if the connection has + * been closed. + */ + public void send(byte[] data) throws IOException { + try { + boolean isSuccess = mService.send(mHandle, data); + if (!isSuccess) { + throw new IOException("Tag has been lost"); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in send(): ", e); + } + } + + @Override + public byte[] getGeneralBytes() { + try { + return mService.getGeneralBytes(mHandle); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in getGeneralBytes(): ", e); + return null; + } + } + + @Override + public int getMode() { + return P2pDevice.MODE_P2P_INITIATOR; + } + +} diff --git a/core/java/com/trustedlogic/trustednfc/android/P2pTarget.java b/core/java/com/trustedlogic/trustednfc/android/P2pTarget.java new file mode 100644 index 0000000..b5e00db --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/P2pTarget.java @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * File : P2PTarget.java + * Original-Author : Trusted Logic S.A. (Daniel Tomas) + */ + +package com.trustedlogic.trustednfc.android; + +import java.io.IOException; + +import com.trustedlogic.trustednfc.android.internal.ErrorCodes; + +import android.os.RemoteException; +import android.util.Log; + +/** + * P2pTarget represents the target in an NFC-IP1 peer-to-peer communication. + * + * @see P2pInitiator + * @since AA02.01 + * @hide + */ +public class P2pTarget extends P2pDevice { + + private static final String TAG = "P2pTarget"; + + /** + * The entry point for P2P tag operations. + * @hide + */ + private IP2pTarget mService; + + /** + * Flag set when the object is closed and thus not usable any more. + * @hide + */ + private boolean isClosed = false; + + /** + * Flag set when the tag is connected. + * @hide + */ + private boolean isConnected = false; + + /** + * Check if tag is still opened. + * + * @return data sent by the P2pInitiator. + * @throws NfcException if accessing a closed target. + * + * @hide + */ + public void checkState() throws NfcException { + if(isClosed) { + throw new NfcException("Tag has been closed."); + } + } + + /** + * Internal constructor for the P2pTarget class. + * + * @param handle The handle returned by the NFC service and used to identify + * the tag in subsequent calls. + * + * @hide + */ + P2pTarget(IP2pTarget service, int handle) { + this.mService = service; + this.mHandle = handle; + } + + /** + * Connects to the P2pTarget. This shall be called prior to any other + * operation on the P2pTarget. + * + * @throws NfcException + */ + public void connect() throws NfcException { + // Check state + checkState(); + if (isConnected) { + throw new NfcException("Already connected"); + } + + // Perform connect + try { + int result = mService.connect(mHandle); + if (ErrorCodes.isError(result)) { + if (result == ErrorCodes.ERROR_IO) { + throw new NfcException("Failed to connect"); + } + else { + throw NfcManager.convertErrorToNfcException(result); + } + } + isConnected = true; + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in connect(): ", e); + } + } + + /** + * Disconnects from the P2p Target. This must be called so that other + * targets can be discovered. It restarts the NFC discovery loop. + * + * @throws NFCException + */ + public void disconnect() throws NfcException { + checkState(); + try { + mService.disconnect(mHandle); + isConnected = true; + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in disconnect(): ", e); + } + } + + /** + * Exchanges raw data with the P2pTarget. + * + * @param data data to be sent to the P2pTarget + * @return data sent in response by the P2pTarget + * @throws IOException if the target has been lost or the connection has + * been closed. + * @throws NfcException in case of failure within the stack + */ + public byte[] transceive(byte[] data) throws IOException, NfcException { + // Check state + checkState(); + + // Perform transceive + try { + byte[] response = mService.transceive(mHandle, data); + if (response == null) { + throw new IOException("Transceive failed"); + } + return response; + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in transceive(): ", e); + return null; + } + } + + /** + * Get the General bytes of the connected P2P Target + * + * @return general bytes of the connected P2P Target + * @throws IOException if the target in not in connected state + */ + public byte[] getGeneralBytes() throws IOException { + try { + if(isConnected){ + return mService.getGeneralBytes(mHandle); + }else{ + throw new IOException("Target not in connected state"); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in getGeneralBytes(): ", e); + return null; + } + } + + @Override + public int getMode() { + return P2pDevice.MODE_P2P_TARGET; + } + +} diff --git a/core/java/com/trustedlogic/trustednfc/android/internal/ErrorCodes.java b/core/java/com/trustedlogic/trustednfc/android/internal/ErrorCodes.java new file mode 100644 index 0000000..ca3b7e0 --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/internal/ErrorCodes.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * File : ErrorCodes.java + * Original-Author : Trusted Logic S.A. (Sylvain Fonteneau) + * Created : 26-02-2010 + */ + +package com.trustedlogic.trustednfc.android.internal; + +/** + * This class defines all the error codes that can be returned by the service + * and producing an exception on the application level. These are needed since + * binders does not support exceptions. + * + * @hide + */ +public class ErrorCodes { + + public static boolean isError(int code) { + if (code < 0) { + return true; + } else { + return false; + } + } + + public static final int SUCCESS = 0; + + public static final int ERROR_IO = -1; + + public static final int ERROR_CANCELLED = -2; + + public static final int ERROR_TIMEOUT = -3; + + public static final int ERROR_BUSY = -4; + + public static final int ERROR_CONNECT = -5; + + public static final int ERROR_DISCONNECT = -5; + + public static final int ERROR_READ = -6; + + public static final int ERROR_WRITE = -7; + + public static final int ERROR_INVALID_PARAM = -8; + + public static final int ERROR_INSUFFICIENT_RESOURCES = -9; + + public static final int ERROR_SOCKET_CREATION = -10; + + public static final int ERROR_SOCKET_NOT_CONNECTED = -11; + + public static final int ERROR_BUFFER_TO_SMALL = -12; + + public static final int ERROR_SAP_USED = -13; + + public static final int ERROR_SERVICE_NAME_USED = -14; + + public static final int ERROR_SOCKET_OPTIONS = -15; + + public static final int ERROR_NFC_ON = -16; + + public static final int ERROR_NOT_INITIALIZED = -17; + + public static final int ERROR_SE_ALREADY_SELECTED = -18; + + public static final int ERROR_SE_CONNECTED = -19; + + public static final int ERROR_NO_SE_CONNECTED = -20; + + + + + + +} diff --git a/core/java/com/trustedlogic/trustednfc/android/internal/NativeLlcpConnectionlessSocket.java b/core/java/com/trustedlogic/trustednfc/android/internal/NativeLlcpConnectionlessSocket.java new file mode 100644 index 0000000..ccfbeb4 --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/internal/NativeLlcpConnectionlessSocket.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * File : NativeLlcpConnectionLessSocket.java + * Original-Author : Trusted Logic S.A. (Sylvain Fonteneau) + * Created : 18-02-2010 + */ + +package com.trustedlogic.trustednfc.android.internal; + +import com.trustedlogic.trustednfc.android.LlcpPacket; + +/** + * LlcpConnectionlessSocket represents a LLCP Connectionless object to be used + * in a connectionless communication + * + * @since AA02.01 + * {@hide} + */ + +public class NativeLlcpConnectionlessSocket { + + private int mHandle; + + private int mSap; + + private int mLinkMiu; + + public NativeLlcpConnectionlessSocket(){; + } + + public NativeLlcpConnectionlessSocket(int sap){ + mSap = sap; + } + + public native boolean doSendTo(int sap, byte[] data); + + public native LlcpPacket doReceiveFrom(int linkMiu); + + public native boolean doClose(); + + public int getLinkMiu(){ + return mLinkMiu; + } + + public int getSap(){ + return mSap; + } + + public int getHandle(){ + return mHandle; + } + +} diff --git a/core/java/com/trustedlogic/trustednfc/android/internal/NativeLlcpServiceSocket.java b/core/java/com/trustedlogic/trustednfc/android/internal/NativeLlcpServiceSocket.java new file mode 100644 index 0000000..a01f135 --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/internal/NativeLlcpServiceSocket.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * File : NativeLlcpServerSocket.java + * Original-Author : Trusted Logic S.A. (Sylvain Fonteneau) + * Created : 18-02-2010 + */ + +package com.trustedlogic.trustednfc.android.internal; + +/** + * LlcpServiceSocket represents a LLCP Service to be used in a + * Connection-oriented communication + * {@hide} + */ + +public class NativeLlcpServiceSocket { + + private int mHandle; + + private int mLocalMiu; + + private int mLocalRw; + + private int mLocalLinearBufferLength; + + private int mSap; + + private int mTimeout; + + private String mServiceName; + + public NativeLlcpServiceSocket(){ + + } + + public NativeLlcpServiceSocket(String serviceName){ + mServiceName = serviceName; + } + + public native NativeLlcpSocket doAccept(int timeout, int miu, int rw, int linearBufferLength); + + public native boolean doClose(); + + public int getHandle(){ + return mHandle; + } + + public void setAcceptTimeout(int timeout){ + mTimeout = timeout; + } + + public int getAcceptTimeout(){ + return mTimeout; + } + + public int getRw(){ + return mLocalRw; + } + + public int getMiu(){ + return mLocalMiu; + } + + public int getLinearBufferLength(){ + return mLocalLinearBufferLength; + } +} diff --git a/core/java/com/trustedlogic/trustednfc/android/internal/NativeLlcpSocket.java b/core/java/com/trustedlogic/trustednfc/android/internal/NativeLlcpSocket.java new file mode 100644 index 0000000..077c5e0 --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/internal/NativeLlcpSocket.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * File : NativeLlcpClientSocket.java + * Original-Author : Trusted Logic S.A. (Sylvain Fonteneau) + * Created : 18-02-2010 + */ + +package com.trustedlogic.trustednfc.android.internal; + +/** + * LlcpClientSocket represents a LLCP Connection-Oriented client to be used in a + * connection-oriented communication + * {@hide} + */ + +public class NativeLlcpSocket { + + private int mHandle; + + private int mSap; + + private int mLocalMiu; + + private int mLocalRw; + + private int mTimeout; + + public NativeLlcpSocket(){ + + } + + public NativeLlcpSocket(int sap, int miu, int rw){ + mSap = sap; + mLocalMiu = miu; + mLocalRw = rw; + } + + public native boolean doConnect(int nSap, int timeout); + + public native boolean doConnectBy(String sn, int timeout); + + public native boolean doClose(); + + public native boolean doSend(byte[] data); + + public native int doReceive(byte[] recvBuff); + + public native int doGetRemoteSocketMiu(); + + public native int doGetRemoteSocketRw(); + + + + public void setConnectTimeout(int timeout){ + mTimeout = timeout; + } + + public int getConnectTimeout(){ + return mTimeout; + } + + public int getSap(){ + return mSap; + } + + public int getMiu(){ + return mLocalMiu; + } + + public int getRw(){ + return mLocalRw; + } + + public int getHandle(){ + return mHandle; + } + +} diff --git a/core/java/com/trustedlogic/trustednfc/android/internal/NativeNdefTag.java b/core/java/com/trustedlogic/trustednfc/android/internal/NativeNdefTag.java new file mode 100644 index 0000000..d1e64a6 --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/internal/NativeNdefTag.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * File : NativeNdefTag.java + * Original-Author : Trusted Logic S.A. (Sylvain Fonteneau) + * Created : 18-02-2010 + */ + +package com.trustedlogic.trustednfc.android.internal; + +/** + * Native interface to the NDEF tag functions + * + * {@hide} + */ +public class NativeNdefTag { + private int mHandle; + + public native byte[] doRead(); + + public native boolean doWrite(byte[] buf); +} diff --git a/core/java/com/trustedlogic/trustednfc/android/internal/NativeNfcManager.java b/core/java/com/trustedlogic/trustednfc/android/internal/NativeNfcManager.java new file mode 100644 index 0000000..2f5a0f0 --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/internal/NativeNfcManager.java @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * File : NativeNfcManager.java + * Original-Author : Trusted Logic S.A. (Sylvain Fonteneau) + * Created : 18-02-2010 + */ + +package com.trustedlogic.trustednfc.android.internal; + +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.content.Context; +import android.content.Intent; +import android.os.Handler; +import android.os.Message; +import android.util.Log; + +import com.trustedlogic.trustednfc.android.NfcManager; +import com.trustedlogic.trustednfc.android.NdefMessage; +import com.trustedlogic.trustednfc.android.NfcTag; + +/** + * Native interface to the NFC Manager functions {@hide} + */ +public class NativeNfcManager { + + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String INTERNAL_LLCP_LINK_STATE_CHANGED_EXTRA = "com.trustedlogic.trustednfc.android.extra.INTERNAL_LLCP_LINK_STATE"; + + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String INTERNAL_LLCP_LINK_STATE_CHANGED_ACTION = "com.trustedlogic.trustednfc.android.action.INTERNAL_LLCP_LINK_STATE_CHANGED"; + + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String INTERNAL_TARGET_DESELECTED_ACTION = "com.trustedlogic.trustednfc.android.action.INTERNAL_TARGET_DESELECTED"; + + /* Native structure */ + private int mNative; + + private Context mContext; + + private Handler mNfcHandler; + + private static final String TAG = "NativeNfcManager"; + + private static final int MSG_NDEF_TAG = 0; + + private static final int MSG_CARD_EMULATION = 1; + + private static final int MSG_LLCP_LINK_ACTIVATION = 2; + + private static final int MSG_LLCP_LINK_DEACTIVATED = 3; + + private static final int MSG_TARGET_DESELECTED = 4; + + public NativeNfcManager(Context context) { + mNfcHandler = new NfcHandler(); + mContext = context; + } + + /** + * Initializes Native structure + */ + public native boolean initializeNativeStructure(); + + /** + * Initializes NFC stack. + */ + public native boolean initialize(); + + /** + * Deinitializes NFC stack. + */ + public native boolean deinitialize(); + + /** + * Enable discory for the NdefMessage and Transaction notification + */ + public native void enableDiscovery(int mode); + + /** + * Disables an NFCManager mode of operation. Allows to disable tag reader, + * peer to peer initiator or target modes. + * + * @param mode discovery mode to enable. Must be one of the provided + * NFCManager.DISCOVERY_MODE_* constants. + */ + public native void disableDiscoveryMode(int mode); + + public native int[] doGetSecureElementList(); + + public native void doSelectSecureElement(int seID); + + public native void doDeselectSecureElement(int seID); + + public native NativeP2pDevice doOpenP2pConnection(int timeout); + + public native NativeNfcTag doOpenTagConnection(int timeout); + + public native int doGetLastError(); + + public native void doSetProperties(int param, int value); + + public native void doCancel(); + + public native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap); + + public native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu, + int rw, int linearBufferLength); + + public native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw, + int linearBufferLength); + + public native boolean doCheckLlcp(); + + public native boolean doActivateLlcp(); + + private class NfcHandler extends Handler { + @Override + public void handleMessage(Message msg) { + + try { + switch (msg.what) { + case MSG_NDEF_TAG: + Log.d(TAG, "Checking for NDEF tag message"); + NativeNfcTag tag = (NativeNfcTag) msg.obj; + if (tag.doConnect()) { + if (tag.checkNDEF()) { + byte[] buff = tag.doRead(); + if (buff != null) { + NdefMessage msgNdef = new NdefMessage(buff); + if (msgNdef != null) { + /* Send broadcast ordered */ + Intent NdefMessageIntent = new Intent(); + NdefMessageIntent + .setAction(NfcManager.NDEF_TAG_DISCOVERED_ACTION); + NdefMessageIntent.putExtra(NfcManager.NDEF_MESSAGE_EXTRA, + msgNdef); + Log.d(TAG, "NDEF message found, broadcasting to applications"); + mContext.sendOrderedBroadcast(NdefMessageIntent, + android.Manifest.permission.NFC_NOTIFY); + /* Disconnect tag */ + tag.doAsyncDisconnect(); + } + } else { + Log.w(TAG, "Unable to read NDEF message (tag empty or not well formated)"); + /* Disconnect tag */ + tag.doAsyncDisconnect(); + } + } else { + Log.d(TAG, "Tag is *not* NDEF compliant"); + /* Disconnect tag */ + tag.doAsyncDisconnect(); + } + } else { + /* Disconnect tag */ + tag.doAsyncDisconnect(); + } + break; + case MSG_CARD_EMULATION: + Log.d(TAG, "Card Emulation message"); + byte[] aid = (byte[]) msg.obj; + /* Send broadcast ordered */ + Intent TransactionIntent = new Intent(); + TransactionIntent.setAction(NfcManager.TRANSACTION_DETECTED_ACTION); + TransactionIntent.putExtra(NfcManager.AID_EXTRA, aid); + Log.d(TAG, "Broadcasting Card Emulation event"); + mContext.sendOrderedBroadcast(TransactionIntent, + android.Manifest.permission.NFC_NOTIFY); + break; + + case MSG_LLCP_LINK_ACTIVATION: + NativeP2pDevice device = (NativeP2pDevice) msg.obj; + + Log.d(TAG, "LLCP Activation message"); + + if (device.getMode() == NativeP2pDevice.MODE_P2P_TARGET) { + if (device.doConnect()) { + /* Check Llcp compliancy */ + if (doCheckLlcp()) { + /* Activate Llcp Link */ + if (doActivateLlcp()) { + Log.d(TAG, "Initiator Activate LLCP OK"); + /* Broadcast Intent Link LLCP activated */ + Intent LlcpLinkIntent = new Intent(); + LlcpLinkIntent + .setAction(INTERNAL_LLCP_LINK_STATE_CHANGED_ACTION); + LlcpLinkIntent.putExtra( + INTERNAL_LLCP_LINK_STATE_CHANGED_EXTRA, + NfcManager.LLCP_LINK_STATE_ACTIVATED); + Log.d(TAG, "Broadcasting internal LLCP activation"); + mContext.sendBroadcast(LlcpLinkIntent); + } + + } else { + device.doDisconnect(); + } + + } + + } else if (device.getMode() == NativeP2pDevice.MODE_P2P_INITIATOR) { + /* Check Llcp compliancy */ + if (doCheckLlcp()) { + /* Activate Llcp Link */ + if (doActivateLlcp()) { + Log.d(TAG, "Target Activate LLCP OK"); + /* Broadcast Intent Link LLCP activated */ + Intent LlcpLinkIntent = new Intent(); + LlcpLinkIntent + .setAction(INTERNAL_LLCP_LINK_STATE_CHANGED_ACTION); + LlcpLinkIntent.putExtra(INTERNAL_LLCP_LINK_STATE_CHANGED_EXTRA, + NfcManager.LLCP_LINK_STATE_ACTIVATED); + Log.d(TAG, "Broadcasting internal LLCP activation"); + mContext.sendBroadcast(LlcpLinkIntent); + } + } + } + break; + + case MSG_LLCP_LINK_DEACTIVATED: + /* Broadcast Intent Link LLCP activated */ + Log.d(TAG, "LLCP Link Deactivated message"); + Intent LlcpLinkIntent = new Intent(); + LlcpLinkIntent.setAction(NfcManager.LLCP_LINK_STATE_CHANGED_ACTION); + LlcpLinkIntent.putExtra(NfcManager.LLCP_LINK_STATE_CHANGED_EXTRA, + NfcManager.LLCP_LINK_STATE_DEACTIVATED); + Log.d(TAG, "Broadcasting LLCP deactivation"); + mContext.sendOrderedBroadcast(LlcpLinkIntent, + android.Manifest.permission.NFC_LLCP); + break; + + case MSG_TARGET_DESELECTED: + /* Broadcast Intent Target Deselected */ + Log.d(TAG, "Target Deselected"); + Intent TargetDeselectedIntent = new Intent(); + TargetDeselectedIntent.setAction(INTERNAL_TARGET_DESELECTED_ACTION); + Log.d(TAG, "Broadcasting Intent"); + mContext.sendOrderedBroadcast(TargetDeselectedIntent, + android.Manifest.permission.NFC_LLCP); + break; + + default: + Log.e(TAG, "Unknown message received"); + break; + } + } catch (Exception e) { + // Log, don't crash! + Log.e(TAG, "Exception in NfcHandler.handleMessage:", e); + } + } + }; + + /** + * Notifies Ndef Message + */ + private void notifyNdefMessageListeners(NativeNfcTag tag) { + Message msg = mNfcHandler.obtainMessage(); + + msg.what = MSG_NDEF_TAG; + msg.obj = tag; + + mNfcHandler.sendMessage(msg); + } + + /** + * Notifies transaction + */ + private void notifyTargetDeselected() { + Message msg = mNfcHandler.obtainMessage(); + + msg.what = MSG_TARGET_DESELECTED; + + mNfcHandler.sendMessage(msg); + } + + /** + * Notifies transaction + */ + private void notifyTransactionListeners(byte[] aid) { + Message msg = mNfcHandler.obtainMessage(); + + msg.what = MSG_CARD_EMULATION; + msg.obj = aid; + + mNfcHandler.sendMessage(msg); + } + + /** + * Notifies P2P Device detected, to activate LLCP link + */ + private void notifyLlcpLinkActivation(NativeP2pDevice device) { + Message msg = mNfcHandler.obtainMessage(); + + msg.what = MSG_LLCP_LINK_ACTIVATION; + msg.obj = device; + + mNfcHandler.sendMessage(msg); + } + + /** + * Notifies P2P Device detected, to activate LLCP link + */ + private void notifyLlcpLinkDeactivated() { + Message msg = mNfcHandler.obtainMessage(); + + msg.what = MSG_LLCP_LINK_DEACTIVATED; + + mNfcHandler.sendMessage(msg); + } + +} diff --git a/core/java/com/trustedlogic/trustednfc/android/internal/NativeNfcTag.java b/core/java/com/trustedlogic/trustednfc/android/internal/NativeNfcTag.java new file mode 100644 index 0000000..b92783d --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/internal/NativeNfcTag.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * File : NativeNfcTag.java + * Original-Author : Trusted Logic S.A. (Sylvain Fonteneau) + * Created : 18-02-2010 + */ + +package com.trustedlogic.trustednfc.android.internal; + +/** + * Native interface to the NFC tag functions + * + * {@hide} + */ +public class NativeNfcTag { + private int mHandle; + + private String mType; + + private byte[] mUid; + + public native boolean doConnect(); + + public native boolean doDisconnect(); + + public native void doAsyncDisconnect(); + + public native byte[] doTransceive(byte[] data); + + public native boolean checkNDEF(); + + public native byte[] doRead(); + + public native boolean doWrite(byte[] buf); + + public int getHandle() { + return mHandle; + } + + public String getType() { + return mType; + } + + public byte[] getUid() { + return mUid; + } +} diff --git a/core/java/com/trustedlogic/trustednfc/android/internal/NativeP2pDevice.java b/core/java/com/trustedlogic/trustednfc/android/internal/NativeP2pDevice.java new file mode 100644 index 0000000..75d25ba --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/internal/NativeP2pDevice.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * File : NativeP2pDevice.java + * Original-Author : Trusted Logic S.A. (Sylvain Fonteneau) + * Created : 18-02-2010 + */ + +package com.trustedlogic.trustednfc.android.internal; + +/** + * Native interface to the P2P Initiator functions + * + * {@hide} + */ +public class NativeP2pDevice { + + /** + * Peer-to-Peer Target. + */ + public static final short MODE_P2P_TARGET = 0x00; + + /** + * Peer-to-Peer Initiator. + */ + public static final short MODE_P2P_INITIATOR = 0x01; + + /** + * Invalid target type. + */ + public static final short MODE_INVALID = 0xff; + + private int mHandle; + + private int mMode; + + private byte[] mGeneralBytes; + + public native byte[] doReceive(); + + public native boolean doSend(byte[] data); + + public native boolean doConnect(); + + public native boolean doDisconnect(); + + public native byte[] doTransceive(byte[] data); + + public int getHandle() { + return mHandle; + } + + public int getMode() { + return mMode; + } + + public byte[] getGeneralBytes() { + return mGeneralBytes; + } + +} diff --git a/core/java/com/trustedlogic/trustednfc/android/package.html b/core/java/com/trustedlogic/trustednfc/android/package.html new file mode 100644 index 0000000..0c0b605 --- /dev/null +++ b/core/java/com/trustedlogic/trustednfc/android/package.html @@ -0,0 +1,473 @@ +<html> +<body> + +<p>Provides classes that manage the NFC functionality.</p> + +<p>The NFC functionality is related to Near Field Communication.</p> + +<p>The NFC APIs let applications:</p> +<ul> + <li>Scan for remote NFC targets (NFC Tag or NFC Peer)</li> + <li>Transfer raw data to and from remote NFC targets (NFC Tags or NFC Peer)</li> + <li>Read/Write NDEF data from/to remote NFC targets (NFC Tags)</li> + <li>Establish LLCP connection with a remote NFC target (NFC Peer with LLCP support)</li> + <li>Exchange data with a remote NFC target through LLCP services (NFC Peer with LLCP support)</li> + <li>Be notified of transactions on the local Secure Element by an external NFC reader</li> +</ul> + + +<h1>Setting Up NFC</h1> + +<p> +Before an application can use the NFC feature, it needs to check if NFC is +supported on the device by getting an instance of the +{@link com.trustedlogic.trustednfc.android.NfcManager} class. +</p> + +<pre> + NfcManager mNfcManager = (NfcManager) getSystemService(Context.NFC_SERVICE); + if (mNfcManager == null) { + // Device does not support NFC + } +</pre> + +<p> +An application can ensure that NFC is enabled. +If not, an application with the needed permission can request that NFC be +enabled. +</p> + +<pre> + if (!mNfcManager.isEnabled) { + // NFC is currently disabled. + // Enable NFC. + mNfcManager.enable(); + } +</pre> + +<p> +Before using the card emulation mode, an application can ensure that a secure +element is selected ({@link com.trustedlogic.trustednfc.android.NfcManager#getSelectedSecureElement}). +If not, an application with the needed permission can recover the list of +available secure elements on the device +({@link com.trustedlogic.trustednfc.android.NfcManager#getSecureElementList}) and select one +({@link com.trustedlogic.trustednfc.android.NfcManager#selectSecureElement}). +</p> + +<p> +Before using the NFC feature, an application can configure the NFC device by +calling {@link com.trustedlogic.trustednfc.android.NfcManager#setProperties}. This function allows: +</p> +<ul> + <li>Enabling/disabling the NFC device capabilities (RF types, baudrates, + NFCIP-1 mode and role...)</li> + <li>Settings the NFCIP-1 general bytes and the LLCP link parameters</li> +</ul> +<p> +The setting properties can be customized according to the Device capabilities. +The next table give the minimal set of properties supported by the Device. +Depending on the implementation, the table may be completed. +</p> +<table> + <TR><TH> Property Name </TH><TH> Property Values </TH></TR> + <TR><TD> discovery.felica </TD><TD> <b>true</b>|false </TD></TR> + <TR><TD> discovery.iso14443A </TD><TD> <b>true</b>|false </TD></TR> + <TR><TD> discovery.iso14443B </TD><TD> <b>true</b>|false </TD></TR> + <TR><TD> discovery.iso15693 </TD><TD> <b>true</b>|false </TD></TR> + <TR><TD> discovery.nfcip </TD><TD> <b>true</b>|false </TD></TR> + <TR><TD> nfcip.baudrate </TD><TD> 106|212|424 </TD></TR> + <TR><TD> nfcip.generalbytes </TD><TD> </TD></TR> + <TR><TD> nfcip.mode </TD><TD> active|passive|<b>all</b> </TD></TR> + <TR><TD> nfcip.role </TD><TD> initiator|target|<b>both</b> </TD></TR> + <TR><TD> llcp.lto </TD><TD> <b>150</b> (0 to 255) </TD></TR> + <TR><TD> llcp.opt </TD><TD> <b>0</b> (0 to 3) </TD></TR> + <TR><TD> llcp.miu </TD><TD> <b>128</b> (128 to 2176) </TD></TR> + <TR><TD> llcp.wks </TD><TD> <b>1</b> (0 to 15) </TD></TR> +</table> +<p>(default values in bold)</p> + + +<h1>NFC Permissions</h1> + +<p> +To change the NFC service settings such as enabling the NFC targets +discovery or activating the secure element, an application must declare the +NFC_ADMIN permission. +</p> +<p> +To perform NFC raw communication with a remote NFC target in +Reader/Write Mode or Peer-to-Peer Mode, an application must declare the NFC_RAW +permission. +</p> +<p> +To receive NDEF message or Secure Element intents, an application must declare +the NFC_NOTIFY permission. +</p> +<p> +To receive the LLCP link intent and perform an LLCP communication with a remote NFC target, an application must +declare the NFC_LLCP permission. +</p> + + +<h1>NFC Usage</h1> + +<p> +The following code samples illustrate the APIs usage regarding the NFC service +use cases. +</p> + +<h2>Reader/Writer Mode NDEF message notification</h2> + +<p> +This code sample illustrates the NDEF message notification through an Intent declared in the manifest and a receiver implemented in the application. +</p> +<p>Main involved classes/methods:</p> + +<p>Manifest Example:</p> +<pre> + <receiver android:name=".NfcReaderDemoReceiver"> + <intent-filter> + <action android:name= "com.trustedlogic.trustednfc.android.action.NDEF_TAG_DISCOVERED"/> + </intent-filter> + </receiver> +</pre> + +<p>Receiver Example:</p> +<ul> + <li>{@link com.trustedlogic.trustednfc.android.NdefMessage}</li> + <li>{@link com.trustedlogic.trustednfc.android.NfcManager#NDEF_TAG_DISCOVERED_ACTION}</li> + <li>{@link com.trustedlogic.trustednfc.android.NfcManager#NDEF_MESSAGE_EXTRA}</li> +</ul> +<pre> +public class NdefMessageReceiverSample extends BroadcastReceiver { + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(NfcManager.NDEF_TAG_DISCOVERERD_ACTION)) { + NdefMessage msg = intent.getParcelableExtra(NfcManager.NDEF_MESSAGE_EXTRA); + + /* Manage the NdefMessage received */ + } +</pre> + +<h2>Reader/Writer Mode raw exchange</h2> + +<p> +This code sample illustrates raw exchanges with a NFC target in Reader/Writer +mode. +</p> +<p>Main involved classes/methods:</p> +<ul> + <li>{@link com.trustedlogic.trustednfc.android.NfcManager#openTagConnection}</li> + <li>{@link com.trustedlogic.trustednfc.android.NfcTag}</li> +</ul> + +<pre> +public class TagReaderSample { + + /** The NFC manager to access NFC features */ + private NfcManager manager = (NfcManager) getSystemService(Context.NFC_SERVICE); + + private void runTagReader() { + NfcTag tag = null; + String type; + byte[] cmd = { 0x01, 0x02, 0x03 }; + byte[] res; + + while (true) { + try { + Log.i("NFC example", "Please wave in front of the tag"); + // Open a connection on next available tag + try { + tag = manager.openTagConnection(); + } catch (NfcException e) { + // TODO: Handle open failure + } + + // Look for a mifare 4k + type = tag.getType(); + if (type.equals("Mifare4K")) { + Log.i("NFC example", "Tag detected"); + tag.connect(); + // Ready to communicate, we can send transceive ! + res = tag.transceive(cmd); + } else { + Log.i("NFC example", "Unknown tag"); + } + } catch (IOException e) { + // TODO: Handle broken connection + } finally { + if (tag != null) { + tag.close(); + } + } + } + } +} +</pre> + +<h2>Peer-to-Peer Mode raw exchange</h2> + +<p> +This code sample illustrates raw exchanges with a NFC target in Peer-to-Peer +mode. +</p> +<p>Main involved classes/methods:</p> +<ul> + <li>{@link com.trustedlogic.trustednfc.android.NfcManager#openP2pConnection}</li> + <li>{@link com.trustedlogic.trustednfc.android.P2pDevice}</li> + <li>{@link com.trustedlogic.trustednfc.android.P2pInitiator}</li> + <li>{@link com.trustedlogic.trustednfc.android.P2pTarget}</li> +</ul> + +<pre> +public class P2pSample { + + /** The NFC manager to access NFC features */ + private NfcManager manager = (NfcManager) getSystemService(Context.NFC_SERVICE); + + private void runP2p() { + P2pDevice deviceP2p; + P2pInitiator initiator; + P2pTarget target; + byte[] data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + byte[] echo = new byte[data.length * 10]; + + try { + deviceP2p = manager.openP2pConnection(); + + if (deviceP2p.getMode() == P2pDevice.MODE_P2P_INITIATOR) { + target = new P2pTarget(deviceP2p); + // Connect to the detected P2P target + target.connect(); + // send data to the target + target.transceive(data); + // disconnect the connected target + target.disconnect(); + } else if (deviceP2p.getMode() == P2pDevice.MODE_P2P_TARGET) { + initiator = new P2pInitiator(deviceP2p); + //target in receive state + echo = initiator.receive(); + // send back the data received + initiator.send(echo); + } + } catch (IOException e0) { + + } catch (NfcException e1) { + + } + } +} +</pre> + +<h2>Peer-to-Peer Mode LLCP exchange</h2> + +<p> +This code sample illustrates how to get LLCP link state notification with the declaration of a Receiver in the manifest of the application and the implementation +of the receiver in the application. +</p> +<p>Manifest Example:</p> +<pre> + <receiver android:name=".LlcpModeReceiverSample"> + <intent-filter> + <action android:name= "com.trustedlogic.trustednfc.android.action.LLCP_LINK_STATE_CHANGED"/> + </intent-filter> + </receiver> +</pre> + +<p>Receiver Example:</p> +<ul> + <li>{@link com.trustedlogic.trustednfc.android.NfcManager#LLCP_LINK_STATE_CHANGED_ACTION}</li> + <li>{@link com.trustedlogic.trustednfc.android.NfcManager#LLCP_LINK_STATE_CHANGED_EXTRA}</li> +</ul> +<pre> +public class LlcpModeReceiverSample extends BroadcastReceiver { + public void onReceive(Context context, Intent intent) { + + if (intent.getAction().equals(NfcManager.LLCP_LINK_STATE_CHANGED_ACTION)){ + byte[] aid = intent.getByteArrayExtra(NfcManager.LLCP_LINK_STATE_CHANGED_EXTRA); + /* Create an LLCP service or client and start an LLCP communication */ + } + } +</pre> + + +<p> +This code samples illustrate LLCP exchanges with a NFC Peer. +</p> +<p>Main involved classes/methods:</p> +<ul> + <li>{@link com.trustedlogic.trustednfc.android.NfcManager#createLlcpSocket}</li> + <li>{@link com.trustedlogic.trustednfc.android.NfcManager#createLlcpConnectionlessSocket}</li> + <li>{@link com.trustedlogic.trustednfc.android.NfcManager#createLlcpServiceSocket}</li> + <li>{@link com.trustedlogic.trustednfc.android.LlcpSocket}</li> + <li>{@link com.trustedlogic.trustednfc.android.LlcpConnectionlessSocket}</li> + <li>{@link com.trustedlogic.trustednfc.android.LlcpPacket}</li> + <li>{@link com.trustedlogic.trustednfc.android.LlcpServiceSocket}</li> +</ul> + +<pre> +public class LlcpServerSample { + + /** The NFC manager to access NFC features */ + private NfcManager manager = (NfcManager) getSystemService(Context.NFC_SERVICE); + + private void runLlcpClient() { + LlcpSocket sock; + byte[] data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + byte[] echo = new byte[data.length * 10]; + int length = 0; + + sock = manager.createLlcpSocket((short) 128, (byte) 2, 1024); + + // set a timeout in ms for connect request + sock.setConnectTimeout(10); + + try { + // Connect to remote service + // NOTE: could be sock.connect("com.trusted-logic.tnfc.testapp"); + sock.connect((byte) 0x10); + + // Send data + for (int i = 0; i < 10; i++) { + sock.send(data); + } + + // Receive echo + while (length < 10 * data.length) { + length += sock.receive(echo); + } + + } catch (IOException e) { + // TODO: Handle broken connection broken (link down, remote closure + // or connect rejected) or Timeout expired + } + } +} +</pre> + +<pre> +public class LlcpClientSample { + + /** The NFC manager to access NFC features */ + private NfcManager manager = (NfcManager) getSystemService(Context.NFC_SERVICE); + + private void runLlcpClient() { + LlcpSocket sock; + byte[] data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + byte[] echo = new byte[data.length * 10]; + int length = 0; + + sock = manager.createLlcpSocket((short) 128, (byte) 2, 1024); + try { + // Connect to remote service + // NOTE: could be sock.connect("com.trusted-logic.tnfc.testapp"); + sock.connect((byte) 0x10); + + // Send data + for (int i = 0; i < 10; i++) { + sock.send(data); + } + + // Receive echo + while (length < 10 * data.length) { + length += sock.receive(echo); + } + + } catch (IOException e) { + // TODO: Handle broken connection broken (link down, remote closure + // or connect rejected) + } + } +} +</pre> + +<h2>Card Emulation Mode transaction notification</h2> + +<p> +This code sample illustrates how to get the card emulation notification with the declaration of a Receiver in the manifest of the application and the implementation +of the receiver in the application. +</p> +<p>Manifest Example:</p> +<pre> + <receiver android:name=".NfcReaderDemoReceiver"> + <intent-filter> + <action android:name= "com.trustedlogic.trustednfc.android.action.TRANSACTION_DETECTED"/> + </intent-filter> + </receiver> +</pre> + +<p>Receiver Example:</p> +<ul> + <li>{@link com.trustedlogic.trustednfc.android.NfcManager#TRANSACTION_DETECTED_ACTION}</li> + <li>{@link com.trustedlogic.trustednfc.android.NfcManager#AID_EXTRA}</li> +</ul> +<pre> +public class CardEmulationReceiverSample extends BroadcastReceiver { + public void onReceive(Context context, Intent intent) { + + if (intent.getAction().equals(NfcManager.TRANSACTION_DETECTED_ACTION)){ + byte[] aid = intent.getByteArrayExtra(NfcManager.AID_EXTRA); + /* Manage the AID: */ + /* For example start an activity related to this AID value or display a popup with the AID */ + } + } +</pre> + + + +<h1>Multiple Applications rules</h1> + +<p> +Several LLCP sockets can be created by a single application or by multiple +applications by calling {@link com.trustedlogic.trustednfc.android.NfcManager#createLlcpSocket}, +{@link com.trustedlogic.trustednfc.android.NfcManager#createLlcpConnectionlessSocket} or +{@link com.trustedlogic.trustednfc.android.NfcManager#createLlcpServiceSocket}, provided the local SAP +numbers are differents. +</p> + +<p> +Only one application can open a raw connection by calling +{@link com.trustedlogic.trustednfc.android.NfcManager#openTagConnection} or +{@link com.trustedlogic.trustednfc.android.NfcManager#openP2pConnection}. +While this application has not closed or cancelled its connection, any other +application that attempts to open another raw connection will raise an +exception. +During an open connnection, the card emulation mode is always enabled and +applications are able to receive card emulation intents. +</p> + +<p> +When an application opens a tag connection by calling +{@link com.trustedlogic.trustednfc.android.NfcManager#openTagConnection}, this operation is exclusive, no NDEF message intent are +broadcast while the connection is not closed or canceled. +</p> + +<p> +When an application opens a peer-to-peer connection by calling +{@link com.trustedlogic.trustednfc.android.NfcManager#openP2pConnection}, this operation is exclusive, no LLCP intent are broadcast and LLCP sockets are +disabled while the connection is not closed or canceled. +</p> + + +<h1>NFC Tag types</h1> + +<p> +The {@link com.trustedlogic.trustednfc.android.NfcTag} type returned by +{@link com.trustedlogic.trustednfc.android.NfcTag#getType} indicates the set of +commands supported by the tag. These commands can be used in +{@link com.trustedlogic.trustednfc.android.NfcTag#transceive}. +</p> + +<TABLE BORDER="1"> + <TR><TH> Tag Type </TH><TH> Returned string </TH></TR> + <TR><TD> Jewel/Topaz </TD><TD> Jewel </TD></TR> + <TR><TD> Mifare UltraLight </TD><TD> MifareUL </TD></TR> + <TR><TD> Mifare Standard 1K </TD><TD> Mifare1K </TD></TR> + <TR><TD> Mifare Standard 4K </TD><TD> Mifare4K </TD></TR> + <TR><TD> Mifare DESFIRE </TD><TD> MifareDESFIRE </TD></TR> + <TR><TD> Felica </TD><TD> Felica </TD></TR> + <TR><TD> ISO14443-4 A or B </TD><TD> Iso14443 </TD></TR> + <TR><TD> ISO15693 </TD><TD> Iso15693 </TD></TR> +</TABLE> + +</body> +</html> diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 8c280b4..f4d1b6e 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -193,6 +193,14 @@ LOCAL_SHARED_LIBRARIES := \ libwpa_client \ libjpeg +ifeq ($(BOARD_HAVE_NFC),true) +LOCAL_SHARED_LIBRARIES += \ + libnfc_jni \ + libnfc + +LOCAL_CFLAGS += -DHAVE_NFC +endif + ifeq ($(BOARD_HAVE_BLUETOOTH),true) LOCAL_C_INCLUDES += \ external/dbus \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index beb49c8..e5d5d8a 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -170,6 +170,18 @@ extern int register_android_view_MotionEvent(JNIEnv* env); extern int register_android_content_res_ObbScanner(JNIEnv* env); extern int register_android_content_res_Configuration(JNIEnv* env); +#ifdef HAVE_NFC +extern int register_com_trustedlogic_trustednfc_android_internal_NativeNfcManager(JNIEnv *env); +extern int register_com_trustedlogic_trustednfc_android_internal_NativeNfcTag(JNIEnv *env); +extern int register_com_trustedlogic_trustednfc_android_internal_NativeNdefTag(JNIEnv *env); +extern int register_com_trustedlogic_trustednfc_android_NdefMessage(JNIEnv *env); +extern int register_com_trustedlogic_trustednfc_android_NdefRecord(JNIEnv *env); +extern int register_com_trustedlogic_trustednfc_android_internal_NativeP2pDevice(JNIEnv *env); +extern int register_com_trustedlogic_trustednfc_android_internal_NativeLlcpSocket(JNIEnv *env); +extern int register_com_trustedlogic_trustednfc_android_internal_NativeLlcpConnectionlessSocket(JNIEnv *env); +extern int register_com_trustedlogic_trustednfc_android_internal_NativeLlcpServiceSocket(JNIEnv *env); +#endif + static AndroidRuntime* gCurRuntime = NULL; static void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL) @@ -1287,6 +1299,18 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_content_res_ObbScanner), REG_JNI(register_android_content_res_Configuration), + +#ifdef HAVE_NFC + REG_JNI(register_com_trustedlogic_trustednfc_android_internal_NativeNfcManager), + REG_JNI(register_com_trustedlogic_trustednfc_android_internal_NativeNfcTag), + REG_JNI(register_com_trustedlogic_trustednfc_android_internal_NativeNdefTag), + REG_JNI(register_com_trustedlogic_trustednfc_android_NdefMessage), + REG_JNI(register_com_trustedlogic_trustednfc_android_NdefRecord), + REG_JNI(register_com_trustedlogic_trustednfc_android_internal_NativeP2pDevice), + REG_JNI(register_com_trustedlogic_trustednfc_android_internal_NativeLlcpSocket), + REG_JNI(register_com_trustedlogic_trustednfc_android_internal_NativeLlcpConnectionlessSocket), + REG_JNI(register_com_trustedlogic_trustednfc_android_internal_NativeLlcpServiceSocket), +#endif }; /* diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 68a5a14..b9eb5d6 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -86,6 +86,10 @@ <protected-broadcast android:name="android.hardware.action.USB_DISCONNECTED" /> <protected-broadcast android:name="android.hardware.action.USB_STATE" /> + <protected-broadcast android:name="com.trustedlogic.trustednfc.android.action.NDEF_TAG_DISCOVERED" /> + <protected-broadcast android:name="com.trustedlogic.trustednfc.android.action.TRANSACTION_DETECTED" /> + <protected-broadcast android:name="com.trustedlogic.trustednfc.android.action.LLCP_LINK_STATE_CHANGED" /> + <!-- ====================================== --> <!-- Permissions for things that cost money --> <!-- ====================================== --> @@ -336,6 +340,30 @@ android:description="@string/permdesc_bluetooth" android:label="@string/permlab_bluetooth" /> + <!-- Allows applications to access remote NFC devices + @hide --> + <permission android:name="com.trustedlogic.trustednfc.permission.NFC_RAW" + android:permissionGroup="android.permission-group.NETWORK" + android:protectionLevel="dangerous" + android:description="@string/permdesc_nfcRaw" + android:label="@string/permlab_nfcRaw" /> + + <!-- Allows applications to be notified of remote NFC devices + @hide --> + <permission android:name="com.trustedlogic.trustednfc.permission.NFC_NOTIFY" + android:permissionGroup="android.permission-group.NETWORK" + android:protectionLevel="dangerous" + android:description="@string/permdesc_nfcNotify" + android:label="@string/permlab_nfcNotify" /> + + <!-- Allows applications to be notified of remote NFC LLCP devices + @hide --> + <permission android:name="com.trustedlogic.trustednfc.permission.NFC_LLCP" + android:permissionGroup="android.permission-group.NETWORK" + android:protectionLevel="dangerous" + android:description="@string/permdesc_nfcLlcp" + android:label="@string/permlab_nfcLlcp" /> + <!-- Allows applications to call into AccountAuthenticators. Only the system can get this permission. --> <permission android:name="android.permission.ACCOUNT_MANAGER" @@ -839,6 +867,14 @@ android:description="@string/permdesc_bluetoothAdmin" android:label="@string/permlab_bluetoothAdmin" /> + <!-- Allows applications to change NFC connectivity settings + @hide --> + <permission android:name="com.trustedlogic.trustednfc.permission.NFC_ADMIN" + android:permissionGroup="android.permission-group.SYSTEM_TOOLS" + android:protectionLevel="dangerous" + android:description="@string/permdesc_nfcAdmin" + android:label="@string/permlab_nfcAdmin" /> + <!-- Allows an application to clear the caches of all installed applications on the device. --> <permission android:name="android.permission.CLEAR_APP_CACHE" diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index ebccfb6..7832f83 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1151,6 +1151,30 @@ connections with paired devices.</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_nfcAdmin">NFC administration</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_nfcAdmin">Allows an application to configure + the local NFC phone.</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_nfcRaw">NFC full access to remote device</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_nfcRaw">Allows an application to access + remote NFC devices.</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_nfcNotify">NFC notification from remote device</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_nfcNotify">Allows an application to be notified + of operations related to remote NFC devices.</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_nfcLlcp">NFC notification from remote LLCP device</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_nfcLlcp">Allows an application to be notified + of LLCP operations related to remote NFC devices.</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_disableKeyguard">disable keylock</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permdesc_disableKeyguard">Allows an application to disable diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index a80ab1d..7f42429 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -19,6 +19,7 @@ package com.android.server; import com.android.server.am.ActivityManagerService; import com.android.internal.os.BinderInternal; import com.android.internal.os.SamplingProfilerIntegration; +import com.trustedlogic.trustednfc.android.server.NfcService; import dalvik.system.VMRuntime; import dalvik.system.Zygote; @@ -41,6 +42,7 @@ import android.server.BluetoothA2dpService; import android.server.BluetoothService; import android.server.search.SearchManagerService; import android.util.EventLog; +import android.util.Log; import android.util.Slog; import android.accounts.AccountManagerService; @@ -409,6 +411,20 @@ class ServerThread extends Thread { } catch (Throwable e) { Slog.e(TAG, "Failure starting Recognition Service", e); } + + try { + Slog.i(TAG, "Nfc Service"); + NfcService nfc; + try { + nfc = new NfcService(context); + } catch (UnsatisfiedLinkError e) { // gross hack to detect NFC + nfc = null; + Slog.w(TAG, "No NFC support"); + } + ServiceManager.addService(Context.NFC_SERVICE, nfc); + } catch (Throwable e) { + Slog.e(TAG, "Failure starting NFC Service", e); + } try { Slog.i(TAG, "DiskStats Service"); diff --git a/services/java/com/trustedlogic/trustednfc/android/server/NfcService.java b/services/java/com/trustedlogic/trustednfc/android/server/NfcService.java new file mode 100644 index 0000000..431b798 --- /dev/null +++ b/services/java/com/trustedlogic/trustednfc/android/server/NfcService.java @@ -0,0 +1,2111 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.trustedlogic.trustednfc.android.server; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.ListIterator; +import java.util.Set; + +import com.trustedlogic.trustednfc.android.ILlcpConnectionlessSocket; +import com.trustedlogic.trustednfc.android.ILlcpServiceSocket; +import com.trustedlogic.trustednfc.android.INfcManager; +import com.trustedlogic.trustednfc.android.ILlcpSocket; +import com.trustedlogic.trustednfc.android.INfcTag; +import com.trustedlogic.trustednfc.android.IP2pInitiator; +import com.trustedlogic.trustednfc.android.IP2pTarget; +import com.trustedlogic.trustednfc.android.LlcpPacket; +import com.trustedlogic.trustednfc.android.NdefMessage; +import com.trustedlogic.trustednfc.android.NfcException; +import com.trustedlogic.trustednfc.android.NfcManager; +import com.trustedlogic.trustednfc.android.internal.NativeLlcpConnectionlessSocket; +import com.trustedlogic.trustednfc.android.internal.NativeLlcpServiceSocket; +import com.trustedlogic.trustednfc.android.internal.NativeLlcpSocket; +import com.trustedlogic.trustednfc.android.internal.NativeNfcManager; +import com.trustedlogic.trustednfc.android.internal.NativeNfcTag; +import com.trustedlogic.trustednfc.android.internal.NativeP2pDevice; +import com.trustedlogic.trustednfc.android.internal.ErrorCodes; + +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.Process; +import android.os.RemoteException; +import android.provider.Settings; +import android.provider.Settings.SettingNotFoundException; +import android.util.Log; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; + +public class NfcService extends INfcManager.Stub implements Runnable { + + /** + * NFC Service tag + */ + private static final String TAG = "NfcService"; + + /** + * NFC features disabled state + */ + private static final short NFC_STATE_DISABLED = 0x00; + + /** + * NFC features enabled state + */ + private static final short NFC_STATE_ENABLED = 0x01; + + /** + * NFC Discovery for Reader mode + */ + private static final int DISCOVERY_MODE_READER = 0; + + /** + * NFC Discovery for Card Emulation Mode + */ + private static final int DISCOVERY_MODE_CARD_EMULATION = 2; + + /** + * LLCP Service Socket type + */ + private static final int LLCP_SERVICE_SOCKET_TYPE = 0; + + /** + * LLCP Socket type + */ + private static final int LLCP_SOCKET_TYPE = 1; + + /** + * LLCP Connectionless socket type + */ + private static final int LLCP_CONNECTIONLESS_SOCKET_TYPE = 2; + + /** + * Maximun number of sockets managed + */ + private static final int LLCP_SOCKET_NB_MAX = 5; + + /** + * Default value for the Maximum Information Unit parameter + */ + private static final int LLCP_LTO_DEFAULT_VALUE = 150; + + /** + * Default value for the Maximum Information Unit parameter + */ + private static final int LLCP_LTO_MAX_VALUE = 255; + + /** + * Maximun value for the Receive Window + */ + private static final int LLCP_RW_MAX_VALUE = 15; + + /** + * Default value for the Maximum Information Unit parameter + */ + private static final int LLCP_MIU_DEFAULT_VALUE = 128; + + /** + * Default value for the Maximum Information Unit parameter + */ + private static final int LLCP_MIU_MAX_VALUE = 2176; + + /** + * Default value for the Well Known Service List parameter + */ + private static final int LLCP_WKS_DEFAULT_VALUE = 1; + + /** + * Max value for the Well Known Service List parameter + */ + private static final int LLCP_WKS_MAX_VALUE = 15; + + /** + * Default value for the Option parameter + */ + private static final int LLCP_OPT_DEFAULT_VALUE = 0; + + /** + * Max value for the Option parameter + */ + private static final int LLCP_OPT_MAX_VALUE = 3; + + /** + * LLCP Properties + */ + private static final int PROPERTY_LLCP_LTO = 0; + + private static final int PROPERTY_LLCP_MIU = 1; + + private static final int PROPERTY_LLCP_WKS = 2; + + private static final int PROPERTY_LLCP_OPT = 3; + + private static final String PROPERTY_LLCP_LTO_VALUE = "llcp.lto"; + + private static final String PROPERTY_LLCP_MIU_VALUE = "llcp.miu"; + + private static final String PROPERTY_LLCP_WKS_VALUE = "llcp.wks"; + + private static final String PROPERTY_LLCP_OPT_VALUE = "llcp.opt"; + + /** + * NFC Reader Properties + */ + private static final int PROPERTY_NFC_DISCOVERY_A = 4; + + private static final int PROPERTY_NFC_DISCOVERY_B = 5; + + private static final int PROPERTY_NFC_DISCOVERY_F = 6; + + private static final int PROPERTY_NFC_DISCOVERY_15693 = 7; + + private static final int PROPERTY_NFC_DISCOVERY_NFCIP = 8; + + private static final String PROPERTY_NFC_DISCOVERY_A_VALUE = "discovery.iso14443A"; + + private static final String PROPERTY_NFC_DISCOVERY_B_VALUE = "discovery.iso14443B"; + + private static final String PROPERTY_NFC_DISCOVERY_F_VALUE = "discovery.felica"; + + private static final String PROPERTY_NFC_DISCOVERY_15693_VALUE = "discovery.iso15693"; + + private static final String PROPERTY_NFC_DISCOVERY_NFCIP_VALUE = "discovery.nfcip"; + + private Context mContext; + + private HashMap<Integer, Object> mObjectMap = new HashMap<Integer, Object>(); + + private HashMap<Integer, Object> mSocketMap = new HashMap<Integer, Object>(); + + private LinkedList<RegisteredSocket> mRegisteredSocketList = new LinkedList<RegisteredSocket>(); + + private int mLlcpLinkState = NfcManager.LLCP_LINK_STATE_DEACTIVATED; + + private int mGeneratedSocketHandle = 0; + + private int mNbSocketCreated = 0; + + private boolean mIsNfcEnabled = false; + + private NfcHandler mNfcHandler; + + private int mSelectedSeId = 0; + + private int mTimeout = 0; + + private int mNfcState; + + private int mNfcSecureElementState; + + private boolean mOpenPending = false; + + private NativeNfcManager mManager; + + private ILlcpSocket mLlcpSocket = new ILlcpSocket.Stub() { + + public int close(int nativeHandle) throws RemoteException { + NativeLlcpSocket socket = null; + boolean isSuccess = false; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return ErrorCodes.ERROR_NOT_INITIALIZED; + } + + /* find the socket in the hmap */ + socket = (NativeLlcpSocket) findSocket(nativeHandle); + if (socket != null) { + if (mLlcpLinkState == NfcManager.LLCP_LINK_STATE_ACTIVATED) { + isSuccess = socket.doClose(); + if (isSuccess) { + /* Remove the socket closed from the hmap */ + RemoveSocket(nativeHandle); + /* Update mNbSocketCreated */ + mNbSocketCreated--; + return ErrorCodes.SUCCESS; + } else { + return ErrorCodes.ERROR_IO; + } + } else { + /* Remove the socket closed from the hmap */ + RemoveSocket(nativeHandle); + + /* Remove registered socket from the list */ + RemoveRegisteredSocket(nativeHandle); + + /* Update mNbSocketCreated */ + mNbSocketCreated--; + + return ErrorCodes.SUCCESS; + } + } else { + return ErrorCodes.ERROR_IO; + } + } + + public int connect(int nativeHandle, int sap) throws RemoteException { + NativeLlcpSocket socket = null; + boolean isSuccess = false; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return ErrorCodes.ERROR_NOT_INITIALIZED; + } + + /* find the socket in the hmap */ + socket = (NativeLlcpSocket) findSocket(nativeHandle); + if (socket != null) { + isSuccess = socket.doConnect(sap, socket.getConnectTimeout()); + if (isSuccess) { + return ErrorCodes.SUCCESS; + } else { + return ErrorCodes.ERROR_IO; + } + } else { + return ErrorCodes.ERROR_IO; + } + + } + + public int connectByName(int nativeHandle, String sn) throws RemoteException { + NativeLlcpSocket socket = null; + boolean isSuccess = false; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return ErrorCodes.ERROR_NOT_INITIALIZED; + } + + /* find the socket in the hmap */ + socket = (NativeLlcpSocket) findSocket(nativeHandle); + if (socket != null) { + isSuccess = socket.doConnectBy(sn, socket.getConnectTimeout()); + if (isSuccess) { + return ErrorCodes.SUCCESS; + } else { + return ErrorCodes.ERROR_IO; + } + } else { + return ErrorCodes.ERROR_IO; + } + + } + + public int getConnectTimeout(int nativeHandle) throws RemoteException { + NativeLlcpSocket socket = null; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return ErrorCodes.ERROR_NOT_INITIALIZED; + } + + /* find the socket in the hmap */ + socket = (NativeLlcpSocket) findSocket(nativeHandle); + if (socket != null) { + return socket.getConnectTimeout(); + } else { + return 0; + } + } + + public int getLocalSap(int nativeHandle) throws RemoteException { + NativeLlcpSocket socket = null; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return ErrorCodes.ERROR_NOT_INITIALIZED; + } + + /* find the socket in the hmap */ + socket = (NativeLlcpSocket) findSocket(nativeHandle); + if (socket != null) { + return socket.getSap(); + } else { + return 0; + } + } + + public int getLocalSocketMiu(int nativeHandle) throws RemoteException { + NativeLlcpSocket socket = null; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return ErrorCodes.ERROR_NOT_INITIALIZED; + } + + /* find the socket in the hmap */ + socket = (NativeLlcpSocket) findSocket(nativeHandle); + if (socket != null) { + return socket.getMiu(); + } else { + return 0; + } + } + + public int getLocalSocketRw(int nativeHandle) throws RemoteException { + NativeLlcpSocket socket = null; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return ErrorCodes.ERROR_NOT_INITIALIZED; + } + + /* find the socket in the hmap */ + socket = (NativeLlcpSocket) findSocket(nativeHandle); + if (socket != null) { + return socket.getRw(); + } else { + return 0; + } + } + + public int getRemoteSocketMiu(int nativeHandle) throws RemoteException { + NativeLlcpSocket socket = null; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return ErrorCodes.ERROR_NOT_INITIALIZED; + } + + /* find the socket in the hmap */ + socket = (NativeLlcpSocket) findSocket(nativeHandle); + if (socket != null) { + if (socket.doGetRemoteSocketMiu() != 0) { + return socket.doGetRemoteSocketMiu(); + } else { + return ErrorCodes.ERROR_SOCKET_NOT_CONNECTED; + } + } else { + return ErrorCodes.ERROR_SOCKET_NOT_CONNECTED; + } + } + + public int getRemoteSocketRw(int nativeHandle) throws RemoteException { + NativeLlcpSocket socket = null; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return ErrorCodes.ERROR_NOT_INITIALIZED; + } + + /* find the socket in the hmap */ + socket = (NativeLlcpSocket) findSocket(nativeHandle); + if (socket != null) { + if (socket.doGetRemoteSocketRw() != 0) { + return socket.doGetRemoteSocketRw(); + } else { + return ErrorCodes.ERROR_SOCKET_NOT_CONNECTED; + } + } else { + return ErrorCodes.ERROR_SOCKET_NOT_CONNECTED; + } + } + + public int receive(int nativeHandle, byte[] receiveBuffer) throws RemoteException { + NativeLlcpSocket socket = null; + int receiveLength = 0; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return ErrorCodes.ERROR_NOT_INITIALIZED; + } + + /* find the socket in the hmap */ + socket = (NativeLlcpSocket) findSocket(nativeHandle); + if (socket != null) { + receiveLength = socket.doReceive(receiveBuffer); + if (receiveLength != 0) { + return receiveLength; + } else { + return ErrorCodes.ERROR_IO; + } + } else { + return ErrorCodes.ERROR_IO; + } + } + + public int send(int nativeHandle, byte[] data) throws RemoteException { + NativeLlcpSocket socket = null; + boolean isSuccess = false; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return ErrorCodes.ERROR_NOT_INITIALIZED; + } + + /* find the socket in the hmap */ + socket = (NativeLlcpSocket) findSocket(nativeHandle); + if (socket != null) { + isSuccess = socket.doSend(data); + if (isSuccess) { + return ErrorCodes.SUCCESS; + } else { + return ErrorCodes.ERROR_IO; + } + } else { + return ErrorCodes.ERROR_IO; + } + } + + public void setConnectTimeout(int nativeHandle, int timeout) throws RemoteException { + NativeLlcpSocket socket = null; + + /* find the socket in the hmap */ + socket = (NativeLlcpSocket) findSocket(nativeHandle); + if (socket != null) { + socket.setConnectTimeout(timeout); + } + } + + }; + + private ILlcpServiceSocket mLlcpServerSocketService = new ILlcpServiceSocket.Stub() { + + public int accept(int nativeHandle) throws RemoteException { + NativeLlcpServiceSocket socket = null; + NativeLlcpSocket clientSocket = null; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return ErrorCodes.ERROR_NOT_INITIALIZED; + } + + if (mNbSocketCreated < LLCP_SOCKET_NB_MAX) { + /* find the socket in the hmap */ + socket = (NativeLlcpServiceSocket) findSocket(nativeHandle); + if (socket != null) { + clientSocket = socket.doAccept(socket.getAcceptTimeout(), socket.getMiu(), + socket.getRw(), socket.getLinearBufferLength()); + if (clientSocket != null) { + /* Add the socket into the socket map */ + mSocketMap.put(clientSocket.getHandle(), clientSocket); + mNbSocketCreated++; + return clientSocket.getHandle(); + } else { + return ErrorCodes.ERROR_IO; + } + } else { + return ErrorCodes.ERROR_IO; + } + } else { + return ErrorCodes.ERROR_INSUFFICIENT_RESOURCES; + } + + } + + public void close(int nativeHandle) throws RemoteException { + NativeLlcpServiceSocket socket = null; + boolean isSuccess = false; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return; + } + + /* find the socket in the hmap */ + socket = (NativeLlcpServiceSocket) findSocket(nativeHandle); + if (socket != null) { + if (mLlcpLinkState == NfcManager.LLCP_LINK_STATE_ACTIVATED) { + isSuccess = socket.doClose(); + if (isSuccess) { + /* Remove the socket closed from the hmap */ + RemoveSocket(nativeHandle); + /* Update mNbSocketCreated */ + mNbSocketCreated--; + } + } else { + /* Remove the socket closed from the hmap */ + RemoveSocket(nativeHandle); + + /* Remove registered socket from the list */ + RemoveRegisteredSocket(nativeHandle); + + /* Update mNbSocketCreated */ + mNbSocketCreated--; + } + } + } + + public int getAcceptTimeout(int nativeHandle) throws RemoteException { + NativeLlcpServiceSocket socket = null; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return ErrorCodes.ERROR_NOT_INITIALIZED; + } + + /* find the socket in the hmap */ + socket = (NativeLlcpServiceSocket) findSocket(nativeHandle); + if (socket != null) { + return socket.getAcceptTimeout(); + } else { + return 0; + } + } + + public void setAcceptTimeout(int nativeHandle, int timeout) throws RemoteException { + NativeLlcpServiceSocket socket = null; + + /* find the socket in the hmap */ + socket = (NativeLlcpServiceSocket) findSocket(nativeHandle); + if (socket != null) { + socket.setAcceptTimeout(timeout); + } + } + }; + + private ILlcpConnectionlessSocket mLlcpConnectionlessSocketService = new ILlcpConnectionlessSocket.Stub() { + + public void close(int nativeHandle) throws RemoteException { + NativeLlcpConnectionlessSocket socket = null; + boolean isSuccess = false; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return; + } + + /* find the socket in the hmap */ + socket = (NativeLlcpConnectionlessSocket) findSocket(nativeHandle); + if (socket != null) { + if (mLlcpLinkState == NfcManager.LLCP_LINK_STATE_ACTIVATED) { + isSuccess = socket.doClose(); + if (isSuccess) { + /* Remove the socket closed from the hmap */ + RemoveSocket(nativeHandle); + /* Update mNbSocketCreated */ + mNbSocketCreated--; + } + } else { + /* Remove the socket closed from the hmap */ + RemoveSocket(nativeHandle); + + /* Remove registered socket from the list */ + RemoveRegisteredSocket(nativeHandle); + + /* Update mNbSocketCreated */ + mNbSocketCreated--; + } + } + } + + public int getSap(int nativeHandle) throws RemoteException { + NativeLlcpConnectionlessSocket socket = null; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return ErrorCodes.ERROR_NOT_INITIALIZED; + } + + /* find the socket in the hmap */ + socket = (NativeLlcpConnectionlessSocket) findSocket(nativeHandle); + if (socket != null) { + return socket.getSap(); + } else { + return 0; + } + } + + public LlcpPacket receiveFrom(int nativeHandle) throws RemoteException { + NativeLlcpConnectionlessSocket socket = null; + LlcpPacket packet; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return null; + } + + /* find the socket in the hmap */ + socket = (NativeLlcpConnectionlessSocket) findSocket(nativeHandle); + if (socket != null) { + packet = socket.doReceiveFrom(socket.getLinkMiu()); + if (packet != null) { + return packet; + } + return null; + } else { + return null; + } + } + + public int sendTo(int nativeHandle, LlcpPacket packet) throws RemoteException { + NativeLlcpConnectionlessSocket socket = null; + boolean isSuccess = false; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return ErrorCodes.ERROR_NOT_INITIALIZED; + } + + /* find the socket in the hmap */ + socket = (NativeLlcpConnectionlessSocket) findSocket(nativeHandle); + if (socket != null) { + isSuccess = socket.doSendTo(packet.getRemoteSap(), packet.getDataBuffer()); + if (isSuccess) { + return ErrorCodes.SUCCESS; + } else { + return ErrorCodes.ERROR_IO; + } + } else { + return ErrorCodes.ERROR_IO; + } + } + }; + + private INfcTag mNfcTagService = new INfcTag.Stub() { + + public int close(int nativeHandle) throws RemoteException { + NativeNfcTag tag = null; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return ErrorCodes.ERROR_NOT_INITIALIZED; + } + + /* find the tag in the hmap */ + tag = (NativeNfcTag) findObject(nativeHandle); + if (tag != null) { + if (tag.doDisconnect()) { + /* Remove the device from the hmap */ + RemoveObject(nativeHandle); + /* Restart polling loop for notification */ + mManager.enableDiscovery(DISCOVERY_MODE_READER); + mOpenPending = false; + return ErrorCodes.SUCCESS; + } + + } + /* Restart polling loop for notification */ + mManager.enableDiscovery(DISCOVERY_MODE_READER); + mOpenPending = false; + return ErrorCodes.ERROR_DISCONNECT; + } + + public int connect(int nativeHandle) throws RemoteException { + NativeNfcTag tag = null; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return ErrorCodes.ERROR_NOT_INITIALIZED; + } + + /* find the tag in the hmap */ + tag = (NativeNfcTag) findObject(nativeHandle); + if (tag != null) { + if (tag.doConnect()) + return ErrorCodes.SUCCESS; + } + /* Restart polling loop for notification */ + mManager.enableDiscovery(DISCOVERY_MODE_READER); + mOpenPending = false; + return ErrorCodes.ERROR_CONNECT; + } + + public String getType(int nativeHandle) throws RemoteException { + NativeNfcTag tag = null; + String type; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return null; + } + + /* find the tag in the hmap */ + tag = (NativeNfcTag) findObject(nativeHandle); + if (tag != null) { + type = tag.getType(); + return type; + } + return null; + } + + public byte[] getUid(int nativeHandle) throws RemoteException { + NativeNfcTag tag = null; + byte[] uid; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return null; + } + + /* find the tag in the hmap */ + tag = (NativeNfcTag) findObject(nativeHandle); + if (tag != null) { + uid = tag.getUid(); + return uid; + } + return null; + } + + public boolean isNdef(int nativeHandle) throws RemoteException { + NativeNfcTag tag = null; + boolean isSuccess = false; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return isSuccess; + } + + /* find the tag in the hmap */ + tag = (NativeNfcTag) findObject(nativeHandle); + if (tag != null) { + isSuccess = tag.checkNDEF(); + } + return isSuccess; + } + + public byte[] transceive(int nativeHandle, byte[] data) throws RemoteException { + NativeNfcTag tag = null; + byte[] response; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return null; + } + + /* find the tag in the hmap */ + tag = (NativeNfcTag) findObject(nativeHandle); + if (tag != null) { + response = tag.doTransceive(data); + return response; + } + return null; + } + + public NdefMessage read(int nativeHandle) throws RemoteException { + NativeNfcTag tag; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return null; + } + + /* find the tag in the hmap */ + tag = (NativeNfcTag) findObject(nativeHandle); + if (tag != null) { + byte[] buf = tag.doRead(); + if (buf == null) + return null; + + /* Create an NdefMessage */ + try { + return new NdefMessage(buf); + } catch (NfcException e) { + return null; + } + } + return null; + } + + public boolean write(int nativeHandle, NdefMessage msg) throws RemoteException { + NativeNfcTag tag; + boolean isSuccess = false; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return isSuccess; + } + + /* find the tag in the hmap */ + tag = (NativeNfcTag) findObject(nativeHandle); + if (tag != null) { + isSuccess = tag.doWrite(msg.toByteArray()); + } + return isSuccess; + + } + + }; + + private IP2pInitiator mP2pInitiatorService = new IP2pInitiator.Stub() { + + public byte[] getGeneralBytes(int nativeHandle) throws RemoteException { + NativeP2pDevice device; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return null; + } + + /* find the device in the hmap */ + device = (NativeP2pDevice) findObject(nativeHandle); + if (device != null) { + byte[] buff = device.getGeneralBytes(); + if (buff == null) + return null; + return buff; + } + return null; + } + + public int getMode(int nativeHandle) throws RemoteException { + NativeP2pDevice device; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return ErrorCodes.ERROR_NOT_INITIALIZED; + } + + /* find the device in the hmap */ + device = (NativeP2pDevice) findObject(nativeHandle); + if (device != null) { + return device.getMode(); + } + return ErrorCodes.ERROR_INVALID_PARAM; + } + + public byte[] receive(int nativeHandle) throws RemoteException { + NativeP2pDevice device; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return null; + } + + /* find the device in the hmap */ + device = (NativeP2pDevice) findObject(nativeHandle); + if (device != null) { + byte[] buff = device.doReceive(); + if (buff == null) + return null; + return buff; + } + /* Restart polling loop for notification */ + mManager.enableDiscovery(DISCOVERY_MODE_READER); + mOpenPending = false; + return null; + } + + public boolean send(int nativeHandle, byte[] data) throws RemoteException { + NativeP2pDevice device; + boolean isSuccess = false; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return isSuccess; + } + + /* find the device in the hmap */ + device = (NativeP2pDevice) findObject(nativeHandle); + if (device != null) { + isSuccess = device.doSend(data); + } + return isSuccess; + } + }; + + private IP2pTarget mP2pTargetService = new IP2pTarget.Stub() { + + public int connect(int nativeHandle) throws RemoteException { + NativeP2pDevice device; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return ErrorCodes.ERROR_NOT_INITIALIZED; + } + + /* find the device in the hmap */ + device = (NativeP2pDevice) findObject(nativeHandle); + if (device != null) { + if (device.doConnect()) { + return ErrorCodes.SUCCESS; + } + } + return ErrorCodes.ERROR_CONNECT; + } + + public boolean disconnect(int nativeHandle) throws RemoteException { + NativeP2pDevice device; + boolean isSuccess = false; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return isSuccess; + } + + /* find the device in the hmap */ + device = (NativeP2pDevice) findObject(nativeHandle); + if (device != null) { + if (isSuccess = device.doDisconnect()) { + mOpenPending = false; + /* remove the device from the hmap */ + RemoveObject(nativeHandle); + /* Restart polling loop for notification */ + mManager.enableDiscovery(DISCOVERY_MODE_READER); + } + } + return isSuccess; + + } + + public byte[] getGeneralBytes(int nativeHandle) throws RemoteException { + NativeP2pDevice device; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return null; + } + + /* find the device in the hmap */ + device = (NativeP2pDevice) findObject(nativeHandle); + if (device != null) { + byte[] buff = device.getGeneralBytes(); + if (buff == null) + return null; + return buff; + } + return null; + } + + public int getMode(int nativeHandle) throws RemoteException { + NativeP2pDevice device; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return ErrorCodes.ERROR_NOT_INITIALIZED; + } + + /* find the device in the hmap */ + device = (NativeP2pDevice) findObject(nativeHandle); + if (device != null) { + return device.getMode(); + } + return ErrorCodes.ERROR_INVALID_PARAM; + } + + public byte[] transceive(int nativeHandle, byte[] data) throws RemoteException { + NativeP2pDevice device; + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return null; + } + + /* find the device in the hmap */ + device = (NativeP2pDevice) findObject(nativeHandle); + if (device != null) { + byte[] buff = device.doTransceive(data); + if (buff == null) + return null; + return buff; + } + return null; + } + }; + + private class NfcHandler extends Handler { + + @Override + public void handleMessage(Message msg) { + try { + + } catch (Exception e) { + // Log, don't crash! + Log.e(TAG, "Exception in NfcHandler.handleMessage:", e); + } + } + + }; + + public NfcService(Context context) { + super(); + mContext = context; + mManager = new NativeNfcManager(mContext); + + mContext.registerReceiver(mNfcServiceReceiver, new IntentFilter( + NativeNfcManager.INTERNAL_LLCP_LINK_STATE_CHANGED_ACTION)); + + mContext.registerReceiver(mNfcServiceReceiver, new IntentFilter( + NfcManager.LLCP_LINK_STATE_CHANGED_ACTION)); + + mContext.registerReceiver(mNfcServiceReceiver, new IntentFilter( + NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION)); + + Thread thread = new Thread(null, this, "NfcService"); + thread.start(); + + mManager.initializeNativeStructure(); + + int nfcState = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.NFC_ON, 0); + + if (nfcState == NFC_STATE_ENABLED) { + if (this._enable()) { + } + } + + } + + public void run() { + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + Looper.prepare(); + mNfcHandler = new NfcHandler(); + Looper.loop(); + } + + public void cancel() throws RemoteException { + mContext.enforceCallingPermission(android.Manifest.permission.NFC_RAW, + "NFC_RAW permission required to cancel NFC opening"); + if (mOpenPending) { + mOpenPending = false; + mManager.doCancel(); + /* Restart polling loop for notification */ + mManager.enableDiscovery(DISCOVERY_MODE_READER); + } + } + + public int createLlcpConnectionlessSocket(int sap) throws RemoteException { + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return ErrorCodes.ERROR_NOT_INITIALIZED; + } + + mContext.enforceCallingPermission(android.Manifest.permission.NFC_LLCP, + "NFC_LLCP permission required for LLCP operations with NFC service"); + + /* Check SAP is not already used */ + + /* Check nb socket created */ + if (mNbSocketCreated < LLCP_SOCKET_NB_MAX) { + /* Store the socket handle */ + int sockeHandle = mGeneratedSocketHandle; + + if (mLlcpLinkState == NfcManager.LLCP_LINK_STATE_ACTIVATED) { + NativeLlcpConnectionlessSocket socket; + + socket = mManager.doCreateLlcpConnectionlessSocket(sap); + if (socket != null) { + /* Update the number of socket created */ + mNbSocketCreated++; + + /* Add the socket into the socket map */ + mSocketMap.put(sockeHandle, socket); + + return sockeHandle; + } else { + /* + * socket creation error - update the socket handle + * generation + */ + mGeneratedSocketHandle -= 1; + + /* Get Error Status */ + int errorStatus = mManager.doGetLastError(); + + switch (errorStatus) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + return ErrorCodes.ERROR_BUFFER_TO_SMALL; + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + return ErrorCodes.ERROR_INSUFFICIENT_RESOURCES; + default: + return ErrorCodes.ERROR_SOCKET_CREATION; + } + } + } else { + /* Check SAP is not already used */ + if (!CheckSocketSap(sap)) { + return ErrorCodes.ERROR_SAP_USED; + } + + NativeLlcpConnectionlessSocket socket = new NativeLlcpConnectionlessSocket(sap); + + /* Add the socket into the socket map */ + mSocketMap.put(sockeHandle, socket); + + /* Update the number of socket created */ + mNbSocketCreated++; + + /* Create new registered socket */ + RegisteredSocket registeredSocket = new RegisteredSocket( + LLCP_CONNECTIONLESS_SOCKET_TYPE, sockeHandle, sap); + + /* Put this socket into a list of registered socket */ + mRegisteredSocketList.add(registeredSocket); + } + + /* update socket handle generation */ + mGeneratedSocketHandle++; + + return sockeHandle; + + } else { + /* No socket available */ + return ErrorCodes.ERROR_INSUFFICIENT_RESOURCES; + } + + } + + public int createLlcpServiceSocket(int sap, String sn, int miu, int rw, int linearBufferLength) + throws RemoteException { + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return ErrorCodes.ERROR_NOT_INITIALIZED; + } + + mContext.enforceCallingPermission(android.Manifest.permission.NFC_LLCP, + "NFC_LLCP permission required for LLCP operations with NFC service"); + + if (mNbSocketCreated < LLCP_SOCKET_NB_MAX) { + int sockeHandle = mGeneratedSocketHandle; + + if (mLlcpLinkState == NfcManager.LLCP_LINK_STATE_ACTIVATED) { + NativeLlcpServiceSocket socket; + + socket = mManager.doCreateLlcpServiceSocket(sap, sn, miu, rw, linearBufferLength); + if (socket != null) { + /* Update the number of socket created */ + mNbSocketCreated++; + /* Add the socket into the socket map */ + mSocketMap.put(sockeHandle, socket); + } else { + /* socket creation error - update the socket handle counter */ + mGeneratedSocketHandle -= 1; + + /* Get Error Status */ + int errorStatus = mManager.doGetLastError(); + + switch (errorStatus) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + return ErrorCodes.ERROR_BUFFER_TO_SMALL; + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + return ErrorCodes.ERROR_INSUFFICIENT_RESOURCES; + default: + return ErrorCodes.ERROR_SOCKET_CREATION; + } + } + } else { + + /* Check SAP is not already used */ + if (!CheckSocketSap(sap)) { + return ErrorCodes.ERROR_SAP_USED; + } + + /* Service Name */ + if (!CheckSocketServiceName(sn)) { + return ErrorCodes.ERROR_SERVICE_NAME_USED; + } + + /* Check socket options */ + if (!CheckSocketOptions(miu, rw, linearBufferLength)) { + return ErrorCodes.ERROR_SOCKET_OPTIONS; + } + + NativeLlcpServiceSocket socket = new NativeLlcpServiceSocket(sn); + + /* Add the socket into the socket map */ + mSocketMap.put(sockeHandle, socket); + + /* Update the number of socket created */ + mNbSocketCreated++; + + /* Create new registered socket */ + RegisteredSocket registeredSocket = new RegisteredSocket(LLCP_SERVICE_SOCKET_TYPE, + sockeHandle, sap, sn, miu, rw, linearBufferLength); + + /* Put this socket into a list of registered socket */ + mRegisteredSocketList.add(registeredSocket); + } + + /* update socket handle generation */ + mGeneratedSocketHandle += 1; + + Log.d(TAG, "Llcp Service Socket Handle =" + sockeHandle); + return sockeHandle; + } else { + /* No socket available */ + return ErrorCodes.ERROR_INSUFFICIENT_RESOURCES; + } + } + + public int createLlcpSocket(int sap, int miu, int rw, int linearBufferLength) + throws RemoteException { + + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return ErrorCodes.ERROR_NOT_INITIALIZED; + } + + mContext.enforceCallingPermission(android.Manifest.permission.NFC_LLCP, + "NFC_LLCP permission required for LLCP operations with NFC service"); + + if (mNbSocketCreated < LLCP_SOCKET_NB_MAX) { + + int sockeHandle = mGeneratedSocketHandle; + + if (mLlcpLinkState == NfcManager.LLCP_LINK_STATE_ACTIVATED) { + NativeLlcpSocket socket; + + socket = mManager.doCreateLlcpSocket(sap, miu, rw, linearBufferLength); + + if (socket != null) { + /* Update the number of socket created */ + mNbSocketCreated++; + /* Add the socket into the socket map */ + mSocketMap.put(sockeHandle, socket); + } else { + /* + * socket creation error - update the socket handle + * generation + */ + mGeneratedSocketHandle -= 1; + + /* Get Error Status */ + int errorStatus = mManager.doGetLastError(); + + switch (errorStatus) { + case ErrorCodes.ERROR_BUFFER_TO_SMALL: + return ErrorCodes.ERROR_BUFFER_TO_SMALL; + case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: + return ErrorCodes.ERROR_INSUFFICIENT_RESOURCES; + default: + return ErrorCodes.ERROR_SOCKET_CREATION; + } + } + } else { + + /* Check SAP is not already used */ + if (!CheckSocketSap(sap)) { + return ErrorCodes.ERROR_SAP_USED; + } + + /* Check Socket options */ + if (!CheckSocketOptions(miu, rw, linearBufferLength)) { + return ErrorCodes.ERROR_SOCKET_OPTIONS; + } + + NativeLlcpSocket socket = new NativeLlcpSocket(sap, miu, rw); + + /* Add the socket into the socket map */ + mSocketMap.put(sockeHandle, socket); + + /* Update the number of socket created */ + mNbSocketCreated++; + /* Create new registered socket */ + RegisteredSocket registeredSocket = new RegisteredSocket(LLCP_SOCKET_TYPE, + sockeHandle, sap, miu, rw, linearBufferLength); + + /* Put this socket into a list of registered socket */ + mRegisteredSocketList.add(registeredSocket); + } + + /* update socket handle generation */ + mGeneratedSocketHandle++; + + return sockeHandle; + } else { + /* No socket available */ + return ErrorCodes.ERROR_INSUFFICIENT_RESOURCES; + } + } + + public int deselectSecureElement() throws RemoteException { + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return ErrorCodes.ERROR_NOT_INITIALIZED; + } + + if (mSelectedSeId == 0) { + return ErrorCodes.ERROR_NO_SE_CONNECTED; + } + + mContext.enforceCallingPermission(android.Manifest.permission.NFC_ADMIN, + "NFC_ADMIN permission required to deselect NFC Secure Element"); + + mManager.doDeselectSecureElement(mSelectedSeId); + mNfcSecureElementState = 0; + mSelectedSeId = 0; + + /* Store that a secure element is deselected */ + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.NFC_SECURE_ELEMENT_ON, 0); + + /* Reset Secure Element ID */ + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.NFC_SECURE_ELEMENT_ID, 0); + + + return ErrorCodes.SUCCESS; + } + + public boolean disable() throws RemoteException { + boolean isSuccess = false; + mContext.enforceCallingPermission(android.Manifest.permission.NFC_ADMIN, + "NFC_ADMIN permission required to disable NFC service"); + if (isEnabled()) { + isSuccess = mManager.deinitialize(); + if (isSuccess) { + mIsNfcEnabled = false; + } + } + + updateNfcOnSetting(); + + return isSuccess; + } + + public boolean enable() throws RemoteException { + boolean isSuccess = false; + mContext.enforceCallingPermission(android.Manifest.permission.NFC_ADMIN, + "NFC_ADMIN permission required to enable NFC service"); + if (!isEnabled()) { + reset(); + isSuccess = _enable(); + } + return isSuccess; + } + + private boolean _enable() { + boolean isSuccess = mManager.initialize(); + if (isSuccess) { + /* Check persistent properties */ + checkProperties(); + + /* Check Secure Element setting */ + mNfcSecureElementState = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.NFC_SECURE_ELEMENT_ON, 0); + + if (mNfcSecureElementState == 1) { + + int secureElementId = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.NFC_SECURE_ELEMENT_ID, 0); + int[] Se_list = mManager.doGetSecureElementList(); + if (Se_list != null) { + for (int i = 0; i < Se_list.length; i++) { + if (Se_list[i] == secureElementId) { + mManager.doSelectSecureElement(Se_list[i]); + mSelectedSeId = Se_list[i]; + break; + } + } + } + } + + /* Start polling loop */ + mManager.enableDiscovery(DISCOVERY_MODE_READER); + + mIsNfcEnabled = true; + } else { + mIsNfcEnabled = false; + } + + updateNfcOnSetting(); + + return isSuccess; + } + + private void updateNfcOnSetting() { + int state; + + if (mIsNfcEnabled) { + state = NFC_STATE_ENABLED; + } else { + state = NFC_STATE_DISABLED; + } + + Settings.System.putInt(mContext.getContentResolver(), Settings.System.NFC_ON, state); + } + + private void checkProperties() { + int value; + + /* LLCP LTO */ + value = Settings.System.getInt(mContext.getContentResolver(), Settings.System.NFC_LLCP_LTO, + LLCP_LTO_DEFAULT_VALUE); + Settings.System.putInt(mContext.getContentResolver(), Settings.System.NFC_LLCP_LTO, value); + mManager.doSetProperties(PROPERTY_LLCP_LTO, value); + + /* LLCP MIU */ + value = Settings.System.getInt(mContext.getContentResolver(), Settings.System.NFC_LLCP_MIU, + LLCP_MIU_DEFAULT_VALUE); + Settings.System.putInt(mContext.getContentResolver(), Settings.System.NFC_LLCP_MIU, value); + mManager.doSetProperties(PROPERTY_LLCP_MIU, value); + + /* LLCP WKS */ + value = Settings.System.getInt(mContext.getContentResolver(), Settings.System.NFC_LLCP_WKS, + LLCP_WKS_DEFAULT_VALUE); + Settings.System.putInt(mContext.getContentResolver(), Settings.System.NFC_LLCP_WKS, value); + mManager.doSetProperties(PROPERTY_LLCP_WKS, value); + + /* LLCP OPT */ + value = Settings.System.getInt(mContext.getContentResolver(), Settings.System.NFC_LLCP_OPT, + LLCP_OPT_DEFAULT_VALUE); + Settings.System.putInt(mContext.getContentResolver(), Settings.System.NFC_LLCP_OPT, value); + mManager.doSetProperties(PROPERTY_LLCP_OPT, value); + + /* NFC READER A */ + value = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.NFC_DISCOVERY_A, 1); + Settings.System.putInt(mContext.getContentResolver(), Settings.System.NFC_DISCOVERY_A, + value); + mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_A, value); + + /* NFC READER B */ + value = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.NFC_DISCOVERY_B, 1); + Settings.System.putInt(mContext.getContentResolver(), Settings.System.NFC_DISCOVERY_B, + value); + mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_B, value); + + /* NFC READER F */ + value = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.NFC_DISCOVERY_F, 1); + Settings.System.putInt(mContext.getContentResolver(), Settings.System.NFC_DISCOVERY_F, + value); + mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_F, value); + + /* NFC READER 15693 */ + value = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.NFC_DISCOVERY_15693, 1); + Settings.System.putInt(mContext.getContentResolver(), Settings.System.NFC_DISCOVERY_15693, + value); + mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_15693, value); + + /* NFC NFCIP */ + value = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.NFC_DISCOVERY_NFCIP, 1); + Settings.System.putInt(mContext.getContentResolver(), Settings.System.NFC_DISCOVERY_NFCIP, + value); + mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_NFCIP, value); + } + + public ILlcpConnectionlessSocket getLlcpConnectionlessInterface() throws RemoteException { + return mLlcpConnectionlessSocketService; + } + + public ILlcpSocket getLlcpInterface() throws RemoteException { + return mLlcpSocket; + } + + public ILlcpServiceSocket getLlcpServiceInterface() throws RemoteException { + return mLlcpServerSocketService; + } + + public INfcTag getNfcTagInterface() throws RemoteException { + return mNfcTagService; + } + + public int getOpenTimeout() throws RemoteException { + return mTimeout; + } + + public IP2pInitiator getP2pInitiatorInterface() throws RemoteException { + return mP2pInitiatorService; + } + + public IP2pTarget getP2pTargetInterface() throws RemoteException { + return mP2pTargetService; + } + + public String getProperties(String param) throws RemoteException { + int value; + + if (param == null) { + return "Wrong parameter"; + } + + if (param.equals(PROPERTY_LLCP_LTO_VALUE)) { + value = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.NFC_LLCP_LTO, 0); + } else if (param.equals(PROPERTY_LLCP_MIU_VALUE)) { + value = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.NFC_LLCP_MIU, 0); + } else if (param.equals(PROPERTY_LLCP_WKS_VALUE)) { + value = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.NFC_LLCP_WKS, 0); + } else if (param.equals(PROPERTY_LLCP_OPT_VALUE)) { + value = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.NFC_LLCP_OPT, 0); + } else if (param.equals(PROPERTY_NFC_DISCOVERY_A_VALUE)) { + value = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.NFC_DISCOVERY_A, 0); + } else if (param.equals(PROPERTY_NFC_DISCOVERY_B_VALUE)) { + value = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.NFC_DISCOVERY_B, 0); + } else if (param.equals(PROPERTY_NFC_DISCOVERY_F_VALUE)) { + value = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.NFC_DISCOVERY_F, 0); + } else if (param.equals(PROPERTY_NFC_DISCOVERY_NFCIP_VALUE)) { + value = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.NFC_DISCOVERY_NFCIP, 0); + } else if (param.equals(PROPERTY_NFC_DISCOVERY_15693_VALUE)) { + value = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.NFC_DISCOVERY_15693, 0); + } else { + return "Unknown property"; + } + + if (param.equals(PROPERTY_NFC_DISCOVERY_A_VALUE) + || param.equals(PROPERTY_NFC_DISCOVERY_B_VALUE) + || param.equals(PROPERTY_NFC_DISCOVERY_F_VALUE) + || param.equals(PROPERTY_NFC_DISCOVERY_NFCIP_VALUE) + || param.equals(PROPERTY_NFC_DISCOVERY_15693_VALUE)) { + if (value == 0) { + return "false"; + } else if (value == 1) { + return "true"; + } else { + return "Unknown Value"; + } + }else{ + return "" + value; + } + + } + + public int[] getSecureElementList() throws RemoteException { + int[] list = null; + if (mIsNfcEnabled == true) { + list = mManager.doGetSecureElementList(); + } + return list; + } + + public int getSelectedSecureElement() throws RemoteException { + return mSelectedSeId; + } + + public boolean isEnabled() throws RemoteException { + return mIsNfcEnabled; + } + + public int openP2pConnection() throws RemoteException { + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return ErrorCodes.ERROR_NOT_INITIALIZED; + } + + mContext.enforceCallingPermission(android.Manifest.permission.NFC_RAW, + "NFC_RAW permission required to open NFC P2P connection"); + if (!mOpenPending) { + NativeP2pDevice device; + mOpenPending = true; + device = mManager.doOpenP2pConnection(mTimeout); + if (device != null) { + /* add device to the Hmap */ + mObjectMap.put(device.getHandle(), device); + return device.getHandle(); + } else { + mOpenPending = false; + /* Restart polling loop for notification */ + mManager.enableDiscovery(DISCOVERY_MODE_READER); + return ErrorCodes.ERROR_IO; + } + } else { + return ErrorCodes.ERROR_BUSY; + } + + } + + public int openTagConnection() throws RemoteException { + NativeNfcTag tag; + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return ErrorCodes.ERROR_NOT_INITIALIZED; + } + + mContext.enforceCallingPermission(android.Manifest.permission.NFC_RAW, + "NFC_RAW permission required to open NFC Tag connection"); + if (!mOpenPending) { + mOpenPending = true; + tag = mManager.doOpenTagConnection(mTimeout); + if (tag != null) { + mObjectMap.put(tag.getHandle(), tag); + return tag.getHandle(); + } else { + mOpenPending = false; + /* Restart polling loop for notification */ + mManager.enableDiscovery(DISCOVERY_MODE_READER); + return ErrorCodes.ERROR_IO; + } + } else { + return ErrorCodes.ERROR_BUSY; + } + } + + public int selectSecureElement(int seId) throws RemoteException { + // Check if NFC is enabled + if (!mIsNfcEnabled) { + return ErrorCodes.ERROR_NOT_INITIALIZED; + } + + if (mSelectedSeId == seId) { + return ErrorCodes.ERROR_SE_ALREADY_SELECTED; + } + + if (mSelectedSeId != 0) { + return ErrorCodes.ERROR_SE_CONNECTED; + } + + mContext.enforceCallingPermission(android.Manifest.permission.NFC_ADMIN, + "NFC_ADMIN permission required to select NFC Secure Element"); + + mSelectedSeId = seId; + mManager.doSelectSecureElement(mSelectedSeId); + + /* Store that a secure element is selected */ + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.NFC_SECURE_ELEMENT_ON, 1); + + /* Store the ID of the Secure Element Selected */ + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.NFC_SECURE_ELEMENT_ID, mSelectedSeId); + + mNfcSecureElementState = 1; + + return ErrorCodes.SUCCESS; + + } + + public void setOpenTimeout(int timeout) throws RemoteException { + mContext.enforceCallingPermission(android.Manifest.permission.NFC_RAW, + "NFC_RAW permission required to set NFC connection timeout"); + mTimeout = timeout; + } + + public int setProperties(String param, String value) throws RemoteException { + mContext.enforceCallingPermission(android.Manifest.permission.NFC_ADMIN, + "NFC_ADMIN permission required to set NFC Properties"); + + if (isEnabled()) { + return ErrorCodes.ERROR_NFC_ON; + } + + int val; + + /* Check params validity */ + if (param == null || value == null) { + return ErrorCodes.ERROR_INVALID_PARAM; + } + + if (param.equals(PROPERTY_LLCP_LTO_VALUE)) { + val = Integer.parseInt(value); + + /* Check params */ + if (val > LLCP_LTO_MAX_VALUE) + return ErrorCodes.ERROR_INVALID_PARAM; + + /* Store value */ + Settings.System + .putInt(mContext.getContentResolver(), Settings.System.NFC_LLCP_LTO, val); + + /* Update JNI */ + mManager.doSetProperties(PROPERTY_LLCP_LTO, val); + + } else if (param.equals(PROPERTY_LLCP_MIU_VALUE)) { + val = Integer.parseInt(value); + + /* Check params */ + if ((val < LLCP_MIU_DEFAULT_VALUE) || (val > LLCP_MIU_MAX_VALUE)) + return ErrorCodes.ERROR_INVALID_PARAM; + + /* Store value */ + Settings.System + .putInt(mContext.getContentResolver(), Settings.System.NFC_LLCP_MIU, val); + + /* Update JNI */ + mManager.doSetProperties(PROPERTY_LLCP_MIU, val); + + } else if (param.equals(PROPERTY_LLCP_WKS_VALUE)) { + val = Integer.parseInt(value); + + /* Check params */ + if (val > LLCP_WKS_MAX_VALUE) + return ErrorCodes.ERROR_INVALID_PARAM; + + /* Store value */ + Settings.System + .putInt(mContext.getContentResolver(), Settings.System.NFC_LLCP_WKS, val); + + /* Update JNI */ + mManager.doSetProperties(PROPERTY_LLCP_WKS, val); + + } else if (param.equals(PROPERTY_LLCP_OPT_VALUE)) { + val = Integer.parseInt(value); + + /* Check params */ + if (val > LLCP_OPT_MAX_VALUE) + return ErrorCodes.ERROR_INVALID_PARAM; + + /* Store value */ + Settings.System + .putInt(mContext.getContentResolver(), Settings.System.NFC_LLCP_OPT, val); + + /* Update JNI */ + mManager.doSetProperties(PROPERTY_LLCP_OPT, val); + + } else if (param.equals(PROPERTY_NFC_DISCOVERY_A_VALUE)) { + + /* Check params */ + if (value.equals("true")) { + val = 1; + } else if (value.equals("false")) { + val = 0; + } else { + return ErrorCodes.ERROR_INVALID_PARAM; + } + /* Store value */ + Settings.System.putInt(mContext.getContentResolver(), Settings.System.NFC_DISCOVERY_A, + val); + + /* Update JNI */ + mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_A, val); + + } else if (param.equals(PROPERTY_NFC_DISCOVERY_B_VALUE)) { + + /* Check params */ + if (value.equals("true")) { + val = 1; + } else if (value.equals("false")) { + val = 0; + } else { + return ErrorCodes.ERROR_INVALID_PARAM; + } + + /* Store value */ + Settings.System.putInt(mContext.getContentResolver(), Settings.System.NFC_DISCOVERY_B, + val); + + /* Update JNI */ + mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_B, val); + + } else if (param.equals(PROPERTY_NFC_DISCOVERY_F_VALUE)) { + + /* Check params */ + if (value.equals("true")) { + val = 1; + } else if (value.equals("false")) { + val = 0; + } else { + return ErrorCodes.ERROR_INVALID_PARAM; + } + + /* Store value */ + Settings.System.putInt(mContext.getContentResolver(), Settings.System.NFC_DISCOVERY_F, + val); + + /* Update JNI */ + mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_F, val); + + } else if (param.equals(PROPERTY_NFC_DISCOVERY_15693_VALUE)) { + + /* Check params */ + if (value.equals("true")) { + val = 1; + } else if (value.equals("false")) { + val = 0; + } else { + return ErrorCodes.ERROR_INVALID_PARAM; + } + + /* Store value */ + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.NFC_DISCOVERY_15693, val); + + /* Update JNI */ + mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_15693, val); + + } else if (param.equals(PROPERTY_NFC_DISCOVERY_NFCIP_VALUE)) { + + /* Check params */ + if (value.equals("true")) { + val = 1; + } else if (value.equals("false")) { + val = 0; + } else { + return ErrorCodes.ERROR_INVALID_PARAM; + } + + /* Store value */ + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.NFC_DISCOVERY_NFCIP, val); + + /* Update JNI */ + mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_NFCIP, val); + } else { + return ErrorCodes.ERROR_INVALID_PARAM; + } + + return ErrorCodes.SUCCESS; + } + + // Reset all internals + private void reset() { + + // Clear tables + mObjectMap.clear(); + mSocketMap.clear(); + mRegisteredSocketList.clear(); + + // Reset variables + mLlcpLinkState = NfcManager.LLCP_LINK_STATE_DEACTIVATED; + mNbSocketCreated = 0; + mIsNfcEnabled = false; + mSelectedSeId = 0; + mTimeout = 0; + mNfcState = NFC_STATE_DISABLED; + mOpenPending = false; + } + + private Object findObject(int key) { + Object device = null; + + device = mObjectMap.get(key); + + return device; + } + + private void RemoveObject(int key) { + mObjectMap.remove(key); + } + + private Object findSocket(int key) { + Object socket = null; + + socket = mSocketMap.get(key); + + return socket; + } + + private void RemoveSocket(int key) { + mSocketMap.remove(key); + } + + private boolean CheckSocketSap(int sap) { + /* List of sockets registered */ + ListIterator<RegisteredSocket> it = mRegisteredSocketList.listIterator(); + + while (it.hasNext()) { + RegisteredSocket registeredSocket = it.next(); + + if (sap == registeredSocket.mSap) { + /* SAP already used */ + return false; + } + } + return true; + } + + private boolean CheckSocketOptions(int miu, int rw, int linearBufferlength) { + + if (rw > LLCP_RW_MAX_VALUE || miu < LLCP_MIU_DEFAULT_VALUE || linearBufferlength < miu) { + return false; + } + return true; + } + + private boolean CheckSocketServiceName(String sn) { + + /* List of sockets registered */ + ListIterator<RegisteredSocket> it = mRegisteredSocketList.listIterator(); + + while (it.hasNext()) { + RegisteredSocket registeredSocket = it.next(); + + if (sn.equals(registeredSocket.mServiceName)) { + /* Service Name already used */ + return false; + } + } + return true; + } + + private void RemoveRegisteredSocket(int nativeHandle) { + /* check if sockets are registered */ + ListIterator<RegisteredSocket> it = mRegisteredSocketList.listIterator(); + + while (it.hasNext()) { + RegisteredSocket registeredSocket = it.next(); + if (registeredSocket.mHandle == nativeHandle) { + /* remove the registered socket from the list */ + it.remove(); + Log.d(TAG, "socket removed"); + } + } + } + + /* + * RegisteredSocket class to store the creation request of socket until the + * LLCP link in not activated + */ + private class RegisteredSocket { + private int mType; + + private int mHandle; + + private int mSap; + + private int mMiu; + + private int mRw; + + private String mServiceName; + + private int mlinearBufferLength; + + RegisteredSocket(int type, int handle, int sap, String sn, int miu, int rw, + int linearBufferLength) { + mType = type; + mHandle = handle; + mSap = sap; + mServiceName = sn; + mRw = rw; + mMiu = miu; + mlinearBufferLength = linearBufferLength; + } + + RegisteredSocket(int type, int handle, int sap, int miu, int rw, int linearBufferLength) { + mType = type; + mHandle = handle; + mSap = sap; + mRw = rw; + mMiu = miu; + mlinearBufferLength = linearBufferLength; + } + + RegisteredSocket(int type, int handle, int sap) { + mType = type; + mHandle = handle; + mSap = sap; + } + } + + private BroadcastReceiver mNfcServiceReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + Log.d(TAG, "Internal NFC Intent received"); + + /* LLCP Link deactivation */ + if (intent.getAction().equals(NfcManager.LLCP_LINK_STATE_CHANGED_ACTION)) { + mLlcpLinkState = intent.getIntExtra(NfcManager.LLCP_LINK_STATE_CHANGED_EXTRA, + NfcManager.LLCP_LINK_STATE_DEACTIVATED); + + if (mLlcpLinkState == NfcManager.LLCP_LINK_STATE_DEACTIVATED) { + /* restart polling loop */ + mManager.enableDiscovery(DISCOVERY_MODE_READER); + } + + } + /* LLCP Link activation */ + else if (intent.getAction().equals( + NativeNfcManager.INTERNAL_LLCP_LINK_STATE_CHANGED_ACTION)) { + + mLlcpLinkState = intent.getIntExtra( + NativeNfcManager.INTERNAL_LLCP_LINK_STATE_CHANGED_EXTRA, + NfcManager.LLCP_LINK_STATE_DEACTIVATED); + + if (mLlcpLinkState == NfcManager.LLCP_LINK_STATE_ACTIVATED) { + /* check if sockets are registered */ + ListIterator<RegisteredSocket> it = mRegisteredSocketList.listIterator(); + + Log.d(TAG, "Nb socket resgistered = " + mRegisteredSocketList.size()); + + while (it.hasNext()) { + RegisteredSocket registeredSocket = it.next(); + + switch (registeredSocket.mType) { + case LLCP_SERVICE_SOCKET_TYPE: + Log.d(TAG, "Registered Llcp Service Socket"); + NativeLlcpServiceSocket serviceSocket; + + serviceSocket = mManager.doCreateLlcpServiceSocket( + registeredSocket.mSap, registeredSocket.mServiceName, + registeredSocket.mMiu, registeredSocket.mRw, + registeredSocket.mlinearBufferLength); + + if (serviceSocket != null) { + /* Add the socket into the socket map */ + mSocketMap.put(registeredSocket.mHandle, serviceSocket); + } else { + /* + * socket creation error - update the socket + * handle counter + */ + mGeneratedSocketHandle -= 1; + } + break; + + case LLCP_SOCKET_TYPE: + Log.d(TAG, "Registered Llcp Socket"); + NativeLlcpSocket clientSocket; + clientSocket = mManager.doCreateLlcpSocket(registeredSocket.mSap, + registeredSocket.mMiu, registeredSocket.mRw, + registeredSocket.mlinearBufferLength); + if (clientSocket != null) { + /* Add the socket into the socket map */ + mSocketMap.put(registeredSocket.mHandle, clientSocket); + } else { + /* + * socket creation error - update the socket + * handle counter + */ + mGeneratedSocketHandle -= 1; + } + break; + + case LLCP_CONNECTIONLESS_SOCKET_TYPE: + Log.d(TAG, "Registered Llcp Connectionless Socket"); + NativeLlcpConnectionlessSocket connectionlessSocket; + connectionlessSocket = mManager + .doCreateLlcpConnectionlessSocket(registeredSocket.mSap); + if (connectionlessSocket != null) { + /* Add the socket into the socket map */ + mSocketMap.put(registeredSocket.mHandle, connectionlessSocket); + } else { + /* + * socket creation error - update the socket + * handle counter + */ + mGeneratedSocketHandle -= 1; + } + break; + + } + } + + /* Remove all registered socket from the list */ + mRegisteredSocketList.clear(); + + /* Broadcast Intent Link LLCP activated */ + Intent LlcpLinkIntent = new Intent(); + LlcpLinkIntent.setAction(NfcManager.LLCP_LINK_STATE_CHANGED_ACTION); + + LlcpLinkIntent.putExtra(NfcManager.LLCP_LINK_STATE_CHANGED_EXTRA, + NfcManager.LLCP_LINK_STATE_ACTIVATED); + + Log.d(TAG, "Broadcasting LLCP activation"); + mContext.sendOrderedBroadcast(LlcpLinkIntent, + android.Manifest.permission.NFC_LLCP); + } + } + /* Target Deactivated */ + else if (intent.getAction().equals( + NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION)) { + if(mOpenPending != false){ + mOpenPending = false; + } + /* Restart polling loop for notification */ + mManager.enableDiscovery(DISCOVERY_MODE_READER); + + } + } + }; +} |